Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(323)

Side by Side Diff: media/filters/chunk_demuxer.cc

Issue 10803019: Chrome-side implementation of media source timestamp offset (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Move logic from parser to demuxer Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/callback_helpers.h" 8 #include "base/callback_helpers.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/message_loop.h" 10 #include "base/message_loop.h"
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
92 // and |has_video| are undefined. 92 // and |has_video| are undefined.
93 static bool IsSupported(const std::string& type, 93 static bool IsSupported(const std::string& type,
94 std::vector<std::string>& codecs, 94 std::vector<std::string>& codecs,
95 ParserFactoryFunction* factory_function, 95 ParserFactoryFunction* factory_function,
96 bool* has_audio, 96 bool* has_audio,
97 bool* has_video) { 97 bool* has_video) {
98 *factory_function = NULL; 98 *factory_function = NULL;
99 *has_audio = false; 99 *has_audio = false;
100 *has_video = false; 100 *has_video = false;
101 101
102 // Search for the SupportedTypeInfo for |type| 102 // Search for the SupportedTypeInfo for |type|.
103 for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) { 103 for (size_t i = 0; i < arraysize(kSupportedTypeInfo); ++i) {
104 const SupportedTypeInfo& type_info = kSupportedTypeInfo[i]; 104 const SupportedTypeInfo& type_info = kSupportedTypeInfo[i];
105 if (type == type_info.type) { 105 if (type == type_info.type) {
106 // Make sure all the codecs specified in |codecs| are 106 // Make sure all the codecs specified in |codecs| are
107 // in the supported type info. 107 // in the supported type info.
108 for (size_t j = 0; j < codecs.size(); ++j) { 108 for (size_t j = 0; j < codecs.size(); ++j) {
109 // Search the type info for a match. 109 // Search the type info for a match.
110 bool found_codec = false; 110 bool found_codec = false;
111 DemuxerStream::Type codec_type = DemuxerStream::UNKNOWN; 111 DemuxerStream::Type codec_type = DemuxerStream::UNKNOWN;
112 112
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 458
459 scoped_refptr<StreamParserBuffer> buffer; 459 scoped_refptr<StreamParserBuffer> buffer;
460 while (!read_cbs_.empty()) { 460 while (!read_cbs_.empty()) {
461 if (!stream_->GetNextBuffer(&buffer)) 461 if (!stream_->GetNextBuffer(&buffer))
462 return; 462 return;
463 closures->push_back(base::Bind(read_cbs_.front(), buffer)); 463 closures->push_back(base::Bind(read_cbs_.front(), buffer));
464 read_cbs_.pop_front(); 464 read_cbs_.pop_front();
465 } 465 }
466 } 466 }
467 467
468 void ChunkDemuxer::AdjustBufferTimestamps(
469 const StreamParser::BufferQueue& buffers,
470 base::TimeDelta timestamp_offset) {
471 if (timestamp_offset == base::TimeDelta())
472 return;
473
474 for (StreamParser::BufferQueue::const_iterator itr = buffers.begin();
475 itr != buffers.end(); ++itr) {
476 (*itr)->SetDecodeTimestamp(
477 (*itr)->GetDecodeTimestamp() + timestamp_offset);
478 (*itr)->SetTimestamp((*itr)->GetTimestamp() + timestamp_offset);
479 }
480 }
481
468 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client) 482 ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client)
469 : state_(WAITING_FOR_INIT), 483 : state_(WAITING_FOR_INIT),
470 host_(NULL), 484 host_(NULL),
471 client_(client), 485 client_(client),
472 start_time_(kNoTimestamp()) { 486 start_time_(kNoTimestamp()) {
473 DCHECK(client); 487 DCHECK(client);
474 } 488 }
475 489
476 void ChunkDemuxer::Initialize(DemuxerHost* host, 490 void ChunkDemuxer::Initialize(DemuxerHost* host,
477 const PipelineStatusCB& cb) { 491 const PipelineStatusCB& cb) {
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
604 scoped_ptr<StreamParser> stream_parser(factory_function()); 618 scoped_ptr<StreamParser> stream_parser(factory_function());
605 CHECK(stream_parser.get()); 619 CHECK(stream_parser.get());
606 620
607 stream_parser->Init( 621 stream_parser->Init(
608 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, this), 622 base::Bind(&ChunkDemuxer::OnStreamParserInitDone, this),
609 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this), 623 base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this),
610 has_audio, has_video), 624 has_audio, has_video),
611 audio_cb, 625 audio_cb,
612 video_cb, 626 video_cb,
613 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)), 627 base::Bind(&ChunkDemuxer::OnNeedKey, base::Unretained(this)),
614 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id)); 628 base::Bind(&ChunkDemuxer::OnNewMediaSegment, base::Unretained(this), id),
629 base::Bind(&ChunkDemuxer::OnEndOfMediaSegment,
630 base::Unretained(this), id));
615 631
616 stream_parser_map_[id] = stream_parser.release(); 632 stream_parser_map_[id] = stream_parser.release();
633 StreamInfo info = { base::TimeDelta(), true };
634 stream_info_map_[id] = info;
617 635
618 return kOk; 636 return kOk;
619 } 637 }
620 638
621 void ChunkDemuxer::RemoveId(const std::string& id) { 639 void ChunkDemuxer::RemoveId(const std::string& id) {
622 CHECK_GT(stream_parser_map_.count(id), 0u); 640 CHECK_GT(stream_parser_map_.count(id), 0u);
623 base::AutoLock auto_lock(lock_); 641 base::AutoLock auto_lock(lock_);
624 642
625 delete stream_parser_map_[id]; 643 delete stream_parser_map_[id];
626 stream_parser_map_.erase(id); 644 stream_parser_map_.erase(id);
645 stream_info_map_.erase(id);
627 646
628 if (source_id_audio_ == id && audio_) 647 if (source_id_audio_ == id && audio_)
629 audio_->Shutdown(); 648 audio_->Shutdown();
630 649
631 if (source_id_video_ == id && video_) 650 if (source_id_video_ == id && video_)
632 video_->Shutdown(); 651 video_->Shutdown();
633 } 652 }
634 653
635 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const { 654 Ranges<TimeDelta> ChunkDemuxer::GetBufferedRanges(const std::string& id) const {
636 DCHECK(!id.empty()); 655 DCHECK(!id.empty());
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
752 } 771 }
753 772
754 void ChunkDemuxer::Abort(const std::string& id) { 773 void ChunkDemuxer::Abort(const std::string& id) {
755 DVLOG(1) << "Abort(" << id << ")"; 774 DVLOG(1) << "Abort(" << id << ")";
756 DCHECK(!id.empty()); 775 DCHECK(!id.empty());
757 DCHECK_GT(stream_parser_map_.count(id), 0u); 776 DCHECK_GT(stream_parser_map_.count(id), 0u);
758 777
759 stream_parser_map_[id]->Flush(); 778 stream_parser_map_[id]->Flush();
760 } 779 }
761 780
781 bool ChunkDemuxer::TimestampOffset(const std::string& id, float offset) {
782 DVLOG(1) << "TimestampOffset(" << id << ", " << offset << ")";
783 DCHECK_GT(stream_parser_map_.count(id), 0u);
784
785 TimeDelta time_offset = TimeDelta::FromMicroseconds(
786 offset * base::Time::kMicrosecondsPerSecond);
787
788 if (!stream_info_map_[id].can_update_offset)
789 return false;
790
791 stream_info_map_[id].timestamp_offset = time_offset;
792 return true;
793 }
794
762 bool ChunkDemuxer::EndOfStream(PipelineStatus status) { 795 bool ChunkDemuxer::EndOfStream(PipelineStatus status) {
763 DVLOG(1) << "EndOfStream(" << status << ")"; 796 DVLOG(1) << "EndOfStream(" << status << ")";
764 base::AutoLock auto_lock(lock_); 797 base::AutoLock auto_lock(lock_);
765 DCHECK_NE(state_, WAITING_FOR_INIT); 798 DCHECK_NE(state_, WAITING_FOR_INIT);
766 DCHECK_NE(state_, ENDED); 799 DCHECK_NE(state_, ENDED);
767 800
768 if (state_ == SHUTDOWN || state_ == PARSE_ERROR) 801 if (state_ == SHUTDOWN || state_ == PARSE_ERROR)
769 return true; 802 return true;
770 803
771 if (state_ == INITIALIZING) { 804 if (state_ == INITIALIZING) {
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
956 return success; 989 return success;
957 } 990 }
958 991
959 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) { 992 bool ChunkDemuxer::OnAudioBuffers(const StreamParser::BufferQueue& buffers) {
960 lock_.AssertAcquired(); 993 lock_.AssertAcquired();
961 DCHECK_NE(state_, SHUTDOWN); 994 DCHECK_NE(state_, SHUTDOWN);
962 995
963 if (!audio_) 996 if (!audio_)
964 return false; 997 return false;
965 998
999 CHECK_GT(stream_info_map_.count(source_id_audio_), 0u);
1000 AdjustBufferTimestamps(
1001 buffers, stream_info_map_[source_id_audio_].timestamp_offset);
1002 stream_info_map_[source_id_video_].can_update_offset = false;
acolwell GONE FROM CHROMIUM 2012/07/20 18:21:01 did you mean source_id_audio_ here?
vrk (LEFT CHROMIUM) 2012/07/25 17:16:48 d'oh. Yes :) My test page only uses video, so I di
1003
966 return audio_->Append(buffers); 1004 return audio_->Append(buffers);
967 } 1005 }
968 1006
969 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) { 1007 bool ChunkDemuxer::OnVideoBuffers(const StreamParser::BufferQueue& buffers) {
970 lock_.AssertAcquired(); 1008 lock_.AssertAcquired();
971 DCHECK_NE(state_, SHUTDOWN); 1009 DCHECK_NE(state_, SHUTDOWN);
972 1010
973 if (!video_) 1011 if (!video_)
974 return false; 1012 return false;
975 1013
1014 CHECK_GT(stream_info_map_.count(source_id_video_), 0u);
1015 AdjustBufferTimestamps(
1016 buffers, stream_info_map_[source_id_video_].timestamp_offset);
1017 stream_info_map_[source_id_video_].can_update_offset = false;
acolwell GONE FROM CHROMIUM 2012/07/20 18:21:01 Perhaps move this to OnNewMediaSegment()? That way
vrk (LEFT CHROMIUM) 2012/07/25 17:16:48 Done and removed from OnAudioBuffers() as well.
1018
976 return video_->Append(buffers); 1019 return video_->Append(buffers);
977 } 1020 }
978 1021
979 bool ChunkDemuxer::OnNeedKey(scoped_array<uint8> init_data, 1022 bool ChunkDemuxer::OnNeedKey(scoped_array<uint8> init_data,
980 int init_data_size) { 1023 int init_data_size) {
981 client_->DemuxerNeedKey(init_data.Pass(), init_data_size); 1024 client_->DemuxerNeedKey(init_data.Pass(), init_data_size);
982 return true; 1025 return true;
983 } 1026 }
984 1027
985 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id, 1028 void ChunkDemuxer::OnNewMediaSegment(const std::string& source_id,
986 TimeDelta start_timestamp) { 1029 TimeDelta timestamp) {
987 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", " 1030 DVLOG(2) << "OnNewMediaSegment(" << source_id << ", "
988 << start_timestamp.InSecondsF() << ")"; 1031 << timestamp.InSecondsF() << ")";
989 lock_.AssertAcquired(); 1032 lock_.AssertAcquired();
990 1033
1034 CHECK_GT(stream_info_map_.count(source_id), 0u);
1035 base::TimeDelta start_timestamp =
1036 timestamp + stream_info_map_[source_id].timestamp_offset;
1037
991 if (start_time_ == kNoTimestamp()) { 1038 if (start_time_ == kNoTimestamp()) {
992 DCHECK(state_ == INITIALIZING || state_ == WAITING_FOR_START_TIME); 1039 DCHECK(state_ == INITIALIZING || state_ == WAITING_FOR_START_TIME);
993 // Use the first reported media segment start time as the |start_time_| 1040 // Use the first reported media segment start time as the |start_time_|
994 // for the demuxer. 1041 // for the demuxer.
995 start_time_ = start_timestamp; 1042 start_time_ = start_timestamp;
996 } 1043 }
997 1044
998 if (audio_ && source_id == source_id_audio_) 1045 if (audio_ && source_id == source_id_audio_)
999 audio_->OnNewMediaSegment(start_timestamp); 1046 audio_->OnNewMediaSegment(start_timestamp);
1000 if (video_ && source_id == source_id_video_) 1047 if (video_ && source_id == source_id_video_)
1001 video_->OnNewMediaSegment(start_timestamp); 1048 video_->OnNewMediaSegment(start_timestamp);
1002 1049
1003 if (state_ != WAITING_FOR_START_TIME) 1050 if (state_ != WAITING_FOR_START_TIME)
1004 return; 1051 return;
1005 1052
1006 if (audio_) { 1053 if (audio_) {
1007 audio_->SetStartTime(start_time_); 1054 audio_->SetStartTime(start_time_);
1008 audio_->Seek(start_time_); 1055 audio_->Seek(start_time_);
1009 } 1056 }
1010 if (video_) { 1057 if (video_) {
1011 video_->SetStartTime(start_time_); 1058 video_->SetStartTime(start_time_);
1012 video_->Seek(start_time_); 1059 video_->Seek(start_time_);
1013 } 1060 }
1014 1061
1015 // The demuxer is now initialized after the |start_timestamp_| was set. 1062 // The demuxer is now initialized after the |start_timestamp_| was set.
1016 ChangeState_Locked(INITIALIZED); 1063 ChangeState_Locked(INITIALIZED);
1017 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); 1064 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
1018 } 1065 }
1019 1066
1067 void ChunkDemuxer::OnEndOfMediaSegment(const std::string& source_id) {
1068 DVLOG(2) << "OnEndOfMediaSegment(" << source_id << ")";
1069 CHECK_GT(stream_info_map_.count(source_id_video_), 0u);
1070 stream_info_map_[source_id_video_].can_update_offset = true;
1071 }
1072
1020 } // namespace media 1073 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698