Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(277)

Side by Side Diff: media/filters/chunk_demuxer.cc

Issue 180153003: Implement core of compliant MediaSource coded frame processing (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase to ToT in preparation for dcommit Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/filters/chunk_demuxer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/filters/chunk_demuxer.h" 5 #include "media/filters/chunk_demuxer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits> 8 #include <limits>
9 #include <list> 9 #include <list>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/callback_helpers.h" 12 #include "base/callback_helpers.h"
13 #include "base/location.h" 13 #include "base/location.h"
14 #include "base/message_loop/message_loop_proxy.h" 14 #include "base/message_loop/message_loop_proxy.h"
15 #include "base/stl_util.h" 15 #include "base/stl_util.h"
16 #include "media/base/audio_decoder_config.h" 16 #include "media/base/audio_decoder_config.h"
17 #include "media/base/bind_to_current_loop.h" 17 #include "media/base/bind_to_current_loop.h"
18 #include "media/base/stream_parser_buffer.h" 18 #include "media/base/stream_parser_buffer.h"
19 #include "media/base/video_decoder_config.h" 19 #include "media/base/video_decoder_config.h"
20 #include "media/filters/frame_processor.h"
20 #include "media/filters/legacy_frame_processor.h" 21 #include "media/filters/legacy_frame_processor.h"
21 #include "media/filters/stream_parser_factory.h" 22 #include "media/filters/stream_parser_factory.h"
22 23
23 using base::TimeDelta; 24 using base::TimeDelta;
24 25
25 namespace media { 26 namespace media {
26 27
27 static TimeDelta EndTimestamp(const StreamParser::BufferQueue& queue) { 28 static TimeDelta EndTimestamp(const StreamParser::BufferQueue& queue) {
28 return queue.back()->timestamp() + queue.back()->duration(); 29 return queue.back()->timestamp() + queue.back()->duration();
29 } 30 }
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 // Calls Remove(|start|, |end|, |duration|) on all 126 // Calls Remove(|start|, |end|, |duration|) on all
126 // ChunkDemuxerStreams managed by this object. 127 // ChunkDemuxerStreams managed by this object.
127 void Remove(TimeDelta start, TimeDelta end, TimeDelta duration); 128 void Remove(TimeDelta start, TimeDelta end, TimeDelta duration);
128 129
129 // Returns true if currently parsing a media segment, or false otherwise. 130 // Returns true if currently parsing a media segment, or false otherwise.
130 bool parsing_media_segment() const { return parsing_media_segment_; } 131 bool parsing_media_segment() const { return parsing_media_segment_; }
131 132
132 // Sets |frame_processor_|'s sequence mode to |sequence_mode|. 133 // Sets |frame_processor_|'s sequence mode to |sequence_mode|.
133 void SetSequenceMode(bool sequence_mode); 134 void SetSequenceMode(bool sequence_mode);
134 135
136 // Signals the coded frame processor to update its group start timestamp to be
137 // |timestamp_offset| if it is in sequence append mode.
138 void SetGroupStartTimestampIfInSequenceMode(base::TimeDelta timestamp_offset);
139
135 // Returns the range of buffered data in this source, capped at |duration|. 140 // Returns the range of buffered data in this source, capped at |duration|.
136 // |ended| - Set to true if end of stream has been signaled and the special 141 // |ended| - Set to true if end of stream has been signaled and the special
137 // end of stream range logic needs to be executed. 142 // end of stream range logic needs to be executed.
138 Ranges<TimeDelta> GetBufferedRanges(TimeDelta duration, bool ended) const; 143 Ranges<TimeDelta> GetBufferedRanges(TimeDelta duration, bool ended) const;
139 144
140 // Returns the highest buffered duration across all streams managed 145 // Returns the highest buffered duration across all streams managed
141 // by this object. 146 // by this object.
142 // Returns TimeDelta() if none of the streams contain buffered data. 147 // Returns TimeDelta() if none of the streams contain buffered data.
143 TimeDelta GetMaxBufferedDuration() const; 148 TimeDelta GetMaxBufferedDuration() const;
144 149
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 227
223 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap; 228 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap;
224 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers. 229 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers.
225 230
226 scoped_ptr<FrameProcessorBase> frame_processor_; 231 scoped_ptr<FrameProcessorBase> frame_processor_;
227 LogCB log_cb_; 232 LogCB log_cb_;
228 StreamParser::InitCB init_cb_; 233 StreamParser::InitCB init_cb_;
229 234
230 // Indicates that timestampOffset should be updated automatically during 235 // Indicates that timestampOffset should be updated automatically during
231 // OnNewBuffers() based on the earliest end timestamp of the buffers provided. 236 // OnNewBuffers() based on the earliest end timestamp of the buffers provided.
237 // TODO(wolenetz): Refactor this function while integrating April 29, 2014
238 // changes to MSE spec. See http://crbug.com/371499.
232 bool auto_update_timestamp_offset_; 239 bool auto_update_timestamp_offset_;
233 240
234 DISALLOW_COPY_AND_ASSIGN(SourceState); 241 DISALLOW_COPY_AND_ASSIGN(SourceState);
235 }; 242 };
236 243
237 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser, 244 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser,
238 scoped_ptr<FrameProcessorBase> frame_processor, 245 scoped_ptr<FrameProcessorBase> frame_processor,
239 const LogCB& log_cb, 246 const LogCB& log_cb,
240 const CreateDemuxerStreamCB& create_demuxer_stream_cb) 247 const CreateDemuxerStreamCB& create_demuxer_stream_cb)
241 : create_demuxer_stream_cb_(create_demuxer_stream_cb), 248 : create_demuxer_stream_cb_(create_demuxer_stream_cb),
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
279 base::Bind(&SourceState::OnEndOfMediaSegment, base::Unretained(this)), 286 base::Bind(&SourceState::OnEndOfMediaSegment, base::Unretained(this)),
280 log_cb_); 287 log_cb_);
281 } 288 }
282 289
283 void SourceState::SetSequenceMode(bool sequence_mode) { 290 void SourceState::SetSequenceMode(bool sequence_mode) {
284 DCHECK(!parsing_media_segment_); 291 DCHECK(!parsing_media_segment_);
285 292
286 frame_processor_->SetSequenceMode(sequence_mode); 293 frame_processor_->SetSequenceMode(sequence_mode);
287 } 294 }
288 295
296 void SourceState::SetGroupStartTimestampIfInSequenceMode(
297 base::TimeDelta timestamp_offset) {
298 DCHECK(!parsing_media_segment_);
299
300 frame_processor_->SetGroupStartTimestampIfInSequenceMode(timestamp_offset);
301 }
302
289 bool SourceState::Append(const uint8* data, size_t length, 303 bool SourceState::Append(const uint8* data, size_t length,
290 TimeDelta append_window_start, 304 TimeDelta append_window_start,
291 TimeDelta append_window_end, 305 TimeDelta append_window_end,
292 TimeDelta* timestamp_offset) { 306 TimeDelta* timestamp_offset) {
293 DCHECK(timestamp_offset); 307 DCHECK(timestamp_offset);
294 DCHECK(!timestamp_offset_during_append_); 308 DCHECK(!timestamp_offset_during_append_);
295 timestamp_offset_during_append_ = timestamp_offset;
296 append_window_start_during_append_ = append_window_start; 309 append_window_start_during_append_ = append_window_start;
297 append_window_end_during_append_ = append_window_end; 310 append_window_end_during_append_ = append_window_end;
311 timestamp_offset_during_append_ = timestamp_offset;
298 312
299 // TODO(wolenetz/acolwell): Curry and pass a NewBuffersCB here bound with 313 // TODO(wolenetz/acolwell): Curry and pass a NewBuffersCB here bound with
300 // append window and timestamp offset pointer. See http://crbug.com/351454. 314 // append window and timestamp offset pointer. See http://crbug.com/351454.
301 bool err = stream_parser_->Parse(data, length); 315 bool err = stream_parser_->Parse(data, length);
302 timestamp_offset_during_append_ = NULL; 316 timestamp_offset_during_append_ = NULL;
303 return err; 317 return err;
304 } 318 }
305 319
306 void SourceState::Abort(TimeDelta append_window_start, 320 void SourceState::Abort(TimeDelta append_window_start,
307 TimeDelta append_window_end, 321 TimeDelta append_window_end,
(...skipping 841 matching lines...) Expand 10 before | Expand all | Expand 10 after
1149 if ((has_audio && !source_id_audio_.empty()) || 1163 if ((has_audio && !source_id_audio_.empty()) ||
1150 (has_video && !source_id_video_.empty())) 1164 (has_video && !source_id_video_.empty()))
1151 return kReachedIdLimit; 1165 return kReachedIdLimit;
1152 1166
1153 if (has_audio) 1167 if (has_audio)
1154 source_id_audio_ = id; 1168 source_id_audio_ = id;
1155 1169
1156 if (has_video) 1170 if (has_video)
1157 source_id_video_ = id; 1171 source_id_video_ = id;
1158 1172
1159 if (!use_legacy_frame_processor) { 1173 scoped_ptr<FrameProcessorBase> frame_processor;
1160 DLOG(WARNING) << "New frame processor is not yet supported. Using legacy."; 1174 if (use_legacy_frame_processor) {
1175 frame_processor.reset(new LegacyFrameProcessor(
1176 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary,
1177 base::Unretained(this))));
1178 } else {
1179 frame_processor.reset(new FrameProcessor(
1180 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary,
1181 base::Unretained(this))));
1161 } 1182 }
1162 1183
1163 scoped_ptr<FrameProcessorBase> frame_processor(new LegacyFrameProcessor(
1164 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary,
1165 base::Unretained(this))));
1166
1167 scoped_ptr<SourceState> source_state( 1184 scoped_ptr<SourceState> source_state(
1168 new SourceState(stream_parser.Pass(), 1185 new SourceState(stream_parser.Pass(),
1169 frame_processor.Pass(), log_cb_, 1186 frame_processor.Pass(), log_cb_,
1170 base::Bind(&ChunkDemuxer::CreateDemuxerStream, 1187 base::Bind(&ChunkDemuxer::CreateDemuxerStream,
1171 base::Unretained(this)))); 1188 base::Unretained(this))));
1172 1189
1173 SourceState::NewTextTrackCB new_text_track_cb; 1190 SourceState::NewTextTrackCB new_text_track_cb;
1174 1191
1175 if (enable_text_) { 1192 if (enable_text_) {
1176 new_text_track_cb = base::Bind(&ChunkDemuxer::OnNewTextTrack, 1193 new_text_track_cb = base::Bind(&ChunkDemuxer::OnNewTextTrack,
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
1382 void ChunkDemuxer::SetSequenceMode(const std::string& id, 1399 void ChunkDemuxer::SetSequenceMode(const std::string& id,
1383 bool sequence_mode) { 1400 bool sequence_mode) {
1384 base::AutoLock auto_lock(lock_); 1401 base::AutoLock auto_lock(lock_);
1385 DVLOG(1) << "SetSequenceMode(" << id << ", " << sequence_mode << ")"; 1402 DVLOG(1) << "SetSequenceMode(" << id << ", " << sequence_mode << ")";
1386 CHECK(IsValidId(id)); 1403 CHECK(IsValidId(id));
1387 DCHECK_NE(state_, ENDED); 1404 DCHECK_NE(state_, ENDED);
1388 1405
1389 source_state_map_[id]->SetSequenceMode(sequence_mode); 1406 source_state_map_[id]->SetSequenceMode(sequence_mode);
1390 } 1407 }
1391 1408
1409 void ChunkDemuxer::SetGroupStartTimestampIfInSequenceMode(
1410 const std::string& id,
1411 base::TimeDelta timestamp_offset) {
1412 base::AutoLock auto_lock(lock_);
1413 DVLOG(1) << "SetGroupStartTimestampIfInSequenceMode(" << id << ", "
1414 << timestamp_offset.InSecondsF() << ")";
1415 CHECK(IsValidId(id));
1416 DCHECK_NE(state_, ENDED);
1417
1418 source_state_map_[id]->SetGroupStartTimestampIfInSequenceMode(
1419 timestamp_offset);
1420 }
1421
1422
1392 void ChunkDemuxer::MarkEndOfStream(PipelineStatus status) { 1423 void ChunkDemuxer::MarkEndOfStream(PipelineStatus status) {
1393 DVLOG(1) << "MarkEndOfStream(" << status << ")"; 1424 DVLOG(1) << "MarkEndOfStream(" << status << ")";
1394 base::AutoLock auto_lock(lock_); 1425 base::AutoLock auto_lock(lock_);
1395 DCHECK_NE(state_, WAITING_FOR_INIT); 1426 DCHECK_NE(state_, WAITING_FOR_INIT);
1396 DCHECK_NE(state_, ENDED); 1427 DCHECK_NE(state_, ENDED);
1397 1428
1398 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) 1429 if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
1399 return; 1430 return;
1400 1431
1401 if (state_ == INITIALIZING) { 1432 if (state_ == INITIALIZING) {
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
1612 1643
1613 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) { 1644 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) {
1614 DCHECK(duration_ != new_duration); 1645 DCHECK(duration_ != new_duration);
1615 user_specified_duration_ = -1; 1646 user_specified_duration_ = -1;
1616 duration_ = new_duration; 1647 duration_ = new_duration;
1617 host_->SetDuration(new_duration); 1648 host_->SetDuration(new_duration);
1618 } 1649 }
1619 1650
1620 void ChunkDemuxer::IncreaseDurationIfNecessary(TimeDelta new_duration) { 1651 void ChunkDemuxer::IncreaseDurationIfNecessary(TimeDelta new_duration) {
1621 DCHECK(new_duration != kNoTimestamp()); 1652 DCHECK(new_duration != kNoTimestamp());
1653 DCHECK(new_duration != kInfiniteDuration());
1654
1655 // Per April 1, 2014 MSE spec editor's draft:
1656 // https://dvcs.w3.org/hg/html-media/raw-file/d471a4412040/media-source/
1657 // media-source.html#sourcebuffer-coded-frame-processing
1658 // 5. If the media segment contains data beyond the current duration, then run
1659 // the duration change algorithm with new duration set to the maximum of
1660 // the current duration and the group end timestamp.
1622 1661
1623 if (new_duration <= duration_) 1662 if (new_duration <= duration_)
1624 return; 1663 return;
1625 1664
1626 DVLOG(2) << __FUNCTION__ << ": Increasing duration: " 1665 DVLOG(2) << __FUNCTION__ << ": Increasing duration: "
1627 << duration_.InSecondsF() << " -> " << new_duration.InSecondsF(); 1666 << duration_.InSecondsF() << " -> " << new_duration.InSecondsF();
1628 1667
1629 UpdateDuration(new_duration); 1668 UpdateDuration(new_duration);
1630 } 1669 }
1631 1670
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
1696 } 1735 }
1697 1736
1698 void ChunkDemuxer::ShutdownAllStreams() { 1737 void ChunkDemuxer::ShutdownAllStreams() {
1699 for (SourceStateMap::iterator itr = source_state_map_.begin(); 1738 for (SourceStateMap::iterator itr = source_state_map_.begin();
1700 itr != source_state_map_.end(); ++itr) { 1739 itr != source_state_map_.end(); ++itr) {
1701 itr->second->Shutdown(); 1740 itr->second->Shutdown();
1702 } 1741 }
1703 } 1742 }
1704 1743
1705 } // namespace media 1744 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/chunk_demuxer.h ('k') | media/filters/chunk_demuxer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698