// Copyright 2018 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_GPU_TEST_VIDEO_TEST_HELPERS_H_ #define MEDIA_GPU_TEST_VIDEO_TEST_HELPERS_H_ #include <memory> #include <optional> #include <string> #include <vector> #include "base/containers/queue.h" #include "base/containers/span.h" #include "base/files/file.h" #include "base/memory/raw_ptr.h" #include "base/memory/scoped_refptr.h" #include "base/synchronization/condition_variable.h" #include "base/synchronization/lock.h" #include "base/time/time.h" #include "build/build_config.h" #include "media/base/decoder_buffer.h" #include "media/base/video_codecs.h" #include "media/base/video_frame.h" #include "media/base/video_frame_layout.h" #include "media/base/video_types.h" #include "media/gpu/test/raw_video.h" #include "media/media_buildflags.h" #include "media/parsers/ivf_parser.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER) #include "media/parsers/h265_parser.h" #endif namespace media { namespace test { // Helper class allowing one thread to wait on a notification from another. // If notifications come in faster than they are Wait()'d for, they are // accumulated (so exactly as many Wait() calls will unblock as Notify() calls // were made, regardless of order). template <typename StateEnum> class ClientStateNotification { … }; template <typename StateEnum> ClientStateNotification<StateEnum>::ClientStateNotification() : … { … } template <typename StateEnum> ClientStateNotification<StateEnum>::~ClientStateNotification() { … } template <typename StateEnum> void ClientStateNotification<StateEnum>::Notify(StateEnum state) { … } template <typename StateEnum> StateEnum ClientStateNotification<StateEnum>::Wait() { … } struct IvfFrame { … }; // Read functions to fill IVF file header and IVF frame header from |data|. // |data| must have sufficient length. IvfFileHeader GetIvfFileHeader(base::span<const uint8_t> data); IvfFrameHeader GetIvfFrameHeader(base::span<const uint8_t> data); // The helper class to save data as ivf format. class IvfWriter { … }; // Helper to extract (full) frames from a video |stream|. class EncodedDataHelper { … }; // This class returns one by one the NALUs in |stream| via GetNextBuffer(). // |stream| must be in H.264 Annex B or H.265 Annex B formats. class EncodedDataHelperH26x : public EncodedDataHelper { … }; #if BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER) // This class returns one by one the full frames (which can be composed of one // or multiple NALUs) in |stream| via GetNextBuffer(). |stream| must be in H.265 // Annex B format (see www.itu.int/rec/T-REC-H.265). // Note that this is an issue specific to testing (which this class serves), // since in production there's always a container to give information about // frame boundaries, hence the logic here. class EncodedDataHelperH265 : public EncodedDataHelper { public: EncodedDataHelperH265(base::span<const uint8_t> stream, VideoCodec codec); ~EncodedDataHelperH265() override; scoped_refptr<DecoderBuffer> GetNextBuffer() override; bool ReachEndOfStream() const override; void Rewind() override; private: // This struct is needed because: // a) We need to keep both a pointer and an index to where a NALU starts (the // pointer is for |data_| arithmetic, the index is for base::span ops. // b) H265NALUs don't provide NALU header size (it can be 3 or 4 bytes long), // so a few pointer ops are needed to calculate the |size_with_header|. struct NALUMetadata { const uint8_t* start_pointer; size_t start_index; size_t header_size; size_t size_with_header; friend std::ostream& operator<<(std::ostream& os, const NALUMetadata& m) { return os << "start_index=" << m.start_index << ", header_size=" << m.header_size << ", size_with_header=" << m.size_with_header; } }; scoped_refptr<DecoderBuffer> ReassembleNALUs( const std::vector<struct NALUMetadata>& nalus); std::unique_ptr<H265Parser> h265_parser_; std::vector<struct NALUMetadata> previous_nalus_; std::unique_ptr<H265SliceHeader> previous_slice_header_; }; #endif // BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER) // This class returns one by one the IVF frames in |stream| via GetNextBuffer(). class EncodedDataHelperIVF : public EncodedDataHelper { … }; #if defined(ARCH_CPU_ARM_FAMILY) // ARM performs CPU cache management with CPU cache line granularity. We thus // need to ensure our buffers are CPU cache line-aligned (64 byte-aligned). // Otherwise newer kernels will refuse to accept them, and on older kernels // we'll be treating ourselves to random corruption. // Moreover, some hardware codecs require 128-byte alignment for physical // buffers. constexpr size_t kPlatformBufferAlignment = 128; #else constexpr size_t kPlatformBufferAlignment = …; #endif // Helper to align data and extract frames from raw video streams. // GetNextFrame() returns VideoFrames with a specified |storage_type|. The // VideoFrames are aligned by the specified |alignment| in the case of // MojoSharedBuffer VideoFrame. On the other hand, GpuMemoryBuffer based // VideoFrame is determined by the GpuMemoryBuffer allocation backend. // GetNextFrame() returns valid frame if AtEndOfStream() returns false, i.e., // until GetNextFrame() is called |num_read_frames| times. // |num_frames| is the number of frames contained in |stream|. |num_read_frames| // can be larger than |num_frames|. // If |reverse| is true , GetNextFrame() for a frame returns frames in a // round-trip playback fashion (0, 1,.., |num_frames| - 2, |num_frames| - 1, // |num_frames| - 1, |num_frames_| - 2,.., 1, 0, 0, 1,..) so that the content of // returned frames is consecutive. // If |reverse| is false, GetNextFrame() just loops the stream (0, 1,.., // |num_frames| - 2, |num_frames| - 1, 0, 1,..), so the content of returned // frames is not consecutive. class AlignedDataHelper { … }; // Small helper class to extract video frames from raw data streams. // However, the data wrapped by VideoFrame is not guaranteed to be aligned. // This class doesn't change |video|, but cannot be mark it as constant because // GetFrame() returns non const |data_| wrapped by the returned VideoFrame. // If |reverse| is true , GetNextFrame() for a frame returns frames in a // round-trip playback fashion (0, 1,.., |num_frames| - 2, |num_frames| - 1, // |num_frames| - 1, |num_frames_| - 2,.., 1, 0, 0, 1,..). // If |reverse| is false, GetNextFrame() just loops the stream (0, 1,.., // |num_frames| - 2, |num_frames| - 1, 0, 1,..). class RawDataHelper { … }; } // namespace test } // namespace media #endif // MEDIA_GPU_TEST_VIDEO_TEST_HELPERS_H_