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