910e62b5创建于 1月15日历史提交
// Copyright 2021 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_VAAPI_TEST_H264_DECODER_H_
#define MEDIA_GPU_VAAPI_TEST_H264_DECODER_H_

#include <queue>

#include "media/gpu/vaapi/test/h264_dpb.h"
#include "media/gpu/vaapi/test/h264_vaapi_wrapper.h"
#include "media/gpu/vaapi/test/video_decoder.h"
#include "media/parsers/h264_parser.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"

namespace media {
namespace vaapi_test {

class H264Decoder : public VideoDecoder {
 public:
  H264Decoder(const uint8_t* stream_data,
              size_t stream_len,
              const VaapiDevice& va_device,
              SharedVASurface::FetchPolicy fetch_policy);
  H264Decoder(const H264Decoder&) = delete;
  H264Decoder& operator=(const H264Decoder&) = delete;
  ~H264Decoder() override;

  // VideoDecoder implementation.
  VideoDecoder::Result DecodeNextFrame() override;

 private:
  // Decode the next frame in the bitstream.
  void DecodeNextFrameInStream();

  // Process a slice.
  void ProcessSlice();

  // Process an SPS NALU.
  void UpdateSequenceParams();

  // Process a PPS NALU.
  void UpdatePictureParams();

  // Issue the final commands to VAAPI to decode the slices we have been
  // inputing.
  void DecodeFrame();

  // Finalize the picture and handle reference picture buffer memory management.
  void FinishPicture(scoped_refptr<H264Picture> pic);

  // Process SPS and PPS NALUs until we hit a slice header.
  bool GetStreamMetadata();

  // Detects if the last slice header refers to a new frame.
  bool IsNewFrame();

  // Populate some local variables based on a slice NALU.
  void ExtractSliceHeader();

  // Create a new picture and hand some metadata to VAAPI.
  void StartNewFrame();

  // Initialize a picture.
  bool InitCurrPicture(const H264SliceHeader* slice_hdr);

  // Some helper functions for preparing the reference picture buffers. H.264
  // has separate P and B frame reference picture buffers.
  void ConstructReferencePicListsP();
  void ConstructReferencePicListsB();

  // Re-order the reference frame buf based on the current frame number.
  void UpdatePicNums(int frame_num);

  // Some helper functions for handling gaps in the frame data.
  bool InitNonexistingPicture(scoped_refptr<H264Picture> pic,
                              int frame_num,
                              bool ref);
  bool HandleFrameNumGap(int frame_num);

  // Calculate Pic Order Counts. This is approximately what we would intuitively
  // think of as the frame number in display order, except it wraps around.
  bool CalculatePicOrderCounts(scoped_refptr<H264Picture> pic);
  void UpdateMaxNumReorderFrames(const H264SPS* sps);

  // Populate the reference lists that we send to VAAPI using data from the
  // DPB.
  bool ModifyReferencePicLists(const H264SliceHeader* slice_hdr,
                               H264Picture::Vector* ref_pic_list0,
                               H264Picture::Vector* ref_pic_list1);
  bool ModifyReferencePicList(const H264SliceHeader* slice_hdr,
                              int list,
                              H264Picture::Vector* ref_pic_listx);

  // Helps manage the DPB and mark what we need to keep for reference and what
  // we can mark as unused. Note that a frame might still be kept around even if
  // it isn't being used as a reference because we might need to output it.
  // Normal H.264 decoder implementations have finer grained cache control, but
  // since we can only output one picture DecodeNextFrame() call, we have to
  // keep a pretty big cache around until the output catches up to the decode.
  bool ReferencePictureMarking(scoped_refptr<H264Picture> pic);
  bool HandleMemoryManagementOps(scoped_refptr<H264Picture> pic);
  bool SlidingWindowPictureMarking();
  int PicNumF(const H264Picture& pic) const;
  int LongTermPicNumF(const H264Picture& pic) const;
  static void ShiftRightAndInsert(H264Picture::Vector* v,
                                  int from,
                                  int to,
                                  scoped_refptr<H264Picture> pic);

  // Used for computing how large the DPB should be for each level.
  static uint32_t H264LevelToMaxDpbMbs(uint8_t level);

  // Output all remaining images in the DPB.
  void FlushDPB();

  // H.264 NALU parser
  std::unique_ptr<H264Parser> parser_;

  // The last sequence param id.
  int curr_sps_id_;

  // The last picture param id.
  int curr_pps_id_;

  // The last slice header parsed.
  std::unique_ptr<H264SliceHeader> curr_slice_hdr_;

  // The last NALU that was parsed.
  std::unique_ptr<H264NALU> curr_nalu_;

  // Picture we are currently decoding. Not necessarily the one we will output
  // since H.264 sends pictures out of order.
  scoped_refptr<H264Picture> curr_picture_;

  // Set once we hit EOS.
  bool is_stream_over_;

  // Reference picture lists. P = forward prediction, B = bidirectional
  // prediction.
  H264Picture::Vector ref_pic_list_p0_;
  H264Picture::Vector ref_pic_list_b0_;
  H264Picture::Vector ref_pic_list_b1_;

  // Some primitive related to frame number to help with the ordering of the
  // reference pictures. Note that "frame_num" in this instance does not
  // intuitively refer to the index of the frame when it gets output, but just
  // the index of the frame in the bitstream. Pic order count is more closely
  // related to output order, but it can also wrap.
  int max_frame_num_;
  int max_pic_num_;
  int max_long_term_frame_idx_;
  size_t max_num_reorder_frames_;
  int prev_frame_num_;
  int prev_ref_frame_num_;
  int prev_frame_num_offset_;
  bool prev_has_memmgmnt5_;

  // These are std::nullopt unless get recovery point SEI message after Reset.
  // A frame_num of the frame at output order that is correct in content.
  std::optional<int> recovery_frame_num_;
  // A value in the recovery point SEI message to compute |recovery_frame_num_|
  // later.
  std::optional<int> recovery_frame_cnt_;

  // Buffer object to keep track of our reference images.
  H264DPB dpb_;

  // Some handy abstractions for issuing VAAPI calls.
  H264VaapiWrapper va_wrapper_;

  // Values related to previously decoded reference picture.
  bool prev_ref_has_memmgmnt5_;
  int prev_ref_top_field_order_cnt_;
  int prev_ref_pic_order_cnt_msb_;
  int prev_ref_pic_order_cnt_lsb_;
  H264Picture::Field prev_ref_field_;

  // The actual size of the output picture.
  gfx::Rect visible_rect_;

  // Pictures to flush in descending POC order.
  std::queue<scoped_refptr<H264Picture>> output_queue;
};

}  // namespace vaapi_test
}  // namespace media

#endif  // MEDIA_GPU_VAAPI_TEST_H264_DECODER_H_