123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "media/base/test_helpers.h"
- #include <stdint.h>
- #include <memory>
- #include "base/bind.h"
- #include "base/check_op.h"
- #include "base/notreached.h"
- #include "base/pickle.h"
- #include "base/run_loop.h"
- #include "base/test/test_timeouts.h"
- #include "base/time/time.h"
- #include "base/timer/timer.h"
- #include "media/base/audio_buffer.h"
- #include "media/base/bind_to_current_loop.h"
- #include "media/base/decoder_buffer.h"
- #include "media/base/media_util.h"
- #include "media/base/mock_filters.h"
- #include "ui/gfx/geometry/rect.h"
- using ::testing::_;
- using ::testing::StrictMock;
- namespace media {
- // Utility mock for testing methods expecting Closures and PipelineStatusCBs.
- class MockCallback : public base::RefCountedThreadSafe<MockCallback> {
- public:
- MockCallback();
- MockCallback(const MockCallback&) = delete;
- MockCallback& operator=(const MockCallback&) = delete;
- MOCK_METHOD0(Run, void());
- MOCK_METHOD1(RunWithBool, void(bool));
- MOCK_METHOD1(RunWithStatus, void(PipelineStatus));
- protected:
- friend class base::RefCountedThreadSafe<MockCallback>;
- virtual ~MockCallback();
- };
- MockCallback::MockCallback() = default;
- MockCallback::~MockCallback() = default;
- base::OnceClosure NewExpectedClosure() {
- StrictMock<MockCallback>* callback = new StrictMock<MockCallback>();
- EXPECT_CALL(*callback, Run());
- return base::BindOnce(&MockCallback::Run, WrapRefCounted(callback));
- }
- base::OnceCallback<void(bool)> NewExpectedBoolCB(bool success) {
- StrictMock<MockCallback>* callback = new StrictMock<MockCallback>();
- EXPECT_CALL(*callback, RunWithBool(success));
- return base::BindOnce(&MockCallback::RunWithBool, WrapRefCounted(callback));
- }
- PipelineStatusCallback NewExpectedStatusCB(PipelineStatus status) {
- StrictMock<MockCallback>* callback = new StrictMock<MockCallback>();
- EXPECT_CALL(*callback, RunWithStatus(status));
- return base::BindOnce(&MockCallback::RunWithStatus, WrapRefCounted(callback));
- }
- WaitableMessageLoopEvent::WaitableMessageLoopEvent()
- : WaitableMessageLoopEvent(TestTimeouts::action_timeout()) {}
- WaitableMessageLoopEvent::WaitableMessageLoopEvent(base::TimeDelta timeout)
- : signaled_(false), status_(PIPELINE_OK), timeout_(timeout) {}
- WaitableMessageLoopEvent::~WaitableMessageLoopEvent() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- }
- base::OnceClosure WaitableMessageLoopEvent::GetClosure() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return BindToCurrentLoop(base::BindOnce(&WaitableMessageLoopEvent::OnCallback,
- base::Unretained(this), PIPELINE_OK));
- }
- PipelineStatusCallback WaitableMessageLoopEvent::GetPipelineStatusCB() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return BindToCurrentLoop(base::BindOnce(&WaitableMessageLoopEvent::OnCallback,
- base::Unretained(this)));
- }
- void WaitableMessageLoopEvent::RunAndWait() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- RunAndWaitForStatus(PIPELINE_OK);
- }
- void WaitableMessageLoopEvent::RunAndWaitForStatus(PipelineStatus expected) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (signaled_) {
- EXPECT_EQ(expected, status_);
- return;
- }
- run_loop_ = std::make_unique<base::RunLoop>();
- base::OneShotTimer timer;
- timer.Start(FROM_HERE, timeout_,
- base::BindOnce(&WaitableMessageLoopEvent::OnTimeout,
- base::Unretained(this)));
- run_loop_->Run();
- EXPECT_TRUE(signaled_);
- EXPECT_EQ(expected, status_);
- run_loop_.reset();
- }
- void WaitableMessageLoopEvent::OnCallback(PipelineStatus status) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- signaled_ = true;
- status_ = status;
- // |run_loop_| may be null if the callback fires before RunAndWaitForStatus().
- if (run_loop_)
- run_loop_->Quit();
- }
- void WaitableMessageLoopEvent::OnTimeout() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- ADD_FAILURE() << "Timed out waiting for message loop to quit";
- run_loop_->Quit();
- }
- static VideoDecoderConfig GetTestConfig(VideoCodec codec,
- VideoCodecProfile profile,
- const VideoColorSpace& color_space,
- VideoRotation rotation,
- gfx::Size coded_size,
- bool is_encrypted) {
- gfx::Rect visible_rect(coded_size.width(), coded_size.height());
- gfx::Size natural_size = coded_size;
- return VideoDecoderConfig(
- codec, profile, VideoDecoderConfig::AlphaMode::kIsOpaque, color_space,
- VideoTransformation(rotation), coded_size, visible_rect, natural_size,
- EmptyExtraData(),
- is_encrypted ? EncryptionScheme::kCenc : EncryptionScheme::kUnencrypted);
- }
- static VideoCodecProfile MinProfile(VideoCodec codec) {
- switch (codec) {
- case VideoCodec::kUnknown:
- case VideoCodec::kVC1:
- case VideoCodec::kMPEG2:
- case VideoCodec::kMPEG4:
- return VIDEO_CODEC_PROFILE_UNKNOWN;
- case VideoCodec::kH264:
- return H264PROFILE_MIN;
- case VideoCodec::kTheora:
- return THEORAPROFILE_MIN;
- case VideoCodec::kVP8:
- return VP8PROFILE_MIN;
- case VideoCodec::kVP9:
- return VP9PROFILE_MIN;
- case VideoCodec::kHEVC:
- return HEVCPROFILE_MIN;
- case VideoCodec::kDolbyVision:
- return DOLBYVISION_PROFILE0;
- case VideoCodec::kAV1:
- return AV1PROFILE_MIN;
- }
- }
- static const gfx::Size kNormalSize(320, 240);
- static const gfx::Size kLargeSize(640, 480);
- static const gfx::Size kExtraLargeSize(15360, 8640);
- // static
- VideoDecoderConfig TestVideoConfig::Invalid() {
- return GetTestConfig(VideoCodec::kUnknown, VIDEO_CODEC_PROFILE_UNKNOWN,
- VideoColorSpace::JPEG(), VIDEO_ROTATION_0, kNormalSize,
- false);
- }
- // static
- VideoDecoderConfig TestVideoConfig::Normal(VideoCodec codec) {
- return GetTestConfig(codec, MinProfile(codec), VideoColorSpace::JPEG(),
- VIDEO_ROTATION_0, kNormalSize, false);
- }
- // static
- VideoDecoderConfig TestVideoConfig::NormalWithColorSpace(
- VideoCodec codec,
- const VideoColorSpace& color_space) {
- return GetTestConfig(codec, MinProfile(codec), color_space, VIDEO_ROTATION_0,
- kNormalSize, false);
- }
- // static
- VideoDecoderConfig TestVideoConfig::NormalH264(VideoCodecProfile config) {
- return GetTestConfig(VideoCodec::kH264, MinProfile(VideoCodec::kH264),
- VideoColorSpace::JPEG(), VIDEO_ROTATION_0, kNormalSize,
- false);
- }
- // static
- VideoDecoderConfig TestVideoConfig::NormalCodecProfile(
- VideoCodec codec,
- VideoCodecProfile profile) {
- return GetTestConfig(codec, profile, VideoColorSpace::JPEG(),
- VIDEO_ROTATION_0, kNormalSize, false);
- }
- // static
- VideoDecoderConfig TestVideoConfig::NormalEncrypted(VideoCodec codec,
- VideoCodecProfile profile) {
- return GetTestConfig(codec, profile, VideoColorSpace::JPEG(),
- VIDEO_ROTATION_0, kNormalSize, true);
- }
- // static
- VideoDecoderConfig TestVideoConfig::NormalRotated(VideoRotation rotation) {
- return GetTestConfig(VideoCodec::kVP8, MinProfile(VideoCodec::kVP8),
- VideoColorSpace::JPEG(), rotation, kNormalSize, false);
- }
- // static
- VideoDecoderConfig TestVideoConfig::Large(VideoCodec codec) {
- return GetTestConfig(codec, MinProfile(codec), VideoColorSpace::JPEG(),
- VIDEO_ROTATION_0, kLargeSize, false);
- }
- // static
- VideoDecoderConfig TestVideoConfig::LargeEncrypted(VideoCodec codec) {
- return GetTestConfig(codec, MinProfile(codec), VideoColorSpace::JPEG(),
- VIDEO_ROTATION_0, kLargeSize, true);
- }
- // static
- VideoDecoderConfig TestVideoConfig::ExtraLarge(VideoCodec codec) {
- return GetTestConfig(codec, MinProfile(codec), VideoColorSpace::JPEG(),
- VIDEO_ROTATION_0, kExtraLargeSize, false);
- }
- // static
- VideoDecoderConfig TestVideoConfig::ExtraLargeEncrypted(VideoCodec codec) {
- return GetTestConfig(codec, MinProfile(codec), VideoColorSpace::JPEG(),
- VIDEO_ROTATION_0, kExtraLargeSize, true);
- }
- // static
- VideoDecoderConfig TestVideoConfig::Custom(gfx::Size size, VideoCodec codec) {
- return GetTestConfig(codec, MinProfile(codec), VideoColorSpace::JPEG(),
- VIDEO_ROTATION_0, size, false);
- }
- // static
- VideoDecoderConfig TestVideoConfig::CustomEncrypted(gfx::Size size,
- VideoCodec codec) {
- return GetTestConfig(codec, MinProfile(codec), VideoColorSpace::JPEG(),
- VIDEO_ROTATION_0, size, true);
- }
- // static
- gfx::Size TestVideoConfig::NormalCodedSize() {
- return kNormalSize;
- }
- // static
- gfx::Size TestVideoConfig::LargeCodedSize() {
- return kLargeSize;
- }
- // static
- gfx::Size TestVideoConfig::ExtraLargeCodedSize() {
- return kExtraLargeSize;
- }
- AudioDecoderConfig TestAudioConfig::Normal() {
- return AudioDecoderConfig(AudioCodec::kVorbis, kSampleFormatPlanarF32,
- CHANNEL_LAYOUT_STEREO, NormalSampleRateValue(),
- EmptyExtraData(), EncryptionScheme::kUnencrypted);
- }
- AudioDecoderConfig TestAudioConfig::NormalEncrypted() {
- return AudioDecoderConfig(AudioCodec::kVorbis, kSampleFormatPlanarF32,
- CHANNEL_LAYOUT_STEREO, NormalSampleRateValue(),
- EmptyExtraData(), EncryptionScheme::kCenc);
- }
- AudioDecoderConfig TestAudioConfig::HighSampleRate() {
- return AudioDecoderConfig(AudioCodec::kVorbis, kSampleFormatPlanarF32,
- CHANNEL_LAYOUT_STEREO, HighSampleRateValue(),
- EmptyExtraData(), EncryptionScheme::kUnencrypted);
- }
- AudioDecoderConfig TestAudioConfig::HighSampleRateEncrypted() {
- return AudioDecoderConfig(AudioCodec::kVorbis, kSampleFormatPlanarF32,
- CHANNEL_LAYOUT_STEREO, HighSampleRateValue(),
- EmptyExtraData(), EncryptionScheme::kCenc);
- }
- int TestAudioConfig::NormalSampleRateValue() {
- return 44100;
- }
- int TestAudioConfig::HighSampleRateValue() {
- return 192000;
- }
- // static
- AudioParameters TestAudioParameters::Normal() {
- return AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
- CHANNEL_LAYOUT_STEREO, 48000, 2048);
- }
- template <class T>
- scoped_refptr<AudioBuffer> MakeAudioBuffer(SampleFormat format,
- ChannelLayout channel_layout,
- size_t channel_count,
- int sample_rate,
- T start,
- T increment,
- size_t frames,
- base::TimeDelta timestamp) {
- const size_t channels = ChannelLayoutToChannelCount(channel_layout);
- scoped_refptr<AudioBuffer> output =
- AudioBuffer::CreateBuffer(format,
- channel_layout,
- static_cast<int>(channel_count),
- sample_rate,
- static_cast<int>(frames));
- output->set_timestamp(timestamp);
- const bool is_planar = IsPlanar(format);
- // Values in channel 0 will be:
- // start
- // start + increment
- // start + 2 * increment, ...
- // While, values in channel 1 will be:
- // start + frames * increment
- // start + (frames + 1) * increment
- // start + (frames + 2) * increment, ...
- for (size_t ch = 0; ch < channels; ++ch) {
- T* buffer =
- reinterpret_cast<T*>(output->channel_data()[is_planar ? ch : 0]);
- const T v = static_cast<T>(start + ch * frames * increment);
- for (size_t i = 0; i < frames; ++i) {
- buffer[is_planar ? i : ch + i * channels] =
- static_cast<T>(v + i * increment);
- }
- }
- return output;
- }
- template <>
- scoped_refptr<AudioBuffer> MakeAudioBuffer<float>(SampleFormat format,
- ChannelLayout channel_layout,
- size_t channel_count,
- int sample_rate,
- float start,
- float increment,
- size_t frames,
- base::TimeDelta timestamp) {
- const size_t channels = ChannelLayoutToChannelCount(channel_layout);
- scoped_refptr<AudioBuffer> output = AudioBuffer::CreateBuffer(
- format, channel_layout, static_cast<int>(channel_count), sample_rate,
- static_cast<int>(frames));
- output->set_timestamp(timestamp);
- const bool is_planar =
- format == kSampleFormatPlanarS16 || format == kSampleFormatPlanarF32;
- // Values in channel 0 will be:
- // (start) / max_value
- // (start + increment) / max_value
- // (start + 2 * increment) / max_value, ...
- // While, values in channel 1 will be:
- // (start + frames * increment) / max_value
- // (start + (frames + 1) * increment) / max_value
- // (start + (frames + 2) * increment) / max_value, ...
- for (size_t ch = 0; ch < channels; ++ch) {
- float* buffer =
- reinterpret_cast<float*>(output->channel_data()[is_planar ? ch : 0]);
- const float v = static_cast<float>(start + ch * frames * increment);
- for (size_t i = 0; i < frames; ++i) {
- buffer[is_planar ? i : ch + i * channels] =
- static_cast<float>(v + i * increment) /
- std::numeric_limits<uint16_t>::max();
- }
- }
- return output;
- }
- scoped_refptr<AudioBuffer> MakeBitstreamAudioBuffer(
- SampleFormat format,
- ChannelLayout channel_layout,
- size_t channel_count,
- int sample_rate,
- uint8_t start,
- uint8_t increment,
- size_t frames,
- size_t data_size,
- base::TimeDelta timestamp) {
- scoped_refptr<AudioBuffer> output = AudioBuffer::CreateBitstreamBuffer(
- format, channel_layout, static_cast<int>(channel_count), sample_rate,
- static_cast<int>(frames), data_size);
- output->set_timestamp(timestamp);
- // Values in channel 0 will be:
- // start
- // start + increment
- // start + 2 * increment, ...
- uint8_t* buffer = reinterpret_cast<uint8_t*>(output->channel_data()[0]);
- for (size_t i = 0; i < data_size; ++i) {
- buffer[i] = static_cast<uint8_t>(start + i * increment);
- }
- return output;
- }
- void VerifyBitstreamAudioBus(AudioBus* bus,
- size_t data_size,
- uint8_t start,
- uint8_t increment) {
- ASSERT_TRUE(bus->is_bitstream_format());
- // Values in channel 0 will be:
- // start
- // start + increment
- // start + 2 * increment, ...
- uint8_t* buffer = reinterpret_cast<uint8_t*>(bus->channel(0));
- for (size_t i = 0; i < data_size; ++i) {
- ASSERT_EQ(buffer[i], static_cast<uint8_t>(start + i * increment));
- }
- }
- // Instantiate all the types of MakeAudioBuffer() and
- // MakeAudioBuffer() needed.
- #define DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(type) \
- template scoped_refptr<AudioBuffer> MakeAudioBuffer<type>( \
- SampleFormat format, \
- ChannelLayout channel_layout, \
- size_t channel_count, \
- int sample_rate, \
- type start, \
- type increment, \
- size_t frames, \
- base::TimeDelta start_time)
- DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(uint8_t);
- DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(int16_t);
- DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(int32_t);
- static const char kFakeVideoBufferHeader[] = "FakeVideoBufferForTest";
- scoped_refptr<DecoderBuffer> CreateFakeVideoBufferForTest(
- const VideoDecoderConfig& config,
- base::TimeDelta timestamp, base::TimeDelta duration) {
- base::Pickle pickle;
- pickle.WriteString(kFakeVideoBufferHeader);
- pickle.WriteInt(config.coded_size().width());
- pickle.WriteInt(config.coded_size().height());
- pickle.WriteInt64(timestamp.InMilliseconds());
- scoped_refptr<DecoderBuffer> buffer =
- DecoderBuffer::CopyFrom(static_cast<const uint8_t*>(pickle.data()),
- static_cast<int>(pickle.size()));
- buffer->set_timestamp(timestamp);
- buffer->set_duration(duration);
- buffer->set_is_key_frame(true);
- return buffer;
- }
- bool VerifyFakeVideoBufferForTest(const DecoderBuffer& buffer,
- const VideoDecoderConfig& config) {
- // Check if the input |buffer| matches the |config|.
- base::PickleIterator pickle(
- base::Pickle(reinterpret_cast<const char*>(buffer.data()),
- static_cast<int>(buffer.data_size())));
- std::string header;
- int width = 0;
- int height = 0;
- bool success = pickle.ReadString(&header) && pickle.ReadInt(&width) &&
- pickle.ReadInt(&height);
- return (success && header == kFakeVideoBufferHeader &&
- width == config.coded_size().width() &&
- height == config.coded_size().height());
- }
- std::unique_ptr<StrictMock<MockDemuxerStream>> CreateMockDemuxerStream(
- DemuxerStream::Type type,
- bool encrypted) {
- auto stream = std::make_unique<StrictMock<MockDemuxerStream>>(type);
- switch (type) {
- case DemuxerStream::AUDIO:
- stream->set_audio_decoder_config(encrypted
- ? TestAudioConfig::NormalEncrypted()
- : TestAudioConfig::Normal());
- break;
- case DemuxerStream::VIDEO:
- stream->set_video_decoder_config(encrypted
- ? TestVideoConfig::NormalEncrypted()
- : TestVideoConfig::Normal());
- break;
- default:
- NOTREACHED();
- break;
- }
- return stream;
- }
- } // namespace media
|