| Index: media/test/pipeline_integration_test.cc
|
| diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
|
| index 53e727037c3f9438a2366f5b7ec0233841ec9735..e1d7f55d7206fb6e10fd1f7c0ba0f237bc55b406 100644
|
| --- a/media/test/pipeline_integration_test.cc
|
| +++ b/media/test/pipeline_integration_test.cc
|
| @@ -19,9 +19,7 @@
|
| #include "base/threading/thread_task_runner_handle.h"
|
| #include "build/build_config.h"
|
| #include "media/base/cdm_callback_promise.h"
|
| -#include "media/base/cdm_context.h"
|
| #include "media/base/cdm_key_information.h"
|
| -#include "media/base/content_decryption_module.h"
|
| #include "media/base/decoder_buffer.h"
|
| #include "media/base/media.h"
|
| #include "media/base/media_switches.h"
|
| @@ -30,9 +28,10 @@
|
| #include "media/base/timestamp_constants.h"
|
| #include "media/cdm/aes_decryptor.h"
|
| #include "media/cdm/json_web_key.h"
|
| -#include "media/filters/chunk_demuxer.h"
|
| #include "media/media_features.h"
|
| #include "media/renderers/renderer_impl.h"
|
| +#include "media/test/fake_encrypted_media.h"
|
| +#include "media/test/mock_media_source.h"
|
| #include "media/test/pipeline_integration_test_base.h"
|
| #include "testing/gmock/include/gmock/gmock.h"
|
| #include "url/gurl.h"
|
| @@ -94,8 +93,6 @@ using testing::SaveArg;
|
|
|
| namespace media {
|
|
|
| -const char kSourceId[] = "SourceId";
|
| -
|
| const char kWebM[] = "video/webm; codecs=\"vp8,vorbis\"";
|
| const char kWebMVP9[] = "video/webm; codecs=\"vp9\"";
|
| const char kAudioOnlyWebM[] = "video/webm; codecs=\"vorbis\"";
|
| @@ -114,8 +111,6 @@ const char kMP3[] = "audio/mpeg";
|
| const char kMP2AudioSBR[] = "video/mp2t; codecs=\"avc1.4D4041,mp4a.40.5\"";
|
| #endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
|
|
|
| -const size_t kAppendWholeFile = std::numeric_limits<size_t>::max();
|
| -
|
| // Constants for the Media Source config change tests.
|
| const int kAppendTimeSec = 1;
|
| const int kAppendTimeMs = kAppendTimeSec * 1000;
|
| @@ -187,86 +182,6 @@ static base::Time kLiveTimelineOffset() {
|
| return timeline_offset;
|
| }
|
|
|
| -// Note: Tests using this class only exercise the DecryptingDemuxerStream path.
|
| -// They do not exercise the Decrypting{Audio|Video}Decoder path.
|
| -class FakeEncryptedMedia {
|
| - public:
|
| - // Defines the behavior of the "app" that responds to EME events.
|
| - class AppBase {
|
| - public:
|
| - virtual ~AppBase() {}
|
| -
|
| - virtual void OnSessionMessage(
|
| - const std::string& session_id,
|
| - ContentDecryptionModule::MessageType message_type,
|
| - const std::vector<uint8_t>& message,
|
| - AesDecryptor* decryptor) = 0;
|
| -
|
| - virtual void OnSessionClosed(const std::string& session_id) = 0;
|
| -
|
| - virtual void OnSessionKeysChange(const std::string& session_id,
|
| - bool has_additional_usable_key,
|
| - CdmKeysInfo keys_info) = 0;
|
| -
|
| - virtual void OnEncryptedMediaInitData(EmeInitDataType init_data_type,
|
| - const std::vector<uint8_t>& init_data,
|
| - AesDecryptor* decryptor) = 0;
|
| - };
|
| -
|
| - FakeEncryptedMedia(AppBase* app)
|
| - : decryptor_(new AesDecryptor(
|
| - GURL::EmptyGURL(),
|
| - base::Bind(&FakeEncryptedMedia::OnSessionMessage,
|
| - base::Unretained(this)),
|
| - base::Bind(&FakeEncryptedMedia::OnSessionClosed,
|
| - base::Unretained(this)),
|
| - base::Bind(&FakeEncryptedMedia::OnSessionKeysChange,
|
| - base::Unretained(this)))),
|
| - cdm_context_(decryptor_.get()),
|
| - app_(app) {}
|
| -
|
| - CdmContext* GetCdmContext() { return &cdm_context_; }
|
| -
|
| - // Callbacks for firing session events. Delegate to |app_|.
|
| - void OnSessionMessage(const std::string& session_id,
|
| - ContentDecryptionModule::MessageType message_type,
|
| - const std::vector<uint8_t>& message) {
|
| - app_->OnSessionMessage(session_id, message_type, message, decryptor_.get());
|
| - }
|
| -
|
| - void OnSessionClosed(const std::string& session_id) {
|
| - app_->OnSessionClosed(session_id);
|
| - }
|
| -
|
| - void OnSessionKeysChange(const std::string& session_id,
|
| - bool has_additional_usable_key,
|
| - CdmKeysInfo keys_info) {
|
| - app_->OnSessionKeysChange(session_id, has_additional_usable_key,
|
| - std::move(keys_info));
|
| - }
|
| -
|
| - void OnEncryptedMediaInitData(EmeInitDataType init_data_type,
|
| - const std::vector<uint8_t>& init_data) {
|
| - app_->OnEncryptedMediaInitData(init_data_type, init_data, decryptor_.get());
|
| - }
|
| -
|
| - private:
|
| - class TestCdmContext : public CdmContext {
|
| - public:
|
| - TestCdmContext(Decryptor* decryptor) : decryptor_(decryptor) {}
|
| -
|
| - Decryptor* GetDecryptor() final { return decryptor_; }
|
| - int GetCdmId() const final { return kInvalidCdmId; }
|
| -
|
| - private:
|
| - Decryptor* decryptor_;
|
| - };
|
| -
|
| - scoped_refptr<AesDecryptor> decryptor_;
|
| - TestCdmContext cdm_context_;
|
| - std::unique_ptr<AppBase> app_;
|
| -};
|
| -
|
| enum PromiseResult { RESOLVED, REJECTED };
|
|
|
| // Provides the test key in response to the encrypted event.
|
| @@ -442,210 +357,6 @@ class NoResponseApp : public FakeEncryptedMedia::AppBase {
|
| AesDecryptor* decryptor) override {}
|
| };
|
|
|
| -// Helper class that emulates calls made on the ChunkDemuxer by the
|
| -// Media Source API.
|
| -class MockMediaSource {
|
| - public:
|
| - MockMediaSource(const std::string& filename,
|
| - const std::string& mimetype,
|
| - size_t initial_append_size)
|
| - : current_position_(0),
|
| - initial_append_size_(initial_append_size),
|
| - mimetype_(mimetype),
|
| - chunk_demuxer_(new ChunkDemuxer(
|
| - base::Bind(&MockMediaSource::DemuxerOpened, base::Unretained(this)),
|
| - base::Bind(&MockMediaSource::OnEncryptedMediaInitData,
|
| - base::Unretained(this)),
|
| - &media_log_)),
|
| - owned_chunk_demuxer_(chunk_demuxer_) {
|
| - file_data_ = ReadTestDataFile(filename);
|
| -
|
| - if (initial_append_size_ == kAppendWholeFile)
|
| - initial_append_size_ = file_data_->data_size();
|
| -
|
| - DCHECK_GT(initial_append_size_, 0u);
|
| - DCHECK_LE(initial_append_size_, file_data_->data_size());
|
| - }
|
| -
|
| - virtual ~MockMediaSource() {}
|
| -
|
| - std::unique_ptr<Demuxer> GetDemuxer() {
|
| - return std::move(owned_chunk_demuxer_);
|
| - }
|
| -
|
| - void set_encrypted_media_init_data_cb(
|
| - const Demuxer::EncryptedMediaInitDataCB& encrypted_media_init_data_cb) {
|
| - encrypted_media_init_data_cb_ = encrypted_media_init_data_cb;
|
| - }
|
| -
|
| - void set_demuxer_failure_cb(const PipelineStatusCB& demuxer_failure_cb) {
|
| - demuxer_failure_cb_ = demuxer_failure_cb;
|
| - }
|
| -
|
| - void Seek(base::TimeDelta seek_time,
|
| - size_t new_position,
|
| - size_t seek_append_size) {
|
| - chunk_demuxer_->StartWaitingForSeek(seek_time);
|
| -
|
| - chunk_demuxer_->ResetParserState(kSourceId, base::TimeDelta(),
|
| - kInfiniteDuration,
|
| - &last_timestamp_offset_);
|
| -
|
| - DCHECK_LT(new_position, file_data_->data_size());
|
| - current_position_ = new_position;
|
| -
|
| - AppendData(seek_append_size);
|
| - }
|
| -
|
| - void Seek(base::TimeDelta seek_time) {
|
| - chunk_demuxer_->StartWaitingForSeek(seek_time);
|
| - }
|
| -
|
| - void AppendData(size_t size) {
|
| - DCHECK(chunk_demuxer_);
|
| - DCHECK_LT(current_position_, file_data_->data_size());
|
| - DCHECK_LE(current_position_ + size, file_data_->data_size());
|
| -
|
| - ASSERT_TRUE(chunk_demuxer_->AppendData(
|
| - kSourceId, file_data_->data() + current_position_, size,
|
| - base::TimeDelta(), kInfiniteDuration, &last_timestamp_offset_));
|
| - current_position_ += size;
|
| - }
|
| -
|
| - bool AppendAtTime(base::TimeDelta timestamp_offset,
|
| - const uint8_t* pData,
|
| - int size) {
|
| - CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId));
|
| - bool success =
|
| - chunk_demuxer_->AppendData(kSourceId, pData, size, base::TimeDelta(),
|
| - kInfiniteDuration, ×tamp_offset);
|
| - last_timestamp_offset_ = timestamp_offset;
|
| - return success;
|
| - }
|
| -
|
| - void AppendAtTimeWithWindow(base::TimeDelta timestamp_offset,
|
| - base::TimeDelta append_window_start,
|
| - base::TimeDelta append_window_end,
|
| - const uint8_t* pData,
|
| - int size) {
|
| - CHECK(!chunk_demuxer_->IsParsingMediaSegment(kSourceId));
|
| - ASSERT_TRUE(
|
| - chunk_demuxer_->AppendData(kSourceId, pData, size, append_window_start,
|
| - append_window_end, ×tamp_offset));
|
| - last_timestamp_offset_ = timestamp_offset;
|
| - }
|
| -
|
| - void SetMemoryLimits(size_t limit_bytes) {
|
| - chunk_demuxer_->SetMemoryLimitsForTest(DemuxerStream::AUDIO, limit_bytes);
|
| - chunk_demuxer_->SetMemoryLimitsForTest(DemuxerStream::VIDEO, limit_bytes);
|
| - }
|
| -
|
| - bool EvictCodedFrames(base::TimeDelta currentMediaTime, size_t newDataSize) {
|
| - return chunk_demuxer_->EvictCodedFrames(kSourceId, currentMediaTime,
|
| - newDataSize);
|
| - }
|
| -
|
| - void RemoveRange(base::TimeDelta start, base::TimeDelta end) {
|
| - chunk_demuxer_->Remove(kSourceId, start, end);
|
| - }
|
| -
|
| - void EndOfStream() { chunk_demuxer_->MarkEndOfStream(PIPELINE_OK); }
|
| -
|
| - void Shutdown() {
|
| - if (!chunk_demuxer_)
|
| - return;
|
| - chunk_demuxer_->ResetParserState(kSourceId, base::TimeDelta(),
|
| - kInfiniteDuration,
|
| - &last_timestamp_offset_);
|
| - chunk_demuxer_->Shutdown();
|
| - chunk_demuxer_ = NULL;
|
| - }
|
| -
|
| - void DemuxerOpened() {
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(
|
| - FROM_HERE, base::Bind(&MockMediaSource::DemuxerOpenedTask,
|
| - base::Unretained(this)));
|
| - }
|
| -
|
| - void DemuxerOpenedTask() {
|
| - ChunkDemuxer::Status status = AddId();
|
| - if (status != ChunkDemuxer::kOk) {
|
| - CHECK(!demuxer_failure_cb_.is_null());
|
| - demuxer_failure_cb_.Run(DEMUXER_ERROR_COULD_NOT_OPEN);
|
| - return;
|
| - }
|
| - chunk_demuxer_->SetTracksWatcher(
|
| - kSourceId, base::Bind(&MockMediaSource::InitSegmentReceived,
|
| - base::Unretained(this)));
|
| -
|
| - AppendData(initial_append_size_);
|
| - }
|
| -
|
| - ChunkDemuxer::Status AddId() {
|
| - // This code assumes that |mimetype_| is one of the following forms.
|
| - // 1. audio/mpeg
|
| - // 2. video/webm;codec="vorbis,vp8".
|
| - size_t semicolon = mimetype_.find(";");
|
| - std::string type = mimetype_;
|
| - std::string codecs_param = "";
|
| - if (semicolon != std::string::npos) {
|
| - type = mimetype_.substr(0, semicolon);
|
| - size_t codecs_param_start = mimetype_.find("codecs=\"", semicolon);
|
| -
|
| - CHECK_NE(codecs_param_start, std::string::npos);
|
| -
|
| - codecs_param_start += 8; // Skip over the codecs=".
|
| -
|
| - size_t codecs_param_end = mimetype_.find("\"", codecs_param_start);
|
| -
|
| - CHECK_NE(codecs_param_end, std::string::npos);
|
| -
|
| - codecs_param = mimetype_.substr(codecs_param_start,
|
| - codecs_param_end - codecs_param_start);
|
| - }
|
| -
|
| - return chunk_demuxer_->AddId(kSourceId, type, codecs_param);
|
| - }
|
| -
|
| - void OnEncryptedMediaInitData(EmeInitDataType init_data_type,
|
| - const std::vector<uint8_t>& init_data) {
|
| - DCHECK(!init_data.empty());
|
| - CHECK(!encrypted_media_init_data_cb_.is_null());
|
| - encrypted_media_init_data_cb_.Run(init_data_type, init_data);
|
| - }
|
| -
|
| - base::TimeDelta last_timestamp_offset() const {
|
| - return last_timestamp_offset_;
|
| - }
|
| -
|
| - void InitSegmentReceived(std::unique_ptr<MediaTracks> tracks) {
|
| - CHECK(tracks.get());
|
| - EXPECT_GT(tracks->tracks().size(), 0u);
|
| - CHECK(chunk_demuxer_);
|
| - // Verify that track ids are unique.
|
| - std::set<MediaTrack::Id> track_ids;
|
| - for (const auto& track : tracks->tracks()) {
|
| - EXPECT_EQ(track_ids.end(), track_ids.find(track->id()));
|
| - track_ids.insert(track->id());
|
| - }
|
| - InitSegmentReceivedMock(tracks);
|
| - }
|
| -
|
| - MOCK_METHOD1(InitSegmentReceivedMock, void(std::unique_ptr<MediaTracks>&));
|
| -
|
| - private:
|
| - MediaLog media_log_;
|
| - scoped_refptr<DecoderBuffer> file_data_;
|
| - size_t current_position_;
|
| - size_t initial_append_size_;
|
| - std::string mimetype_;
|
| - ChunkDemuxer* chunk_demuxer_;
|
| - std::unique_ptr<Demuxer> owned_chunk_demuxer_;
|
| - PipelineStatusCB demuxer_failure_cb_;
|
| - Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb_;
|
| - base::TimeDelta last_timestamp_offset_;
|
| -};
|
| -
|
| // A rough simulation of GpuVideoDecoder that fails every Decode() request. This
|
| // is used to test post-Initialize() fallback paths.
|
| class FailingVideoDecoder : public VideoDecoder {
|
| @@ -673,10 +384,10 @@ class FailingVideoDecoder : public VideoDecoder {
|
| // preferably by eliminating multiple inheritance here which is
|
| // banned by Google C++ style.
|
| #if defined(MOJO_RENDERER) && defined(ENABLE_MOJO_PIPELINE_INTEGRATION_TEST)
|
| -class PipelineIntegrationTestHost : public service_manager::test::ServiceTest,
|
| - public PipelineIntegrationTestBase {
|
| +class PipelineIntegrationTest : public service_manager::test::ServiceTest,
|
| + public PipelineIntegrationTestBase {
|
| public:
|
| - PipelineIntegrationTestHost()
|
| + PipelineIntegrationTest()
|
| : service_manager::test::ServiceTest(
|
| "media_pipeline_integration_shelltests") {}
|
|
|
| @@ -703,74 +414,9 @@ class PipelineIntegrationTestHost : public service_manager::test::ServiceTest,
|
| mojom::InterfaceFactoryPtr media_interface_factory_;
|
| };
|
| #else
|
| -class PipelineIntegrationTestHost : public testing::Test,
|
| - public PipelineIntegrationTestBase {};
|
| -#endif // defined(MOJO_RENDERER)
|
| -
|
| -class PipelineIntegrationTest : public PipelineIntegrationTestHost {
|
| +class PipelineIntegrationTest : public testing::Test,
|
| + public PipelineIntegrationTestBase {
|
| public:
|
| - PipelineStatus StartPipelineWithMediaSource(MockMediaSource* source) {
|
| - return StartPipelineWithMediaSource(source, kNormal, nullptr);
|
| - }
|
| -
|
| - PipelineStatus StartPipelineWithEncryptedMedia(
|
| - MockMediaSource* source,
|
| - FakeEncryptedMedia* encrypted_media) {
|
| - return StartPipelineWithMediaSource(source, kNormal, encrypted_media);
|
| - }
|
| -
|
| - PipelineStatus StartPipelineWithMediaSource(
|
| - MockMediaSource* source,
|
| - uint8_t test_type,
|
| - FakeEncryptedMedia* encrypted_media) {
|
| - hashing_enabled_ = test_type & kHashed;
|
| - clockless_playback_ = test_type & kClockless;
|
| -
|
| - if (!(test_type & kExpectDemuxerFailure))
|
| - EXPECT_CALL(*source, InitSegmentReceivedMock(_)).Times(AtLeast(1));
|
| -
|
| - EXPECT_CALL(*this, OnMetadata(_))
|
| - .Times(AtMost(1))
|
| - .WillRepeatedly(SaveArg<0>(&metadata_));
|
| - EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH))
|
| - .Times(AnyNumber());
|
| - EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING))
|
| - .Times(AnyNumber());
|
| - EXPECT_CALL(*this, OnDurationChange()).Times(AnyNumber());
|
| - EXPECT_CALL(*this, OnVideoNaturalSizeChange(_)).Times(AtMost(1));
|
| - EXPECT_CALL(*this, OnVideoOpacityChange(_)).Times(AtMost(1));
|
| -
|
| - source->set_demuxer_failure_cb(base::Bind(
|
| - &PipelineIntegrationTest::OnStatusCallback, base::Unretained(this)));
|
| - demuxer_ = source->GetDemuxer();
|
| -
|
| - if (encrypted_media) {
|
| - EXPECT_CALL(*this, DecryptorAttached(true));
|
| -
|
| - // Encrypted content used but keys provided in advance, so this is
|
| - // never called.
|
| - EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
|
| - pipeline_->SetCdm(encrypted_media->GetCdmContext(),
|
| - base::Bind(&PipelineIntegrationTest::DecryptorAttached,
|
| - base::Unretained(this)));
|
| - } else {
|
| - // Encrypted content not used, so this is never called.
|
| - EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
|
| - }
|
| -
|
| - pipeline_->Start(demuxer_.get(), CreateRenderer(), this,
|
| - base::Bind(&PipelineIntegrationTest::OnStatusCallback,
|
| - base::Unretained(this)));
|
| -
|
| - if (encrypted_media) {
|
| - source->set_encrypted_media_init_data_cb(
|
| - base::Bind(&FakeEncryptedMedia::OnEncryptedMediaInitData,
|
| - base::Unretained(encrypted_media)));
|
| - }
|
| - base::RunLoop().Run();
|
| - return pipeline_status_;
|
| - }
|
| -
|
| // Verifies that seeking works properly for ChunkDemuxer when the
|
| // seek happens while there is a pending read on the ChunkDemuxer
|
| // and no data is available.
|
| @@ -801,6 +447,7 @@ class PipelineIntegrationTest : public PipelineIntegrationTestHost {
|
| return true;
|
| }
|
| };
|
| +#endif // defined(MOJO_RENDERER)
|
|
|
| struct PlaybackTestData {
|
| const std::string filename;
|
|
|