// Copyright 2022 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_V4L2_TEST_H264_DECODER_H_
#define MEDIA_GPU_V4L2_TEST_H264_DECODER_H_
#include <queue>
#include "base/files/memory_mapped_file.h"
#include "base/memory/raw_ref.h"
#include "media/gpu/v4l2/test/h264_dpb.h"
#include "media/gpu/v4l2/test/v4l2_ioctl_shim.h"
#include "media/gpu/v4l2/test/video_decoder.h"
namespace media {
namespace v4l2_test {
// PreviousRefPicOrder contains data regarding the picture
// order counts for the previously decoded frame.
struct PreviousRefPicOrder {
int prev_ref_pic_order_cnt_msb = 0;
int prev_ref_pic_order_cnt_lsb = 0;
};
class H264Decoder : public VideoDecoder {
public:
H264Decoder(const H264Decoder&) = delete;
H264Decoder& operator=(const H264Decoder&) = delete;
~H264Decoder() override;
// Creates a H264Decoder after verifying that the bitstream is h.264
// and the underlying implementation supports H.264 slice decoding.
static std::unique_ptr<H264Decoder> Create(
const base::MemoryMappedFile& stream);
// Parses next frame from the input and decodes the frame. This method will
// place the Y, U, and V values into the respective vectors and update the
// size with the display area size of the decoded frame.
VideoDecoder::Result DecodeNextFrame(const int frame_number,
std::vector<uint8_t>& y_plane,
std::vector<uint8_t>& u_plane,
std::vector<uint8_t>& v_plane,
gfx::Size& size,
BitDepth& bit_depth) override;
private:
H264Decoder(std::unique_ptr<V4L2IoctlShim> v4l2_ioctl,
gfx::Size display_resolution,
const base::MemoryMappedFile& data_stream);
// Processes NALU's until reaching the start of the new frame. Function
// starts by starting a new frame and transmitting control data through
// ioctl calls. The function will then parse and process each NALU until
// reaching the start of the next frame, at which point it will finish
// processing the picture and add it to the picture queue.
void ProcessNextFrame();
// Sends IOCTL call to device with the frame's SPS, PPS, and Scaling Matrix
// data which indicates the beginning of a new frame. Additionally
// this initializes the decode parameter's dpb parameter from the DPB.
VideoDecoder::Result StartNewFrame(bool is_OUTPUT_queue_new,
H264SliceMetadata* slice_metadata);
// Finishes frame processing for the current decoded frame. Performs decoded
// ref picture marking process as defined in section 8.2.5. Finally, using
// the DPB, transmit H264 Slices to the slice_ready_queue_.
void FinishPicture(H264SliceMetadata picture, const int sps_id);
// Initializes H264 Slice Metadata based on slice header and
// based on H264 specifications which it calculates its pic order count.
VideoDecoder::Result InitializeSliceMetadata(
const H264SliceHeader& slice_hdr,
const H264SPS* sps,
H264SliceMetadata* slice_metadata) const;
// Returns all CAPTURE buffer indexes that can be reused for a
// VIDIOC_QBUF ioctl call.
std::set<uint32_t> GetReusableReferenceSlots(
const MmappedBuffer& buffer,
std::set<uint32_t> queued_buffer_ids);
// Calculates decoding parameters based on SPS corresponding to sps_id.
// If decoding parameters change, this can result in flushing the DPB.
void ProcessSPS(const int sps_id);
// Transmits the current slice data to the OUTPUT queue and transmits it
// to the device via an VIDIOC_QBUF ioctl call.
VideoDecoder::Result SubmitSlice();
// Moves all non output pictures in the DPB to the slice_ready_queue.
// Finishes by clearing the entire DPB.
void FlushDPB();
// Initializes the H.264 Decoder to Process the initial SPS NALU as well
// as to iterate until it reaches the start of a new frame for the
// ProcessNextFrame function to be able to work properly.
void InitializeDecoderLogic();
std::unique_ptr<H264Parser> parser_;
// Previous pic order counts from previous frame
PreviousRefPicOrder prev_pic_order_;
int global_pic_count_ = 0;
H264DPB dpb_;
std::queue<H264SliceMetadata> slice_ready_queue_;
std::unique_ptr<H264SliceHeader> curr_slice_hdr_;
// Number of non-outputted pictures needed in DPB before a picture
// can be outputted.
size_t max_num_reorder_frames_;
// Decoding profile parameters
gfx::Size pic_size_;
VideoCodecProfile profile_;
uint8_t bit_depth_ = -1;
bool stream_finished_;
const raw_ref<const base::MemoryMappedFile> data_stream_;
int prev_frame_num_ = -1;
int prev_frame_num_offset_ = -1;
};
} // namespace v4l2_test
} // namespace media
#endif // MEDIA_GPU_V4L2_TEST_H264_DECODER_H_