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 3 // found in the LICENSE file. 4 5 #include "media/filters/chunk_demuxer.h" 6 7 #include <algorithm> 8 #include <deque> 9 #include <limits> 10 11 #include "base/bind.h" 12 #include "base/callback_helpers.h" 13 #include "base/location.h" 14 #include "base/message_loop/message_loop_proxy.h" 15 #include "media/base/audio_decoder_config.h" 16 #include "media/base/bind_to_loop.h" 17 #include "media/base/stream_parser_buffer.h" 18 #include "media/base/video_decoder_config.h" 19 #include "media/filters/stream_parser_factory.h" 20 #include "media/webm/webm_webvtt_parser.h" 21 22 using base::TimeDelta; 23 24 namespace media { 25 26 // Contains state belonging to a source id. 27 class SourceState { 28 public: 29 // Callback signature used to create ChunkDemuxerStreams. 30 typedef base::Callback<ChunkDemuxerStream*( 31 DemuxerStream::Type)> CreateDemuxerStreamCB; 32 33 // Callback signature used to notify ChunkDemuxer of timestamps 34 // that may cause the duration to be updated. 35 typedef base::Callback<void( 36 TimeDelta, ChunkDemuxerStream*)> IncreaseDurationCB; 37 38 SourceState(scoped_ptr<StreamParser> stream_parser, const LogCB& log_cb, 39 const CreateDemuxerStreamCB& create_demuxer_stream_cb, 40 const IncreaseDurationCB& increase_duration_cb); 41 42 void Init(const StreamParser::InitCB& init_cb, 43 bool allow_audio, 44 bool allow_video, 45 const StreamParser::NewTextBuffersCB& text_cb, 46 const StreamParser::NeedKeyCB& need_key_cb, 47 const AddTextTrackCB& add_text_track_cb); 48 49 // Appends new data to the StreamParser. 50 // Returns true if the data was successfully appended. Returns false if an 51 // error occurred. 52 bool Append(const uint8* data, size_t length); 53 54 // Aborts the current append sequence and resets the parser. 55 void Abort(); 56 57 // Sets |timestamp_offset_| if possible. 58 // Returns if the offset was set. Returns false if the offset could not be 59 // updated at this time. 60 bool SetTimestampOffset(TimeDelta timestamp_offset); 61 62 TimeDelta timestamp_offset() const { return timestamp_offset_; } 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 69 private: 70 // Called by the |stream_parser_| when a new initialization segment is 71 // encountered. 72 // Returns true on a successful call. Returns false if an error occured while 73 // processing decoder configurations. 74 bool OnNewConfigs(bool allow_audio, bool allow_video, 75 const AudioDecoderConfig& audio_config, 76 const VideoDecoderConfig& video_config); 77 78 // Called by the |stream_parser_| at the beginning of a new media segment. 79 void OnNewMediaSegment(); 80 81 // Called by the |stream_parser_| at the end of a media segment. 82 void OnEndOfMediaSegment(); 83 84 // Called by the |stream_parser_| when new buffers have been parsed. It 85 // applies |timestamp_offset_| to all buffers in |audio_buffers| and 86 // |video_buffers| and then calls Append() on |audio_| and/or 87 // |video_| with the modified buffers. 88 // Returns true on a successful call. Returns false if an error occured while 89 // processing the buffers. 90 bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, 91 const StreamParser::BufferQueue& video_buffers); 92 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 95 // |new_buffers_cb| with the modified buffers. 96 // Returns true on a successful call. Returns false if an error occured while 97 // processing the buffers. 98 bool OnTextBuffers(const StreamParser::NewTextBuffersCB& new_buffers_cb, 99 TextTrack* text_track, 100 const StreamParser::BufferQueue& buffers); 101 102 // Helper function that adds |timestamp_offset_| to each buffer in |buffers|. 103 void AdjustBufferTimestamps(const StreamParser::BufferQueue& buffers); 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 116 CreateDemuxerStreamCB create_demuxer_stream_cb_; 117 IncreaseDurationCB increase_duration_cb_; 118 119 // The offset to apply to media segment timestamps. 120 TimeDelta timestamp_offset_; 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 133 // Keeps track of whether |timestamp_offset_| can be modified. 134 bool can_update_offset_; 135 136 // The object used to parse appended data. 137 scoped_ptr<StreamParser> stream_parser_; 138 139 ChunkDemuxerStream* audio_; 140 bool audio_needs_keyframe_; 141 142 ChunkDemuxerStream* video_; 143 bool video_needs_keyframe_; 144 145 LogCB log_cb_; 146 147 DISALLOW_COPY_AND_ASSIGN(SourceState); 148 }; 149 150 class ChunkDemuxerStream : public DemuxerStream { 151 public: 152 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; 153 154 explicit ChunkDemuxerStream(Type type); 155 virtual ~ChunkDemuxerStream(); 156 157 // ChunkDemuxerStream control methods. 158 void StartReturningData(); 159 void AbortReads(); 160 void CompletePendingReadIfPossible(); 161 void Shutdown(); 162 163 // SourceBufferStream manipulation methods. 164 void Seek(TimeDelta time); 165 bool IsSeekWaitingForData() const; 166 167 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, 168 // which handle ordering and overlap resolution. 169 // Returns true if buffers were successfully added. 170 bool Append(const StreamParser::BufferQueue& buffers); 171 172 // Removes buffers between |start| and |end| according to the steps 173 // in the "Coded Frame Removal Algorithm" in the Media Source 174 // Extensions Spec. 175 // https://dvcs.w3.org/hg/html-media/raw-file/default/media-source/media-source.html#sourcebuffer-coded-frame-removal 176 // 177 // |duration| is the current duration of the presentation. It is 178 // required by the computation outlined in the spec. 179 void Remove(TimeDelta start, TimeDelta end, TimeDelta duration); 180 181 // Signal to the stream that duration has changed to |duration|. 182 void OnSetDuration(TimeDelta duration); 183 184 // Returns the range of buffered data in this stream, capped at |duration|. 185 Ranges<TimeDelta> GetBufferedRanges(TimeDelta duration) const; 186 187 // Signal to the stream that buffers handed in through subsequent calls to 188 // Append() belong to a media segment that starts at |start_timestamp|. 189 void OnNewMediaSegment(TimeDelta start_timestamp); 190 191 // Called when midstream config updates occur. 192 // Returns true if the new config is accepted. 193 // Returns false if the new config should trigger an error. 194 bool UpdateAudioConfig(const AudioDecoderConfig& config, const LogCB& log_cb); 195 bool UpdateVideoConfig(const VideoDecoderConfig& config, const LogCB& log_cb); 196 197 void MarkEndOfStream(); 198 void UnmarkEndOfStream(); 199 200 // DemuxerStream methods. 201 virtual void Read(const ReadCB& read_cb) OVERRIDE; 202 virtual Type type() OVERRIDE; 203 virtual void EnableBitstreamConverter() OVERRIDE; 204 virtual AudioDecoderConfig audio_decoder_config() OVERRIDE; 205 virtual VideoDecoderConfig video_decoder_config() OVERRIDE; 206 207 void set_memory_limit_for_testing(int memory_limit) { 208 stream_->set_memory_limit_for_testing(memory_limit); 209 } 210 211 private: 212 enum State { 213 UNINITIALIZED, 214 RETURNING_DATA_FOR_READS, 215 RETURNING_ABORT_FOR_READS, 216 SHUTDOWN, 217 }; 218 219 // Assigns |state_| to |state| 220 void ChangeState_Locked(State state); 221 222 void CompletePendingReadIfPossible_Locked(); 223 224 // Gets the value to pass to the next Read() callback. Returns true if 225 // |status| and |buffer| should be passed to the callback. False indicates 226 // that |status| and |buffer| were not set and more data is needed. 227 bool GetNextBuffer_Locked(DemuxerStream::Status* status, 228 scoped_refptr<StreamParserBuffer>* buffer); 229 230 // Specifies the type of the stream (must be AUDIO or VIDEO for now). 231 Type type_; 232 233 scoped_ptr<SourceBufferStream> stream_; 234 235 mutable base::Lock lock_; 236 State state_; 237 ReadCB read_cb_; 238 239 DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream); 240 }; 241 242 SourceState::SourceState(scoped_ptr<StreamParser> stream_parser, 243 const LogCB& log_cb, 244 const CreateDemuxerStreamCB& create_demuxer_stream_cb, 245 const IncreaseDurationCB& increase_duration_cb) 246 : create_demuxer_stream_cb_(create_demuxer_stream_cb), 247 increase_duration_cb_(increase_duration_cb), 248 append_window_end_(kInfiniteDuration()), 249 new_media_segment_(false), 250 can_update_offset_(true), 251 stream_parser_(stream_parser.release()), 252 audio_(NULL), 253 audio_needs_keyframe_(true), 254 video_(NULL), 255 video_needs_keyframe_(true), 256 log_cb_(log_cb) { 257 DCHECK(!create_demuxer_stream_cb_.is_null()); 258 DCHECK(!increase_duration_cb_.is_null()); 259 } 260 261 void SourceState::Init(const StreamParser::InitCB& init_cb, 262 bool allow_audio, 263 bool allow_video, 264 const StreamParser::NewTextBuffersCB& text_cb, 265 const StreamParser::NeedKeyCB& need_key_cb, 266 const AddTextTrackCB& add_text_track_cb) { 267 StreamParser::NewBuffersCB audio_cb; 268 269 stream_parser_->Init(init_cb, 270 base::Bind(&SourceState::OnNewConfigs, 271 base::Unretained(this), 272 allow_audio, 273 allow_video), 274 base::Bind(&SourceState::OnNewBuffers, 275 base::Unretained(this)), 276 base::Bind(&SourceState::OnTextBuffers, 277 base::Unretained(this), text_cb), 278 need_key_cb, 279 add_text_track_cb, 280 base::Bind(&SourceState::OnNewMediaSegment, 281 base::Unretained(this)), 282 base::Bind(&SourceState::OnEndOfMediaSegment, 283 base::Unretained(this)), 284 log_cb_); 285 } 286 287 bool SourceState::SetTimestampOffset(TimeDelta timestamp_offset) { 288 if (!can_update_offset_) 289 return false; 290 291 timestamp_offset_ = timestamp_offset; 292 return true; 293 } 294 295 bool SourceState::Append(const uint8* data, size_t length) { 296 return stream_parser_->Parse(data, length); 297 } 298 299 void SourceState::Abort() { 300 stream_parser_->Flush(); 301 audio_needs_keyframe_ = true; 302 video_needs_keyframe_ = true; 303 can_update_offset_ = true; 304 } 305 306 void SourceState::AdjustBufferTimestamps( 307 const StreamParser::BufferQueue& buffers) { 308 if (timestamp_offset_ == TimeDelta()) 309 return; 310 311 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); 312 itr != buffers.end(); ++itr) { 313 (*itr)->SetDecodeTimestamp( 314 (*itr)->GetDecodeTimestamp() + timestamp_offset_); 315 (*itr)->set_timestamp((*itr)->timestamp() + timestamp_offset_); 316 } 317 } 318 319 bool SourceState::OnNewConfigs(bool allow_audio, bool allow_video, 320 const AudioDecoderConfig& audio_config, 321 const VideoDecoderConfig& video_config) { 322 DVLOG(1) << "OnNewConfigs(" << allow_audio << ", " << allow_video 323 << ", " << audio_config.IsValidConfig() 324 << ", " << video_config.IsValidConfig() << ")"; 325 326 if (!audio_config.IsValidConfig() && !video_config.IsValidConfig()) { 327 DVLOG(1) << "OnNewConfigs() : Audio & video config are not valid!"; 328 return false; 329 } 330 331 // Signal an error if we get configuration info for stream types that weren't 332 // specified in AddId() or more configs after a stream is initialized. 333 if (allow_audio != audio_config.IsValidConfig()) { 334 MEDIA_LOG(log_cb_) 335 << "Initialization segment" 336 << (audio_config.IsValidConfig() ? " has" : " does not have") 337 << " an audio track, but the mimetype" 338 << (allow_audio ? " specifies" : " does not specify") 339 << " an audio codec."; 340 return false; 341 } 342 343 if (allow_video != video_config.IsValidConfig()) { 344 MEDIA_LOG(log_cb_) 345 << "Initialization segment" 346 << (video_config.IsValidConfig() ? " has" : " does not have") 347 << " a video track, but the mimetype" 348 << (allow_video ? " specifies" : " does not specify") 349 << " a video codec."; 350 return false; 351 } 352 353 bool success = true; 354 if (audio_config.IsValidConfig()) { 355 if (!audio_) { 356 audio_ = create_demuxer_stream_cb_.Run(DemuxerStream::AUDIO); 357 358 if (!audio_) { 359 DVLOG(1) << "Failed to create an audio stream."; 360 return false; 361 } 362 } 363 364 success &= audio_->UpdateAudioConfig(audio_config, log_cb_); 365 } 366 367 if (video_config.IsValidConfig()) { 368 if (!video_) { 369 video_ = create_demuxer_stream_cb_.Run(DemuxerStream::VIDEO); 370 371 if (!video_) { 372 DVLOG(1) << "Failed to create a video stream."; 373 return false; 374 } 375 } 376 377 success &= video_->UpdateVideoConfig(video_config, log_cb_); 378 } 379 380 DVLOG(1) << "OnNewConfigs() : " << (success ? "success" : "failed"); 381 return success; 382 } 383 384 void SourceState::OnNewMediaSegment() { 385 DVLOG(2) << "OnNewMediaSegment()"; 386 can_update_offset_ = false; 387 new_media_segment_ = true; 388 } 389 390 void SourceState::OnEndOfMediaSegment() { 391 DVLOG(2) << "OnEndOfMediaSegment()"; 392 can_update_offset_ = true; 393 new_media_segment_ = false; 394 } 395 396 bool SourceState::OnNewBuffers(const StreamParser::BufferQueue& audio_buffers, 397 const StreamParser::BufferQueue& video_buffers) { 398 DCHECK(!audio_buffers.empty() || !video_buffers.empty()); 399 AdjustBufferTimestamps(audio_buffers); 400 AdjustBufferTimestamps(video_buffers); 401 402 StreamParser::BufferQueue filtered_audio; 403 StreamParser::BufferQueue filtered_video; 404 405 FilterWithAppendWindow(audio_buffers, &audio_needs_keyframe_, 406 &filtered_audio); 407 408 FilterWithAppendWindow(video_buffers, &video_needs_keyframe_, 409 &filtered_video); 410 411 if (filtered_audio.empty() && filtered_video.empty()) 412 return true; 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); 435 } 436 437 if (!filtered_audio.empty()) { 438 if (!audio_ || !audio_->Append(filtered_audio)) 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 449 return true; 450 } 451 452 bool SourceState::OnTextBuffers( 453 const StreamParser::NewTextBuffersCB& new_buffers_cb, 454 TextTrack* text_track, 455 const StreamParser::BufferQueue& buffers) { 456 if (new_buffers_cb.is_null()) 457 return false; 458 459 AdjustBufferTimestamps(buffers); 460 461 return new_buffers_cb.Run(text_track, buffers); 462 } 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 516 ChunkDemuxerStream::ChunkDemuxerStream(Type type) 517 : type_(type), 518 state_(UNINITIALIZED) { 519 } 520 521 void ChunkDemuxerStream::StartReturningData() { 522 DVLOG(1) << "ChunkDemuxerStream::StartReturningData()"; 523 base::AutoLock auto_lock(lock_); 524 DCHECK(read_cb_.is_null()); 525 ChangeState_Locked(RETURNING_DATA_FOR_READS); 526 } 527 528 void ChunkDemuxerStream::AbortReads() { 529 DVLOG(1) << "ChunkDemuxerStream::AbortReads()"; 530 base::AutoLock auto_lock(lock_); 531 ChangeState_Locked(RETURNING_ABORT_FOR_READS); 532 if (!read_cb_.is_null()) 533 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL); 534 } 535 536 void ChunkDemuxerStream::CompletePendingReadIfPossible() { 537 base::AutoLock auto_lock(lock_); 538 if (read_cb_.is_null()) 539 return; 540 541 CompletePendingReadIfPossible_Locked(); 542 } 543 544 void ChunkDemuxerStream::Shutdown() { 545 DVLOG(1) << "ChunkDemuxerStream::Shutdown()"; 546 base::AutoLock auto_lock(lock_); 547 ChangeState_Locked(SHUTDOWN); 548 549 // Pass an end of stream buffer to the pending callback to signal that no more 550 // data will be sent. 551 if (!read_cb_.is_null()) { 552 base::ResetAndReturn(&read_cb_).Run(DemuxerStream::kOk, 553 StreamParserBuffer::CreateEOSBuffer()); 554 } 555 } 556 557 bool ChunkDemuxerStream::IsSeekWaitingForData() const { 558 base::AutoLock auto_lock(lock_); 559 return stream_->IsSeekPending(); 560 } 561 562 void ChunkDemuxerStream::Seek(TimeDelta time) { 563 DVLOG(1) << "ChunkDemuxerStream::Seek(" << time.InSecondsF() << ")"; 564 base::AutoLock auto_lock(lock_); 565 DCHECK(read_cb_.is_null()); 566 DCHECK(state_ == UNINITIALIZED || state_ == RETURNING_ABORT_FOR_READS); 567 568 stream_->Seek(time); 569 } 570 571 bool ChunkDemuxerStream::Append(const StreamParser::BufferQueue& buffers) { 572 if (buffers.empty()) 573 return false; 574 575 base::AutoLock auto_lock(lock_); 576 DCHECK_NE(state_, SHUTDOWN); 577 if (!stream_->Append(buffers)) { 578 DVLOG(1) << "ChunkDemuxerStream::Append() : stream append failed"; 579 return false; 580 } 581 582 if (!read_cb_.is_null()) 583 CompletePendingReadIfPossible_Locked(); 584 585 return true; 586 } 587 588 void ChunkDemuxerStream::Remove(TimeDelta start, TimeDelta end, 589 TimeDelta duration) { 590 base::AutoLock auto_lock(lock_); 591 stream_->Remove(start, end, duration); 592 } 593 594 void ChunkDemuxerStream::OnSetDuration(TimeDelta duration) { 595 base::AutoLock auto_lock(lock_); 596 stream_->OnSetDuration(duration); 597 } 598 599 Ranges<TimeDelta> ChunkDemuxerStream::GetBufferedRanges( 600 TimeDelta duration) const { 601 base::AutoLock auto_lock(lock_); 602 Ranges<TimeDelta> range = stream_->GetBufferedTime(); 603 604 if (range.size() == 0u) 605 return range; 606 607 // Clamp the end of the stream's buffered ranges to fit within the duration. 608 // This can be done by intersecting the stream's range with the valid time 609 // range. 610 Ranges<TimeDelta> valid_time_range; 611 valid_time_range.Add(range.start(0), duration); 612 return range.IntersectionWith(valid_time_range); 613 } 614 615 void ChunkDemuxerStream::OnNewMediaSegment(TimeDelta start_timestamp) { 616 DVLOG(2) << "ChunkDemuxerStream::OnNewMediaSegment(" 617 << start_timestamp.InSecondsF() << ")"; 618 base::AutoLock auto_lock(lock_); 619 stream_->OnNewMediaSegment(start_timestamp); 620 } 621 622 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config, 623 const LogCB& log_cb) { 624 DCHECK(config.IsValidConfig()); 625 DCHECK_EQ(type_, AUDIO); 626 base::AutoLock auto_lock(lock_); 627 if (!stream_) { 628 DCHECK_EQ(state_, UNINITIALIZED); 629 stream_.reset(new SourceBufferStream(config, log_cb)); 630 return true; 631 } 632 633 return stream_->UpdateAudioConfig(config); 634 } 635 636 bool ChunkDemuxerStream::UpdateVideoConfig(const VideoDecoderConfig& config, 637 const LogCB& log_cb) { 638 DCHECK(config.IsValidConfig()); 639 DCHECK_EQ(type_, VIDEO); 640 base::AutoLock auto_lock(lock_); 641 642 if (!stream_) { 643 DCHECK_EQ(state_, UNINITIALIZED); 644 stream_.reset(new SourceBufferStream(config, log_cb)); 645 return true; 646 } 647 648 return stream_->UpdateVideoConfig(config); 649 } 650 651 void ChunkDemuxerStream::MarkEndOfStream() { 652 base::AutoLock auto_lock(lock_); 653 stream_->MarkEndOfStream(); 654 } 655 656 void ChunkDemuxerStream::UnmarkEndOfStream() { 657 base::AutoLock auto_lock(lock_); 658 stream_->UnmarkEndOfStream(); 659 } 660 661 // DemuxerStream methods. 662 void ChunkDemuxerStream::Read(const ReadCB& read_cb) { 663 base::AutoLock auto_lock(lock_); 664 DCHECK_NE(state_, UNINITIALIZED); 665 DCHECK(read_cb_.is_null()); 666 667 read_cb_ = BindToCurrentLoop(read_cb); 668 CompletePendingReadIfPossible_Locked(); 669 } 670 671 DemuxerStream::Type ChunkDemuxerStream::type() { return type_; } 672 673 void ChunkDemuxerStream::EnableBitstreamConverter() {} 674 675 AudioDecoderConfig ChunkDemuxerStream::audio_decoder_config() { 676 CHECK_EQ(type_, AUDIO); 677 base::AutoLock auto_lock(lock_); 678 return stream_->GetCurrentAudioDecoderConfig(); 679 } 680 681 VideoDecoderConfig ChunkDemuxerStream::video_decoder_config() { 682 CHECK_EQ(type_, VIDEO); 683 base::AutoLock auto_lock(lock_); 684 return stream_->GetCurrentVideoDecoderConfig(); 685 } 686 687 void ChunkDemuxerStream::ChangeState_Locked(State state) { 688 lock_.AssertAcquired(); 689 DVLOG(1) << "ChunkDemuxerStream::ChangeState_Locked() : " 690 << "type " << type_ 691 << " - " << state_ << " -> " << state; 692 state_ = state; 693 } 694 695 ChunkDemuxerStream::~ChunkDemuxerStream() {} 696 697 void ChunkDemuxerStream::CompletePendingReadIfPossible_Locked() { 698 lock_.AssertAcquired(); 699 DCHECK(!read_cb_.is_null()); 700 701 DemuxerStream::Status status; 702 scoped_refptr<StreamParserBuffer> buffer; 703 704 switch (state_) { 705 case UNINITIALIZED: 706 NOTREACHED(); 707 return; 708 case RETURNING_DATA_FOR_READS: 709 switch (stream_->GetNextBuffer(&buffer)) { 710 case SourceBufferStream::kSuccess: 711 status = DemuxerStream::kOk; 712 break; 713 case SourceBufferStream::kNeedBuffer: 714 // Return early without calling |read_cb_| since we don't have 715 // any data to return yet. 716 return; 717 case SourceBufferStream::kEndOfStream: 718 status = DemuxerStream::kOk; 719 buffer = StreamParserBuffer::CreateEOSBuffer(); 720 break; 721 case SourceBufferStream::kConfigChange: 722 DVLOG(2) << "Config change reported to ChunkDemuxerStream."; 723 status = kConfigChanged; 724 buffer = NULL; 725 break; 726 } 727 break; 728 case RETURNING_ABORT_FOR_READS: 729 // Null buffers should be returned in this state since we are waiting 730 // for a seek. Any buffers in the SourceBuffer should NOT be returned 731 // because they are associated with the seek. 732 status = DemuxerStream::kAborted; 733 buffer = NULL; 734 break; 735 case SHUTDOWN: 736 status = DemuxerStream::kOk; 737 buffer = StreamParserBuffer::CreateEOSBuffer(); 738 break; 739 } 740 741 base::ResetAndReturn(&read_cb_).Run(status, buffer); 742 } 743 744 ChunkDemuxer::ChunkDemuxer(const base::Closure& open_cb, 745 const NeedKeyCB& need_key_cb, 746 const AddTextTrackCB& add_text_track_cb, 747 const LogCB& log_cb) 748 : state_(WAITING_FOR_INIT), 749 cancel_next_seek_(false), 750 host_(NULL), 751 open_cb_(open_cb), 752 need_key_cb_(need_key_cb), 753 add_text_track_cb_(add_text_track_cb), 754 log_cb_(log_cb), 755 duration_(kNoTimestamp()), 756 user_specified_duration_(-1) { 757 DCHECK(!open_cb_.is_null()); 758 DCHECK(!need_key_cb_.is_null()); 759 } 760 761 void ChunkDemuxer::Initialize(DemuxerHost* host, const PipelineStatusCB& cb) { 762 DVLOG(1) << "Init()"; 763 764 base::AutoLock auto_lock(lock_); 765 766 init_cb_ = BindToCurrentLoop(cb); 767 if (state_ == SHUTDOWN) { 768 base::ResetAndReturn(&init_cb_).Run(DEMUXER_ERROR_COULD_NOT_OPEN); 769 return; 770 } 771 DCHECK_EQ(state_, WAITING_FOR_INIT); 772 host_ = host; 773 774 ChangeState_Locked(INITIALIZING); 775 776 base::ResetAndReturn(&open_cb_).Run(); 777 } 778 779 void ChunkDemuxer::Stop(const base::Closure& callback) { 780 DVLOG(1) << "Stop()"; 781 Shutdown(); 782 callback.Run(); 783 } 784 785 void ChunkDemuxer::Seek(TimeDelta time, const PipelineStatusCB& cb) { 786 DVLOG(1) << "Seek(" << time.InSecondsF() << ")"; 787 DCHECK(time >= TimeDelta()); 788 789 base::AutoLock auto_lock(lock_); 790 DCHECK(seek_cb_.is_null()); 791 792 seek_cb_ = BindToCurrentLoop(cb); 793 if (state_ != INITIALIZED && state_ != ENDED) { 794 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_ERROR_INVALID_STATE); 795 return; 796 } 797 798 if (cancel_next_seek_) { 799 cancel_next_seek_ = false; 800 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); 801 return; 802 } 803 804 SeekAllSources(time); 805 StartReturningData(); 806 807 if (IsSeekWaitingForData_Locked()) { 808 DVLOG(1) << "Seek() : waiting for more data to arrive."; 809 return; 810 } 811 812 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); 813 } 814 815 void ChunkDemuxer::OnAudioRendererDisabled() { 816 base::AutoLock auto_lock(lock_); 817 audio_->Shutdown(); 818 disabled_audio_ = audio_.Pass(); 819 } 820 821 // Demuxer implementation. 822 DemuxerStream* ChunkDemuxer::GetStream(DemuxerStream::Type type) { 823 base::AutoLock auto_lock(lock_); 824 if (type == DemuxerStream::VIDEO) 825 return video_.get(); 826 827 if (type == DemuxerStream::AUDIO) 828 return audio_.get(); 829 830 return NULL; 831 } 832 833 TimeDelta ChunkDemuxer::GetStartTime() const { 834 return TimeDelta(); 835 } 836 837 void ChunkDemuxer::StartWaitingForSeek(TimeDelta seek_time) { 838 DVLOG(1) << "StartWaitingForSeek()"; 839 base::AutoLock auto_lock(lock_); 840 DCHECK(state_ == INITIALIZED || state_ == ENDED || state_ == SHUTDOWN || 841 state_ == PARSE_ERROR) << state_; 842 DCHECK(seek_cb_.is_null()); 843 844 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) 845 return; 846 847 AbortPendingReads(); 848 SeekAllSources(seek_time); 849 850 // Cancel state set in CancelPendingSeek() since we want to 851 // accept the next Seek(). 852 cancel_next_seek_ = false; 853 } 854 855 void ChunkDemuxer::CancelPendingSeek(TimeDelta seek_time) { 856 base::AutoLock auto_lock(lock_); 857 DCHECK_NE(state_, INITIALIZING); 858 DCHECK(seek_cb_.is_null() || IsSeekWaitingForData_Locked()); 859 860 if (cancel_next_seek_) 861 return; 862 863 AbortPendingReads(); 864 SeekAllSources(seek_time); 865 866 if (seek_cb_.is_null()) { 867 cancel_next_seek_ = true; 868 return; 869 } 870 871 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); 872 } 873 874 ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id, 875 const std::string& type, 876 std::vector<std::string>& codecs) { 877 DCHECK_GT(codecs.size(), 0u); 878 base::AutoLock auto_lock(lock_); 879 880 if ((state_ != WAITING_FOR_INIT && state_ != INITIALIZING) || IsValidId(id)) 881 return kReachedIdLimit; 882 883 bool has_audio = false; 884 bool has_video = false; 885 scoped_ptr<media::StreamParser> stream_parser( 886 StreamParserFactory::Create(type, codecs, log_cb_, 887 &has_audio, &has_video)); 888 889 if (!stream_parser) 890 return ChunkDemuxer::kNotSupported; 891 892 if ((has_audio && !source_id_audio_.empty()) || 893 (has_video && !source_id_video_.empty())) 894 return kReachedIdLimit; 895 896 if (has_audio) 897 source_id_audio_ = id; 898 899 if (has_video) 900 source_id_video_ = id; 901 902 scoped_ptr<SourceState> source_state( 903 new SourceState(stream_parser.Pass(), log_cb_, 904 base::Bind(&ChunkDemuxer::CreateDemuxerStream, 905 base::Unretained(this)), 906 base::Bind(&ChunkDemuxer::IncreaseDurationIfNecessary, 907 base::Unretained(this)))); 908 909 source_state->Init( 910 base::Bind(&ChunkDemuxer::OnSourceInitDone, base::Unretained(this)), 911 has_audio, 912 has_video, 913 base::Bind(&ChunkDemuxer::OnTextBuffers, base::Unretained(this)), 914 need_key_cb_, 915 add_text_track_cb_); 916 917 source_state_map_[id] = source_state.release(); 918 return kOk; 919 } 920 921 void ChunkDemuxer::RemoveId(const std::string& id) { 922 base::AutoLock auto_lock(lock_); 923 CHECK(IsValidId(id)); 924 925 delete source_state_map_[id]; 926 source_state_map_.erase(id); 927 928 if (source_id_audio_ == id) { 929 if (audio_) 930 audio_->Shutdown(); 931 source_id_audio_.clear(); 932 } 933 934 if (source_id_video_ == id) { 935 if (video_) 936 video_->Shutdown(); 937 source_id_video_.clear(); 938 } 939 } 940 941 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { 942 base::AutoLock auto_lock(lock_); 943 DCHECK(!id.empty()); 944 DCHECK(IsValidId(id)); 945 DCHECK(id == source_id_audio_ || id == source_id_video_); 946 947 if (id == source_id_audio_ && id != source_id_video_) { 948 // Only include ranges that have been buffered in |audio_| 949 return audio_ ? audio_->GetBufferedRanges(duration_) : Ranges<TimeDelta>(); 950 } 951 952 if (id != source_id_audio_ && id == source_id_video_) { 953 // Only include ranges that have been buffered in |video_| 954 return video_ ? video_->GetBufferedRanges(duration_) : Ranges<TimeDelta>(); 955 } 956 957 return ComputeIntersection(); 958 } 959 960 Ranges<TimeDelta> ChunkDemuxer::ComputeIntersection() const { 961 lock_.AssertAcquired(); 962 963 if (!audio_ || !video_) 964 return Ranges<TimeDelta>(); 965 966 // Include ranges that have been buffered in both |audio_| and |video_|. 967 Ranges<TimeDelta> audio_ranges = audio_->GetBufferedRanges(duration_); 968 Ranges<TimeDelta> video_ranges = video_->GetBufferedRanges(duration_); 969 Ranges<TimeDelta> result = audio_ranges.IntersectionWith(video_ranges); 970 971 if (state_ == ENDED && result.size() > 0) { 972 // If appending has ended, extend the last intersection range to include the 973 // max end time of the last audio/video range. This allows the buffered 974 // information to match the actual time range that will get played out if 975 // the streams have slightly different lengths. 976 TimeDelta audio_start = audio_ranges.start(audio_ranges.size() - 1); 977 TimeDelta audio_end = audio_ranges.end(audio_ranges.size() - 1); 978 TimeDelta video_start = video_ranges.start(video_ranges.size() - 1); 979 TimeDelta video_end = video_ranges.end(video_ranges.size() - 1); 980 981 // Verify the last audio range overlaps with the last video range. 982 // This is enforced by the logic that controls the transition to ENDED. 983 DCHECK((audio_start <= video_start && video_start <= audio_end) || 984 (video_start <= audio_start && audio_start <= video_end)); 985 result.Add(result.end(result.size()-1), std::max(audio_end, video_end)); 986 } 987 988 return result; 989 } 990 991 void ChunkDemuxer::AppendData(const std::string& id, 992 const uint8* data, 993 size_t length) { 994 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; 995 996 DCHECK(!id.empty()); 997 998 Ranges<TimeDelta> ranges; 999 1000 { 1001 base::AutoLock auto_lock(lock_); 1002 DCHECK_NE(state_, ENDED); 1003 1004 // Capture if any of the SourceBuffers are waiting for data before we start 1005 // parsing. 1006 bool old_waiting_for_data = IsSeekWaitingForData_Locked(); 1007 1008 if (length == 0u) 1009 return; 1010 1011 DCHECK(data); 1012 1013 switch (state_) { 1014 case INITIALIZING: 1015 DCHECK(IsValidId(id)); 1016 if (!source_state_map_[id]->Append(data, length)) { 1017 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 1018 return; 1019 } 1020 break; 1021 1022 case INITIALIZED: { 1023 DCHECK(IsValidId(id)); 1024 if (!source_state_map_[id]->Append(data, length)) { 1025 ReportError_Locked(PIPELINE_ERROR_DECODE); 1026 return; 1027 } 1028 } break; 1029 1030 case PARSE_ERROR: 1031 DVLOG(1) << "AppendData(): Ignoring data after a parse error."; 1032 return; 1033 1034 case WAITING_FOR_INIT: 1035 case ENDED: 1036 case SHUTDOWN: 1037 DVLOG(1) << "AppendData(): called in unexpected state " << state_; 1038 return; 1039 } 1040 1041 // Check to see if data was appended at the pending seek point. This 1042 // indicates we have parsed enough data to complete the seek. 1043 if (old_waiting_for_data && !IsSeekWaitingForData_Locked() && 1044 !seek_cb_.is_null()) { 1045 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); 1046 } 1047 1048 ranges = GetBufferedRanges(); 1049 } 1050 1051 for (size_t i = 0; i < ranges.size(); ++i) 1052 host_->AddBufferedTimeRange(ranges.start(i), ranges.end(i)); 1053 } 1054 1055 void ChunkDemuxer::Abort(const std::string& id) { 1056 DVLOG(1) << "Abort(" << id << ")"; 1057 base::AutoLock auto_lock(lock_); 1058 DCHECK(!id.empty()); 1059 CHECK(IsValidId(id)); 1060 source_state_map_[id]->Abort(); 1061 } 1062 1063 void ChunkDemuxer::Remove(const std::string& id, base::TimeDelta start, 1064 base::TimeDelta end) { 1065 DVLOG(1) << "Remove(" << id << ", " << start.InSecondsF() 1066 << ", " << end.InSecondsF() << ")"; 1067 base::AutoLock auto_lock(lock_); 1068 1069 if (id == source_id_audio_ && audio_) 1070 audio_->Remove(start, end, duration_); 1071 1072 if (id == source_id_video_ && video_) 1073 video_->Remove(start, end, duration_); 1074 } 1075 1076 double ChunkDemuxer::GetDuration() { 1077 base::AutoLock auto_lock(lock_); 1078 return GetDuration_Locked(); 1079 } 1080 1081 double ChunkDemuxer::GetDuration_Locked() { 1082 lock_.AssertAcquired(); 1083 if (duration_ == kNoTimestamp()) 1084 return std::numeric_limits<double>::quiet_NaN(); 1085 1086 // Return positive infinity if the resource is unbounded. 1087 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-media-duration 1088 if (duration_ == kInfiniteDuration()) 1089 return std::numeric_limits<double>::infinity(); 1090 1091 if (user_specified_duration_ >= 0) 1092 return user_specified_duration_; 1093 1094 return duration_.InSecondsF(); 1095 } 1096 1097 void ChunkDemuxer::SetDuration(double duration) { 1098 base::AutoLock auto_lock(lock_); 1099 DVLOG(1) << "SetDuration(" << duration << ")"; 1100 DCHECK_GE(duration, 0); 1101 1102 if (duration == GetDuration_Locked()) 1103 return; 1104 1105 // Compute & bounds check the TimeDelta representation of duration. 1106 // This can be different if the value of |duration| doesn't fit the range or 1107 // precision of TimeDelta. 1108 TimeDelta min_duration = TimeDelta::FromInternalValue(1); 1109 TimeDelta max_duration = TimeDelta::FromInternalValue(kint64max - 1); 1110 double min_duration_in_seconds = min_duration.InSecondsF(); 1111 double max_duration_in_seconds = max_duration.InSecondsF(); 1112 1113 TimeDelta duration_td; 1114 if (duration == std::numeric_limits<double>::infinity()) { 1115 duration_td = media::kInfiniteDuration(); 1116 } else if (duration < min_duration_in_seconds) { 1117 duration_td = min_duration; 1118 } else if (duration > max_duration_in_seconds) { 1119 duration_td = max_duration; 1120 } else { 1121 duration_td = TimeDelta::FromMicroseconds( 1122 duration * base::Time::kMicrosecondsPerSecond); 1123 } 1124 1125 DCHECK(duration_td > TimeDelta()); 1126 1127 user_specified_duration_ = duration; 1128 duration_ = duration_td; 1129 host_->SetDuration(duration_); 1130 1131 if (audio_) 1132 audio_->OnSetDuration(duration_); 1133 1134 if (video_) 1135 video_->OnSetDuration(duration_); 1136 } 1137 1138 bool ChunkDemuxer::SetTimestampOffset(const std::string& id, TimeDelta offset) { 1139 base::AutoLock auto_lock(lock_); 1140 DVLOG(1) << "SetTimestampOffset(" << id << ", " << offset.InSecondsF() << ")"; 1141 CHECK(IsValidId(id)); 1142 1143 return source_state_map_[id]->SetTimestampOffset(offset); 1144 } 1145 1146 void ChunkDemuxer::MarkEndOfStream(PipelineStatus status) { 1147 DVLOG(1) << "MarkEndOfStream(" << status << ")"; 1148 base::AutoLock auto_lock(lock_); 1149 DCHECK_NE(state_, WAITING_FOR_INIT); 1150 DCHECK_NE(state_, ENDED); 1151 1152 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) 1153 return; 1154 1155 if (state_ == INITIALIZING) { 1156 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 1157 return; 1158 } 1159 1160 bool old_waiting_for_data = IsSeekWaitingForData_Locked(); 1161 if (audio_) 1162 audio_->MarkEndOfStream(); 1163 1164 if (video_) 1165 video_->MarkEndOfStream(); 1166 1167 CompletePendingReadsIfPossible(); 1168 1169 // Give a chance to resume the pending seek process. 1170 if (status != PIPELINE_OK) { 1171 ReportError_Locked(status); 1172 return; 1173 } 1174 1175 ChangeState_Locked(ENDED); 1176 DecreaseDurationIfNecessary(); 1177 1178 if (old_waiting_for_data && !IsSeekWaitingForData_Locked() && 1179 !seek_cb_.is_null()) { 1180 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_OK); 1181 } 1182 } 1183 1184 void ChunkDemuxer::UnmarkEndOfStream() { 1185 DVLOG(1) << "UnmarkEndOfStream()"; 1186 base::AutoLock auto_lock(lock_); 1187 DCHECK_EQ(state_, ENDED); 1188 1189 ChangeState_Locked(INITIALIZED); 1190 1191 if (audio_) 1192 audio_->UnmarkEndOfStream(); 1193 1194 if (video_) 1195 video_->UnmarkEndOfStream(); 1196 } 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]->set_append_window_start(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]->set_append_window_end(end); 1212 } 1213 1214 void ChunkDemuxer::Shutdown() { 1215 DVLOG(1) << "Shutdown()"; 1216 base::AutoLock auto_lock(lock_); 1217 1218 if (state_ == SHUTDOWN) 1219 return; 1220 1221 if (audio_) 1222 audio_->Shutdown(); 1223 1224 if (video_) 1225 video_->Shutdown(); 1226 1227 ChangeState_Locked(SHUTDOWN); 1228 1229 if(!seek_cb_.is_null()) 1230 base::ResetAndReturn(&seek_cb_).Run(PIPELINE_ERROR_ABORT); 1231 } 1232 1233 void ChunkDemuxer::SetMemoryLimitsForTesting(int memory_limit) { 1234 if (audio_) 1235 audio_->set_memory_limit_for_testing(memory_limit); 1236 1237 if (video_) 1238 video_->set_memory_limit_for_testing(memory_limit); 1239 } 1240 1241 void ChunkDemuxer::ChangeState_Locked(State new_state) { 1242 lock_.AssertAcquired(); 1243 DVLOG(1) << "ChunkDemuxer::ChangeState_Locked() : " 1244 << state_ << " -> " << new_state; 1245 state_ = new_state; 1246 } 1247 1248 ChunkDemuxer::~ChunkDemuxer() { 1249 DCHECK_NE(state_, INITIALIZED); 1250 for (SourceStateMap::iterator it = source_state_map_.begin(); 1251 it != source_state_map_.end(); ++it) { 1252 delete it->second; 1253 } 1254 source_state_map_.clear(); 1255 } 1256 1257 void ChunkDemuxer::ReportError_Locked(PipelineStatus error) { 1258 DVLOG(1) << "ReportError_Locked(" << error << ")"; 1259 lock_.AssertAcquired(); 1260 DCHECK_NE(error, PIPELINE_OK); 1261 1262 ChangeState_Locked(PARSE_ERROR); 1263 1264 PipelineStatusCB cb; 1265 1266 if (!init_cb_.is_null()) { 1267 std::swap(cb, init_cb_); 1268 } else { 1269 if (!seek_cb_.is_null()) 1270 std::swap(cb, seek_cb_); 1271 1272 if (audio_) 1273 audio_->Shutdown(); 1274 1275 if (video_) 1276 video_->Shutdown(); 1277 } 1278 1279 if (!cb.is_null()) { 1280 cb.Run(error); 1281 return; 1282 } 1283 1284 base::AutoUnlock auto_unlock(lock_); 1285 host_->OnDemuxerError(error); 1286 } 1287 1288 bool ChunkDemuxer::IsSeekWaitingForData_Locked() const { 1289 lock_.AssertAcquired(); 1290 bool waiting_for_data = false; 1291 1292 if (audio_) 1293 waiting_for_data = audio_->IsSeekWaitingForData(); 1294 1295 if (!waiting_for_data && video_) 1296 waiting_for_data = video_->IsSeekWaitingForData(); 1297 1298 return waiting_for_data; 1299 } 1300 1301 void ChunkDemuxer::OnSourceInitDone(bool success, TimeDelta duration) { 1302 DVLOG(1) << "OnSourceInitDone(" << success << ", " 1303 << duration.InSecondsF() << ")"; 1304 lock_.AssertAcquired(); 1305 DCHECK_EQ(state_, INITIALIZING); 1306 if (!success || (!audio_ && !video_)) { 1307 ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN); 1308 return; 1309 } 1310 1311 if (duration != TimeDelta() && duration_ == kNoTimestamp()) 1312 UpdateDuration(duration); 1313 1314 // Wait until all streams have initialized. 1315 if ((!source_id_audio_.empty() && !audio_) || 1316 (!source_id_video_.empty() && !video_)) 1317 return; 1318 1319 SeekAllSources(GetStartTime()); 1320 StartReturningData(); 1321 1322 if (duration_ == kNoTimestamp()) 1323 duration_ = kInfiniteDuration(); 1324 1325 // The demuxer is now initialized after the |start_timestamp_| was set. 1326 ChangeState_Locked(INITIALIZED); 1327 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); 1328 } 1329 1330 ChunkDemuxerStream* 1331 ChunkDemuxer::CreateDemuxerStream(DemuxerStream::Type type) { 1332 switch (type) { 1333 case DemuxerStream::AUDIO: 1334 if (audio_) 1335 return NULL; 1336 audio_.reset(new ChunkDemuxerStream(DemuxerStream::AUDIO)); 1337 return audio_.get(); 1338 break; 1339 case DemuxerStream::VIDEO: 1340 if (video_) 1341 return NULL; 1342 video_.reset(new ChunkDemuxerStream(DemuxerStream::VIDEO)); 1343 return video_.get(); 1344 break; 1345 case DemuxerStream::UNKNOWN: 1346 case DemuxerStream::NUM_TYPES: 1347 NOTREACHED(); 1348 return NULL; 1349 } 1350 NOTREACHED(); 1351 return NULL; 1352 } 1353 1354 bool ChunkDemuxer::OnTextBuffers( 1355 TextTrack* text_track, 1356 const StreamParser::BufferQueue& buffers) { 1357 lock_.AssertAcquired(); 1358 DCHECK_NE(state_, SHUTDOWN); 1359 1360 // TODO(matthewjheaney): IncreaseDurationIfNecessary 1361 1362 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin(); 1363 itr != buffers.end(); ++itr) { 1364 const StreamParserBuffer* const buffer = itr->get(); 1365 const TimeDelta start = buffer->timestamp(); 1366 const TimeDelta end = start + buffer->duration(); 1367 1368 std::string id, settings, content; 1369 1370 WebMWebVTTParser::Parse(buffer->data(), 1371 buffer->data_size(), 1372 &id, &settings, &content); 1373 1374 text_track->addWebVTTCue(start, end, id, content, settings); 1375 } 1376 1377 return true; 1378 } 1379 1380 bool ChunkDemuxer::IsValidId(const std::string& source_id) const { 1381 lock_.AssertAcquired(); 1382 return source_state_map_.count(source_id) > 0u; 1383 } 1384 1385 void ChunkDemuxer::UpdateDuration(TimeDelta new_duration) { 1386 DCHECK(duration_ != new_duration); 1387 user_specified_duration_ = -1; 1388 duration_ = new_duration; 1389 host_->SetDuration(new_duration); 1390 } 1391 1392 void ChunkDemuxer::IncreaseDurationIfNecessary( 1393 TimeDelta last_appended_buffer_timestamp, 1394 ChunkDemuxerStream* stream) { 1395 DCHECK(last_appended_buffer_timestamp != kNoTimestamp()); 1396 if (last_appended_buffer_timestamp <= duration_) 1397 return; 1398 1399 Ranges<TimeDelta> ranges = stream->GetBufferedRanges(kInfiniteDuration()); 1400 DCHECK_GT(ranges.size(), 0u); 1401 1402 TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1); 1403 if (last_timestamp_buffered > duration_) 1404 UpdateDuration(last_timestamp_buffered); 1405 } 1406 1407 void ChunkDemuxer::DecreaseDurationIfNecessary() { 1408 Ranges<TimeDelta> ranges = GetBufferedRanges(); 1409 if (ranges.size() == 0u) 1410 return; 1411 1412 TimeDelta last_timestamp_buffered = ranges.end(ranges.size() - 1); 1413 if (last_timestamp_buffered < duration_) 1414 UpdateDuration(last_timestamp_buffered); 1415 } 1416 1417 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges() const { 1418 if (audio_ && !video_) 1419 return audio_->GetBufferedRanges(duration_); 1420 else if (!audio_ && video_) 1421 return video_->GetBufferedRanges(duration_); 1422 return ComputeIntersection(); 1423 } 1424 1425 void ChunkDemuxer::StartReturningData() { 1426 if (audio_) 1427 audio_->StartReturningData(); 1428 1429 if (video_) 1430 video_->StartReturningData(); 1431 } 1432 1433 void ChunkDemuxer::AbortPendingReads() { 1434 if (audio_) 1435 audio_->AbortReads(); 1436 1437 if (video_) 1438 video_->AbortReads(); 1439 } 1440 1441 void ChunkDemuxer::SeekAllSources(TimeDelta seek_time) { 1442 if (audio_) 1443 audio_->Seek(seek_time); 1444 1445 if (video_) 1446 video_->Seek(seek_time); 1447 } 1448 1449 void ChunkDemuxer::CompletePendingReadsIfPossible() { 1450 if (audio_) 1451 audio_->CompletePendingReadIfPossible(); 1452 1453 if (video_) 1454 video_->CompletePendingReadIfPossible(); 1455 } 1456 1457 } // namespace media 1458