chromium/media/gpu/test/video_test_helpers.h

// 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_