chromium/media/base/test_helpers.h

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_BASE_TEST_HELPERS_H_
#define MEDIA_BASE_TEST_HELPERS_H_

#include <stddef.h>
#include <memory>

#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "media/base/audio_parameters.h"
#include "media/base/channel_layout.h"
#include "media/base/decoder_status.h"
#include "media/base/demuxer_stream.h"
#include "media/base/media_log.h"
#include "media/base/pipeline_status.h"
#include "media/base/sample_format.h"
#include "media/base/status.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_frame.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "ui/gfx/geometry/size.h"

namespace base {
class RunLoop;
class TimeDelta;
}  // namespace base

namespace media {

class AudioBuffer;
class AudioBus;
class DecoderBuffer;
class MockDemuxerStream;

// Return a callback that expects to be run once.
base::OnceClosure NewExpectedClosure();
base::OnceCallback<void(bool)> NewExpectedBoolCB(bool success);
PipelineStatusCallback NewExpectedStatusCB(PipelineStatus status);

// Helper class for running a message loop until a callback has run. Useful for
// testing classes that run on more than a single thread.
//
// Events are intended for single use and cannot be reset.
class WaitableMessageLoopEvent {};

// Provides pre-canned VideoDecoderConfig. These types are used for tests that
// don't care about detailed parameters of the config.
class TestVideoConfig {};

// Provides pre-canned AudioDecoderConfig. These types are used for tests that
// don't care about detailed parameters of the config.
class TestAudioConfig {};

// Provides pre-canned AudioParameters objects.
class TestAudioParameters {};

// Create an AudioBuffer containing |frames| frames of data, where each sample
// is of type T.  |start| and |increment| are used to specify the values for the
// samples, which are created in channel order.  The value for frame and channel
// is determined by:
//
//   |start| + |channel| * |frames| * |increment| + index * |increment|
//
// E.g., for a stereo buffer the 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, ...
//
// |start_time| will be used as the start time for the samples.
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);

// Similar to above, but for float types where the maximum range is limited to
// [-1.0f, 1.0f]. Here the stored values will be divided by 65536.
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);

// Create an AudioBuffer containing bitstream data. |start| and |increment| are
// used to specify the values for the data. The value is determined by:
//   start + frames * increment
//   start + (frames + 1) * increment
//   start + (frames + 2) * increment, ...
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);

// Verify the bitstream data in an AudioBus. |start| and |increment| are
// used to specify the values for the data. The value is determined by:
//   start + frames * increment
//   start + (frames + 1) * increment
//   start + (frames + 2) * increment, ...
void VerifyBitstreamAudioBus(AudioBus* bus,
                             size_t data_size,
                             uint8_t start,
                             uint8_t increment);

// Create a fake video DecoderBuffer for testing purpose. The buffer contains
// part of video decoder config info embedded so that the testing code can do
// some sanity check.
scoped_refptr<DecoderBuffer> CreateFakeVideoBufferForTest(
    const VideoDecoderConfig& config,
    base::TimeDelta timestamp,
    base::TimeDelta duration);

// Create a mismatched DecoderBuffer to verify in unit tests that we error
// out and do not continue to decode or decrypt if subsamples do not match.
scoped_refptr<DecoderBuffer> CreateMismatchedBufferForTest();

// Create fake encrypted buffer for testing purposes.
scoped_refptr<DecoderBuffer> CreateFakeEncryptedBuffer();

// Create fake clear buffer for testing purposes.
scoped_refptr<DecoderBuffer> CreateClearBuffer();

// Verify if a fake video DecoderBuffer is valid.
bool VerifyFakeVideoBufferForTest(const DecoderBuffer& buffer,
                                  const VideoDecoderConfig& config);

// Create a MockDemuxerStream for testing purposes.
std::unique_ptr<::testing::StrictMock<MockDemuxerStream>>
CreateMockDemuxerStream(DemuxerStream::Type type, bool encrypted);

// Fills `dest_frame` with a four color frame which looks like:
//
//   YYYYRRRR
//   BBBBGGGG
//
// Supports 8-bit xRGB, BGRx, NV12x, and I4xxx formats. If `xor_mask` is
// provided the standard four colors will be XOR'd with the provided 00RRGGBB
// value (alpha value must be zero).
void FillFourColors(VideoFrame& dest_frame,
                    std::optional<uint32_t> xor_mask = std::nullopt);

// Convert RGB color to YUV.
std::tuple<uint8_t, uint8_t, uint8_t, uint8_t> RGBToYUV(uint32_t argb);

// Compares two media::Status by StatusCode only.  Also allows the ok helper to
// match kOk.  It's a special case because we don't know the TypedStatus traits
// we'll be comparing against until now.
MATCHER_P(SameStatusCode, status, "") {}

