blob: c85b4ca8586e3d3b8009e72b036ab1c437e81ec6 [file] [log] [blame]
// 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_VAAPI_VAAPI_VIDEO_ENCODER_DELEGATE_H_
#define MEDIA_GPU_VAAPI_VAAPI_VIDEO_ENCODER_DELEGATE_H_
#include <va/va.h>
#include <optional>
#include <vector>
#include "base/containers/queue.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "media/base/video_bitrate_allocation.h"
#include "media/base/video_codecs.h"
#include "media/video/video_encode_accelerator.h"
#include "media/video/video_encoder_info.h"
#include "ui/gfx/geometry/size.h"
namespace media {
struct BitstreamBufferMetadata;
class CodecPicture;
class ScopedVABuffer;
class VideoFrame;
class VaapiWrapper;
// An VaapiVideoEncoderDelegate performs high-level, platform-independent
// encoding process tasks, such as managing codec state, reference frames, etc.,
// but may require support from an external accelerator (typically a hardware
// accelerator) to offload some stages of the actual encoding process, using
// the parameters that the Delegate prepares beforehand.
//
// For each frame to be encoded, clients provide an EncodeJob object to be set
// up by a Delegate subclass with job parameters, and execute the job
// afterwards. Any resources required for the job are also provided by the
// clients, and associated with the EncodeJob object.
class VaapiVideoEncoderDelegate {
public:
struct Config {
// Maximum number of reference frames.
// For H.264 encoding, the value represents the maximum number of reference
// frames for both the reference picture list 0 (bottom 16 bits) and the
// reference picture list 1 (top 16 bits).
size_t max_num_ref_frames;
};
// EncodeResult owns the necessary resource to keep the encoded buffer. The
// encoded buffer can be downloaded with the EncodeResult, for example, by
// calling VaapiWrapper::DownloadFromVABuffer().
class EncodeResult {
public:
EncodeResult(std::unique_ptr<ScopedVABuffer> coded_buffer,
const BitstreamBufferMetadata& metadata);
~EncodeResult();
EncodeResult(EncodeResult&&);
EncodeResult& operator=(EncodeResult&&);
EncodeResult(const EncodeResult&) = delete;
EncodeResult& operator=(const EncodeResult&) = delete;
VABufferID coded_buffer_id() const;
const BitstreamBufferMetadata& metadata() const;
bool IsFrameDropped() const { return !coded_buffer_; }
private:
std::unique_ptr<ScopedVABuffer> coded_buffer_;
BitstreamBufferMetadata metadata_;
};
// An abstraction of an encode job for one frame. Parameters required for an
// EncodeJob to be executed are prepared by an VaapiVideoEncoderDelegate,
// while the accelerator-specific callbacks required to set up and execute it
// are provided by the accelerator itself, based on these parameters.
// Accelerators are also responsible for providing any resources (such as
// memory for output, etc.) as needed.
class EncodeJob {
public:
// Creates an EncodeJob to encode the va surface associated with
// |input_surface_id|, which will be executed by
// VaapiVideoEncoderDelegate::Encode().
// If |keyframe| is true, requests this job to produce a keyframe.
// |picture| is for a reconstructed frame and the encoded chunk is written
// into the buffer of |coded_buffer|.
EncodeJob(bool keyframe,
base::TimeDelta timestamp,
uint8_t spatial_index,
bool end_of_picture,
VASurfaceID input_surface_id,
scoped_refptr<CodecPicture> picture,
std::unique_ptr<ScopedVABuffer> coded_buffer);
EncodeJob(const EncodeJob&) = delete;
EncodeJob& operator=(const EncodeJob&) = delete;
~EncodeJob();
// Creates EncodeResult with |metadata|. This passes ownership of the
// resources owned by EncodeJob and therefore must be called with
// std::move().
EncodeResult CreateEncodeResult(const BitstreamBufferMetadata& metadata) &&;
// Requests this job to produce a keyframe; requesting a keyframe may not
// always result in one being produced by the encoder (e.g. if it would
// not fit in the bitrate budget).
void ProduceKeyframe() { keyframe_ = true; }
// Returns true if this job has been requested to produce a keyframe.
bool IsKeyframeRequested() const { return keyframe_; }
void DropFrame() { coded_buffer_.reset(); }
bool IsFrameDropped() const { return !coded_buffer_; }
base::TimeDelta timestamp() const;
uint8_t spatial_index() const;
// This is a frame in the top spatial layer.
bool end_of_picture() const;
uint8_t spatial_idx() const;
// VA-API specific methods.
VABufferID coded_buffer_id() const;
VASurfaceID input_surface_id() const;
const scoped_refptr<CodecPicture>& picture() const;
private:
// True if this job is to produce a keyframe.
bool keyframe_;
// |timestamp_| to be added to the produced encoded chunk.
const base::TimeDelta timestamp_;
const uint8_t spatial_index_ = 0;
const bool end_of_picture_;
// VA-API specific members.
// Input surface ID and size for video frame data or scaled data.
const VASurfaceID input_surface_id_;
const scoped_refptr<CodecPicture> picture_;
// Buffer that will contain the output bitstream data for this frame.
std::unique_ptr<ScopedVABuffer> coded_buffer_;
};
VaapiVideoEncoderDelegate(scoped_refptr<VaapiWrapper> vaapi_wrapper,
base::RepeatingClosure error_cb);
virtual ~VaapiVideoEncoderDelegate();
// Initializes the encoder with requested parameter set |config| and
// |ave_config|. Returns false if the requested set of parameters is not
// supported, true on success.
virtual bool Initialize(
const VideoEncodeAccelerator::Config& config,
const VaapiVideoEncoderDelegate::Config& ave_config) = 0;
// Updates current framerate and/or bitrate to |framerate| in FPS
// and the specified video bitrate allocation.
virtual bool UpdateRates(const VideoBitrateAllocation& bitrate_allocation,
uint32_t framerate) = 0;
// Returns coded size for the input buffers required to encode, in pixels;
// typically visible size adjusted to match codec alignment requirements.
virtual gfx::Size GetCodedSize() const = 0;
// Returns minimum size in bytes for bitstream buffers required to fit output
// stream buffers produced.
virtual size_t GetBitstreamBufferSize() const;
// Returns maximum number of reference frames that may be used by the
// encoder to encode one frame. The client should be able to provide up to
// at least this many frames simultaneously for encode to make progress.
virtual size_t GetMaxNumOfRefFrames() const = 0;
// Prepares and submits the encode operation to underlying driver for an
// EncodeJob for one frame and returns true on success.
bool Encode(EncodeJob& encode_job);
// Creates and returns the encode result for specified EncodeJob by
// synchronizing the corresponding encode operation. std::nullopt is returned
// on failure.
std::optional<EncodeResult> GetEncodeResult(
std::unique_ptr<EncodeJob> encode_job);
// Gets the active spatial layer resolutions for K-SVC encoding, VaapiVEA
// can get this info from the encoder delegate. Returns empty vector on
// failure.
virtual std::vector<gfx::Size> GetSVCLayerResolutions() = 0;
protected:
// Friend in order o access PrepareEncodeJobResult declaration.
friend class H264VaapiVideoEncoderDelegateTest;
friend class VP9VaapiVideoEncoderDelegateTest;
friend class VaapiVideoEncodeAcceleratorTest;
enum class PrepareEncodeJobResult {
kSuccess, // Submit the encode job successfully.
kFail, // Error happens in submitting the encode job.
kDrop, // Encode job is dropped. An returned encoded chunk is empty.
};
const scoped_refptr<VaapiWrapper> vaapi_wrapper_;
base::RepeatingClosure error_cb_;
SEQUENCE_CHECKER(sequence_checker_);
private:
virtual BitstreamBufferMetadata GetMetadata(const EncodeJob& encode_job,
size_t payload_size) = 0;
// Prepares a new |encode_job| to be executed in Accelerator. Returns
// kSuccess on success, and kFail on failure.
virtual PrepareEncodeJobResult PrepareEncodeJob(EncodeJob& encode_job) = 0;
// Notifies the encoded chunk size in bytes with layers info through
// BitstreamBufferMetadata to update a bitrate controller in
// VaapiVideoEncoderDelegate. This should be called only if constant
// quantization encoding is used, which currently is true for VP8 and VP9.
virtual void BitrateControlUpdate(const BitstreamBufferMetadata& metadata);
};
} // namespace media
#endif // MEDIA_GPU_VAAPI_VAAPI_VIDEO_ENCODER_DELEGATE_H_