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);
};
......
......@@ -76,6 +76,12 @@ static void OnReadDone(const base::TimeDelta& expected_time,
*called = true;
}
static void OnReadDone_EOSExpected(bool* called,
const scoped_refptr<DecoderBuffer>& buffer) {
EXPECT_TRUE(buffer->IsEndOfStream());
*called = true;
}
class MockChunkDemuxerClient : public ChunkDemuxerClient {
public:
MockChunkDemuxerClient() {}
......@@ -197,17 +203,41 @@ class ChunkDemuxerTest : public testing::Test {
}
ChunkDemuxer::Status AddId() {
std::vector<std::string> codecs(2);
codecs[0] = "vp8";
codecs[1] = "vorbis";
return demuxer_->AddId(kSourceId, "video/webm", codecs);
return AddId(kSourceId, true, true);
}
ChunkDemuxer::Status AddId(const std::string& source_id,
bool has_audio, bool has_video) {
std::vector<std::string> codecs;
std::string type;
if (has_audio) {
codecs.push_back("vorbis");
type = "audio/webm";
}
if (has_video) {
codecs.push_back("vp8");
type = "video/webm";
}
if (!has_audio && !has_video) {
return AddId(kSourceId, true, true);
}
return demuxer_->AddId(source_id, type, codecs);
}
bool AppendData(const uint8* data, size_t length) {
return AppendData(kSourceId, data, length);
}
bool AppendData(const std::string& source_id,
const uint8* data, size_t length) {
CHECK(length);
EXPECT_CALL(host_, AddBufferedByteRange(_, _)).Times(AnyNumber())
.WillRepeatedly(SaveArg<1>(&buffered_bytes_));
return demuxer_->AppendData(kSourceId, data, length);
return demuxer_->AppendData(source_id, data, length);
}
bool AppendDataInPieces(const uint8* data, size_t length) {
......@@ -232,11 +262,18 @@ class ChunkDemuxerTest : public testing::Test {
bool AppendInitSegment(bool has_audio, bool has_video,
bool video_content_encoded) {
return AppendInitSegment(kSourceId, has_audio, has_video,
video_content_encoded);
}
bool AppendInitSegment(const std::string& source_id,
bool has_audio, bool has_video,
bool video_content_encoded) {
scoped_array<uint8> info_tracks;
int info_tracks_size = 0;
CreateInitSegment(has_audio, has_video, video_content_encoded,
&info_tracks, &info_tracks_size);
return AppendData(info_tracks.get(), info_tracks_size);
return AppendData(source_id, info_tracks.get(), info_tracks_size);
}
void InitDoneCalled(PipelineStatus expected_status,
......@@ -263,12 +300,28 @@ class ChunkDemuxerTest : public testing::Test {
demuxer_->Initialize(
&host_, CreateInitDoneCB(kDefaultDuration(), expected_status));
if (AddId() != ChunkDemuxer::kOk)
if (AddId(kSourceId, has_audio, has_video) != ChunkDemuxer::kOk)
return false;
return AppendInitSegment(has_audio, has_video, video_content_encoded);
}
bool InitDemuxerAudioAndVideoSources(const std::string& audio_id,
const std::string& video_id) {
EXPECT_CALL(*client_, DemuxerOpened(_));
demuxer_->Initialize(
&host_, CreateInitDoneCB(kDefaultDuration(), PIPELINE_OK));
if (AddId(audio_id, true, false) != ChunkDemuxer::kOk)
return false;
if (AddId(video_id, false, true) != ChunkDemuxer::kOk)
return false;
bool success = AppendInitSegment(audio_id, true, false, false);
success &= AppendInitSegment(video_id, false, true, false);
return success;
}
void ShutdownDemuxer() {
if (demuxer_) {
EXPECT_CALL(*client_, DemuxerClosed());
......@@ -335,6 +388,32 @@ class ChunkDemuxerTest : public testing::Test {
return cb.Finish();
}
scoped_ptr<Cluster> GenerateSingleStreamCluster(int timecode,
int block_count,
int track_number,
int block_duration) {
CHECK_GT(block_count, 0);
int size = 10;
scoped_array<uint8> data(new uint8[size]);
ClusterBuilder cb;
cb.SetClusterTimecode(timecode);
// Create simple blocks for everything except the last block.
for (int i = 0; i < block_count - 1; i++) {
cb.AddSimpleBlock(track_number, timecode, kWebMFlagKeyframe,
data.get(), size);
timecode += block_duration;
}
// Make the last block a BlockGroup so that it doesn't get delayed by the
// block duration calculation logic.
cb.AddBlockGroup(track_number, timecode, block_duration,
kWebMFlagKeyframe, data.get(), size);
return cb.Finish();
}
void GenerateExpectedReads(int timecode, int block_count,
DemuxerStream* audio,
DemuxerStream* video) {
......@@ -359,6 +438,17 @@ class ChunkDemuxerTest : public testing::Test {
}
}
void GenerateExpectedReads(int timecode, int block_count,
DemuxerStream* stream, int block_duration) {
CHECK_GT(block_count, 0);
int stream_timecode = timecode;
for (int i = 0; i < block_count; i++) {
ExpectRead(stream, stream_timecode);
stream_timecode += block_duration;
}
}
MOCK_METHOD1(ReadDone, void(const scoped_refptr<DecoderBuffer>&));
void ExpectRead(DemuxerStream* stream, int64 timestamp_in_ms) {
......@@ -384,11 +474,18 @@ class ChunkDemuxerTest : public testing::Test {
bool ParseWebMFile(const std::string& filename,
const BufferTimestamps* timestamps,
const base::TimeDelta& duration) {
return ParseWebMFile(filename, timestamps, duration, true, true);
}
bool ParseWebMFile(const std::string& filename,
const BufferTimestamps* timestamps,
const base::TimeDelta& duration,
bool has_audio, bool has_video) {
EXPECT_CALL(*client_, DemuxerOpened(_));
demuxer_->Initialize(
&host_, CreateInitDoneCB(duration, PIPELINE_OK));
if (AddId() != ChunkDemuxer::kOk)
if (AddId(kSourceId, has_audio, has_video) != ChunkDemuxer::kOk)
return false;
// Read a WebM file into memory and send the data to the demuxer.
......@@ -976,7 +1073,8 @@ TEST_F(ChunkDemuxerTest, TestWebMFile_AudioOnly) {
};
ASSERT_TRUE(ParseWebMFile("bear-320x240-audio-only.webm", buffer_timestamps,
base::TimeDelta::FromMilliseconds(2744)));
base::TimeDelta::FromMilliseconds(2744),
true, false));
}
TEST_F(ChunkDemuxerTest, TestWebMFile_VideoOnly) {
......@@ -990,7 +1088,8 @@ TEST_F(ChunkDemuxerTest, TestWebMFile_VideoOnly) {
};
ASSERT_TRUE(ParseWebMFile("bear-320x240-video-only.webm", buffer_timestamps,
base::TimeDelta::FromMilliseconds(2703)));
base::TimeDelta::FromMilliseconds(2703),
false, true));
}
TEST_F(ChunkDemuxerTest, TestWebMFile_AltRefFrames) {
......@@ -1136,4 +1235,148 @@ TEST_F(ChunkDemuxerTest, TestMultipleHeaders) {
GenerateExpectedReads(0, 9, audio, video);
}
TEST_F(ChunkDemuxerTest, TestAddSeparateSourcesForAudioAndVideo) {
std::string audio_id = "audio1";
std::string video_id = "video1";
ASSERT_TRUE(InitDemuxerAudioAndVideoSources(audio_id, video_id));
scoped_refptr<DemuxerStream> audio =
demuxer_->GetStream(DemuxerStream::AUDIO);
scoped_refptr<DemuxerStream> video =
demuxer_->GetStream(DemuxerStream::VIDEO);
scoped_ptr<Cluster> cluster_a(
GenerateSingleStreamCluster(0, 4, kAudioTrackNum, kAudioBlockDuration));
scoped_ptr<Cluster> cluster_v(
GenerateSingleStreamCluster(0, 4, kVideoTrackNum, kVideoBlockDuration));
// Append audio and video data into separate source ids.
ASSERT_TRUE(AppendData(audio_id, cluster_a->data(), cluster_a->size()));
GenerateExpectedReads(0, 4, audio, kAudioBlockDuration);
ASSERT_TRUE(AppendData(video_id, cluster_v->data(), cluster_v->size()));
GenerateExpectedReads(0, 4, video, kVideoBlockDuration);
}
TEST_F(ChunkDemuxerTest, TestAddIdFailures) {
EXPECT_CALL(*client_, DemuxerOpened(_));
demuxer_->Initialize(
&host_, CreateInitDoneCB(kDefaultDuration(), PIPELINE_OK));
std::string audio_id = "audio1";
std::string video_id = "video1";
ASSERT_EQ(AddId(audio_id, true, false), ChunkDemuxer::kOk);
// Adding an id with audio/video should fail because we already added audio.
ASSERT_EQ(AddId(), ChunkDemuxer::kReachedIdLimit);
ASSERT_TRUE(AppendInitSegment(audio_id, true, false, false));
// Adding an id after append should fail.
ASSERT_EQ(AddId(video_id, false, true), ChunkDemuxer::kReachedIdLimit);
}
// Test that Read() calls after a RemoveId() return "end of stream" buffers.
TEST_F(ChunkDemuxerTest, TestRemoveId) {
std::string audio_id = "audio1";
std::string video_id = "video1";
ASSERT_TRUE(InitDemuxerAudioAndVideoSources(audio_id, video_id));
scoped_ptr<Cluster> cluster_a(
GenerateSingleStreamCluster(0, 4, kAudioTrackNum, kAudioBlockDuration));
scoped_ptr<Cluster> cluster_v(
GenerateSingleStreamCluster(0, 4, kVideoTrackNum, kVideoBlockDuration));
// Append audio and video data into separate source ids.
ASSERT_TRUE(AppendData(audio_id, cluster_a->data(), cluster_a->size()));
ASSERT_TRUE(AppendData(video_id, cluster_v->data(), cluster_v->size()));
// Read() from audio should return normal buffers.
scoped_refptr<DemuxerStream> audio =
demuxer_->GetStream(DemuxerStream::AUDIO);
GenerateExpectedReads(0, 4, audio, kAudioBlockDuration);
// Remove the audio id.
demuxer_->RemoveId(audio_id);
// Read() from audio should return "end of stream" buffers.
bool audio_read_done = false;
audio->Read(base::Bind(&OnReadDone_EOSExpected,
&audio_read_done));
EXPECT_TRUE(audio_read_done);
// Read() from video should still return normal buffers.
scoped_refptr<DemuxerStream> video =
demuxer_->GetStream(DemuxerStream::VIDEO);
GenerateExpectedReads(0, 4, video, kVideoBlockDuration);
}
// Test that Seek() successfully seeks to all source IDs.
TEST_F(ChunkDemuxerTest, TestSeekAudioAndVideoSources) {
std::string audio_id = "audio1";
std::string video_id = "video1";
ASSERT_TRUE(InitDemuxerAudioAndVideoSources(audio_id, video_id));
scoped_ptr<Cluster> cluster_a1(
GenerateSingleStreamCluster(0, 4, kAudioTrackNum, kAudioBlockDuration));
scoped_ptr<Cluster> cluster_v1(
GenerateSingleStreamCluster(0, 4, kVideoTrackNum, kVideoBlockDuration));
ASSERT_TRUE(AppendData(audio_id, cluster_a1->data(), cluster_a1->size()));
ASSERT_TRUE(AppendData(video_id, cluster_v1->data(), cluster_v1->size()));
// Read() should return buffers at 0.
bool audio_read_done = false;
bool video_read_done = false;
scoped_refptr<DemuxerStream> audio =
demuxer_->GetStream(DemuxerStream::AUDIO);
scoped_refptr<DemuxerStream> video =
demuxer_->GetStream(DemuxerStream::VIDEO);
audio->Read(base::Bind(&OnReadDone,
base::TimeDelta::FromMilliseconds(0),
&audio_read_done));
video->Read(base::Bind(&OnReadDone,
base::TimeDelta::FromMilliseconds(0),
&video_read_done));
EXPECT_TRUE(audio_read_done);
EXPECT_TRUE(video_read_done);
// Seek to 3 (an unbuffered region).
demuxer_->StartWaitingForSeek();
demuxer_->Seek(base::TimeDelta::FromSeconds(3),
NewExpectedStatusCB(PIPELINE_OK));
audio_read_done = false;
video_read_done = false;
audio->Read(base::Bind(&OnReadDone,
base::TimeDelta::FromSeconds(3),
&audio_read_done));
video->Read(base::Bind(&OnReadDone,
base::TimeDelta::FromSeconds(3),
&video_read_done));
// Read()s should not return until after data is appended at the Seek point.
EXPECT_FALSE(audio_read_done);
EXPECT_FALSE(video_read_done);
scoped_ptr<Cluster> cluster_a2(
GenerateSingleStreamCluster(3000, 4, kAudioTrackNum,
kAudioBlockDuration));
scoped_ptr<Cluster> cluster_v2(
GenerateSingleStreamCluster(3000, 4, kVideoTrackNum,
kVideoBlockDuration));
ASSERT_TRUE(AppendData(audio_id, cluster_a2->data(), cluster_a2->size()));
ASSERT_TRUE(AppendData(video_id, cluster_v2->data(), cluster_v2->size()));
// Read() should return buffers at 3.
EXPECT_TRUE(audio_read_done);
EXPECT_TRUE(video_read_done);
}
} // namespace media
......@@ -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