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

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

Issue 195973006: Allow StreamParsers to request automatic timestampOffset updates. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Unittest. Created 6 years, 9 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
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/legacy_frame_processor.h" 20 #include "media/filters/legacy_frame_processor.h"
21 #include "media/filters/stream_parser_factory.h" 21 #include "media/filters/stream_parser_factory.h"
22 22
23 using base::TimeDelta; 23 using base::TimeDelta;
24 24
25 namespace media { 25 namespace media {
26 26
27 static TimeDelta EndTimestamp(const StreamParser::BufferQueue& queue) {
28 return queue.back()->timestamp() + queue.back()->duration();
29 }
30
27 // List of time ranges for each SourceBuffer. 31 // List of time ranges for each SourceBuffer.
28 typedef std::list<Ranges<TimeDelta> > RangesList; 32 typedef std::list<Ranges<TimeDelta> > RangesList;
29 static Ranges<TimeDelta> ComputeIntersection(const RangesList& activeRanges, 33 static Ranges<TimeDelta> ComputeIntersection(const RangesList& activeRanges,
30 bool ended) { 34 bool ended) {
31 // Implementation of HTMLMediaElement.buffered algorithm in MSE spec. 35 // Implementation of HTMLMediaElement.buffered algorithm in MSE spec.
32 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-sourc e.html#dom-htmlmediaelement.buffered 36 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-sourc e.html#dom-htmlmediaelement.buffered
33 37
34 // Step 1: If activeSourceBuffers.length equals 0 then return an empty 38 // Step 1: If activeSourceBuffers.length equals 0 then return an empty
35 // TimeRanges object and abort these steps. 39 // TimeRanges object and abort these steps.
36 if (activeRanges.empty()) 40 if (activeRanges.empty())
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
82 // Contains state belonging to a source id. 86 // Contains state belonging to a source id.
83 class SourceState { 87 class SourceState {
84 public: 88 public:
85 // Callback signature used to create ChunkDemuxerStreams. 89 // Callback signature used to create ChunkDemuxerStreams.
86 typedef base::Callback<ChunkDemuxerStream*( 90 typedef base::Callback<ChunkDemuxerStream*(
87 DemuxerStream::Type)> CreateDemuxerStreamCB; 91 DemuxerStream::Type)> CreateDemuxerStreamCB;
88 92
89 typedef base::Callback<void( 93 typedef base::Callback<void(
90 ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB; 94 ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB;
91 95
96 // First parameter - Indicates initialization success. Set to true if
97 // initialization was successful. False if an error
98 // occurred.
99 // Second parameter - Indicates the stream duration. Only contains a valid
100 // value if the first parameter is true.
101 typedef base::Callback<void(bool, base::TimeDelta)> InitCB;
acolwell GONE FROM CHROMIUM 2014/03/18 00:21:54 nit: drop base::
DaleCurtis 2014/03/18 01:26:56 Done.
102
92 SourceState( 103 SourceState(
93 scoped_ptr<StreamParser> stream_parser, 104 scoped_ptr<StreamParser> stream_parser,
94 scoped_ptr<FrameProcessorBase> frame_processor, const LogCB& log_cb, 105 scoped_ptr<FrameProcessorBase> frame_processor, const LogCB& log_cb,
95 const CreateDemuxerStreamCB& create_demuxer_stream_cb); 106 const CreateDemuxerStreamCB& create_demuxer_stream_cb);
96 107
97 ~SourceState(); 108 ~SourceState();
98 109
99 void Init(const StreamParser::InitCB& init_cb, 110 void Init(const InitCB& init_cb,
100 bool allow_audio, 111 bool allow_audio,
101 bool allow_video, 112 bool allow_video,
102 const StreamParser::NeedKeyCB& need_key_cb, 113 const StreamParser::NeedKeyCB& need_key_cb,
103 const NewTextTrackCB& new_text_track_cb); 114 const NewTextTrackCB& new_text_track_cb);
104 115
105 // Appends new data to the StreamParser. 116 // Appends new data to the StreamParser.
106 // Returns true if the data was successfully appended. Returns false if an 117 // Returns true if the data was successfully appended. Returns false if an
107 // error occurred. |*timestamp_offset| is used and possibly updated by the 118 // error occurred. |*timestamp_offset| is used and possibly updated by the
108 // append. |append_window_start| and |append_window_end| correspond to the MSE 119 // append. |append_window_start| and |append_window_end| correspond to the MSE
109 // spec's similarly named source buffer attributes that are used in coded 120 // spec's similarly named source buffer attributes that are used in coded
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 // Called by the |stream_parser_| when new buffers have been parsed. 181 // Called by the |stream_parser_| when new buffers have been parsed.
171 // It processes the new buffers using |frame_processor_|, which includes 182 // It processes the new buffers using |frame_processor_|, which includes
172 // appending the processed frames to associated demuxer streams for each 183 // appending the processed frames to associated demuxer streams for each
173 // frame's track. 184 // frame's track.
174 // Returns true on a successful call. Returns false if an error occurred while 185 // Returns true on a successful call. Returns false if an error occurred while
175 // processing the buffers. 186 // processing the buffers.
176 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, 187 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers,
177 const StreamParser::BufferQueue& video_buffers, 188 const StreamParser::BufferQueue& video_buffers,
178 const StreamParser::TextBufferQueueMap& text_map); 189 const StreamParser::TextBufferQueueMap& text_map);
179 190
191 void OnSourceInitDone(bool success,
192 TimeDelta duration,
193 bool auto_update_timestamp_offset);
194
180 CreateDemuxerStreamCB create_demuxer_stream_cb_; 195 CreateDemuxerStreamCB create_demuxer_stream_cb_;
181 NewTextTrackCB new_text_track_cb_; 196 NewTextTrackCB new_text_track_cb_;
182 197
183 // During Append(), if OnNewBuffers() coded frame processing updates the 198 // During Append(), if OnNewBuffers() coded frame processing updates the
184 // timestamp offset then |*timestamp_offset_during_append_| is also updated 199 // timestamp offset then |*timestamp_offset_during_append_| is also updated
185 // so Append()'s caller can know the new offset. This pointer is only non-NULL 200 // so Append()'s caller can know the new offset. This pointer is only non-NULL
186 // during the lifetime of an Append() call. 201 // during the lifetime of an Append() call.
187 TimeDelta* timestamp_offset_during_append_; 202 TimeDelta* timestamp_offset_during_append_;
188 203
189 // During Append(), coded frame processing triggered by OnNewBuffers() 204 // During Append(), coded frame processing triggered by OnNewBuffers()
(...skipping 19 matching lines...) Expand all
209 scoped_ptr<StreamParser> stream_parser_; 224 scoped_ptr<StreamParser> stream_parser_;
210 225
211 ChunkDemuxerStream* audio_; // Not owned by |this|. 226 ChunkDemuxerStream* audio_; // Not owned by |this|.
212 ChunkDemuxerStream* video_; // Not owned by |this|. 227 ChunkDemuxerStream* video_; // Not owned by |this|.
213 228
214 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap; 229 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap;
215 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers. 230 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers.
216 231
217 scoped_ptr<FrameProcessorBase> frame_processor_; 232 scoped_ptr<FrameProcessorBase> frame_processor_;
218 LogCB log_cb_; 233 LogCB log_cb_;
234 InitCB init_cb_;
235
236 // Indicates that timestampOffset should be updated automatically during
237 // OnNewBuffers() based on the earliest end timestamp of the buffers provided.
238 bool auto_update_timestamp_offset_;
219 239
220 DISALLOW_COPY_AND_ASSIGN(SourceState); 240 DISALLOW_COPY_AND_ASSIGN(SourceState);
221 }; 241 };
222 242
223 SourceState::SourceState( 243 SourceState::SourceState(
224 scoped_ptr<StreamParser> stream_parser, 244 scoped_ptr<StreamParser> stream_parser,
225 scoped_ptr<FrameProcessorBase> frame_processor, 245 scoped_ptr<FrameProcessorBase> frame_processor,
226 const LogCB& log_cb, 246 const LogCB& log_cb,
227 const CreateDemuxerStreamCB& create_demuxer_stream_cb) 247 const CreateDemuxerStreamCB& create_demuxer_stream_cb)
228 : create_demuxer_stream_cb_(create_demuxer_stream_cb), 248 : create_demuxer_stream_cb_(create_demuxer_stream_cb),
229 timestamp_offset_during_append_(NULL), 249 timestamp_offset_during_append_(NULL),
230 new_media_segment_(false), 250 new_media_segment_(false),
231 parsing_media_segment_(false), 251 parsing_media_segment_(false),
232 stream_parser_(stream_parser.release()), 252 stream_parser_(stream_parser.release()),
233 audio_(NULL), 253 audio_(NULL),
234 video_(NULL), 254 video_(NULL),
235 frame_processor_(frame_processor.release()), 255 frame_processor_(frame_processor.release()),
236 log_cb_(log_cb) { 256 log_cb_(log_cb),
257 auto_update_timestamp_offset_(false) {
237 DCHECK(!create_demuxer_stream_cb_.is_null()); 258 DCHECK(!create_demuxer_stream_cb_.is_null());
238 DCHECK(frame_processor_); 259 DCHECK(frame_processor_);
239 } 260 }
240 261
241 SourceState::~SourceState() { 262 SourceState::~SourceState() {
242 Shutdown(); 263 Shutdown();
243 264
244 STLDeleteValues(&text_stream_map_); 265 STLDeleteValues(&text_stream_map_);
245 } 266 }
246 267
247 void SourceState::Init(const StreamParser::InitCB& init_cb, 268 void SourceState::Init(const InitCB& init_cb,
248 bool allow_audio, 269 bool allow_audio,
249 bool allow_video, 270 bool allow_video,
250 const StreamParser::NeedKeyCB& need_key_cb, 271 const StreamParser::NeedKeyCB& need_key_cb,
251 const NewTextTrackCB& new_text_track_cb) { 272 const NewTextTrackCB& new_text_track_cb) {
252 new_text_track_cb_ = new_text_track_cb; 273 new_text_track_cb_ = new_text_track_cb;
274 init_cb_ = init_cb;
253 275
254 stream_parser_->Init(init_cb, 276 stream_parser_->Init(base::Bind(&SourceState::OnSourceInitDone,
277 base::Unretained(this)),
255 base::Bind(&SourceState::OnNewConfigs, 278 base::Bind(&SourceState::OnNewConfigs,
256 base::Unretained(this), 279 base::Unretained(this),
257 allow_audio, 280 allow_audio,
258 allow_video), 281 allow_video),
259 base::Bind(&SourceState::OnNewBuffers, 282 base::Bind(&SourceState::OnNewBuffers,
260 base::Unretained(this)), 283 base::Unretained(this)),
261 new_text_track_cb_.is_null(), 284 new_text_track_cb_.is_null(),
262 need_key_cb, 285 need_key_cb,
263 base::Bind(&SourceState::OnNewMediaSegment, 286 base::Bind(&SourceState::OnNewMediaSegment,
264 base::Unretained(this)), 287 base::Unretained(this)),
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 new_media_segment_ = false; 654 new_media_segment_ = false;
632 } 655 }
633 656
634 bool SourceState::OnNewBuffers( 657 bool SourceState::OnNewBuffers(
635 const StreamParser::BufferQueue& audio_buffers, 658 const StreamParser::BufferQueue& audio_buffers,
636 const StreamParser::BufferQueue& video_buffers, 659 const StreamParser::BufferQueue& video_buffers,
637 const StreamParser::TextBufferQueueMap& text_map) { 660 const StreamParser::TextBufferQueueMap& text_map) {
638 DVLOG(2) << "OnNewBuffers()"; 661 DVLOG(2) << "OnNewBuffers()";
639 DCHECK(timestamp_offset_during_append_); 662 DCHECK(timestamp_offset_during_append_);
640 663
641 return frame_processor_->ProcessFrames( 664 const TimeDelta current_timestamp_offset = *timestamp_offset_during_append_;
642 audio_buffers, video_buffers, text_map, 665 const bool success =
643 append_window_start_during_append_, append_window_end_during_append_, 666 frame_processor_->ProcessFrames(audio_buffers,
644 &new_media_segment_, timestamp_offset_during_append_); 667 video_buffers,
668 text_map,
669 append_window_start_during_append_,
670 append_window_end_during_append_,
671 &new_media_segment_,
672 timestamp_offset_during_append_);
673
674 // Update the timestamp offset for audio/video tracks if it hasn't already
675 // been updated by the frame processor.
676 const bool have_audio_buffers = !audio_buffers.empty();
677 const bool have_video_buffers = !video_buffers.empty();
678 if (auto_update_timestamp_offset_ &&
679 current_timestamp_offset == *timestamp_offset_during_append_) {
680 if (have_audio_buffers && have_video_buffers) {
681 *timestamp_offset_during_append_ =
682 std::min(EndTimestamp(audio_buffers), EndTimestamp(video_buffers));
683 } else if (have_audio_buffers) {
684 *timestamp_offset_during_append_ = EndTimestamp(audio_buffers);
685 } else if (have_video_buffers) {
686 *timestamp_offset_during_append_ = EndTimestamp(video_buffers);
687 }
688 }
689
690 return success;
691 }
692
693 void SourceState::OnSourceInitDone(bool success,
694 TimeDelta duration,
695 bool auto_update_timestamp_offset) {
696 auto_update_timestamp_offset_ = auto_update_timestamp_offset;
697 init_cb_.Run(success, duration);
acolwell GONE FROM CHROMIUM 2014/03/18 00:21:54 nit: Use base::ResetAndReturn(&init_cb_) here.
DaleCurtis 2014/03/18 01:26:56 Done.
645 } 698 }
646 699
647 ChunkDemuxerStream::ChunkDemuxerStream(Type type) 700 ChunkDemuxerStream::ChunkDemuxerStream(Type type)
648 : type_(type), 701 : type_(type),
649 state_(UNINITIALIZED) { 702 state_(UNINITIALIZED) {
650 } 703 }
651 704
652 void ChunkDemuxerStream::StartReturningData() { 705 void ChunkDemuxerStream::StartReturningData() {
653 DVLOG(1) << "ChunkDemuxerStream::StartReturningData()"; 706 DVLOG(1) << "ChunkDemuxerStream::StartReturningData()";
654 base::AutoLock auto_lock(lock_); 707 base::AutoLock auto_lock(lock_);
(...skipping 755 matching lines...) Expand 10 before | Expand all | Expand 10 after
1410 for (SourceStateMap::const_iterator itr = source_state_map_.begin(); 1463 for (SourceStateMap::const_iterator itr = source_state_map_.begin();
1411 itr != source_state_map_.end(); ++itr) { 1464 itr != source_state_map_.end(); ++itr) {
1412 if (itr->second->IsSeekWaitingForData()) 1465 if (itr->second->IsSeekWaitingForData())
1413 return true; 1466 return true;
1414 } 1467 }
1415 1468
1416 return false; 1469 return false;
1417 } 1470 }
1418 1471
1419 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { 1472 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) {
1420 DVLOG(1) << "OnSourceInitDone(" << success << ", " 1473 DVLOG(1) << "OnSourceInitDone(" << success
1421 << duration.InSecondsF() << ")"; 1474 << ", " << duration.InSecondsF() << ")";
1422 lock_.AssertAcquired(); 1475 lock_.AssertAcquired();
1423 DCHECK_EQ(state_, INITIALIZING); 1476 DCHECK_EQ(state_, INITIALIZING);
1424 if (!success || (!audio_ && !video_)) { 1477 if (!success || (!audio_ && !video_)) {
1425 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 1478 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1426 return; 1479 return;
1427 } 1480 }
1428 1481
1429 if (duration != TimeDelta() && duration_ == kNoTimestamp()) 1482 if (duration != TimeDelta() && duration_ == kNoTimestamp())
1430 UpdateDuration(duration); 1483 UpdateDuration(duration);
1431 1484
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
1573 } 1626 }
1574 1627
1575 void ChunkDemuxer::ShutdownAllStreams() { 1628 void ChunkDemuxer::ShutdownAllStreams() {
1576 for (SourceStateMap::iterator itr = source_state_map_.begin(); 1629 for (SourceStateMap::iterator itr = source_state_map_.begin();
1577 itr != source_state_map_.end(); ++itr) { 1630 itr != source_state_map_.end(); ++itr) {
1578 itr->second->Shutdown(); 1631 itr->second->Shutdown();
1579 } 1632 }
1580 } 1633 }
1581 1634
1582 } // namespace media 1635 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698