Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/filters/chunk_demuxer.h" | 5 #include "media/filters/chunk_demuxer.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 66 return new mp4::MP4StreamParser(); | 66 return new mp4::MP4StreamParser(); |
| 67 } | 67 } |
| 68 | 68 |
| 69 static const SupportedTypeInfo kSupportedTypeInfo[] = { | 69 static const SupportedTypeInfo kSupportedTypeInfo[] = { |
| 70 { "video/webm", &BuildWebMParser, kVideoWebMCodecs }, | 70 { "video/webm", &BuildWebMParser, kVideoWebMCodecs }, |
| 71 { "audio/webm", &BuildWebMParser, kAudioWebMCodecs }, | 71 { "audio/webm", &BuildWebMParser, kAudioWebMCodecs }, |
| 72 { "video/mp4", &BuildMP4Parser, kVideoMP4Codecs }, | 72 { "video/mp4", &BuildMP4Parser, kVideoMP4Codecs }, |
| 73 { "audio/mp4", &BuildMP4Parser, kAudioMP4Codecs }, | 73 { "audio/mp4", &BuildMP4Parser, kAudioMP4Codecs }, |
| 74 }; | 74 }; |
| 75 | 75 |
| 76 | |
| 77 // The fake total size we use for converting times to bytes | |
| 78 // for AddBufferedByteRange() calls. | |
| 79 enum { kFakeTotalBytes = 1000000 }; | |
|
Ami GONE FROM CHROMIUM
2012/06/19 17:40:37
TODO to drop this in favor of teaching Pipeline to
acolwell GONE FROM CHROMIUM
2012/06/19 19:50:15
Done.
| |
| 80 | |
| 76 // Checks to see if the specified |type| and |codecs| list are supported. | 81 // Checks to see if the specified |type| and |codecs| list are supported. |
| 77 // Returns true if |type| and all codecs listed in |codecs| are supported. | 82 // Returns true if |type| and all codecs listed in |codecs| are supported. |
| 78 // |factory_function| contains a function that can build a StreamParser | 83 // |factory_function| contains a function that can build a StreamParser |
| 79 // for this type. | 84 // for this type. |
| 80 // |has_audio| is true if an audio codec was specified. | 85 // |has_audio| is true if an audio codec was specified. |
| 81 // |has_video| is true if a video codec was specified. | 86 // |has_video| is true if a video codec was specified. |
| 82 // Returns false otherwise. The values of |factory_function|, |has_audio|, | 87 // Returns false otherwise. The values of |factory_function|, |has_audio|, |
| 83 // and |has_video| are undefined. | 88 // and |has_video| are undefined. |
| 84 static bool IsSupported(const std::string& type, | 89 static bool IsSupported(const std::string& type, |
| 85 std::vector<std::string>& codecs, | 90 std::vector<std::string>& codecs, |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 140 class ChunkDemuxerStream : public DemuxerStream { | 145 class ChunkDemuxerStream : public DemuxerStream { |
| 141 public: | 146 public: |
| 142 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; | 147 typedef std::deque<scoped_refptr<StreamParserBuffer> > BufferQueue; |
| 143 typedef std::deque<ReadCB> ReadCBQueue; | 148 typedef std::deque<ReadCB> ReadCBQueue; |
| 144 typedef std::deque<base::Closure> ClosureQueue; | 149 typedef std::deque<base::Closure> ClosureQueue; |
| 145 | 150 |
| 146 explicit ChunkDemuxerStream(const AudioDecoderConfig& audio_config); | 151 explicit ChunkDemuxerStream(const AudioDecoderConfig& audio_config); |
| 147 explicit ChunkDemuxerStream(const VideoDecoderConfig& video_config); | 152 explicit ChunkDemuxerStream(const VideoDecoderConfig& video_config); |
| 148 | 153 |
| 149 void StartWaitingForSeek(); | 154 void StartWaitingForSeek(); |
| 150 void Seek(base::TimeDelta time); | 155 void Seek(base::TimeDelta time); |
|
Ami GONE FROM CHROMIUM
2012/06/19 17:40:37
At 21 occurrences in this file, I'd say base::Time
acolwell GONE FROM CHROMIUM
2012/06/19 19:50:15
Done.
| |
| 151 bool IsSeekPending() const; | 156 bool IsSeekPending() const; |
| 152 void Flush(); | 157 void Flush(); |
| 153 | 158 |
| 154 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, | 159 // Add buffers to this stream. Buffers are stored in SourceBufferStreams, |
| 155 // which handle ordering and overlap resolution. | 160 // which handle ordering and overlap resolution. |
| 156 // Returns true if buffers were successfully added. | 161 // Returns true if buffers were successfully added. |
| 157 bool Append(const StreamParser::BufferQueue& buffers); | 162 bool Append(const StreamParser::BufferQueue& buffers); |
| 158 | 163 |
| 159 // Returns a list of the buffered time ranges. | 164 // Returns a list of the buffered time ranges. |
| 160 SourceBufferStream::TimespanList GetBufferedTime() const; | 165 Ranges<base::TimeDelta> GetBufferedTime() const; |
| 161 | 166 |
| 162 // Signal to the stream that buffers handed in through subsequent calls to | 167 // Signal to the stream that buffers handed in through subsequent calls to |
| 163 // Append() belong to a media segment that starts at |start_timestamp|. | 168 // Append() belong to a media segment that starts at |start_timestamp|. |
| 164 void OnNewMediaSegment(base::TimeDelta start_timestamp); | 169 void OnNewMediaSegment(base::TimeDelta start_timestamp); |
| 165 | 170 |
| 166 // Called when mid-stream config updates occur. | 171 // Called when mid-stream config updates occur. |
| 167 // Returns true if the new config is accepted. | 172 // Returns true if the new config is accepted. |
| 168 // Returns false if the new config should trigger an error. | 173 // Returns false if the new config should trigger an error. |
| 169 bool UpdateAudioConfig(const AudioDecoderConfig& config); | 174 bool UpdateAudioConfig(const AudioDecoderConfig& config); |
| 170 bool UpdateVideoConfig(const VideoDecoderConfig& config); | 175 bool UpdateVideoConfig(const VideoDecoderConfig& config); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 283 } | 288 } |
| 284 CreateReadDoneClosures_Locked(&closures); | 289 CreateReadDoneClosures_Locked(&closures); |
| 285 } | 290 } |
| 286 | 291 |
| 287 for (ClosureQueue::iterator it = closures.begin(); it != closures.end(); ++it) | 292 for (ClosureQueue::iterator it = closures.begin(); it != closures.end(); ++it) |
| 288 it->Run(); | 293 it->Run(); |
| 289 | 294 |
| 290 return true; | 295 return true; |
| 291 } | 296 } |
| 292 | 297 |
| 293 SourceBufferStream::TimespanList ChunkDemuxerStream::GetBufferedTime() const { | 298 Ranges<base::TimeDelta> ChunkDemuxerStream::GetBufferedTime() const { |
| 294 base::AutoLock auto_lock(lock_); | 299 base::AutoLock auto_lock(lock_); |
| 295 return stream_->GetBufferedTime(); | 300 return stream_->GetBufferedTime(); |
| 296 } | 301 } |
| 297 | 302 |
| 298 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config) { | 303 bool ChunkDemuxerStream::UpdateAudioConfig(const AudioDecoderConfig& config) { |
| 299 DCHECK(config.IsValidConfig()); | 304 DCHECK(config.IsValidConfig()); |
| 300 DCHECK_EQ(type_, AUDIO); | 305 DCHECK_EQ(type_, AUDIO); |
| 301 | 306 |
| 302 const AudioDecoderConfig& current_config = | 307 const AudioDecoderConfig& current_config = |
| 303 stream_->GetCurrentAudioDecoderConfig(); | 308 stream_->GetCurrentAudioDecoderConfig(); |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 456 if (!stream_->GetNextBuffer(&buffer)) | 461 if (!stream_->GetNextBuffer(&buffer)) |
| 457 return; | 462 return; |
| 458 closures->push_back(base::Bind(read_cbs_.front(), buffer)); | 463 closures->push_back(base::Bind(read_cbs_.front(), buffer)); |
| 459 read_cbs_.pop_front(); | 464 read_cbs_.pop_front(); |
| 460 } | 465 } |
| 461 } | 466 } |
| 462 | 467 |
| 463 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) | 468 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) |
| 464 : state_(WAITING_FOR_INIT), | 469 : state_(WAITING_FOR_INIT), |
| 465 host_(NULL), | 470 host_(NULL), |
| 466 client_(client), | 471 client_(client) { |
| 467 buffered_bytes_(0) { | |
| 468 DCHECK(client); | 472 DCHECK(client); |
| 469 } | 473 } |
| 470 | 474 |
| 471 void ChunkDemuxer::Initialize(DemuxerHost* host, | 475 void ChunkDemuxer::Initialize(DemuxerHost* host, |
| 472 const PipelineStatusCB& cb) { | 476 const PipelineStatusCB& cb) { |
| 473 DVLOG(1) << "Init()"; | 477 DVLOG(1) << "Init()"; |
| 474 { | 478 { |
| 475 base::AutoLock auto_lock(lock_); | 479 base::AutoLock auto_lock(lock_); |
| 476 DCHECK_EQ(state_, WAITING_FOR_INIT); | 480 DCHECK_EQ(state_, WAITING_FOR_INIT); |
| 477 host_ = host; | 481 host_ = host; |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 620 delete stream_parser_map_[id]; | 624 delete stream_parser_map_[id]; |
| 621 stream_parser_map_.erase(id); | 625 stream_parser_map_.erase(id); |
| 622 | 626 |
| 623 if (source_id_audio_ == id && audio_) | 627 if (source_id_audio_ == id && audio_) |
| 624 audio_->Shutdown(); | 628 audio_->Shutdown(); |
| 625 | 629 |
| 626 if (source_id_video_ == id && video_) | 630 if (source_id_video_ == id && video_) |
| 627 video_->Shutdown(); | 631 video_->Shutdown(); |
| 628 } | 632 } |
| 629 | 633 |
| 630 bool ChunkDemuxer::GetBufferedRanges(const std::string& id, | 634 Ranges<base::TimeDelta> ChunkDemuxer::GetBufferedRanges( |
| 631 Ranges* ranges_out) const { | 635 const std::string& id) const { |
| 632 DCHECK(!id.empty()); | 636 DCHECK(!id.empty()); |
| 633 DCHECK_GT(stream_parser_map_.count(id), 0u); | 637 DCHECK_GT(stream_parser_map_.count(id), 0u); |
| 634 DCHECK(id == source_id_audio_ || id == source_id_video_); | 638 DCHECK(id == source_id_audio_ || id == source_id_video_); |
| 635 DCHECK(ranges_out); | |
| 636 | 639 |
| 637 base::AutoLock auto_lock(lock_); | 640 base::AutoLock auto_lock(lock_); |
| 638 | 641 |
| 639 if (id == source_id_audio_ && id != source_id_video_) { | 642 if (id == source_id_audio_ && id != source_id_video_) { |
| 640 // Only include ranges that have been buffered in |audio_| | 643 // Only include ranges that have been buffered in |audio_| |
| 641 return CopyIntoRanges(audio_->GetBufferedTime(), ranges_out); | 644 return audio_->GetBufferedTime(); |
| 642 } | 645 } |
| 643 | 646 |
| 644 if (id != source_id_audio_ && id == source_id_video_) { | 647 if (id != source_id_audio_ && id == source_id_video_) { |
| 645 // Only include ranges that have been buffered in |video_| | 648 // Only include ranges that have been buffered in |video_| |
| 646 return CopyIntoRanges(video_->GetBufferedTime(), ranges_out); | 649 return video_->GetBufferedTime(); |
| 647 } | 650 } |
| 648 | 651 |
| 652 return ComputeIntersection(); | |
| 653 } | |
| 654 | |
| 655 Ranges<base::TimeDelta> ChunkDemuxer::ComputeIntersection() const { | |
| 656 lock_.AssertAcquired(); | |
| 657 | |
| 658 if (!audio_ || !video_) | |
| 659 return Ranges<base::TimeDelta>(); | |
| 660 | |
| 649 // Include ranges that have been buffered in both |audio_| and |video_|. | 661 // Include ranges that have been buffered in both |audio_| and |video_|. |
| 650 SourceBufferStream::TimespanList audio_ranges = audio_->GetBufferedTime(); | 662 Ranges<base::TimeDelta> audio_ranges = audio_->GetBufferedTime(); |
| 651 SourceBufferStream::TimespanList video_ranges = video_->GetBufferedTime(); | 663 Ranges<base::TimeDelta> video_ranges = video_->GetBufferedTime(); |
| 652 SourceBufferStream::TimespanList::const_iterator video_ranges_itr = | 664 Ranges<base::TimeDelta> result = audio_ranges.IntersectionWith(video_ranges); |
| 653 video_ranges.begin(); | |
| 654 SourceBufferStream::TimespanList::const_iterator audio_ranges_itr = | |
| 655 audio_ranges.begin(); | |
| 656 bool success = false; | |
| 657 | 665 |
| 658 while (audio_ranges_itr != audio_ranges.end() && | 666 if (state_ == ENDED) { |
| 659 video_ranges_itr != video_ranges.end()) { | 667 // If appending has ended, extend the intersection to include all of the |
| 660 // If this is the last range and EndOfStream() was called (i.e. all data | 668 // data from the last ranges for each stream. This allows the buffered |
| 661 // has been appended), choose the max end point of the ranges. | 669 // information to match the actual time range that will get played out if |
| 662 bool last_range_after_ended = | 670 // the streams have slightly different lengths. We only do this if the |
| 663 state_ == ENDED && | 671 // final ranges overlap because this indicates there is actually a location |
| 664 (audio_ranges_itr + 1) == audio_ranges.end() && | 672 // you can seek to, near the end, where we have data for both streams. |
| 665 (video_ranges_itr + 1) == video_ranges.end(); | 673 base::TimeDelta audio_start = audio_ranges.start(audio_ranges.size() - 1); |
| 674 base::TimeDelta audio_end = audio_ranges.end(audio_ranges.size() - 1); | |
| 675 base::TimeDelta video_start = video_ranges.start(video_ranges.size() - 1); | |
| 676 base::TimeDelta video_end = video_ranges.end(video_ranges.size() - 1); | |
| 666 | 677 |
| 667 // Audio range start time is within the video range. | 678 if ((audio_start <= video_start && video_start <= audio_end) || |
| 668 if ((*audio_ranges_itr).first >= (*video_ranges_itr).first && | 679 (video_start <= audio_start && audio_start <= video_end)) { |
| 669 (*audio_ranges_itr).first <= (*video_ranges_itr).second) { | 680 result.Add(std::max(audio_start, video_start), |
|
Ami GONE FROM CHROMIUM
2012/06/19 17:40:37
should this be a "min" instead of a max? Otherwis
acolwell GONE FROM CHROMIUM
2012/06/19 19:50:15
I don't want min here. I only want the intersectio
| |
| 670 AddIntersectionRange(*audio_ranges_itr, *video_ranges_itr, | 681 std::max(audio_end, video_end)); |
| 671 last_range_after_ended, ranges_out); | |
| 672 audio_ranges_itr++; | |
| 673 success = true; | |
| 674 continue; | |
| 675 } | 682 } |
| 676 | |
| 677 // Video range start time is within the audio range. | |
| 678 if ((*video_ranges_itr).first >= (*audio_ranges_itr).first && | |
| 679 (*video_ranges_itr).first <= (*audio_ranges_itr).second) { | |
| 680 AddIntersectionRange(*video_ranges_itr, *audio_ranges_itr, | |
| 681 last_range_after_ended, ranges_out); | |
| 682 video_ranges_itr++; | |
| 683 success = true; | |
| 684 continue; | |
| 685 } | |
| 686 | |
| 687 // No overlap was found. Increment the earliest one and keep looking. | |
| 688 if ((*audio_ranges_itr).first < (*video_ranges_itr).first) | |
| 689 audio_ranges_itr++; | |
| 690 else | |
| 691 video_ranges_itr++; | |
| 692 } | 683 } |
| 693 | 684 |
| 694 return success; | 685 return result; |
| 695 } | |
| 696 | |
| 697 bool ChunkDemuxer::CopyIntoRanges( | |
| 698 const SourceBufferStream::TimespanList& timespans, | |
| 699 Ranges* ranges_out) const { | |
| 700 for (SourceBufferStream::TimespanList::const_iterator itr = timespans.begin(); | |
| 701 itr != timespans.end(); ++itr) { | |
| 702 ranges_out->push_back(*itr); | |
| 703 } | |
| 704 return !timespans.empty(); | |
| 705 } | |
| 706 | |
| 707 void ChunkDemuxer::AddIntersectionRange( | |
| 708 SourceBufferStream::Timespan timespan_a, | |
| 709 SourceBufferStream::Timespan timespan_b, | |
| 710 bool last_range_after_ended, | |
| 711 Ranges* ranges_out) const { | |
| 712 base::TimeDelta start = timespan_a.first; | |
| 713 | |
| 714 // If this is the last range after EndOfStream() was called, choose the later | |
| 715 // end point of the ranges, otherwise choose the earlier. | |
| 716 base::TimeDelta end; | |
| 717 if (last_range_after_ended) | |
| 718 end = std::max(timespan_a.second, timespan_b.second); | |
| 719 else | |
| 720 end = std::min(timespan_a.second, timespan_b.second); | |
| 721 | |
| 722 ranges_out->push_back(std::make_pair(start, end)); | |
| 723 } | 686 } |
| 724 | 687 |
| 725 bool ChunkDemuxer::AppendData(const std::string& id, | 688 bool ChunkDemuxer::AppendData(const std::string& id, |
| 726 const uint8* data, | 689 const uint8* data, |
| 727 size_t length) { | 690 size_t length) { |
| 728 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; | 691 DVLOG(1) << "AppendData(" << id << ", " << length << ")"; |
| 729 | 692 |
| 730 DCHECK(!id.empty()); | 693 DCHECK(!id.empty()); |
| 731 DCHECK(data); | 694 DCHECK(data); |
| 732 DCHECK_GT(length, 0u); | 695 DCHECK_GT(length, 0u); |
| 733 | 696 |
| 734 int64 buffered_bytes = 0; | 697 Ranges<base::TimeDelta> ranges; |
| 735 | 698 |
| 736 PipelineStatusCB cb; | 699 PipelineStatusCB cb; |
| 737 { | 700 { |
| 738 base::AutoLock auto_lock(lock_); | 701 base::AutoLock auto_lock(lock_); |
| 739 | 702 |
| 740 // Capture if the SourceBuffer has a pending seek before we start parsing. | 703 // Capture if the SourceBuffer has a pending seek before we start parsing. |
| 741 bool old_seek_pending = IsSeekPending_Locked(); | 704 bool old_seek_pending = IsSeekPending_Locked(); |
| 742 | 705 |
| 743 switch (state_) { | 706 switch (state_) { |
| 744 case INITIALIZING: | 707 case INITIALIZING: |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 765 DVLOG(1) << "AppendData(): called in unexpected state " << state_; | 728 DVLOG(1) << "AppendData(): called in unexpected state " << state_; |
| 766 return false; | 729 return false; |
| 767 } | 730 } |
| 768 | 731 |
| 769 // Check to see if data was appended at the pending seek point. This | 732 // Check to see if data was appended at the pending seek point. This |
| 770 // indicates we have parsed enough data to complete the seek. | 733 // indicates we have parsed enough data to complete the seek. |
| 771 if (old_seek_pending && !IsSeekPending_Locked() && !seek_cb_.is_null()) { | 734 if (old_seek_pending && !IsSeekPending_Locked() && !seek_cb_.is_null()) { |
| 772 std::swap(cb, seek_cb_); | 735 std::swap(cb, seek_cb_); |
| 773 } | 736 } |
| 774 | 737 |
| 775 buffered_bytes_ += length; | 738 if (duration_ > base::TimeDelta() && duration_ != kInfiniteDuration()) { |
| 776 buffered_bytes = buffered_bytes_; | 739 if (audio_ && !video_) { |
| 740 ranges = audio_->GetBufferedTime(); | |
| 741 } else if (!audio_ && video_) { | |
| 742 ranges = video_->GetBufferedTime(); | |
| 743 } else { | |
| 744 ranges = ComputeIntersection(); | |
| 745 } | |
| 746 } | |
| 777 } | 747 } |
| 778 | 748 |
| 779 // Notify the host of 'network activity' because we got data, using a bogus | 749 for (size_t i = 0; i < ranges.size(); ++i) { |
| 780 // range. | 750 DCHECK(duration_ > base::TimeDelta()); |
|
Ami GONE FROM CHROMIUM
2012/06/19 17:40:37
silly to do this inside the for-loop; move up as:
acolwell GONE FROM CHROMIUM
2012/06/19 19:50:15
Done. Used !ranges.size() since empty() doesn't ex
| |
| 781 host_->AddBufferedByteRange(0, buffered_bytes); | 751 |
| 752 // Notify the host of 'network activity' because we got data. | |
| 753 int64 start = | |
| 754 kFakeTotalBytes * ranges.start(i).InSecondsF() / duration_.InSecondsF(); | |
| 755 int64 end = | |
| 756 kFakeTotalBytes * ranges.end(i).InSecondsF() / duration_.InSecondsF(); | |
| 757 host_->AddBufferedByteRange(start, end); | |
| 758 } | |
| 782 | 759 |
| 783 if (!cb.is_null()) | 760 if (!cb.is_null()) |
| 784 cb.Run(PIPELINE_OK); | 761 cb.Run(PIPELINE_OK); |
| 785 | 762 |
| 786 return true; | 763 return true; |
| 787 } | 764 } |
| 788 | 765 |
| 789 void ChunkDemuxer::Abort(const std::string& id) { | 766 void ChunkDemuxer::Abort(const std::string& id) { |
| 790 DVLOG(1) << "Abort(" << id << ")"; | 767 DVLOG(1) << "Abort(" << id << ")"; |
| 791 DCHECK(!id.empty()); | 768 DCHECK(!id.empty()); |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 940 } | 917 } |
| 941 | 918 |
| 942 if (duration > duration_) | 919 if (duration > duration_) |
| 943 duration_ = duration; | 920 duration_ = duration; |
| 944 | 921 |
| 945 // Wait until all streams have initialized. | 922 // Wait until all streams have initialized. |
| 946 if ((!source_id_audio_.empty() && !audio_) || | 923 if ((!source_id_audio_.empty() && !audio_) || |
| 947 (!source_id_video_.empty() && !video_)) | 924 (!source_id_video_.empty() && !video_)) |
| 948 return; | 925 return; |
| 949 | 926 |
| 927 if (duration_ > base::TimeDelta() && duration_ != kInfiniteDuration()) | |
| 928 host_->SetTotalBytes(kFakeTotalBytes); | |
| 950 host_->SetDuration(duration_); | 929 host_->SetDuration(duration_); |
| 951 | 930 |
| 952 ChangeState_Locked(INITIALIZED); | 931 ChangeState_Locked(INITIALIZED); |
| 953 PipelineStatusCB cb; | 932 PipelineStatusCB cb; |
| 954 std::swap(cb, init_cb_); | 933 std::swap(cb, init_cb_); |
| 955 cb.Run(PIPELINE_OK); | 934 cb.Run(PIPELINE_OK); |
| 956 } | 935 } |
| 957 | 936 |
| 958 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video, | 937 bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video, |
| 959 const AudioDecoderConfig& audio_config, | 938 const AudioDecoderConfig& audio_config, |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1028 // TODO(vrk): There should be a special case for the first appends where all | 1007 // TODO(vrk): There should be a special case for the first appends where all |
| 1029 // streams (for both demuxed and muxed case) begin at the earliest stream | 1008 // streams (for both demuxed and muxed case) begin at the earliest stream |
| 1030 // timestamp. (crbug.com/132815) | 1009 // timestamp. (crbug.com/132815) |
| 1031 if (audio_ && source_id == source_id_audio_) | 1010 if (audio_ && source_id == source_id_audio_) |
| 1032 audio_->OnNewMediaSegment(start_timestamp); | 1011 audio_->OnNewMediaSegment(start_timestamp); |
| 1033 if (video_ && source_id == source_id_video_) | 1012 if (video_ && source_id == source_id_video_) |
| 1034 video_->OnNewMediaSegment(start_timestamp); | 1013 video_->OnNewMediaSegment(start_timestamp); |
| 1035 } | 1014 } |
| 1036 | 1015 |
| 1037 } // namespace media | 1016 } // namespace media |
| OLD | NEW |