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

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: Fix timestamp offset. 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
« no previous file with comments | « media/base/stream_parser.h ('k') | media/filters/pipeline_integration_test.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/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 // Compute the end timestamp for buffers within an append window range.
28 // TODO(dalecurtis): This code should probably live in the frame processor, but
29 // requires some spec updates before we can do so. For now it's a logical clone
30 // of LegacyFrameProcessor::FilterWithAppendWindow().
31 static TimeDelta EndTimestamp(const StreamParser::BufferQueue& buffers,
32 TimeDelta append_window_start,
33 TimeDelta append_window_end) {
34 TimeDelta end_timestamp = kNoTimestamp();
35
36 // Find the last buffer within the append window range.
37 for (StreamParser::BufferQueue::const_reverse_iterator itr = buffers.rbegin();
38 itr != buffers.rend();
39 ++itr) {
40 const scoped_refptr<StreamParserBuffer>& buffer = *itr;
41 if (buffer->timestamp() >= append_window_start &&
42 buffer->timestamp() <= append_window_end) {
43 end_timestamp = buffer->timestamp() + buffer->duration();
44 break;
45 }
46 }
47
48 return end_timestamp;
49 }
50
27 // List of time ranges for each SourceBuffer. 51 // List of time ranges for each SourceBuffer.
28 typedef std::list<Ranges<TimeDelta> > RangesList; 52 typedef std::list<Ranges<TimeDelta> > RangesList;
29 static Ranges<TimeDelta> ComputeIntersection(const RangesList& activeRanges, 53 static Ranges<TimeDelta> ComputeIntersection(const RangesList& activeRanges,
30 bool ended) { 54 bool ended) {
31 // Implementation of HTMLMediaElement.buffered algorithm in MSE spec. 55 // 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 56 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-sourc e.html#dom-htmlmediaelement.buffered
33 57
34 // Step 1: If activeSourceBuffers.length equals 0 then return an empty 58 // Step 1: If activeSourceBuffers.length equals 0 then return an empty
35 // TimeRanges object and abort these steps. 59 // TimeRanges object and abort these steps.
36 if (activeRanges.empty()) 60 if (activeRanges.empty())
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
82 // Contains state belonging to a source id. 106 // Contains state belonging to a source id.
83 class SourceState { 107 class SourceState {
84 public: 108 public:
85 // Callback signature used to create ChunkDemuxerStreams. 109 // Callback signature used to create ChunkDemuxerStreams.
86 typedef base::Callback<ChunkDemuxerStream*( 110 typedef base::Callback<ChunkDemuxerStream*(
87 DemuxerStream::Type)> CreateDemuxerStreamCB; 111 DemuxerStream::Type)> CreateDemuxerStreamCB;
88 112
89 typedef base::Callback<void( 113 typedef base::Callback<void(
90 ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB; 114 ChunkDemuxerStream*, const TextTrackConfig&)> NewTextTrackCB;
91 115
116 // First parameter - Indicates initialization success. Set to true if
117 // initialization was successful. False if an error
118 // occurred.
119 // Second parameter - Indicates the stream duration. Only contains a valid
120 // value if the first parameter is true.
121 typedef base::Callback<void(bool, TimeDelta)> InitCB;
122
92 SourceState( 123 SourceState(
93 scoped_ptr<StreamParser> stream_parser, 124 scoped_ptr<StreamParser> stream_parser,
94 scoped_ptr<FrameProcessorBase> frame_processor, const LogCB& log_cb, 125 scoped_ptr<FrameProcessorBase> frame_processor, const LogCB& log_cb,
95 const CreateDemuxerStreamCB& create_demuxer_stream_cb); 126 const CreateDemuxerStreamCB& create_demuxer_stream_cb);
96 127
97 ~SourceState(); 128 ~SourceState();
98 129
99 void Init(const StreamParser::InitCB& init_cb, 130 void Init(const InitCB& init_cb,
100 bool allow_audio, 131 bool allow_audio,
101 bool allow_video, 132 bool allow_video,
102 const StreamParser::NeedKeyCB& need_key_cb, 133 const StreamParser::NeedKeyCB& need_key_cb,
103 const NewTextTrackCB& new_text_track_cb); 134 const NewTextTrackCB& new_text_track_cb);
104 135
105 // Appends new data to the StreamParser. 136 // Appends new data to the StreamParser.
106 // Returns true if the data was successfully appended. Returns false if an 137 // Returns true if the data was successfully appended. Returns false if an
107 // error occurred. |*timestamp_offset| is used and possibly updated by the 138 // error occurred. |*timestamp_offset| is used and possibly updated by the
108 // append. |append_window_start| and |append_window_end| correspond to the MSE 139 // 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 140 // 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. 201 // Called by the |stream_parser_| when new buffers have been parsed.
171 // It processes the new buffers using |frame_processor_|, which includes 202 // It processes the new buffers using |frame_processor_|, which includes
172 // appending the processed frames to associated demuxer streams for each 203 // appending the processed frames to associated demuxer streams for each
173 // frame's track. 204 // frame's track.
174 // Returns true on a successful call. Returns false if an error occurred while 205 // Returns true on a successful call. Returns false if an error occurred while
175 // processing the buffers. 206 // processing the buffers.
176 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, 207 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers,
177 const StreamParser::BufferQueue& video_buffers, 208 const StreamParser::BufferQueue& video_buffers,
178 const StreamParser::TextBufferQueueMap& text_map); 209 const StreamParser::TextBufferQueueMap& text_map);
179 210
211 void OnSourceInitDone(bool success,
212 TimeDelta duration,
213 bool auto_update_timestamp_offset);
214
180 CreateDemuxerStreamCB create_demuxer_stream_cb_; 215 CreateDemuxerStreamCB create_demuxer_stream_cb_;
181 NewTextTrackCB new_text_track_cb_; 216 NewTextTrackCB new_text_track_cb_;
182 217
183 // During Append(), if OnNewBuffers() coded frame processing updates the 218 // During Append(), if OnNewBuffers() coded frame processing updates the
184 // timestamp offset then |*timestamp_offset_during_append_| is also updated 219 // 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 220 // so Append()'s caller can know the new offset. This pointer is only non-NULL
186 // during the lifetime of an Append() call. 221 // during the lifetime of an Append() call.
187 TimeDelta* timestamp_offset_during_append_; 222 TimeDelta* timestamp_offset_during_append_;
188 223
189 // During Append(), coded frame processing triggered by OnNewBuffers() 224 // During Append(), coded frame processing triggered by OnNewBuffers()
(...skipping 19 matching lines...) Expand all
209 scoped_ptr<StreamParser> stream_parser_; 244 scoped_ptr<StreamParser> stream_parser_;
210 245
211 ChunkDemuxerStream* audio_; // Not owned by |this|. 246 ChunkDemuxerStream* audio_; // Not owned by |this|.
212 ChunkDemuxerStream* video_; // Not owned by |this|. 247 ChunkDemuxerStream* video_; // Not owned by |this|.
213 248
214 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap; 249 typedef std::map<StreamParser::TrackId, ChunkDemuxerStream*> TextStreamMap;
215 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers. 250 TextStreamMap text_stream_map_; // |this| owns the map's stream pointers.
216 251
217 scoped_ptr<FrameProcessorBase> frame_processor_; 252 scoped_ptr<FrameProcessorBase> frame_processor_;
218 LogCB log_cb_; 253 LogCB log_cb_;
254 InitCB init_cb_;
255
256 // Indicates that timestampOffset should be updated automatically during
257 // OnNewBuffers() based on the earliest end timestamp of the buffers provided.
258 bool auto_update_timestamp_offset_;
219 259
220 DISALLOW_COPY_AND_ASSIGN(SourceState); 260 DISALLOW_COPY_AND_ASSIGN(SourceState);
221 }; 261 };
222 262
223 SourceState::SourceState( 263 SourceState::SourceState(
224 scoped_ptr<StreamParser> stream_parser, 264 scoped_ptr<StreamParser> stream_parser,
225 scoped_ptr<FrameProcessorBase> frame_processor, 265 scoped_ptr<FrameProcessorBase> frame_processor,
226 const LogCB& log_cb, 266 const LogCB& log_cb,
227 const CreateDemuxerStreamCB& create_demuxer_stream_cb) 267 const CreateDemuxerStreamCB& create_demuxer_stream_cb)
228 : create_demuxer_stream_cb_(create_demuxer_stream_cb), 268 : create_demuxer_stream_cb_(create_demuxer_stream_cb),
229 timestamp_offset_during_append_(NULL), 269 timestamp_offset_during_append_(NULL),
230 new_media_segment_(false), 270 new_media_segment_(false),
231 parsing_media_segment_(false), 271 parsing_media_segment_(false),
232 stream_parser_(stream_parser.release()), 272 stream_parser_(stream_parser.release()),
233 audio_(NULL), 273 audio_(NULL),
234 video_(NULL), 274 video_(NULL),
235 frame_processor_(frame_processor.release()), 275 frame_processor_(frame_processor.release()),
236 log_cb_(log_cb) { 276 log_cb_(log_cb),
277 auto_update_timestamp_offset_(false) {
237 DCHECK(!create_demuxer_stream_cb_.is_null()); 278 DCHECK(!create_demuxer_stream_cb_.is_null());
238 DCHECK(frame_processor_); 279 DCHECK(frame_processor_);
239 } 280 }
240 281
241 SourceState::~SourceState() { 282 SourceState::~SourceState() {
242 Shutdown(); 283 Shutdown();
243 284
244 STLDeleteValues(&text_stream_map_); 285 STLDeleteValues(&text_stream_map_);
245 } 286 }
246 287
247 void SourceState::Init(const StreamParser::InitCB& init_cb, 288 void SourceState::Init(const InitCB& init_cb,
248 bool allow_audio, 289 bool allow_audio,
249 bool allow_video, 290 bool allow_video,
250 const StreamParser::NeedKeyCB& need_key_cb, 291 const StreamParser::NeedKeyCB& need_key_cb,
251 const NewTextTrackCB& new_text_track_cb) { 292 const NewTextTrackCB& new_text_track_cb) {
252 new_text_track_cb_ = new_text_track_cb; 293 new_text_track_cb_ = new_text_track_cb;
294 init_cb_ = init_cb;
253 295
254 stream_parser_->Init(init_cb, 296 stream_parser_->Init(base::Bind(&SourceState::OnSourceInitDone,
297 base::Unretained(this)),
255 base::Bind(&SourceState::OnNewConfigs, 298 base::Bind(&SourceState::OnNewConfigs,
256 base::Unretained(this), 299 base::Unretained(this),
257 allow_audio, 300 allow_audio,
258 allow_video), 301 allow_video),
259 base::Bind(&SourceState::OnNewBuffers, 302 base::Bind(&SourceState::OnNewBuffers,
260 base::Unretained(this)), 303 base::Unretained(this)),
261 new_text_track_cb_.is_null(), 304 new_text_track_cb_.is_null(),
262 need_key_cb, 305 need_key_cb,
263 base::Bind(&SourceState::OnNewMediaSegment, 306 base::Bind(&SourceState::OnNewMediaSegment,
264 base::Unretained(this)), 307 base::Unretained(this)),
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 new_media_segment_ = false; 674 new_media_segment_ = false;
632 } 675 }
633 676
634 bool SourceState::OnNewBuffers( 677 bool SourceState::OnNewBuffers(
635 const StreamParser::BufferQueue& audio_buffers, 678 const StreamParser::BufferQueue& audio_buffers,
636 const StreamParser::BufferQueue& video_buffers, 679 const StreamParser::BufferQueue& video_buffers,
637 const StreamParser::TextBufferQueueMap& text_map) { 680 const StreamParser::TextBufferQueueMap& text_map) {
638 DVLOG(2) << "OnNewBuffers()"; 681 DVLOG(2) << "OnNewBuffers()";
639 DCHECK(timestamp_offset_during_append_); 682 DCHECK(timestamp_offset_during_append_);
640 683
641 return frame_processor_->ProcessFrames( 684 const TimeDelta current_timestamp_offset = *timestamp_offset_during_append_;
642 audio_buffers, video_buffers, text_map, 685 const bool success =
wolenetz 2014/03/18 02:09:30 nit: If |success| is false, this indicates a parse
DaleCurtis 2014/03/18 02:16:04 Done.
643 append_window_start_during_append_, append_window_end_during_append_, 686 frame_processor_->ProcessFrames(audio_buffers,
644 &new_media_segment_, timestamp_offset_during_append_); 687 video_buffers,
688 text_map,
689 append_window_start_during_append_,
690 append_window_end_during_append_,
691 &new_media_segment_,
692 timestamp_offset_during_append_);
693
694 // Update the timestamp offset for audio/video tracks if it hasn't already
695 // been updated by the frame processor.
696 if (auto_update_timestamp_offset_ &&
697 current_timestamp_offset == *timestamp_offset_during_append_) {
698 const TimeDelta audio_end = EndTimestamp(audio_buffers,
699 append_window_start_during_append_,
700 append_window_end_during_append_);
701 const TimeDelta video_end = EndTimestamp(audio_buffers,
wolenetz 2014/03/18 02:09:30 s/audio_buf/video_buf/
DaleCurtis 2014/03/18 02:16:04 Done.
702 append_window_start_during_append_,
703 append_window_end_during_append_);
704 const bool have_audio_buffers = audio_end != kNoTimestamp();
705 const bool have_video_buffers = video_end != kNoTimestamp();
706 if (have_audio_buffers && have_video_buffers) {
707 *timestamp_offset_during_append_ = std::min(audio_end, video_end);
708 } else if (have_audio_buffers) {
709 *timestamp_offset_during_append_ = audio_end;
710 } else if (have_video_buffers) {
711 *timestamp_offset_during_append_ = video_end;
712 }
713 }
714
715 return success;
716 }
717
718 void SourceState::OnSourceInitDone(bool success,
719 TimeDelta duration,
720 bool auto_update_timestamp_offset) {
721 auto_update_timestamp_offset_ = auto_update_timestamp_offset;
722 base::ResetAndReturn(&init_cb_).Run(success, duration);
645 } 723 }
646 724
647 ChunkDemuxerStream::ChunkDemuxerStream(Type type) 725 ChunkDemuxerStream::ChunkDemuxerStream(Type type)
648 : type_(type), 726 : type_(type),
649 state_(UNINITIALIZED) { 727 state_(UNINITIALIZED) {
650 } 728 }
651 729
652 void ChunkDemuxerStream::StartReturningData() { 730 void ChunkDemuxerStream::StartReturningData() {
653 DVLOG(1) << "ChunkDemuxerStream::StartReturningData()"; 731 DVLOG(1) << "ChunkDemuxerStream::StartReturningData()";
654 base::AutoLock auto_lock(lock_); 732 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(); 1488 for (SourceStateMap::const_iterator itr = source_state_map_.begin();
1411 itr != source_state_map_.end(); ++itr) { 1489 itr != source_state_map_.end(); ++itr) {
1412 if (itr->second->IsSeekWaitingForData()) 1490 if (itr->second->IsSeekWaitingForData())
1413 return true; 1491 return true;
1414 } 1492 }
1415 1493
1416 return false; 1494 return false;
1417 } 1495 }
1418 1496
1419 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { 1497 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) {
1420 DVLOG(1) << "OnSourceInitDone(" << success << ", " 1498 DVLOG(1) << "OnSourceInitDone(" << success
1421 << duration.InSecondsF() << ")"; 1499 << ", " << duration.InSecondsF() << ")";
1422 lock_.AssertAcquired(); 1500 lock_.AssertAcquired();
1423 DCHECK_EQ(state_, INITIALIZING); 1501 DCHECK_EQ(state_, INITIALIZING);
1424 if (!success || (!audio_ && !video_)) { 1502 if (!success || (!audio_ && !video_)) {
1425 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 1503 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
1426 return; 1504 return;
1427 } 1505 }
1428 1506
1429 if (duration != TimeDelta() && duration_ == kNoTimestamp()) 1507 if (duration != TimeDelta() && duration_ == kNoTimestamp())
1430 UpdateDuration(duration); 1508 UpdateDuration(duration);
1431 1509
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
1573 } 1651 }
1574 1652
1575 void ChunkDemuxer::ShutdownAllStreams() { 1653 void ChunkDemuxer::ShutdownAllStreams() {
1576 for (SourceStateMap::iterator itr = source_state_map_.begin(); 1654 for (SourceStateMap::iterator itr = source_state_map_.begin();
1577 itr != source_state_map_.end(); ++itr) { 1655 itr != source_state_map_.end(); ++itr) {
1578 itr->second->Shutdown(); 1656 itr->second->Shutdown();
1579 } 1657 }
1580 } 1658 }
1581 1659
1582 } // namespace media 1660 } // namespace media
OLDNEW
« no previous file with comments | « media/base/stream_parser.h ('k') | media/filters/pipeline_integration_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698