// Compares an `arg` TypedStatus<T>.code() to a test-supplied StatusCode.
MATCHER_P(HasStatusCode, status_code, "") {}

MATCHER(IsOkStatus, "") {}

// True if and only if the Status would be interpreted as an error from a decode
// callback (not okay, not aborted).
MATCHER(IsDecodeErrorStatus, "") {}

// Compares two {Audio|Video}DecoderConfigs
MATCHER_P(DecoderConfigEq, config, "") {}

MATCHER_P(ReadOneAndHasTimestamp, timestamp_in_ms, "") {}

MATCHER(ReadOneAndIsEndOfStream, "") {}

MATCHER(IsEmpty, "") {}

MATCHER(EosBeforeHaveMetadata, "") {}

MATCHER_P(SegmentMissingFrames, track_id, "") {}

MATCHER(MuxedSequenceModeWarning, "") {}

MATCHER_P2(KeyframeTimeGreaterThanDependant,
           keyframe_time_string,
           nonkeyframe_time_string,
           "") {}

MATCHER(StreamParsingFailed, "") {}

MATCHER(ParsedBuffersNotInDTSSequence, "") {}

MATCHER_P2(CodecUnsupportedInContainer, codec, container, "") {}

MATCHER_P(FoundStream, stream_type_string, "") {}

MATCHER_P2(CodecName, stream_type_string, codec_string, "") {}

MATCHER_P2(FlacAudioSampleRateOverriddenByStreaminfo,
           original_rate_string,
           streaminfo_rate_string,
           "") {}

MATCHER_P2(InitSegmentMismatchesMimeType, stream_type, codec_name, "") {}

MATCHER_P(InitSegmentMissesExpectedTrack, missing_codec, "") {}

MATCHER_P2(UnexpectedTrack, track_type, id, "") {}

MATCHER_P2(FrameTypeMismatchesTrackType, frame_type, track_type, "") {}

MATCHER_P2(AudioNonKeyframe, pts_microseconds, dts_microseconds, "") {}

MATCHER(AudioNonKeyframeOutOfOrder, "") {}

MATCHER_P2(SkippingSpliceAtOrBefore,
           new_microseconds,
           existing_microseconds,
           "") {}

MATCHER_P(SkippingSpliceAlreadySpliced, time_microseconds, "") {}

MATCHER_P2(SkippingSpliceTooLittleOverlap,
           pts_microseconds,
           overlap_microseconds,
           "") {}

// Prefer WebMSimpleBlockDurationEstimated over this matcher, unless the actual
// estimated duration value is unimportant to the test.
MATCHER(WebMSimpleBlockDurationEstimatedAny, "") {}

MATCHER_P(WebMSimpleBlockDurationEstimated, estimated_duration_ms, "") {}

MATCHER(WebMOutOfOrderTimecode, "") {}

MATCHER(WebMClusterBeforeFirstInfo, "") {}

MATCHER_P3(TrimmedSpliceOverlap,
           splice_time_us,
           overlapped_start_us,
           trim_duration_us,
           "") {}

MATCHER_P2(NoSpliceForBadMux, overlapped_buffer_count, splice_time_us, "") {}

MATCHER(ChunkDemuxerCtor, "") {}

MATCHER_P2(DiscardingEmptyFrame, pts_us, dts_us, "") {}

MATCHER_P4(TruncatedFrame,
           pts_us,
           pts_end_us,
           start_or_end,
           append_window_us,
           "") {}

MATCHER_P2(DroppedFrame, frame_type, pts_us, "") {}

MATCHER_P3(DroppedFrameCheckAppendWindow,
           frame_type,
           append_window_start_us,
           append_window_end_us,
           "") {}

MATCHER_P3(DroppedAppendWindowUnusedPreroll,
           pts_us,
           delta_us,
           next_pts_us,
           "") {}

MATCHER_P(PtsUnknown, frame_type, "") {}

MATCHER_P2(FrameDurationUnknown, frame_type, pts_us, "") {}

MATCHER_P3(FrameTimeOutOfRange, when, pts_or_dts, frame_type, "") {}

MATCHER(SequenceOffsetUpdateOutOfRange, "") {}

MATCHER(SequenceOffsetUpdatePreventedByOutOfRangeGroupStartTimestamp, "") {}

MATCHER(OffsetOutOfRange, "") {}

MATCHER_P(FrameEndTimestampOutOfRange, frame_type, "") {}

MATCHER(HlsDemuxerCtor, "") {}

}  // namespace media

#endif  // MEDIA_BASE_TEST_HELPERS_H_