OLD | NEW |
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 26 matching lines...) Expand all Loading... |
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 | 41 |
42 void Init(const StreamParser::InitCB& init_cb, | 42 void Init(const StreamParser::InitCB& init_cb, |
43 bool allow_audio, | 43 bool allow_audio, |
44 bool allow_video, | 44 bool allow_video, |
45 const StreamParser::NewTextBuffersCB& text_cb, | 45 const StreamParser::NewTextBuffersCB& text_cb, |
46 const StreamParser::NeedKeyCB& need_key_cb, | 46 const StreamParser::NeedKeyCB& need_key_cb, |
47 const AddTextTrackCB& add_text_track_cb, | 47 const AddTextTrackCB& add_text_track_cb); |
48 const StreamParser::NewMediaSegmentCB& new_segment_cb); | |
49 | 48 |
50 // Appends new data to the StreamParser. | 49 // Appends new data to the StreamParser. |
51 // Returns true if the data was successfully appended. Returns false if an | 50 // Returns true if the data was successfully appended. Returns false if an |
52 // error occurred. | 51 // error occurred. |
53 bool Append(const uint8* data, size_t length); | 52 bool Append(const uint8* data, size_t length); |
54 | 53 |
55 // Aborts the current append sequence and resets the parser. | 54 // Aborts the current append sequence and resets the parser. |
56 void Abort(); | 55 void Abort(); |
57 | 56 |
58 // Sets |timestamp_offset_| if possible. | 57 // Sets |timestamp_offset_| if possible. |
59 // Returns if the offset was set. Returns false if the offset could not be | 58 // Returns if the offset was set. Returns false if the offset could not be |
60 // updated at this time. | 59 // updated at this time. |
61 bool SetTimestampOffset(TimeDelta timestamp_offset); | 60 bool SetTimestampOffset(TimeDelta timestamp_offset); |
62 | 61 |
63 TimeDelta timestamp_offset() const { return timestamp_offset_; } | 62 TimeDelta timestamp_offset() const { return timestamp_offset_; } |
64 | 63 |
| 64 void set_append_window_start(TimeDelta start) { |
| 65 append_window_start_ = start; |
| 66 } |
| 67 void set_append_window_end(TimeDelta end) { append_window_end_ = end; } |
| 68 |
65 private: | 69 private: |
66 // Called by the |stream_parser_| when a new initialization segment is | 70 // Called by the |stream_parser_| when a new initialization segment is |
67 // encountered. | 71 // encountered. |
68 // Returns true on a successful call. Returns false if an error occured while | 72 // Returns true on a successful call. Returns false if an error occured while |
69 // processing decoder configurations. | 73 // processing decoder configurations. |
70 bool OnNewConfigs(bool allow_audio, bool allow_video, | 74 bool OnNewConfigs(bool allow_audio, bool allow_video, |
71 const AudioDecoderConfig& audio_config, | 75 const AudioDecoderConfig& audio_config, |
72 const VideoDecoderConfig& video_config); | 76 const VideoDecoderConfig& video_config); |
73 | 77 |
74 // Called by the |stream_parser_| at the beginning of a new media segment. | 78 // 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. | 79 void OnNewMediaSegment(); |
76 // It modifies the state of this object and then calls |new_segment_cb| with | |
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 // Buffers that are inside the append window are appended to the end |
| 111 // of |filtered_buffers|. |
| 112 void FilterWithAppendWindow(const StreamParser::BufferQueue& buffers, |
| 113 bool* needs_keyframe, |
| 114 StreamParser::BufferQueue* filtered_buffers); |
| 115 |
105 CreateDemuxerStreamCB create_demuxer_stream_cb_; | 116 CreateDemuxerStreamCB create_demuxer_stream_cb_; |
106 IncreaseDurationCB increase_duration_cb_; | 117 IncreaseDurationCB increase_duration_cb_; |
107 | 118 |
108 // The offset to apply to media segment timestamps. | 119 // The offset to apply to media segment timestamps. |
109 TimeDelta timestamp_offset_; | 120 TimeDelta timestamp_offset_; |
110 | 121 |
| 122 TimeDelta append_window_start_; |
| 123 TimeDelta append_window_end_; |
| 124 |
| 125 // Set to true if the next buffers appended within the append window |
| 126 // represent the start of a new media segment. This flag being set |
| 127 // triggers a call to |new_segment_cb_| when the new buffers are |
| 128 // appended. The flag is set on actual media segment boundaries and |
| 129 // when the "append window" filtering causes discontinuities in the |
| 130 // appended data. |
| 131 bool new_media_segment_; |
| 132 |
111 // Keeps track of whether |timestamp_offset_| can be modified. | 133 // Keeps track of whether |timestamp_offset_| can be modified. |
112 bool can_update_offset_; | 134 bool can_update_offset_; |
113 | 135 |
114 // The object used to parse appended data. | 136 // The object used to parse appended data. |
115 scoped_ptr<StreamParser> stream_parser_; | 137 scoped_ptr<StreamParser> stream_parser_; |
116 | 138 |
117 ChunkDemuxerStream* audio_; | 139 ChunkDemuxerStream* audio_; |
| 140 bool audio_needs_keyframe_; |
| 141 |
118 ChunkDemuxerStream* video_; | 142 ChunkDemuxerStream* video_; |
| 143 bool video_needs_keyframe_; |
119 | 144 |
120 LogCB log_cb_; | 145 LogCB log_cb_; |
121 | 146 |
122 DISALLOW_COPY_AND_ASSIGN(SourceState); | 147 DISALLOW_COPY_AND_ASSIGN(SourceState); |
123 }; | 148 }; |
124 | 149 |
125 class ChunkDemuxerStream : public DemuxerStream { | 150 class ChunkDemuxerStream : public DemuxerStream { |
126 public: | 151 public: |
127 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; | 152 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; |
128 | 153 |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
213 | 238 |
214 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); | 239 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); |
215 }; | 240 }; |
216 | 241 |
217 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser, | 242 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser, |
218 const LogCB& log_cb, | 243 const LogCB& log_cb, |
219 const CreateDemuxerStreamCB& create_demuxer_stream_cb, | 244 const CreateDemuxerStreamCB& create_demuxer_stream_cb, |
220 const IncreaseDurationCB& increase_duration_cb) | 245 const IncreaseDurationCB& increase_duration_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 append_window_end_(kInfiniteDuration()), |
| 249 new_media_segment_(false), |
223 can_update_offset_(true), | 250 can_update_offset_(true), |
224 stream_parser_(stream_parser.release()), | 251 stream_parser_(stream_parser.release()), |
225 audio_(NULL), | 252 audio_(NULL), |
| 253 audio_needs_keyframe_(true), |
226 video_(NULL), | 254 video_(NULL), |
| 255 video_needs_keyframe_(true), |
227 log_cb_(log_cb) { | 256 log_cb_(log_cb) { |
228 DCHECK(!create_demuxer_stream_cb_.is_null()); | 257 DCHECK(!create_demuxer_stream_cb_.is_null()); |
229 DCHECK(!increase_duration_cb_.is_null()); | 258 DCHECK(!increase_duration_cb_.is_null()); |
230 } | 259 } |
231 | 260 |
232 void SourceState::Init(const StreamParser::InitCB& init_cb, | 261 void SourceState::Init(const StreamParser::InitCB& init_cb, |
233 bool allow_audio, | 262 bool allow_audio, |
234 bool allow_video, | 263 bool allow_video, |
235 const StreamParser::NewTextBuffersCB& text_cb, | 264 const StreamParser::NewTextBuffersCB& text_cb, |
236 const StreamParser::NeedKeyCB& need_key_cb, | 265 const StreamParser::NeedKeyCB& need_key_cb, |
237 const AddTextTrackCB& add_text_track_cb, | 266 const AddTextTrackCB& add_text_track_cb) { |
238 const StreamParser::NewMediaSegmentCB& new_segment_cb) { | |
239 StreamParser::NewBuffersCB audio_cb; | 267 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 | 268 |
252 stream_parser_->Init(init_cb, | 269 stream_parser_->Init(init_cb, |
253 base::Bind(&SourceState::OnNewConfigs, | 270 base::Bind(&SourceState::OnNewConfigs, |
254 base::Unretained(this), | 271 base::Unretained(this), |
255 allow_audio, | 272 allow_audio, |
256 allow_video), | 273 allow_video), |
257 audio_cb, | 274 base::Bind(&SourceState::OnNewBuffers, |
258 video_cb, | 275 base::Unretained(this)), |
259 base::Bind(&SourceState::OnTextBuffers, | 276 base::Bind(&SourceState::OnTextBuffers, |
260 base::Unretained(this), text_cb), | 277 base::Unretained(this), text_cb), |
261 need_key_cb, | 278 need_key_cb, |
262 add_text_track_cb, | 279 add_text_track_cb, |
263 base::Bind(&SourceState::OnNewMediaSegment, | 280 base::Bind(&SourceState::OnNewMediaSegment, |
264 base::Unretained(this), new_segment_cb), | 281 base::Unretained(this)), |
265 base::Bind(&SourceState::OnEndOfMediaSegment, | 282 base::Bind(&SourceState::OnEndOfMediaSegment, |
266 base::Unretained(this)), | 283 base::Unretained(this)), |
267 log_cb_); | 284 log_cb_); |
268 } | 285 } |
269 | 286 |
270 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) { | 287 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) { |
271 if (!can_update_offset_) | 288 if (!can_update_offset_) |
272 return false; | 289 return false; |
273 | 290 |
274 timestamp_offset_ = timestamp_offset; | 291 timestamp_offset_ = timestamp_offset; |
275 return true; | 292 return true; |
276 } | 293 } |
277 | 294 |
278 bool SourceState::Append(const uint8* data, size_t length) { | 295 bool SourceState::Append(const uint8* data, size_t length) { |
279 return stream_parser_->Parse(data, length); | 296 return stream_parser_->Parse(data, length); |
280 } | 297 } |
281 | 298 |
282 void SourceState::Abort() { | 299 void SourceState::Abort() { |
283 stream_parser_->Flush(); | 300 stream_parser_->Flush(); |
| 301 audio_needs_keyframe_ = true; |
| 302 video_needs_keyframe_ = true; |
284 can_update_offset_ = true; | 303 can_update_offset_ = true; |
285 } | 304 } |
286 | 305 |
287 void SourceState::AdjustBufferTimestamps( | 306 void SourceState::AdjustBufferTimestamps( |
288 const StreamParser::BufferQueue& buffers) { | 307 const StreamParser::BufferQueue& buffers) { |
289 if (timestamp_offset_ == TimeDelta()) | 308 if (timestamp_offset_ == TimeDelta()) |
290 return; | 309 return; |
291 | 310 |
292 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); | 311 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); |
293 itr != buffers.end(); ++itr) { | 312 itr != buffers.end(); ++itr) { |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
355 } | 374 } |
356 } | 375 } |
357 | 376 |
358 success &= video_->UpdateVideoConfig(video_config, log_cb_); | 377 success &= video_->UpdateVideoConfig(video_config, log_cb_); |
359 } | 378 } |
360 | 379 |
361 DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); | 380 DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); |
362 return success; | 381 return success; |
363 } | 382 } |
364 | 383 |
365 void SourceState::OnNewMediaSegment( | 384 void SourceState::OnNewMediaSegment() { |
366 const StreamParser::NewMediaSegmentCB& new_segment_cb, | 385 DVLOG(2) << "OnNewMediaSegment()"; |
367 TimeDelta timestamp) { | |
368 DCHECK(timestamp != kNoTimestamp()); | |
369 DVLOG(2) << "OnNewMediaSegment(" << timestamp.InSecondsF() << ")"; | |
370 | |
371 can_update_offset_ = false; | 386 can_update_offset_ = false; |
372 new_segment_cb.Run(timestamp + timestamp_offset_); | 387 new_media_segment_ = true; |
373 } | 388 } |
374 | 389 |
375 void SourceState::OnEndOfMediaSegment() { | 390 void SourceState::OnEndOfMediaSegment() { |
376 DVLOG(2) << "OnEndOfMediaSegment()"; | 391 DVLOG(2) << "OnEndOfMediaSegment()"; |
377 can_update_offset_ = true; | 392 can_update_offset_ = true; |
| 393 new_media_segment_ = false; |
378 } | 394 } |
379 | 395 |
380 bool SourceState::OnBuffers(DemuxerStream::Type type, | 396 bool SourceState::OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, |
381 const StreamParser::BufferQueue& buffers) { | 397 const StreamParser::BufferQueue& video_buffers) { |
382 DCHECK(!buffers.empty()); | 398 DCHECK(!audio_buffers.empty() || !video_buffers.empty()); |
383 AdjustBufferTimestamps(buffers); | 399 AdjustBufferTimestamps(audio_buffers); |
| 400 AdjustBufferTimestamps(video_buffers); |
384 | 401 |
385 ChunkDemuxerStream* stream = NULL; | 402 StreamParser::BufferQueue filtered_audio; |
386 switch (type) { | 403 StreamParser::BufferQueue filtered_video; |
387 case DemuxerStream::AUDIO: | 404 |
388 stream = audio_; | 405 FilterWithAppendWindow(audio_buffers, &audio_needs_keyframe_, |
389 break; | 406 &filtered_audio); |
390 case DemuxerStream::VIDEO: | 407 |
391 stream = video_; | 408 FilterWithAppendWindow(video_buffers, &video_needs_keyframe_, |
392 break; | 409 &filtered_video); |
393 case DemuxerStream::UNKNOWN: | 410 |
394 case DemuxerStream::NUM_TYPES: | 411 if (filtered_audio.empty() && filtered_video.empty()) |
395 NOTREACHED(); | 412 return true; |
396 return false; | 413 |
| 414 if (new_media_segment_) { |
| 415 // Find the earliest timestamp in the filtered buffers and use that for the |
| 416 // segment start timestamp. |
| 417 TimeDelta segment_timestamp = kNoTimestamp(); |
| 418 |
| 419 if (!filtered_audio.empty()) |
| 420 segment_timestamp = filtered_audio.front()->GetDecodeTimestamp(); |
| 421 |
| 422 if (!filtered_video.empty() && |
| 423 (segment_timestamp == kNoTimestamp() || |
| 424 filtered_video.front()->GetDecodeTimestamp() < segment_timestamp)) { |
| 425 segment_timestamp = filtered_video.front()->GetDecodeTimestamp(); |
| 426 } |
| 427 |
| 428 new_media_segment_ = false; |
| 429 |
| 430 if (audio_) |
| 431 audio_->OnNewMediaSegment(segment_timestamp); |
| 432 |
| 433 if (video_) |
| 434 video_->OnNewMediaSegment(segment_timestamp); |
397 } | 435 } |
398 | 436 |
399 if (!stream->Append(buffers)) | 437 if (!filtered_audio.empty()) { |
400 return false; | 438 if (!audio_ || !audio_->Append(filtered_audio)) |
401 increase_duration_cb_.Run(buffers.back()->timestamp(), stream); | 439 return false; |
| 440 increase_duration_cb_.Run(filtered_audio.back()->timestamp(), audio_); |
| 441 } |
| 442 |
| 443 if (!filtered_video.empty()) { |
| 444 if (!video_ || !video_->Append(filtered_video)) |
| 445 return false; |
| 446 increase_duration_cb_.Run(filtered_video.back()->timestamp(), video_); |
| 447 } |
| 448 |
402 return true; | 449 return true; |
403 } | 450 } |
404 | 451 |
405 bool SourceState::OnTextBuffers( | 452 bool SourceState::OnTextBuffers( |
406 const StreamParser::NewTextBuffersCB& new_buffers_cb, | 453 const StreamParser::NewTextBuffersCB& new_buffers_cb, |
407 TextTrack* text_track, | 454 TextTrack* text_track, |
408 const StreamParser::BufferQueue& buffers) { | 455 const StreamParser::BufferQueue& buffers) { |
409 if (new_buffers_cb.is_null()) | 456 if (new_buffers_cb.is_null()) |
410 return false; | 457 return false; |
411 | 458 |
412 AdjustBufferTimestamps(buffers); | 459 AdjustBufferTimestamps(buffers); |
413 | 460 |
414 return new_buffers_cb.Run(text_track, buffers); | 461 return new_buffers_cb.Run(text_track, buffers); |
415 } | 462 } |
416 | 463 |
| 464 void SourceState::FilterWithAppendWindow( |
| 465 const StreamParser::BufferQueue& buffers, bool* needs_keyframe, |
| 466 StreamParser::BufferQueue* filtered_buffers) { |
| 467 DCHECK(needs_keyframe); |
| 468 DCHECK(filtered_buffers); |
| 469 |
| 470 // This loop implements steps 1.9, 1.10, & 1.11 of the "Coded frame |
| 471 // processing loop" in the Media Source Extensions spec. |
| 472 // These steps filter out buffers that are not within the "append |
| 473 // window" and handles resyncing on the next random access point |
| 474 // (i.e., next keyframe) if a buffer gets dropped. |
| 475 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); |
| 476 itr != buffers.end(); ++itr) { |
| 477 // Filter out buffers that are outside the append window. Anytime |
| 478 // a buffer gets dropped we need to set |*needs_keyframe| to true |
| 479 // because we can only resume decoding at keyframes. |
| 480 TimeDelta presentation_timestamp = (*itr)->timestamp(); |
| 481 |
| 482 // TODO(acolwell): Change |frame_end_timestamp| value to |
| 483 // |presentation_timestamp + (*itr)->duration()|, like the spec |
| 484 // requires, once frame durations are actually present in all buffers. |
| 485 TimeDelta frame_end_timestamp = presentation_timestamp; |
| 486 if (presentation_timestamp < append_window_start_ || |
| 487 frame_end_timestamp > append_window_end_) { |
| 488 DVLOG(1) << "Dropping buffer outside append window." |
| 489 << " presentation_timestamp " |
| 490 << presentation_timestamp.InSecondsF(); |
| 491 *needs_keyframe = true; |
| 492 |
| 493 // This triggers a discontinuity so we need to treat the next frames |
| 494 // appended within the append window as if they were the beginning of a |
| 495 // new segment. |
| 496 new_media_segment_ = true; |
| 497 continue; |
| 498 } |
| 499 |
| 500 // If |*needs_keyframe| is true then filter out buffers until we |
| 501 // encounter the next keyframe. |
| 502 if (*needs_keyframe) { |
| 503 if (!(*itr)->IsKeyframe()) { |
| 504 DVLOG(1) << "Dropping non-keyframe. presentation_timestamp " |
| 505 << presentation_timestamp.InSecondsF(); |
| 506 continue; |
| 507 } |
| 508 |
| 509 *needs_keyframe = false; |
| 510 } |
| 511 |
| 512 filtered_buffers->push_back(*itr); |
| 513 } |
| 514 } |
| 515 |
417 ChunkDemuxerStream::ChunkDemuxerStream(Type type) | 516 ChunkDemuxerStream::ChunkDemuxerStream(Type type) |
418 : type_(type), | 517 : type_(type), |
419 state_(UNINITIALIZED) { | 518 state_(UNINITIALIZED) { |
420 } | 519 } |
421 | 520 |
422 void ChunkDemuxerStream::StartReturningData() { | 521 void ChunkDemuxerStream::StartReturningData() { |
423 DVLOG(1) << "ChunkDemuxerStream::StartReturningData()"; | 522 DVLOG(1) << "ChunkDemuxerStream::StartReturningData()"; |
424 base::AutoLock auto_lock(lock_); | 523 base::AutoLock auto_lock(lock_); |
425 DCHECK(read_cb_.is_null()); | 524 DCHECK(read_cb_.is_null()); |
426 ChangeState_Locked(RETURNING_DATA_FOR_READS); | 525 ChangeState_Locked(RETURNING_DATA_FOR_READS); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
507 | 606 |
508 // Clamp the end of the stream's buffered ranges to fit within the duration. | 607 // 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 | 608 // This can be done by intersecting the stream's range with the valid time |
510 // range. | 609 // range. |
511 Ranges<TimeDelta> valid_time_range; | 610 Ranges<TimeDelta> valid_time_range; |
512 valid_time_range.Add(range.start(0), duration); | 611 valid_time_range.Add(range.start(0), duration); |
513 return range.IntersectionWith(valid_time_range); | 612 return range.IntersectionWith(valid_time_range); |
514 } | 613 } |
515 | 614 |
516 void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) { | 615 void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) { |
| 616 DVLOG(2) << "ChunkDemuxerStream::OnNewMediaSegment(" |
| 617 << start_timestamp.InSecondsF() << ")"; |
517 base::AutoLock auto_lock(lock_); | 618 base::AutoLock auto_lock(lock_); |
518 stream_->OnNewMediaSegment(start_timestamp); | 619 stream_->OnNewMediaSegment(start_timestamp); |
519 } | 620 } |
520 | 621 |
521 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config, | 622 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config, |
522 const LogCB& log_cb) { | 623 const LogCB& log_cb) { |
523 DCHECK(config.IsValidConfig()); | 624 DCHECK(config.IsValidConfig()); |
524 DCHECK_EQ(type_, AUDIO); | 625 DCHECK_EQ(type_, AUDIO); |
525 base::AutoLock auto_lock(lock_); | 626 base::AutoLock auto_lock(lock_); |
526 if (!stream_) { | 627 if (!stream_) { |
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
796 | 897 |
797 if (has_video) | 898 if (has_video) |
798 source_id_video_ = id; | 899 source_id_video_ = id; |
799 | 900 |
800 scoped_ptr<SourceState> source_state( | 901 scoped_ptr<SourceState> source_state( |
801 new SourceState(stream_parser.Pass(), log_cb_, | 902 new SourceState(stream_parser.Pass(), log_cb_, |
802 base::Bind(&ChunkDemuxer::CreateDemuxerStream, | 903 base::Bind(&ChunkDemuxer::CreateDemuxerStream, |
803 base::Unretained(this)), | 904 base::Unretained(this)), |
804 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, | 905 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, |
805 base::Unretained(this)))); | 906 base::Unretained(this)))); |
| 907 |
806 source_state->Init( | 908 source_state->Init( |
807 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), | 909 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), |
808 has_audio, | 910 has_audio, |
809 has_video, | 911 has_video, |
810 base::Bind(&ChunkDemuxer::OnTextBuffers, base::Unretained(this)), | 912 base::Bind(&ChunkDemuxer::OnTextBuffers, base::Unretained(this)), |
811 need_key_cb_, | 913 need_key_cb_, |
812 add_text_track_cb_, | 914 add_text_track_cb_); |
813 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id)); | |
814 | 915 |
815 source_state_map_[id] = source_state.release(); | 916 source_state_map_[id] = source_state.release(); |
816 return kOk; | 917 return kOk; |
817 } | 918 } |
818 | 919 |
819 void ChunkDemuxer::RemoveId(const std::string& id) { | 920 void ChunkDemuxer::RemoveId(const std::string& id) { |
820 base::AutoLock auto_lock(lock_); | 921 base::AutoLock auto_lock(lock_); |
821 CHECK(IsValidId(id)); | 922 CHECK(IsValidId(id)); |
822 | 923 |
823 delete source_state_map_[id]; | 924 delete source_state_map_[id]; |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1086 | 1187 |
1087 ChangeState_Locked(INITIALIZED); | 1188 ChangeState_Locked(INITIALIZED); |
1088 | 1189 |
1089 if (audio_) | 1190 if (audio_) |
1090 audio_->UnmarkEndOfStream(); | 1191 audio_->UnmarkEndOfStream(); |
1091 | 1192 |
1092 if (video_) | 1193 if (video_) |
1093 video_->UnmarkEndOfStream(); | 1194 video_->UnmarkEndOfStream(); |
1094 } | 1195 } |
1095 | 1196 |
| 1197 void ChunkDemuxer::SetAppendWindowStart(const std::string& id, |
| 1198 TimeDelta start) { |
| 1199 base::AutoLock auto_lock(lock_); |
| 1200 DVLOG(1) << "SetAppendWindowStart(" << id << ", " |
| 1201 << start.InSecondsF() << ")"; |
| 1202 CHECK(IsValidId(id)); |
| 1203 source_state_map_[id]->set_append_window_start(start); |
| 1204 } |
| 1205 |
| 1206 void ChunkDemuxer::SetAppendWindowEnd(const std::string& id, TimeDelta end) { |
| 1207 base::AutoLock auto_lock(lock_); |
| 1208 DVLOG(1) << "SetAppendWindowEnd(" << id << ", " << end.InSecondsF() << ")"; |
| 1209 CHECK(IsValidId(id)); |
| 1210 source_state_map_[id]->set_append_window_end(end); |
| 1211 } |
| 1212 |
1096 void ChunkDemuxer::Shutdown() { | 1213 void ChunkDemuxer::Shutdown() { |
1097 DVLOG(1) << "Shutdown()"; | 1214 DVLOG(1) << "Shutdown()"; |
1098 base::AutoLock auto_lock(lock_); | 1215 base::AutoLock auto_lock(lock_); |
1099 | 1216 |
1100 if (state_ == SHUTDOWN) | 1217 if (state_ == SHUTDOWN) |
1101 return; | 1218 return; |
1102 | 1219 |
1103 if (audio_) | 1220 if (audio_) |
1104 audio_->Shutdown(); | 1221 audio_->Shutdown(); |
1105 | 1222 |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1252 WebMWebVTTParser::Parse(buffer->data(), | 1369 WebMWebVTTParser::Parse(buffer->data(), |
1253 buffer->data_size(), | 1370 buffer->data_size(), |
1254 &id, &settings, &content); | 1371 &id, &settings, &content); |
1255 | 1372 |
1256 text_track->addWebVTTCue(start, end, id, content, settings); | 1373 text_track->addWebVTTCue(start, end, id, content, settings); |
1257 } | 1374 } |
1258 | 1375 |
1259 return true; | 1376 return true; |
1260 } | 1377 } |
1261 | 1378 |
1262 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, | |
1263 TimeDelta timestamp) { | |
1264 DCHECK(timestamp != kNoTimestamp()); | |
1265 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", " | |
1266 << timestamp.InSecondsF() << ")"; | |
1267 lock_.AssertAcquired(); | |
1268 | |
1269 CHECK(IsValidId(source_id)); | |
1270 if (audio_ && source_id == source_id_audio_) | |
1271 audio_->OnNewMediaSegment(timestamp); | |
1272 if (video_ && source_id == source_id_video_) | |
1273 video_->OnNewMediaSegment(timestamp); | |
1274 } | |
1275 | |
1276 bool ChunkDemuxer::IsValidId(const std::string& source_id) const { | 1379 bool ChunkDemuxer::IsValidId(const std::string& source_id) const { |
1277 lock_.AssertAcquired(); | 1380 lock_.AssertAcquired(); |
1278 return source_state_map_.count(source_id) > 0u; | 1381 return source_state_map_.count(source_id) > 0u; |
1279 } | 1382 } |
1280 | 1383 |
1281 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) { | 1384 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) { |
1282 DCHECK(duration_ != new_duration); | 1385 DCHECK(duration_ != new_duration); |
1283 user_specified_duration_ = -1; | 1386 user_specified_duration_ = -1; |
1284 duration_ = new_duration; | 1387 duration_ = new_duration; |
1285 host_->SetDuration(new_duration); | 1388 host_->SetDuration(new_duration); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1344 | 1447 |
1345 void ChunkDemuxer::CompletePendingReadsIfPossible() { | 1448 void ChunkDemuxer::CompletePendingReadsIfPossible() { |
1346 if (audio_) | 1449 if (audio_) |
1347 audio_->CompletePendingReadIfPossible(); | 1450 audio_->CompletePendingReadIfPossible(); |
1348 | 1451 |
1349 if (video_) | 1452 if (video_) |
1350 video_->CompletePendingReadIfPossible(); | 1453 video_->CompletePendingReadIfPossible(); |
1351 } | 1454 } |
1352 | 1455 |
1353 } // namespace media | 1456 } // namespace media |
OLD | NEW |