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

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

Issue 20123002: Add Chromium-side support for SourceBuffer.appendWindowStart and SourceBuffer.appendWindowEnd. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 5 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 <deque> 8 #include <deque>
9 #include <limits> 9 #include <limits>
10 10
(...skipping 19 matching lines...) Expand all
30 typedef base::Callback<ChunkDemuxerStream*( 30 typedef base::Callback<ChunkDemuxerStream*(
31 DemuxerStream::Type)> CreateDemuxerStreamCB; 31 DemuxerStream::Type)> CreateDemuxerStreamCB;
32 32
33 // Callback signature used to notify ChunkDemuxer of timestamps 33 // Callback signature used to notify ChunkDemuxer of timestamps
34 // that may cause the duration to be updated. 34 // that may cause the duration to be updated.
35 typedef base::Callback<void( 35 typedef base::Callback<void(
36 TimeDelta, ChunkDemuxerStream*)> IncreaseDurationCB; 36 TimeDelta, ChunkDemuxerStream*)> IncreaseDurationCB;
37 37
38 SourceState(scoped_ptr<StreamParser> stream_parser, const LogCB& log_cb, 38 SourceState(scoped_ptr<StreamParser> stream_parser, const LogCB& log_cb,
39 const CreateDemuxerStreamCB& create_demuxer_stream_cb, 39 const CreateDemuxerStreamCB& create_demuxer_stream_cb,
40 const IncreaseDurationCB& increase_duration_cb); 40 const IncreaseDurationCB& increase_duration_cb,
41 const StreamParser::NewMediaSegmentCB& new_segment_cb);
41 42
42 void Init(const StreamParser::InitCB& init_cb, 43 void Init(const StreamParser::InitCB& init_cb,
43 bool allow_audio, 44 bool allow_audio,
44 bool allow_video, 45 bool allow_video,
45 const StreamParser::NewTextBuffersCB& text_cb, 46 const StreamParser::NewTextBuffersCB& text_cb,
46 const StreamParser::NeedKeyCB& need_key_cb, 47 const StreamParser::NeedKeyCB& need_key_cb,
47 const AddTextTrackCB& add_text_track_cb, 48 const AddTextTrackCB& add_text_track_cb);
48 const StreamParser::NewMediaSegmentCB& new_segment_cb);
49 49
50 // Appends new data to the StreamParser. 50 // Appends new data to the StreamParser.
51 // Returns true if the data was successfully appended. Returns false if an 51 // Returns true if the data was successfully appended. Returns false if an
52 // error occurred. 52 // error occurred.
53 bool Append(const uint8* data, size_t length); 53 bool Append(const uint8* data, size_t length);
54 54
55 // Aborts the current append sequence and resets the parser. 55 // Aborts the current append sequence and resets the parser.
56 void Abort(); 56 void Abort();
57 57
58 // Sets |timestamp_offset_| if possible. 58 // Sets |timestamp_offset_| if possible.
59 // Returns if the offset was set. Returns false if the offset could not be 59 // Returns if the offset was set. Returns false if the offset could not be
60 // updated at this time. 60 // updated at this time.
61 bool SetTimestampOffset(TimeDelta timestamp_offset); 61 bool SetTimestampOffset(TimeDelta timestamp_offset);
62 62
63 TimeDelta timestamp_offset() const { return timestamp_offset_; } 63 TimeDelta timestamp_offset() const { return timestamp_offset_; }
64 64
65 void SetAppendWindowStart(TimeDelta start) { append_window_start_ = start; }
scherkus (not reviewing) 2013/07/24 22:47:41 these should be unix_hacker style as they're inlin
acolwell GONE FROM CHROMIUM 2013/07/25 20:39:33 Done.
66 void SetAppendWindowEnd(TimeDelta end) { append_window_end_ = end; }
67
65 private: 68 private:
66 // Called by the |stream_parser_| when a new initialization segment is 69 // Called by the |stream_parser_| when a new initialization segment is
67 // encountered. 70 // encountered.
68 // Returns true on a successful call. Returns false if an error occured while 71 // Returns true on a successful call. Returns false if an error occured while
69 // processing decoder configurations. 72 // processing decoder configurations.
70 bool OnNewConfigs(bool allow_audio, bool allow_video, 73 bool OnNewConfigs(bool allow_audio, bool allow_video,
71 const AudioDecoderConfig& audio_config, 74 const AudioDecoderConfig& audio_config,
72 const VideoDecoderConfig& video_config); 75 const VideoDecoderConfig& video_config);
73 76
74 // Called by the |stream_parser_| at the beginning of a new media segment. 77 // Called by the |stream_parser_| at the beginning of a new media segment.
75 // |timestamp| is the timestamp on the first buffer in the segment. 78 // |timestamp| is the timestamp on the first buffer in the segment.
76 // It modifies the state of this object and then calls |new_segment_cb| with 79 void OnNewMediaSegment(TimeDelta timestamp);
77 // modified version of |timestamp|.
78 void OnNewMediaSegment(const StreamParser::NewMediaSegmentCB& new_segment_cb,
79 TimeDelta timestamp);
80 80
81 // Called by the |stream_parser_| at the end of a media segment. 81 // Called by the |stream_parser_| at the end of a media segment.
82 void OnEndOfMediaSegment(); 82 void OnEndOfMediaSegment();
83 83
84 // Called by the |stream_parser_| when new buffers have been parsed. It 84 // Called by the |stream_parser_| when new buffers have been parsed. It
85 // applies |timestamp_offset_| to all buffers in |buffers| and then calls 85 // applies |timestamp_offset_| to all buffers in |audio_buffers| and
86 // Append() on either |audio_| or |video_| with the modified buffers based on 86 // |video_buffers| and then calls Append() on |audio_| and/or
87 // the value of |type|. 87 // |video_| with the modified buffers.
88 // Returns true on a successful call. Returns false if an error occured while 88 // Returns true on a successful call. Returns false if an error occured while
89 // processing the buffers. 89 // processing the buffers.
90 bool OnBuffers(DemuxerStream::Type type, 90 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers,
91 const StreamParser::BufferQueue& buffers); 91 const StreamParser::BufferQueue& video_buffers);
92 92
93 // Called by the |stream_parser_| when new text buffers have been parsed. It 93 // Called by the |stream_parser_| when new text buffers have been parsed. It
94 // applies |timestamp_offset_| to all buffers in |buffers| and then calls 94 // applies |timestamp_offset_| to all buffers in |buffers| and then calls
95 // |new_buffers_cb| with the modified buffers. 95 // |new_buffers_cb| with the modified buffers.
96 // Returns true on a successful call. Returns false if an error occured while 96 // Returns true on a successful call. Returns false if an error occured while
97 // processing the buffers. 97 // processing the buffers.
98 bool OnTextBuffers(const StreamParser::NewTextBuffersCB& new_buffers_cb, 98 bool OnTextBuffers(const StreamParser::NewTextBuffersCB& new_buffers_cb,
99 TextTrack* text_track, 99 TextTrack* text_track,
100 const StreamParser::BufferQueue& buffers); 100 const StreamParser::BufferQueue& buffers);
101 101
102 // Helper function that adds |timestamp_offset_| to each buffer in |buffers|. 102 // Helper function that adds |timestamp_offset_| to each buffer in |buffers|.
103 void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers); 103 void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers);
104 104
105 // Filters out buffers that are outside of the append window
106 // [|append_window_start_|, |append_window_end_|).
107 // |needs_keyframe| is a pointer to the |xxx_need_keyframe_| flag
108 // associated with the |buffers|. Its state is read an updated as
109 // this method filters |buffers|.
110 // Returns a filtered queue of buffers that are inside the append window.
111 StreamParser::BufferQueue FilterWithAppendWindow(
112 const StreamParser::BufferQueue& buffers, bool* needs_keyframe);
113
105 CreateDemuxerStreamCB create_demuxer_stream_cb_; 114 CreateDemuxerStreamCB create_demuxer_stream_cb_;
106 IncreaseDurationCB increase_duration_cb_; 115 IncreaseDurationCB increase_duration_cb_;
116 StreamParser::NewMediaSegmentCB new_segment_cb_;
107 117
108 // The offset to apply to media segment timestamps. 118 // The offset to apply to media segment timestamps.
109 TimeDelta timestamp_offset_; 119 TimeDelta timestamp_offset_;
110 120
121 TimeDelta append_window_start_;
122 TimeDelta append_window_end_;
123
124 // Set to true if the next buffers appended within the append window
125 // represent the start of a new media segment. This flag being set
126 // triggers a call to |new_segment_cb_| when the new buffers are
127 // appended. The flag is set on actual media segment boundaries and
128 // when the "append window" filtering causes discontinuities in the
129 // appended data.
130 bool new_media_segment_;
131
111 // Keeps track of whether |timestamp_offset_| can be modified. 132 // Keeps track of whether |timestamp_offset_| can be modified.
112 bool can_update_offset_; 133 bool can_update_offset_;
113 134
114 // The object used to parse appended data. 135 // The object used to parse appended data.
115 scoped_ptr<StreamParser> stream_parser_; 136 scoped_ptr<StreamParser> stream_parser_;
116 137
117 ChunkDemuxerStream* audio_; 138 ChunkDemuxerStream* audio_;
139 bool audio_needs_keyframe_;
140
118 ChunkDemuxerStream* video_; 141 ChunkDemuxerStream* video_;
142 bool video_needs_keyframe_;
119 143
120 LogCB log_cb_; 144 LogCB log_cb_;
121 145
122 DISALLOW_COPY_AND_ASSIGN(SourceState); 146 DISALLOW_COPY_AND_ASSIGN(SourceState);
123 }; 147 };
124 148
125 class ChunkDemuxerStream : public DemuxerStream { 149 class ChunkDemuxerStream : public DemuxerStream {
126 public: 150 public:
127 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; 151 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue;
128 152
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 mutable base::Lock lock_; 234 mutable base::Lock lock_;
211 State state_; 235 State state_;
212 ReadCB read_cb_; 236 ReadCB read_cb_;
213 237
214 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); 238 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream);
215 }; 239 };
216 240
217 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser, 241 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser,
218 const LogCB& log_cb, 242 const LogCB& log_cb,
219 const CreateDemuxerStreamCB& create_demuxer_stream_cb, 243 const CreateDemuxerStreamCB& create_demuxer_stream_cb,
220 const IncreaseDurationCB& increase_duration_cb) 244 const IncreaseDurationCB& increase_duration_cb,
245 const StreamParser::NewMediaSegmentCB& new_segment_cb)
221 : create_demuxer_stream_cb_(create_demuxer_stream_cb), 246 : create_demuxer_stream_cb_(create_demuxer_stream_cb),
222 increase_duration_cb_(increase_duration_cb), 247 increase_duration_cb_(increase_duration_cb),
248 new_segment_cb_(new_segment_cb),
249 append_window_start_(TimeDelta()),
scherkus (not reviewing) 2013/07/24 22:47:41 do you have this here to make it more explicit? i
acolwell GONE FROM CHROMIUM 2013/07/25 20:39:33 Yeah that was the original idea, but it's a pretty
250 append_window_end_(kInfiniteDuration()),
251 new_media_segment_(false),
223 can_update_offset_(true), 252 can_update_offset_(true),
224 stream_parser_(stream_parser.release()), 253 stream_parser_(stream_parser.release()),
225 audio_(NULL), 254 audio_(NULL),
255 audio_needs_keyframe_(true),
226 video_(NULL), 256 video_(NULL),
257 video_needs_keyframe_(true),
227 log_cb_(log_cb) { 258 log_cb_(log_cb) {
228 DCHECK(!create_demuxer_stream_cb_.is_null()); 259 DCHECK(!create_demuxer_stream_cb_.is_null());
229 DCHECK(!increase_duration_cb_.is_null()); 260 DCHECK(!increase_duration_cb_.is_null());
261 DCHECK(!new_segment_cb_.is_null());
230 } 262 }
231 263
232 void SourceState::Init(const StreamParser::InitCB& init_cb, 264 void SourceState::Init(const StreamParser::InitCB& init_cb,
233 bool allow_audio, 265 bool allow_audio,
234 bool allow_video, 266 bool allow_video,
235 const StreamParser::NewTextBuffersCB& text_cb, 267 const StreamParser::NewTextBuffersCB& text_cb,
236 const StreamParser::NeedKeyCB& need_key_cb, 268 const StreamParser::NeedKeyCB& need_key_cb,
237 const AddTextTrackCB& add_text_track_cb, 269 const AddTextTrackCB& add_text_track_cb) {
238 const StreamParser::NewMediaSegmentCB& new_segment_cb) {
239 StreamParser::NewBuffersCB audio_cb; 270 StreamParser::NewBuffersCB audio_cb;
240 StreamParser::NewBuffersCB video_cb;
241
242 if (allow_audio) {
243 audio_cb = base::Bind(&SourceState::OnBuffers,
244 base::Unretained(this), DemuxerStream::AUDIO);
245 }
246
247 if (allow_video) {
248 video_cb = base::Bind(&SourceState::OnBuffers,
249 base::Unretained(this), DemuxerStream::VIDEO);
250 }
251 271
252 stream_parser_->Init(init_cb, 272 stream_parser_->Init(init_cb,
253 base::Bind(&SourceState::OnNewConfigs, 273 base::Bind(&SourceState::OnNewConfigs,
254 base::Unretained(this), 274 base::Unretained(this),
255 allow_audio, 275 allow_audio,
256 allow_video), 276 allow_video),
257 audio_cb, 277 base::Bind(&SourceState::OnNewBuffers,
258 video_cb, 278 base::Unretained(this)),
259 base::Bind(&SourceState::OnTextBuffers, 279 base::Bind(&SourceState::OnTextBuffers,
260 base::Unretained(this), text_cb), 280 base::Unretained(this), text_cb),
261 need_key_cb, 281 need_key_cb,
262 add_text_track_cb, 282 add_text_track_cb,
263 base::Bind(&SourceState::OnNewMediaSegment, 283 base::Bind(&SourceState::OnNewMediaSegment,
264 base::Unretained(this), new_segment_cb), 284 base::Unretained(this)),
265 base::Bind(&SourceState::OnEndOfMediaSegment, 285 base::Bind(&SourceState::OnEndOfMediaSegment,
266 base::Unretained(this)), 286 base::Unretained(this)),
267 log_cb_); 287 log_cb_);
268 } 288 }
269 289
270 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) { 290 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) {
271 if (!can_update_offset_) 291 if (!can_update_offset_)
272 return false; 292 return false;
273 293
274 timestamp_offset_ = timestamp_offset; 294 timestamp_offset_ = timestamp_offset;
275 return true; 295 return true;
276 } 296 }
277 297
278 bool SourceState::Append(const uint8* data, size_t length) { 298 bool SourceState::Append(const uint8* data, size_t length) {
279 return stream_parser_->Parse(data, length); 299 return stream_parser_->Parse(data, length);
280 } 300 }
281 301
282 void SourceState::Abort() { 302 void SourceState::Abort() {
283 stream_parser_->Flush(); 303 stream_parser_->Flush();
304 audio_needs_keyframe_ = true;
305 video_needs_keyframe_ = true;
284 can_update_offset_ = true; 306 can_update_offset_ = true;
scherkus (not reviewing) 2013/07/24 22:47:41 sanity check: does new_media_segment_ need to be u
acolwell GONE FROM CHROMIUM 2013/07/25 20:39:33 No. We will always get an OnNewMediaSegment() call
285 } 307 }
286 308
287 void SourceState::AdjustBufferTimestamps( 309 void SourceState::AdjustBufferTimestamps(
288 const StreamParser::BufferQueue& buffers) { 310 const StreamParser::BufferQueue& buffers) {
289 if (timestamp_offset_ == TimeDelta()) 311 if (timestamp_offset_ == TimeDelta())
290 return; 312 return;
291 313
292 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); 314 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin();
293 itr != buffers.end(); ++itr) { 315 itr != buffers.end(); ++itr) {
294 (*itr)->SetDecodeTimestamp( 316 (*itr)->SetDecodeTimestamp(
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 } 377 }
356 } 378 }
357 379
358 success &= video_->UpdateVideoConfig(video_config, log_cb_); 380 success &= video_->UpdateVideoConfig(video_config, log_cb_);
359 } 381 }
360 382
361 DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); 383 DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed");
362 return success; 384 return success;
363 } 385 }
364 386
365 void SourceState::OnNewMediaSegment( 387 void SourceState::OnNewMediaSegment(TimeDelta timestamp) {
scherkus (not reviewing) 2013/07/24 22:47:41 |timestamp| isn't used anymore other than for DCHE
acolwell GONE FROM CHROMIUM 2013/07/25 20:39:33 Done.
366 const StreamParser::NewMediaSegmentCB& new_segment_cb,
367 TimeDelta timestamp) {
368 DCHECK(timestamp != kNoTimestamp()); 388 DCHECK(timestamp != kNoTimestamp());
369 DVLOG(2) << "OnNewMediaSegment(" << timestamp.InSecondsF() << ")"; 389 DVLOG(2) << "SourceState::OnNewMediaSegment("
370 390 << timestamp.InSecondsF() << ")";
371 can_update_offset_ = false; 391 can_update_offset_ = false;
372 new_segment_cb.Run(timestamp + timestamp_offset_); 392 new_media_segment_ = true;
373 } 393 }
374 394
375 void SourceState::OnEndOfMediaSegment() { 395 void SourceState::OnEndOfMediaSegment() {
376 DVLOG(2) << "OnEndOfMediaSegment()"; 396 DVLOG(2) << "OnEndOfMediaSegment()";
377 can_update_offset_ = true; 397 can_update_offset_ = true;
398 new_media_segment_ = false;
378 } 399 }
379 400
380 bool SourceState::OnBuffers(DemuxerStream::Type type, 401 bool SourceState::OnNewBuffers(const StreamParser::BufferQueue& audio_buffers,
381 const StreamParser::BufferQueue& buffers) { 402 const StreamParser::BufferQueue& video_buffers) {
382 DCHECK(!buffers.empty()); 403 DCHECK(!audio_buffers.empty() || !video_buffers.empty());
383 AdjustBufferTimestamps(buffers); 404 AdjustBufferTimestamps(audio_buffers);
405 AdjustBufferTimestamps(video_buffers);
384 406
385 ChunkDemuxerStream* stream = NULL; 407 StreamParser::BufferQueue filtered_audio =
386 switch (type) { 408 FilterWithAppendWindow(audio_buffers, &audio_needs_keyframe_);
387 case DemuxerStream::AUDIO: 409
388 stream = audio_; 410 StreamParser::BufferQueue filtered_video =
389 break; 411 FilterWithAppendWindow(video_buffers, &video_needs_keyframe_);
390 case DemuxerStream::VIDEO: 412
391 stream = video_; 413 if (filtered_audio.empty() && filtered_video.empty())
392 break; 414 return true;
393 case DemuxerStream::UNKNOWN: 415
394 case DemuxerStream::NUM_TYPES: 416 if (new_media_segment_) {
395 NOTREACHED(); 417 // Find the earliest timestamp in the filtered buffers and use
scherkus (not reviewing) 2013/07/24 22:47:41 nit: you can fit a few more words on this line
acolwell GONE FROM CHROMIUM 2013/07/25 20:39:33 Done.
396 return false; 418 // that for the segment start timestamp.
419 TimeDelta segment_timestamp = kNoTimestamp();
420
421 if (!filtered_audio.empty())
422 segment_timestamp = filtered_audio.front()->GetDecodeTimestamp();
423
424 if (!filtered_video.empty() &&
425 (segment_timestamp == kNoTimestamp() ||
426 filtered_video.front()->GetDecodeTimestamp() < segment_timestamp)) {
427 segment_timestamp = filtered_video.front()->GetDecodeTimestamp();
428 }
429
430 new_media_segment_ = false;
scherkus (not reviewing) 2013/07/24 22:47:41 sanity check: does can_update_offset_ need to be u
acolwell GONE FROM CHROMIUM 2013/07/25 20:39:33 No. can_update_offset_ tracks the actual media seg
431 new_segment_cb_.Run(segment_timestamp);
397 } 432 }
398 433
399 if (!stream->Append(buffers)) 434 if (!filtered_audio.empty()) {
400 return false; 435 if (!audio_ || !audio_->Append(filtered_audio))
401 increase_duration_cb_.Run(buffers.back()->timestamp(), stream); 436 return false;
437 increase_duration_cb_.Run(filtered_audio.back()->timestamp(), audio_);
438 }
439
440 if (!filtered_video.empty()) {
441 if (!video_ || !video_->Append(filtered_video))
442 return false;
443 increase_duration_cb_.Run(filtered_video.back()->timestamp(), video_);
444 }
445
402 return true; 446 return true;
403 } 447 }
404 448
405 bool SourceState::OnTextBuffers( 449 bool SourceState::OnTextBuffers(
406 const StreamParser::NewTextBuffersCB& new_buffers_cb, 450 const StreamParser::NewTextBuffersCB& new_buffers_cb,
407 TextTrack* text_track, 451 TextTrack* text_track,
408 const StreamParser::BufferQueue& buffers) { 452 const StreamParser::BufferQueue& buffers) {
409 if (new_buffers_cb.is_null()) 453 if (new_buffers_cb.is_null())
410 return false; 454 return false;
411 455
412 AdjustBufferTimestamps(buffers); 456 AdjustBufferTimestamps(buffers);
413 457
414 return new_buffers_cb.Run(text_track, buffers); 458 return new_buffers_cb.Run(text_track, buffers);
415 } 459 }
416 460
461 StreamParser::BufferQueue SourceState::FilterWithAppendWindow(
scherkus (not reviewing) 2013/07/24 22:47:41 do we know how large this queue can get? any reas
acolwell GONE FROM CHROMIUM 2013/07/25 20:39:33 Nope. Done.
462 const StreamParser::BufferQueue& buffers, bool* needs_keyframe) {
463 StreamParser::BufferQueue filtered_buffers;
464 DCHECK(needs_keyframe);
465
466 // This loop implements steps 1.9, 1.10, & 1.11 of the "Coded frame
467 // processing loop" in the Media Source Extensions spec.
468 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-sourc e.html#sourcebuffer-coded-frame-processing
469 // These steps filter out buffers that are not within the "append
470 // window" and handles resyncing on the next random access point
471 // (i.e., next keyframe) if a buffer gets dropped.
472 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin();
473 itr != buffers.end(); ++itr) {
474 // Filter out buffers that are outside the append window. Anytime
475 // a buffer gets dropped we need to set |*needs_keyframe| to true
476 // because we can only resume decoding at keyframes.
477 TimeDelta presentation_timestamp = (*itr)->timestamp();
478
479 // TODO(acolwell): Change |frame_end_timestamp| value to
480 // |presentation_timestamp + (*itr)->duration()|, like the spec
481 // requires, once frame durations are actually present in all buffers.
482 TimeDelta frame_end_timestamp = presentation_timestamp;
483 if (presentation_timestamp < append_window_start_ ||
484 frame_end_timestamp > append_window_end_) {
485 DVLOG(1) << "Dropping buffer outside append window."
486 << " presentation_timestamp "
487 << presentation_timestamp.InSecondsF();
488 *needs_keyframe = true;
489
490 // This triggers a discontinuity so we need to treat the next frames
491 // appended within the append window as if they were the beginning of a
492 // new segment.
493 new_media_segment_ = true;
scherkus (not reviewing) 2013/07/24 22:47:41 sanity check: does can_update_offset_ need to be u
acolwell GONE FROM CHROMIUM 2013/07/25 20:39:33 No. This is a "virtual" media segment (i.e., a new
494 continue;
495 }
496
497 // If |*needs_keyframe| is true then filter out buffers until we
498 // encounter the next keyframe.
499 if (*needs_keyframe) {
500 if (!(*itr)->IsKeyframe()) {
501 DVLOG(1) << "Dropping non-keyframe. presentation_timestamp "
502 << presentation_timestamp.InSecondsF();
503 continue;
504 }
505
506 *needs_keyframe = false;
507 }
508
509 filtered_buffers.push_back(*itr);
510 }
511
512 return filtered_buffers;
513 }
514
417 ChunkDemuxerStream::ChunkDemuxerStream(Type type) 515 ChunkDemuxerStream::ChunkDemuxerStream(Type type)
418 : type_(type), 516 : type_(type),
419 state_(UNINITIALIZED) { 517 state_(UNINITIALIZED) {
420 } 518 }
421 519
422 void ChunkDemuxerStream::StartReturningData() { 520 void ChunkDemuxerStream::StartReturningData() {
423 DVLOG(1) << "ChunkDemuxerStream::StartReturningData()"; 521 DVLOG(1) << "ChunkDemuxerStream::StartReturningData()";
424 base::AutoLock auto_lock(lock_); 522 base::AutoLock auto_lock(lock_);
425 DCHECK(read_cb_.is_null()); 523 DCHECK(read_cb_.is_null());
426 ChangeState_Locked(RETURNING_DATA_FOR_READS); 524 ChangeState_Locked(RETURNING_DATA_FOR_READS);
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
507 605
508 // Clamp the end of the stream's buffered ranges to fit within the duration. 606 // Clamp the end of the stream's buffered ranges to fit within the duration.
509 // This can be done by intersecting the stream's range with the valid time 607 // This can be done by intersecting the stream's range with the valid time
510 // range. 608 // range.
511 Ranges<TimeDelta> valid_time_range; 609 Ranges<TimeDelta> valid_time_range;
512 valid_time_range.Add(range.start(0), duration); 610 valid_time_range.Add(range.start(0), duration);
513 return range.IntersectionWith(valid_time_range); 611 return range.IntersectionWith(valid_time_range);
514 } 612 }
515 613
516 void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) { 614 void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) {
615 DVLOG(2) << "ChunkDemuxerStream::OnNewMediaSegment("
616 << start_timestamp.InSecondsF() << ")";
517 base::AutoLock auto_lock(lock_); 617 base::AutoLock auto_lock(lock_);
518 stream_->OnNewMediaSegment(start_timestamp); 618 stream_->OnNewMediaSegment(start_timestamp);
519 } 619 }
520 620
521 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config, 621 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config,
522 const LogCB& log_cb) { 622 const LogCB& log_cb) {
523 DCHECK(config.IsValidConfig()); 623 DCHECK(config.IsValidConfig());
524 DCHECK_EQ(type_, AUDIO); 624 DCHECK_EQ(type_, AUDIO);
525 base::AutoLock auto_lock(lock_); 625 base::AutoLock auto_lock(lock_);
526 if (!stream_) { 626 if (!stream_) {
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after
795 source_id_audio_ = id; 895 source_id_audio_ = id;
796 896
797 if (has_video) 897 if (has_video)
798 source_id_video_ = id; 898 source_id_video_ = id;
799 899
800 scoped_ptr<SourceState> source_state( 900 scoped_ptr<SourceState> source_state(
801 new SourceState(stream_parser.Pass(), log_cb_, 901 new SourceState(stream_parser.Pass(), log_cb_,
802 base::Bind(&ChunkDemuxer::CreateDemuxerStream, 902 base::Bind(&ChunkDemuxer::CreateDemuxerStream,
803 base::Unretained(this)), 903 base::Unretained(this)),
804 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, 904 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary,
805 base::Unretained(this)))); 905 base::Unretained(this)),
906 base::Bind(&ChunkDemuxer::OnNewMediaSegment,
907 base::Unretained(this), id)));
908
806 source_state->Init( 909 source_state->Init(
807 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), 910 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)),
808 has_audio, 911 has_audio,
809 has_video, 912 has_video,
810 base::Bind(&ChunkDemuxer::OnTextBuffers, base::Unretained(this)), 913 base::Bind(&ChunkDemuxer::OnTextBuffers, base::Unretained(this)),
811 need_key_cb_, 914 need_key_cb_,
812 add_text_track_cb_, 915 add_text_track_cb_);
813 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id));
814 916
815 source_state_map_[id] = source_state.release(); 917 source_state_map_[id] = source_state.release();
816 return kOk; 918 return kOk;
817 } 919 }
818 920
819 void ChunkDemuxer::RemoveId(const std::string& id) { 921 void ChunkDemuxer::RemoveId(const std::string& id) {
820 base::AutoLock auto_lock(lock_); 922 base::AutoLock auto_lock(lock_);
821 CHECK(IsValidId(id)); 923 CHECK(IsValidId(id));
822 924
823 delete source_state_map_[id]; 925 delete source_state_map_[id];
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
1086 1188
1087 ChangeState_Locked(INITIALIZED); 1189 ChangeState_Locked(INITIALIZED);
1088 1190
1089 if (audio_) 1191 if (audio_)
1090 audio_->UnmarkEndOfStream(); 1192 audio_->UnmarkEndOfStream();
1091 1193
1092 if (video_) 1194 if (video_)
1093 video_->UnmarkEndOfStream(); 1195 video_->UnmarkEndOfStream();
1094 } 1196 }
1095 1197
1198 void ChunkDemuxer::SetAppendWindowStart(const std::string& id,
1199 TimeDelta start) {
1200 base::AutoLock auto_lock(lock_);
1201 DVLOG(1) << "SetAppendWindowStart(" << id << ", "
1202 << start.InSecondsF() << ")";
1203 CHECK(IsValidId(id));
1204 source_state_map_[id]->SetAppendWindowStart(start);
1205 }
1206
1207 void ChunkDemuxer::SetAppendWindowEnd(const std::string& id, TimeDelta end) {
1208 base::AutoLock auto_lock(lock_);
1209 DVLOG(1) << "SetAppendWindowEnd(" << id << ", " << end.InSecondsF() << ")";
1210 CHECK(IsValidId(id));
1211 source_state_map_[id]->SetAppendWindowEnd(end);
1212 }
1213
1096 void ChunkDemuxer::Shutdown() { 1214 void ChunkDemuxer::Shutdown() {
1097 DVLOG(1) << "Shutdown()"; 1215 DVLOG(1) << "Shutdown()";
1098 base::AutoLock auto_lock(lock_); 1216 base::AutoLock auto_lock(lock_);
1099 1217
1100 if (state_ == SHUTDOWN) 1218 if (state_ == SHUTDOWN)
1101 return; 1219 return;
1102 1220
1103 if (audio_) 1221 if (audio_)
1104 audio_->Shutdown(); 1222 audio_->Shutdown();
1105 1223
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
1255 1373
1256 text_track->addWebVTTCue(start, end, id, content, settings); 1374 text_track->addWebVTTCue(start, end, id, content, settings);
1257 } 1375 }
1258 1376
1259 return true; 1377 return true;
1260 } 1378 }
1261 1379
1262 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, 1380 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id,
1263 TimeDelta timestamp) { 1381 TimeDelta timestamp) {
1264 DCHECK(timestamp != kNoTimestamp()); 1382 DCHECK(timestamp != kNoTimestamp());
1265 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", " 1383 DVLOG(2) << "ChunkDemuxer::OnNewMediaSegment(" << source_id << ", "
scherkus (not reviewing) 2013/07/24 22:47:41 FYI the DVLOGs in this class are inconsistent re:
acolwell GONE FROM CHROMIUM 2013/07/25 20:39:33 Actually this method doesn't need to exist anymore
1266 << timestamp.InSecondsF() << ")"; 1384 << timestamp.InSecondsF() << ")";
1267 lock_.AssertAcquired(); 1385 lock_.AssertAcquired();
1268 1386
1269 CHECK(IsValidId(source_id)); 1387 CHECK(IsValidId(source_id));
1270 if (audio_ && source_id == source_id_audio_) 1388 if (audio_ && source_id == source_id_audio_)
1271 audio_->OnNewMediaSegment(timestamp); 1389 audio_->OnNewMediaSegment(timestamp);
1272 if (video_ && source_id == source_id_video_) 1390 if (video_ && source_id == source_id_video_)
1273 video_->OnNewMediaSegment(timestamp); 1391 video_->OnNewMediaSegment(timestamp);
1274 } 1392 }
1275 1393
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1344 1462
1345 void ChunkDemuxer::CompletePendingReadsIfPossible() { 1463 void ChunkDemuxer::CompletePendingReadsIfPossible() {
1346 if (audio_) 1464 if (audio_)
1347 audio_->CompletePendingReadIfPossible(); 1465 audio_->CompletePendingReadIfPossible();
1348 1466
1349 if (video_) 1467 if (video_)
1350 video_->CompletePendingReadIfPossible(); 1468 video_->CompletePendingReadIfPossible();
1351 } 1469 }
1352 1470
1353 } // namespace media 1471 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698