| 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 |