Commit f221f7d3 authored by annacc@chromium.org's avatar annacc@chromium.org

Implement support for 2 source ids (1 for audio and 1 for video).

This patch allows data to be appended to 2 different sources (1 audio and 1 video).  Also makes sure that appended data matches the mimetype provided in AddId().

BUG=122909
TEST=ChunkDemuxerTest.*


Review URL: https://chromiumcodereview.appspot.com/10545066

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@141679 0039d316-1c4b-4281-b951-d872f2087c98
parent b44642be
......@@ -415,9 +415,7 @@ ChunkDemuxer::ChunkDemuxer(ChunkDemuxerClient* client)
: state_(WAITING_FOR_INIT),
host_(NULL),
client_(client),
buffered_bytes_(0),
has_audio_(false),
has_video_(false) {
buffered_bytes_(0) {
DCHECK(client);
}
......@@ -518,6 +516,10 @@ ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id,
const std::string& type,
std::vector<std::string>& codecs) {
DCHECK_GT(codecs.size(), 0u);
base::AutoLock auto_lock(lock_);
if (state_ != WAITING_FOR_INIT && state_ != INITIALIZING)
return kReachedIdLimit;
bool has_audio = false;
bool has_video = false;
......@@ -525,55 +527,59 @@ ChunkDemuxer::Status ChunkDemuxer::AddId(const std::string& id,
if (!IsSupported(type, codecs, &factory_function, &has_audio, &has_video))
return kNotSupported;
// TODO(acolwell): Support for more than one ID
// will be added as part of http://crbug.com/122909
if (!source_id_.empty() ||
(has_audio && has_audio_) ||
(has_video && has_video_))
if ((has_audio && !source_id_audio_.empty()) ||
(has_video && !source_id_video_.empty()))
return kReachedIdLimit;
source_id_ = id;
StreamParser::NewBuffersCB audio_cb;
StreamParser::NewBuffersCB video_cb;
if (has_audio) {
has_audio_ = true;
source_id_audio_ = id;
audio_cb = base::Bind(&ChunkDemuxer::OnAudioBuffers,
base::Unretained(this));
}
if (has_video) {
has_video_ = true;
source_id_video_ = id;
video_cb = base::Bind(&ChunkDemuxer::OnVideoBuffers,
base::Unretained(this));
}
stream_parser_.reset(factory_function());
CHECK(stream_parser_.get());
scoped_ptr<StreamParser> stream_parser(factory_function());
CHECK(stream_parser.get());
stream_parser_->Init(
stream_parser->Init(
base::Bind(&ChunkDemuxer::OnStreamParserInitDone, this),
base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this)),
base::Bind(&ChunkDemuxer::OnNewConfigs, base::Unretained(this),
has_audio, has_video),
audio_cb,
video_cb,
base::Bind(&ChunkDemuxer::OnKeyNeeded, base::Unretained(this)));
stream_parser_map_[id] = stream_parser.release();
return kOk;
}
void ChunkDemuxer::RemoveId(const std::string& id) {
CHECK(!source_id_.empty());
CHECK_EQ(source_id_, id);
source_id_ = "";
has_audio_ = false;
has_video_ = false;
CHECK_GT(stream_parser_map_.count(id), 0u);
base::AutoLock auto_lock(lock_);
delete stream_parser_map_[id];
stream_parser_map_.erase(id);
if (source_id_audio_ == id && audio_)
audio_->Shutdown();
if (source_id_video_ == id && video_)
video_->Shutdown();
}
bool ChunkDemuxer::GetBufferedRanges(const std::string& id,
Ranges* ranges_out) const {
DCHECK(!id.empty());
DCHECK_EQ(source_id_, id);
DCHECK_GT(stream_parser_map_.count(id), 0u);
DCHECK(ranges_out);
base::AutoLock auto_lock(lock_);
......@@ -587,16 +593,6 @@ bool ChunkDemuxer::AppendData(const std::string& id,
size_t length) {
DVLOG(1) << "AppendData(" << id << ", " << length << ")";
// TODO(acolwell): Remove when http://webk.it/83788 fix lands.
if (source_id_.empty()) {
std::vector<std::string> codecs(2);
codecs[0] = "vp8";
codecs[1] = "vorbis";
AddId(id, "video/webm", codecs);
}
DCHECK(!source_id_.empty());
DCHECK_EQ(source_id_, id);
DCHECK(!id.empty());
DCHECK(data);
DCHECK_GT(length, 0u);
......@@ -612,7 +608,8 @@ bool ChunkDemuxer::AppendData(const std::string& id,
switch (state_) {
case INITIALIZING:
if (!stream_parser_->Parse(data, length)) {
DCHECK_GT(stream_parser_map_.count(id), 0u);
if (!stream_parser_map_[id]->Parse(data, length)) {
DCHECK_EQ(state_, INITIALIZING);
ReportError_Locked(DEMUXER_ERROR_COULD_NOT_OPEN);
return true;
......@@ -620,7 +617,8 @@ bool ChunkDemuxer::AppendData(const std::string& id,
break;
case INITIALIZED: {
if (!stream_parser_->Parse(data, length)) {
DCHECK_GT(stream_parser_map_.count(id), 0u);
if (!stream_parser_map_[id]->Parse(data, length)) {
ReportError_Locked(PIPELINE_ERROR_DECODE);
return true;
}
......@@ -657,9 +655,9 @@ bool ChunkDemuxer::AppendData(const std::string& id,
void ChunkDemuxer::Abort(const std::string& id) {
DVLOG(1) << "Abort(" << id << ")";
DCHECK(!id.empty());
DCHECK_EQ(source_id_, id);
DCHECK_GT(stream_parser_map_.count(id), 0u);
stream_parser_->Flush();
stream_parser_map_[id]->Flush();
}
bool ChunkDemuxer::EndOfStream(PipelineStatus status) {
......@@ -710,7 +708,11 @@ void ChunkDemuxer::Shutdown() {
if (video_)
video_->Shutdown();
stream_parser_.reset();
for (StreamParserMap::iterator it = stream_parser_map_.begin();
it != stream_parser_map_.end(); ++it) {
delete it->second;
}
stream_parser_map_.clear();
ChangeState_Locked(SHUTDOWN);
}
......@@ -730,6 +732,11 @@ void ChunkDemuxer::ChangeState_Locked(State new_state) {
ChunkDemuxer::~ChunkDemuxer() {
DCHECK_NE(state_, INITIALIZED);
for (StreamParserMap::iterator it = stream_parser_map_.begin();
it != stream_parser_map_.end(); ++it) {
delete it->second;
}
stream_parser_map_.clear();
}
void ChunkDemuxer::ReportError_Locked(PipelineStatus error) {
......@@ -794,7 +801,14 @@ void ChunkDemuxer::OnStreamParserInitDone(bool success,
return;
}
if (duration > duration_)
duration_ = duration;
// Wait until all streams have initialized.
if ((!source_id_audio_.empty() && !audio_) ||
(!source_id_video_.empty() && !video_))
return;
host_->SetDuration(duration_);
ChangeState_Locked(INITIALIZED);
......@@ -803,9 +817,11 @@ void ChunkDemuxer::OnStreamParserInitDone(bool success,
cb.Run(PIPELINE_OK);
}
bool ChunkDemuxer::OnNewConfigs(const AudioDecoderConfig& audio_config,
bool ChunkDemuxer::OnNewConfigs(bool has_audio, bool has_video,
const AudioDecoderConfig& audio_config,
const VideoDecoderConfig& video_config) {
DVLOG(1) << "OnNewConfigs(" << audio_config.IsValidConfig()
DVLOG(1) << "OnNewConfigs(" << has_audio << ", " << has_video
<< ", " << audio_config.IsValidConfig()
<< ", " << video_config.IsValidConfig() << ")";
CHECK(audio_config.IsValidConfig() || video_config.IsValidConfig());
lock_.AssertAcquired();
......@@ -813,13 +829,13 @@ bool ChunkDemuxer::OnNewConfigs(const AudioDecoderConfig& audio_config,
// Signal an error if we get configuration info for stream types that weren't
// specified in AddId() or more configs after a stream is initialized.
// Only allow a single audio config for now.
if (audio_config.IsValidConfig() && !has_audio_) {
if (has_audio != audio_config.IsValidConfig()) {
DVLOG(1) << "OnNewConfigs() : Got unexpected audio config.";
return false;
}
// Only allow a single video config for now.
if (video_config.IsValidConfig() && !has_video_) {
if (has_video != video_config.IsValidConfig()) {
DVLOG(1) << "OnNewConfigs() : Got unexpected video config.";
return false;
}
......
......@@ -5,7 +5,7 @@
#ifndef MEDIA_FILTERS_CHUNK_DEMUXER_H_
#define MEDIA_FILTERS_CHUNK_DEMUXER_H_
#include <list>
#include <map>
#include <string>
#include <utility>
#include <vector>
......@@ -112,7 +112,8 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
// StreamParser callbacks.
void OnStreamParserInitDone(bool success, base::TimeDelta duration);
bool OnNewConfigs(const AudioDecoderConfig& audio_config,
bool OnNewConfigs(bool has_audio, bool has_video,
const AudioDecoderConfig& audio_config,
const VideoDecoderConfig& video_config);
bool OnAudioBuffers(const StreamParser::BufferQueue& buffers);
bool OnVideoBuffers(const StreamParser::BufferQueue& buffers);
......@@ -133,15 +134,14 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer {
base::TimeDelta duration_;
scoped_ptr<StreamParser> stream_parser_;
typedef std::map<std::string, StreamParser*> StreamParserMap;
StreamParserMap stream_parser_map_;
// TODO(annacc): Remove these when fixing: http://crbug.com/122909
// Used to ensure config data matches the type and codec provided in AddId().
bool has_audio_;
bool has_video_;
// TODO(acolwell): Remove this when fixing http://crbug.com/122909
std::string source_id_;
// Used to ensure that (1) config data matches the type and codec provided in
// AddId(), (2) only 1 audio and 1 video sources are added, and (3) ids may be
// removed with RemoveID() but can not be re-added (yet).
std::string source_id_audio_;
std::string source_id_video_;
DISALLOW_COPY_AND_ASSIGN(ChunkDemuxer);
};
......
This diff is collapsed.
......@@ -21,10 +21,13 @@ static const char* kSourceId = "SourceId";
// Media Source API.
class MockMediaSource : public ChunkDemuxerClient {
public:
MockMediaSource(const std::string& filename, int initial_append_size)
MockMediaSource(const std::string& filename, int initial_append_size,
bool has_audio, bool has_video)
: url_(GetTestDataURL(filename)),
current_position_(0),
initial_append_size_(initial_append_size) {
initial_append_size_(initial_append_size),
has_audio_(has_audio),
has_video_(has_video) {
file_data_ = ReadTestDataFile(filename);
DCHECK_GT(initial_append_size_, 0);
......@@ -77,9 +80,13 @@ class MockMediaSource : public ChunkDemuxerClient {
virtual void DemuxerOpened(ChunkDemuxer* demuxer) {
chunk_demuxer_ = demuxer;
std::vector<std::string> codecs(2);
codecs[0] = "vp8";
codecs[1] = "vorbis";
std::vector<std::string> codecs;
if (has_audio_)
codecs.push_back("vorbis");
if (has_video_)
codecs.push_back("vp8");
chunk_demuxer_->AddId(kSourceId, "video/webm", codecs);
AppendData(initial_append_size_);
}
......@@ -103,6 +110,8 @@ class MockMediaSource : public ChunkDemuxerClient {
scoped_refptr<DecoderBuffer> file_data_;
int current_position_;
int initial_append_size_;
bool has_audio_;
bool has_video_;
scoped_refptr<ChunkDemuxer> chunk_demuxer_;
AesDecryptor* decryptor_;
};
......@@ -132,8 +141,10 @@ class PipelineIntegrationTest
base::TimeDelta start_seek_time,
base::TimeDelta seek_time,
int seek_file_position,
int seek_append_size) {
MockMediaSource source(filename, initial_append_size);
int seek_append_size,
bool has_audio,
bool has_video) {
MockMediaSource source(filename, initial_append_size, has_audio, has_video);
StartPipelineWithMediaSource(source);
if (pipeline_status_ != PIPELINE_OK)
......@@ -176,7 +187,7 @@ TEST_F(PipelineIntegrationTest, BasicPlaybackHashed) {
}
TEST_F(PipelineIntegrationTest, EncryptedPlayback) {
MockMediaSource source("bear-320x240-encrypted.webm", 219726);
MockMediaSource source("bear-320x240-encrypted.webm", 219726, true, true);
StartPipelineWithMediaSource(source);
source.EndOfStream();
......@@ -238,7 +249,7 @@ TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) {
ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", 8192,
base::TimeDelta::FromMilliseconds(464),
base::TimeDelta::FromMilliseconds(617),
0x10CA, 19730));
0x10CA, 19730, true, false));
}
// Verify video decoder & renderer can handle aborted demuxer reads.
......@@ -246,7 +257,7 @@ TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) {
ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", 32768,
base::TimeDelta::FromMilliseconds(200),
base::TimeDelta::FromMilliseconds(1668),
0x1C896, 65536));
0x1C896, 65536, false, true));
}
} // namespace media
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment