mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
avcodec/vaapi_encode: move the dpb logic from VAAPI to base layer
Move receive_packet function to base. This requires adding *alloc, *issue, *output, *free as hardware callbacks. HWBaseEncodePicture is introduced as the base layer structure. The related parameters in VAAPIEncodeContext are also extracted to HWBaseEncodeContext. Then DPB management logic can be fully extracted to base layer as-is. Signed-off-by: Tong Wu <tong1.wu@intel.com>
This commit is contained in:
parent
f303c26292
commit
aa82340b0c
@ -165,7 +165,7 @@ OBJS-$(CONFIG_STARTCODE) += startcode.o
|
||||
OBJS-$(CONFIG_TEXTUREDSP) += texturedsp.o
|
||||
OBJS-$(CONFIG_TEXTUREDSPENC) += texturedspenc.o
|
||||
OBJS-$(CONFIG_TPELDSP) += tpeldsp.o
|
||||
OBJS-$(CONFIG_VAAPI_ENCODE) += vaapi_encode.o
|
||||
OBJS-$(CONFIG_VAAPI_ENCODE) += vaapi_encode.o hw_base_encode.o
|
||||
OBJS-$(CONFIG_AV1_AMF_ENCODER) += amfenc_av1.o
|
||||
OBJS-$(CONFIG_VC1DSP) += vc1dsp.o
|
||||
OBJS-$(CONFIG_VIDEODSP) += videodsp.o
|
||||
|
594
libavcodec/hw_base_encode.c
Normal file
594
libavcodec/hw_base_encode.c
Normal file
@ -0,0 +1,594 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/common.h"
|
||||
#include "libavutil/internal.h"
|
||||
#include "libavutil/log.h"
|
||||
#include "libavutil/mem.h"
|
||||
#include "libavutil/pixdesc.h"
|
||||
|
||||
#include "encode.h"
|
||||
#include "avcodec.h"
|
||||
#include "hw_base_encode.h"
|
||||
|
||||
static void hw_base_encode_add_ref(FFHWBaseEncodePicture *pic,
|
||||
FFHWBaseEncodePicture *target,
|
||||
int is_ref, int in_dpb, int prev)
|
||||
{
|
||||
int refs = 0;
|
||||
|
||||
if (is_ref) {
|
||||
av_assert0(pic != target);
|
||||
av_assert0(pic->nb_refs[0] < MAX_PICTURE_REFERENCES &&
|
||||
pic->nb_refs[1] < MAX_PICTURE_REFERENCES);
|
||||
if (target->display_order < pic->display_order)
|
||||
pic->refs[0][pic->nb_refs[0]++] = target;
|
||||
else
|
||||
pic->refs[1][pic->nb_refs[1]++] = target;
|
||||
++refs;
|
||||
}
|
||||
|
||||
if (in_dpb) {
|
||||
av_assert0(pic->nb_dpb_pics < MAX_DPB_SIZE);
|
||||
pic->dpb[pic->nb_dpb_pics++] = target;
|
||||
++refs;
|
||||
}
|
||||
|
||||
if (prev) {
|
||||
av_assert0(!pic->prev);
|
||||
pic->prev = target;
|
||||
++refs;
|
||||
}
|
||||
|
||||
target->ref_count[0] += refs;
|
||||
target->ref_count[1] += refs;
|
||||
}
|
||||
|
||||
static void hw_base_encode_remove_refs(FFHWBaseEncodePicture *pic, int level)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (pic->ref_removed[level])
|
||||
return;
|
||||
|
||||
for (i = 0; i < pic->nb_refs[0]; i++) {
|
||||
av_assert0(pic->refs[0][i]);
|
||||
--pic->refs[0][i]->ref_count[level];
|
||||
av_assert0(pic->refs[0][i]->ref_count[level] >= 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < pic->nb_refs[1]; i++) {
|
||||
av_assert0(pic->refs[1][i]);
|
||||
--pic->refs[1][i]->ref_count[level];
|
||||
av_assert0(pic->refs[1][i]->ref_count[level] >= 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < pic->nb_dpb_pics; i++) {
|
||||
av_assert0(pic->dpb[i]);
|
||||
--pic->dpb[i]->ref_count[level];
|
||||
av_assert0(pic->dpb[i]->ref_count[level] >= 0);
|
||||
}
|
||||
|
||||
av_assert0(pic->prev || pic->type == FF_HW_PICTURE_TYPE_IDR);
|
||||
if (pic->prev) {
|
||||
--pic->prev->ref_count[level];
|
||||
av_assert0(pic->prev->ref_count[level] >= 0);
|
||||
}
|
||||
|
||||
pic->ref_removed[level] = 1;
|
||||
}
|
||||
|
||||
static void hw_base_encode_set_b_pictures(AVCodecContext *avctx,
|
||||
FFHWBaseEncodePicture *start,
|
||||
FFHWBaseEncodePicture *end,
|
||||
FFHWBaseEncodePicture *prev,
|
||||
int current_depth,
|
||||
FFHWBaseEncodePicture **last)
|
||||
{
|
||||
FFHWBaseEncodeContext *ctx = avctx->priv_data;
|
||||
FFHWBaseEncodePicture *pic, *next, *ref;
|
||||
int i, len;
|
||||
|
||||
av_assert0(start && end && start != end && start->next != end);
|
||||
|
||||
// If we are at the maximum depth then encode all pictures as
|
||||
// non-referenced B-pictures. Also do this if there is exactly one
|
||||
// picture left, since there will be nothing to reference it.
|
||||
if (current_depth == ctx->max_b_depth || start->next->next == end) {
|
||||
for (pic = start->next; pic; pic = pic->next) {
|
||||
if (pic == end)
|
||||
break;
|
||||
pic->type = FF_HW_PICTURE_TYPE_B;
|
||||
pic->b_depth = current_depth;
|
||||
|
||||
hw_base_encode_add_ref(pic, start, 1, 1, 0);
|
||||
hw_base_encode_add_ref(pic, end, 1, 1, 0);
|
||||
hw_base_encode_add_ref(pic, prev, 0, 0, 1);
|
||||
|
||||
for (ref = end->refs[1][0]; ref; ref = ref->refs[1][0])
|
||||
hw_base_encode_add_ref(pic, ref, 0, 1, 0);
|
||||
}
|
||||
*last = prev;
|
||||
|
||||
} else {
|
||||
// Split the current list at the midpoint with a referenced
|
||||
// B-picture, then descend into each side separately.
|
||||
len = 0;
|
||||
for (pic = start->next; pic != end; pic = pic->next)
|
||||
++len;
|
||||
for (pic = start->next, i = 1; 2 * i < len; pic = pic->next, i++);
|
||||
|
||||
pic->type = FF_HW_PICTURE_TYPE_B;
|
||||
pic->b_depth = current_depth;
|
||||
|
||||
pic->is_reference = 1;
|
||||
|
||||
hw_base_encode_add_ref(pic, pic, 0, 1, 0);
|
||||
hw_base_encode_add_ref(pic, start, 1, 1, 0);
|
||||
hw_base_encode_add_ref(pic, end, 1, 1, 0);
|
||||
hw_base_encode_add_ref(pic, prev, 0, 0, 1);
|
||||
|
||||
for (ref = end->refs[1][0]; ref; ref = ref->refs[1][0])
|
||||
hw_base_encode_add_ref(pic, ref, 0, 1, 0);
|
||||
|
||||
if (i > 1)
|
||||
hw_base_encode_set_b_pictures(avctx, start, pic, pic,
|
||||
current_depth + 1, &next);
|
||||
else
|
||||
next = pic;
|
||||
|
||||
hw_base_encode_set_b_pictures(avctx, pic, end, next,
|
||||
current_depth + 1, last);
|
||||
}
|
||||
}
|
||||
|
||||
static void hw_base_encode_add_next_prev(AVCodecContext *avctx,
|
||||
FFHWBaseEncodePicture *pic)
|
||||
{
|
||||
FFHWBaseEncodeContext *ctx = avctx->priv_data;
|
||||
int i;
|
||||
|
||||
if (!pic)
|
||||
return;
|
||||
|
||||
if (pic->type == FF_HW_PICTURE_TYPE_IDR) {
|
||||
for (i = 0; i < ctx->nb_next_prev; i++) {
|
||||
--ctx->next_prev[i]->ref_count[0];
|
||||
ctx->next_prev[i] = NULL;
|
||||
}
|
||||
ctx->next_prev[0] = pic;
|
||||
++pic->ref_count[0];
|
||||
ctx->nb_next_prev = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx->nb_next_prev < MAX_PICTURE_REFERENCES) {
|
||||
ctx->next_prev[ctx->nb_next_prev++] = pic;
|
||||
++pic->ref_count[0];
|
||||
} else {
|
||||
--ctx->next_prev[0]->ref_count[0];
|
||||
for (i = 0; i < MAX_PICTURE_REFERENCES - 1; i++)
|
||||
ctx->next_prev[i] = ctx->next_prev[i + 1];
|
||||
ctx->next_prev[i] = pic;
|
||||
++pic->ref_count[0];
|
||||
}
|
||||
}
|
||||
|
||||
static int hw_base_encode_pick_next(AVCodecContext *avctx,
|
||||
FFHWBaseEncodePicture **pic_out)
|
||||
{
|
||||
FFHWBaseEncodeContext *ctx = avctx->priv_data;
|
||||
FFHWBaseEncodePicture *pic = NULL, *prev = NULL, *next, *start;
|
||||
int i, b_counter, closed_gop_end;
|
||||
|
||||
// If there are any B-frames already queued, the next one to encode
|
||||
// is the earliest not-yet-issued frame for which all references are
|
||||
// available.
|
||||
for (pic = ctx->pic_start; pic; pic = pic->next) {
|
||||
if (pic->encode_issued)
|
||||
continue;
|
||||
if (pic->type != FF_HW_PICTURE_TYPE_B)
|
||||
continue;
|
||||
for (i = 0; i < pic->nb_refs[0]; i++) {
|
||||
if (!pic->refs[0][i]->encode_issued)
|
||||
break;
|
||||
}
|
||||
if (i != pic->nb_refs[0])
|
||||
continue;
|
||||
|
||||
for (i = 0; i < pic->nb_refs[1]; i++) {
|
||||
if (!pic->refs[1][i]->encode_issued)
|
||||
break;
|
||||
}
|
||||
if (i == pic->nb_refs[1])
|
||||
break;
|
||||
}
|
||||
|
||||
if (pic) {
|
||||
av_log(avctx, AV_LOG_DEBUG, "Pick B-picture at depth %d to "
|
||||
"encode next.\n", pic->b_depth);
|
||||
*pic_out = pic;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Find the B-per-Pth available picture to become the next picture
|
||||
// on the top layer.
|
||||
start = NULL;
|
||||
b_counter = 0;
|
||||
closed_gop_end = ctx->closed_gop ||
|
||||
ctx->idr_counter == ctx->gop_per_idr;
|
||||
for (pic = ctx->pic_start; pic; pic = next) {
|
||||
next = pic->next;
|
||||
if (pic->encode_issued) {
|
||||
start = pic;
|
||||
continue;
|
||||
}
|
||||
// If the next available picture is force-IDR, encode it to start
|
||||
// a new GOP immediately.
|
||||
if (pic->force_idr)
|
||||
break;
|
||||
if (b_counter == ctx->b_per_p)
|
||||
break;
|
||||
// If this picture ends a closed GOP or starts a new GOP then it
|
||||
// needs to be in the top layer.
|
||||
if (ctx->gop_counter + b_counter + closed_gop_end >= ctx->gop_size)
|
||||
break;
|
||||
// If the picture after this one is force-IDR, we need to encode
|
||||
// this one in the top layer.
|
||||
if (next && next->force_idr)
|
||||
break;
|
||||
++b_counter;
|
||||
}
|
||||
|
||||
// At the end of the stream the last picture must be in the top layer.
|
||||
if (!pic && ctx->end_of_stream) {
|
||||
--b_counter;
|
||||
pic = ctx->pic_end;
|
||||
if (pic->encode_complete)
|
||||
return AVERROR_EOF;
|
||||
else if (pic->encode_issued)
|
||||
return AVERROR(EAGAIN);
|
||||
}
|
||||
|
||||
if (!pic) {
|
||||
av_log(avctx, AV_LOG_DEBUG, "Pick nothing to encode next - "
|
||||
"need more input for reference pictures.\n");
|
||||
return AVERROR(EAGAIN);
|
||||
}
|
||||
if (ctx->input_order <= ctx->decode_delay && !ctx->end_of_stream) {
|
||||
av_log(avctx, AV_LOG_DEBUG, "Pick nothing to encode next - "
|
||||
"need more input for timestamps.\n");
|
||||
return AVERROR(EAGAIN);
|
||||
}
|
||||
|
||||
if (pic->force_idr) {
|
||||
av_log(avctx, AV_LOG_DEBUG, "Pick forced IDR-picture to "
|
||||
"encode next.\n");
|
||||
pic->type = FF_HW_PICTURE_TYPE_IDR;
|
||||
ctx->idr_counter = 1;
|
||||
ctx->gop_counter = 1;
|
||||
|
||||
} else if (ctx->gop_counter + b_counter >= ctx->gop_size) {
|
||||
if (ctx->idr_counter == ctx->gop_per_idr) {
|
||||
av_log(avctx, AV_LOG_DEBUG, "Pick new-GOP IDR-picture to "
|
||||
"encode next.\n");
|
||||
pic->type = FF_HW_PICTURE_TYPE_IDR;
|
||||
ctx->idr_counter = 1;
|
||||
} else {
|
||||
av_log(avctx, AV_LOG_DEBUG, "Pick new-GOP I-picture to "
|
||||
"encode next.\n");
|
||||
pic->type = FF_HW_PICTURE_TYPE_I;
|
||||
++ctx->idr_counter;
|
||||
}
|
||||
ctx->gop_counter = 1;
|
||||
|
||||
} else {
|
||||
if (ctx->gop_counter + b_counter + closed_gop_end == ctx->gop_size) {
|
||||
av_log(avctx, AV_LOG_DEBUG, "Pick group-end P-picture to "
|
||||
"encode next.\n");
|
||||
} else {
|
||||
av_log(avctx, AV_LOG_DEBUG, "Pick normal P-picture to "
|
||||
"encode next.\n");
|
||||
}
|
||||
pic->type = FF_HW_PICTURE_TYPE_P;
|
||||
av_assert0(start);
|
||||
ctx->gop_counter += 1 + b_counter;
|
||||
}
|
||||
pic->is_reference = 1;
|
||||
*pic_out = pic;
|
||||
|
||||
hw_base_encode_add_ref(pic, pic, 0, 1, 0);
|
||||
if (pic->type != FF_HW_PICTURE_TYPE_IDR) {
|
||||
// TODO: apply both previous and forward multi reference for all vaapi encoders.
|
||||
// And L0/L1 reference frame number can be set dynamically through query
|
||||
// VAConfigAttribEncMaxRefFrames attribute.
|
||||
if (avctx->codec_id == AV_CODEC_ID_AV1) {
|
||||
for (i = 0; i < ctx->nb_next_prev; i++)
|
||||
hw_base_encode_add_ref(pic, ctx->next_prev[i],
|
||||
pic->type == FF_HW_PICTURE_TYPE_P,
|
||||
b_counter > 0, 0);
|
||||
} else
|
||||
hw_base_encode_add_ref(pic, start,
|
||||
pic->type == FF_HW_PICTURE_TYPE_P,
|
||||
b_counter > 0, 0);
|
||||
|
||||
hw_base_encode_add_ref(pic, ctx->next_prev[ctx->nb_next_prev - 1], 0, 0, 1);
|
||||
}
|
||||
|
||||
if (b_counter > 0) {
|
||||
hw_base_encode_set_b_pictures(avctx, start, pic, pic, 1,
|
||||
&prev);
|
||||
} else {
|
||||
prev = pic;
|
||||
}
|
||||
hw_base_encode_add_next_prev(avctx, prev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hw_base_encode_clear_old(AVCodecContext *avctx)
|
||||
{
|
||||
FFHWBaseEncodeContext *ctx = avctx->priv_data;
|
||||
FFHWBaseEncodePicture *pic, *prev, *next;
|
||||
|
||||
av_assert0(ctx->pic_start);
|
||||
|
||||
// Remove direct references once each picture is complete.
|
||||
for (pic = ctx->pic_start; pic; pic = pic->next) {
|
||||
if (pic->encode_complete && pic->next)
|
||||
hw_base_encode_remove_refs(pic, 0);
|
||||
}
|
||||
|
||||
// Remove indirect references once a picture has no direct references.
|
||||
for (pic = ctx->pic_start; pic; pic = pic->next) {
|
||||
if (pic->encode_complete && pic->ref_count[0] == 0)
|
||||
hw_base_encode_remove_refs(pic, 1);
|
||||
}
|
||||
|
||||
// Clear out all complete pictures with no remaining references.
|
||||
prev = NULL;
|
||||
for (pic = ctx->pic_start; pic; pic = next) {
|
||||
next = pic->next;
|
||||
if (pic->encode_complete && pic->ref_count[1] == 0) {
|
||||
av_assert0(pic->ref_removed[0] && pic->ref_removed[1]);
|
||||
if (prev)
|
||||
prev->next = next;
|
||||
else
|
||||
ctx->pic_start = next;
|
||||
ctx->op->free(avctx, pic);
|
||||
} else {
|
||||
prev = pic;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hw_base_encode_check_frame(AVCodecContext *avctx,
|
||||
const AVFrame *frame)
|
||||
{
|
||||
FFHWBaseEncodeContext *ctx = avctx->priv_data;
|
||||
|
||||
if ((frame->crop_top || frame->crop_bottom ||
|
||||
frame->crop_left || frame->crop_right) && !ctx->crop_warned) {
|
||||
av_log(avctx, AV_LOG_WARNING, "Cropping information on input "
|
||||
"frames ignored due to lack of API support.\n");
|
||||
ctx->crop_warned = 1;
|
||||
}
|
||||
|
||||
if (!ctx->roi_allowed) {
|
||||
AVFrameSideData *sd =
|
||||
av_frame_get_side_data(frame, AV_FRAME_DATA_REGIONS_OF_INTEREST);
|
||||
|
||||
if (sd && !ctx->roi_warned) {
|
||||
av_log(avctx, AV_LOG_WARNING, "ROI side data on input "
|
||||
"frames ignored due to lack of driver support.\n");
|
||||
ctx->roi_warned = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hw_base_encode_send_frame(AVCodecContext *avctx, AVFrame *frame)
|
||||
{
|
||||
FFHWBaseEncodeContext *ctx = avctx->priv_data;
|
||||
FFHWBaseEncodePicture *pic;
|
||||
int err;
|
||||
|
||||
if (frame) {
|
||||
av_log(avctx, AV_LOG_DEBUG, "Input frame: %ux%u (%"PRId64").\n",
|
||||
frame->width, frame->height, frame->pts);
|
||||
|
||||
err = hw_base_encode_check_frame(avctx, frame);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
pic = ctx->op->alloc(avctx, frame);
|
||||
if (!pic)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
pic->input_image = av_frame_alloc();
|
||||
if (!pic->input_image) {
|
||||
err = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pic->recon_image = av_frame_alloc();
|
||||
if (!pic->recon_image) {
|
||||
err = AVERROR(ENOMEM);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ctx->input_order == 0 || frame->pict_type == AV_PICTURE_TYPE_I)
|
||||
pic->force_idr = 1;
|
||||
|
||||
pic->pts = frame->pts;
|
||||
pic->duration = frame->duration;
|
||||
|
||||
if (avctx->flags & AV_CODEC_FLAG_COPY_OPAQUE) {
|
||||
err = av_buffer_replace(&pic->opaque_ref, frame->opaque_ref);
|
||||
if (err < 0)
|
||||
goto fail;
|
||||
|
||||
pic->opaque = frame->opaque;
|
||||
}
|
||||
|
||||
av_frame_move_ref(pic->input_image, frame);
|
||||
|
||||
if (ctx->input_order == 0)
|
||||
ctx->first_pts = pic->pts;
|
||||
if (ctx->input_order == ctx->decode_delay)
|
||||
ctx->dts_pts_diff = pic->pts - ctx->first_pts;
|
||||
if (ctx->output_delay > 0)
|
||||
ctx->ts_ring[ctx->input_order %
|
||||
(3 * ctx->output_delay + ctx->async_depth)] = pic->pts;
|
||||
|
||||
pic->display_order = ctx->input_order;
|
||||
++ctx->input_order;
|
||||
|
||||
if (ctx->pic_start) {
|
||||
ctx->pic_end->next = pic;
|
||||
ctx->pic_end = pic;
|
||||
} else {
|
||||
ctx->pic_start = pic;
|
||||
ctx->pic_end = pic;
|
||||
}
|
||||
|
||||
} else {
|
||||
ctx->end_of_stream = 1;
|
||||
|
||||
// Fix timestamps if we hit end-of-stream before the initial decode
|
||||
// delay has elapsed.
|
||||
if (ctx->input_order < ctx->decode_delay)
|
||||
ctx->dts_pts_diff = ctx->pic_end->pts - ctx->first_pts;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
ctx->op->free(avctx, pic);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ff_hw_base_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt)
|
||||
{
|
||||
FFHWBaseEncodeContext *ctx = avctx->priv_data;
|
||||
FFHWBaseEncodePicture *pic = NULL;
|
||||
AVFrame *frame = ctx->frame;
|
||||
int err;
|
||||
|
||||
av_assert0(ctx->op && ctx->op->alloc && ctx->op->issue &&
|
||||
ctx->op->output && ctx->op->free);
|
||||
|
||||
start:
|
||||
/** if no B frame before repeat P frame, sent repeat P frame out. */
|
||||
if (ctx->tail_pkt->size) {
|
||||
for (FFHWBaseEncodePicture *tmp = ctx->pic_start; tmp; tmp = tmp->next) {
|
||||
if (tmp->type == FF_HW_PICTURE_TYPE_B && tmp->pts < ctx->tail_pkt->pts)
|
||||
break;
|
||||
else if (!tmp->next) {
|
||||
av_packet_move_ref(pkt, ctx->tail_pkt);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = ff_encode_get_frame(avctx, frame);
|
||||
if (err < 0 && err != AVERROR_EOF)
|
||||
return err;
|
||||
|
||||
if (err == AVERROR_EOF)
|
||||
frame = NULL;
|
||||
|
||||
err = hw_base_encode_send_frame(avctx, frame);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (!ctx->pic_start) {
|
||||
if (ctx->end_of_stream)
|
||||
return AVERROR_EOF;
|
||||
else
|
||||
return AVERROR(EAGAIN);
|
||||
}
|
||||
|
||||
if (ctx->async_encode) {
|
||||
if (av_fifo_can_write(ctx->encode_fifo)) {
|
||||
err = hw_base_encode_pick_next(avctx, &pic);
|
||||
if (!err) {
|
||||
av_assert0(pic);
|
||||
pic->encode_order = ctx->encode_order +
|
||||
av_fifo_can_read(ctx->encode_fifo);
|
||||
err = ctx->op->issue(avctx, pic);
|
||||
if (err < 0) {
|
||||
av_log(avctx, AV_LOG_ERROR, "Encode failed: %d.\n", err);
|
||||
return err;
|
||||
}
|
||||
pic->encode_issued = 1;
|
||||
av_fifo_write(ctx->encode_fifo, &pic, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!av_fifo_can_read(ctx->encode_fifo))
|
||||
return err;
|
||||
|
||||
// More frames can be buffered
|
||||
if (av_fifo_can_write(ctx->encode_fifo) && !ctx->end_of_stream)
|
||||
return AVERROR(EAGAIN);
|
||||
|
||||
av_fifo_read(ctx->encode_fifo, &pic, 1);
|
||||
ctx->encode_order = pic->encode_order + 1;
|
||||
} else {
|
||||
err = hw_base_encode_pick_next(avctx, &pic);
|
||||
if (err < 0)
|
||||
return err;
|
||||
av_assert0(pic);
|
||||
|
||||
pic->encode_order = ctx->encode_order++;
|
||||
|
||||
err = ctx->op->issue(avctx, pic);
|
||||
if (err < 0) {
|
||||
av_log(avctx, AV_LOG_ERROR, "Encode failed: %d.\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
pic->encode_issued = 1;
|
||||
}
|
||||
|
||||
err = ctx->op->output(avctx, pic, pkt);
|
||||
if (err < 0) {
|
||||
av_log(avctx, AV_LOG_ERROR, "Output failed: %d.\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ctx->output_order = pic->encode_order;
|
||||
hw_base_encode_clear_old(avctx);
|
||||
|
||||
/** loop to get an available pkt in encoder flushing. */
|
||||
if (ctx->end_of_stream && !pkt->size)
|
||||
goto start;
|
||||
|
||||
end:
|
||||
if (pkt->size)
|
||||
av_log(avctx, AV_LOG_DEBUG, "Output packet: pts %"PRId64", dts %"PRId64", "
|
||||
"size %d bytes.\n", pkt->pts, pkt->dts, pkt->size);
|
||||
|
||||
return 0;
|
||||
}
|
@ -19,6 +19,8 @@
|
||||
#ifndef AVCODEC_HW_BASE_ENCODE_H
|
||||
#define AVCODEC_HW_BASE_ENCODE_H
|
||||
|
||||
#include "libavutil/fifo.h"
|
||||
|
||||
#define MAX_DPB_SIZE 16
|
||||
#define MAX_PICTURE_REFERENCES 2
|
||||
#define MAX_REORDER_DELAY 16
|
||||
@ -54,13 +56,135 @@ enum {
|
||||
FF_HW_FLAG_NON_IDR_KEY_PICTURES = 1 << 5,
|
||||
};
|
||||
|
||||
typedef struct FFHWBaseEncodePicture {
|
||||
struct FFHWBaseEncodePicture *next;
|
||||
|
||||
int64_t display_order;
|
||||
int64_t encode_order;
|
||||
int64_t pts;
|
||||
int64_t duration;
|
||||
int force_idr;
|
||||
|
||||
void *opaque;
|
||||
AVBufferRef *opaque_ref;
|
||||
|
||||
int type;
|
||||
int b_depth;
|
||||
int encode_issued;
|
||||
int encode_complete;
|
||||
|
||||
AVFrame *input_image;
|
||||
AVFrame *recon_image;
|
||||
|
||||
void *priv_data;
|
||||
|
||||
// Whether this picture is a reference picture.
|
||||
int is_reference;
|
||||
|
||||
// The contents of the DPB after this picture has been decoded.
|
||||
// This will contain the picture itself if it is a reference picture,
|
||||
// but not if it isn't.
|
||||
int nb_dpb_pics;
|
||||
struct FFHWBaseEncodePicture *dpb[MAX_DPB_SIZE];
|
||||
// The reference pictures used in decoding this picture. If they are
|
||||
// used by later pictures they will also appear in the DPB. ref[0][] for
|
||||
// previous reference frames. ref[1][] for future reference frames.
|
||||
int nb_refs[MAX_REFERENCE_LIST_NUM];
|
||||
struct FFHWBaseEncodePicture *refs[MAX_REFERENCE_LIST_NUM][MAX_PICTURE_REFERENCES];
|
||||
// The previous reference picture in encode order. Must be in at least
|
||||
// one of the reference list and DPB list.
|
||||
struct FFHWBaseEncodePicture *prev;
|
||||
// Reference count for other pictures referring to this one through
|
||||
// the above pointers, directly from incomplete pictures and indirectly
|
||||
// through completed pictures.
|
||||
int ref_count[2];
|
||||
int ref_removed[2];
|
||||
} FFHWBaseEncodePicture;
|
||||
|
||||
typedef struct FFHWEncodePictureOperation {
|
||||
// Alloc memory for the picture structure and initialize the API-specific internals
|
||||
// based of the given frame.
|
||||
FFHWBaseEncodePicture * (*alloc)(AVCodecContext *avctx, const AVFrame *frame);
|
||||
// Issue the picture structure, which will send the frame surface to HW Encode API.
|
||||
int (*issue)(AVCodecContext *avctx, const FFHWBaseEncodePicture *base_pic);
|
||||
// Get the output AVPacket.
|
||||
int (*output)(AVCodecContext *avctx, const FFHWBaseEncodePicture *base_pic, AVPacket *pkt);
|
||||
// Free the picture structure.
|
||||
int (*free)(AVCodecContext *avctx, FFHWBaseEncodePicture *base_pic);
|
||||
} FFHWEncodePictureOperation;
|
||||
|
||||
typedef struct FFHWBaseEncodeContext {
|
||||
const AVClass *class;
|
||||
|
||||
// Hardware-specific hooks.
|
||||
const struct FFHWEncodePictureOperation *op;
|
||||
|
||||
// Current encoding window, in display (input) order.
|
||||
FFHWBaseEncodePicture *pic_start, *pic_end;
|
||||
// The next picture to use as the previous reference picture in
|
||||
// encoding order. Order from small to large in encoding order.
|
||||
FFHWBaseEncodePicture *next_prev[MAX_PICTURE_REFERENCES];
|
||||
int nb_next_prev;
|
||||
|
||||
// Next input order index (display order).
|
||||
int64_t input_order;
|
||||
// Number of frames that output is behind input.
|
||||
int64_t output_delay;
|
||||
// Next encode order index.
|
||||
int64_t encode_order;
|
||||
// Number of frames decode output will need to be delayed.
|
||||
int64_t decode_delay;
|
||||
// Next output order index (in encode order).
|
||||
int64_t output_order;
|
||||
|
||||
// Timestamp handling.
|
||||
int64_t first_pts;
|
||||
int64_t dts_pts_diff;
|
||||
int64_t ts_ring[MAX_REORDER_DELAY * 3 +
|
||||
MAX_ASYNC_DEPTH];
|
||||
|
||||
// Frame type decision.
|
||||
int gop_size;
|
||||
int closed_gop;
|
||||
int gop_per_idr;
|
||||
int p_per_i;
|
||||
int max_b_depth;
|
||||
int b_per_p;
|
||||
int force_idr;
|
||||
int idr_counter;
|
||||
int gop_counter;
|
||||
int end_of_stream;
|
||||
int p_to_gpb;
|
||||
|
||||
// Whether the driver supports ROI at all.
|
||||
int roi_allowed;
|
||||
|
||||
// The encoder does not support cropping information, so warn about
|
||||
// it the first time we encounter any nonzero crop fields.
|
||||
int crop_warned;
|
||||
// If the driver does not support ROI then warn the first time we
|
||||
// encounter a frame with ROI side data.
|
||||
int roi_warned;
|
||||
|
||||
// The frame to be filled with data.
|
||||
AVFrame *frame;
|
||||
|
||||
// Whether the HW supports sync buffer function.
|
||||
// If supported, encode_fifo/async_depth will be used together.
|
||||
// Used for output buffer synchronization.
|
||||
int async_encode;
|
||||
|
||||
// Store buffered pic.
|
||||
AVFifo *encode_fifo;
|
||||
// Max number of frame buffered in encoder.
|
||||
int async_depth;
|
||||
|
||||
/** Tail data of a pic, now only used for av1 repeat frame header. */
|
||||
AVPacket *tail_pkt;
|
||||
} FFHWBaseEncodeContext;
|
||||
|
||||
int ff_hw_base_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt);
|
||||
|
||||
#define HW_BASE_ENCODE_COMMON_OPTIONS \
|
||||
{ "async_depth", "Maximum processing parallelism. " \
|
||||
"Increase this to improve single channel performance.", \
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -29,7 +29,6 @@
|
||||
|
||||
#include "libavutil/hwcontext.h"
|
||||
#include "libavutil/hwcontext_vaapi.h"
|
||||
#include "libavutil/fifo.h"
|
||||
|
||||
#include "avcodec.h"
|
||||
#include "hwconfig.h"
|
||||
@ -64,16 +63,7 @@ typedef struct VAAPIEncodeSlice {
|
||||
} VAAPIEncodeSlice;
|
||||
|
||||
typedef struct VAAPIEncodePicture {
|
||||
struct VAAPIEncodePicture *next;
|
||||
|
||||
int64_t display_order;
|
||||
int64_t encode_order;
|
||||
int64_t pts;
|
||||
int64_t duration;
|
||||
int force_idr;
|
||||
|
||||
void *opaque;
|
||||
AVBufferRef *opaque_ref;
|
||||
FFHWBaseEncodePicture base;
|
||||
|
||||
#if VA_CHECK_VERSION(1, 0, 0)
|
||||
// ROI regions.
|
||||
@ -82,15 +72,7 @@ typedef struct VAAPIEncodePicture {
|
||||
void *roi;
|
||||
#endif
|
||||
|
||||
int type;
|
||||
int b_depth;
|
||||
int encode_issued;
|
||||
int encode_complete;
|
||||
|
||||
AVFrame *input_image;
|
||||
VASurfaceID input_surface;
|
||||
|
||||
AVFrame *recon_image;
|
||||
VASurfaceID recon_surface;
|
||||
|
||||
int nb_param_buffers;
|
||||
@ -100,31 +82,8 @@ typedef struct VAAPIEncodePicture {
|
||||
VABufferID *output_buffer_ref;
|
||||
VABufferID output_buffer;
|
||||
|
||||
void *priv_data;
|
||||
void *codec_picture_params;
|
||||
|
||||
// Whether this picture is a reference picture.
|
||||
int is_reference;
|
||||
|
||||
// The contents of the DPB after this picture has been decoded.
|
||||
// This will contain the picture itself if it is a reference picture,
|
||||
// but not if it isn't.
|
||||
int nb_dpb_pics;
|
||||
struct VAAPIEncodePicture *dpb[MAX_DPB_SIZE];
|
||||
// The reference pictures used in decoding this picture. If they are
|
||||
// used by later pictures they will also appear in the DPB. ref[0][] for
|
||||
// previous reference frames. ref[1][] for future reference frames.
|
||||
int nb_refs[MAX_REFERENCE_LIST_NUM];
|
||||
struct VAAPIEncodePicture *refs[MAX_REFERENCE_LIST_NUM][MAX_PICTURE_REFERENCES];
|
||||
// The previous reference picture in encode order. Must be in at least
|
||||
// one of the reference list and DPB list.
|
||||
struct VAAPIEncodePicture *prev;
|
||||
// Reference count for other pictures referring to this one through
|
||||
// the above pointers, directly from incomplete pictures and indirectly
|
||||
// through completed pictures.
|
||||
int ref_count[2];
|
||||
int ref_removed[2];
|
||||
|
||||
int nb_slices;
|
||||
VAAPIEncodeSlice *slices;
|
||||
|
||||
@ -298,30 +257,6 @@ typedef struct VAAPIEncodeContext {
|
||||
// structure (VAEncPictureParameterBuffer*).
|
||||
void *codec_picture_params;
|
||||
|
||||
// Current encoding window, in display (input) order.
|
||||
VAAPIEncodePicture *pic_start, *pic_end;
|
||||
// The next picture to use as the previous reference picture in
|
||||
// encoding order. Order from small to large in encoding order.
|
||||
VAAPIEncodePicture *next_prev[MAX_PICTURE_REFERENCES];
|
||||
int nb_next_prev;
|
||||
|
||||
// Next input order index (display order).
|
||||
int64_t input_order;
|
||||
// Number of frames that output is behind input.
|
||||
int64_t output_delay;
|
||||
// Next encode order index.
|
||||
int64_t encode_order;
|
||||
// Number of frames decode output will need to be delayed.
|
||||
int64_t decode_delay;
|
||||
// Next output order index (in encode order).
|
||||
int64_t output_order;
|
||||
|
||||
// Timestamp handling.
|
||||
int64_t first_pts;
|
||||
int64_t dts_pts_diff;
|
||||
int64_t ts_ring[MAX_REORDER_DELAY * 3 +
|
||||
MAX_ASYNC_DEPTH];
|
||||
|
||||
// Slice structure.
|
||||
int slice_block_rows;
|
||||
int slice_block_cols;
|
||||
@ -340,41 +275,12 @@ typedef struct VAAPIEncodeContext {
|
||||
// Location of the i-th tile row boundary.
|
||||
int row_bd[MAX_TILE_ROWS + 1];
|
||||
|
||||
// Frame type decision.
|
||||
int gop_size;
|
||||
int closed_gop;
|
||||
int gop_per_idr;
|
||||
int p_per_i;
|
||||
int max_b_depth;
|
||||
int b_per_p;
|
||||
int force_idr;
|
||||
int idr_counter;
|
||||
int gop_counter;
|
||||
int end_of_stream;
|
||||
int p_to_gpb;
|
||||
|
||||
// Whether the driver supports ROI at all.
|
||||
int roi_allowed;
|
||||
// Maximum number of regions supported by the driver.
|
||||
int roi_max_regions;
|
||||
// Quantisation range for offset calculations. Set by codec-specific
|
||||
// code, as it may change based on parameters.
|
||||
int roi_quant_range;
|
||||
|
||||
// The encoder does not support cropping information, so warn about
|
||||
// it the first time we encounter any nonzero crop fields.
|
||||
int crop_warned;
|
||||
// If the driver does not support ROI then warn the first time we
|
||||
// encounter a frame with ROI side data.
|
||||
int roi_warned;
|
||||
|
||||
AVFrame *frame;
|
||||
|
||||
// Whether the driver support vaSyncBuffer
|
||||
int has_sync_buffer_func;
|
||||
// Store buffered pic
|
||||
AVFifo *encode_fifo;
|
||||
|
||||
/** Head data for current output pkt, used only for AV1. */
|
||||
//void *header_data;
|
||||
//size_t header_data_size;
|
||||
@ -384,9 +290,6 @@ typedef struct VAAPIEncodeContext {
|
||||
* This is a RefStruct reference.
|
||||
*/
|
||||
VABufferID *coded_buffer_ref;
|
||||
|
||||
/** Tail data of a pic, now only used for av1 repeat frame header. */
|
||||
AVPacket *tail_pkt;
|
||||
} VAAPIEncodeContext;
|
||||
|
||||
typedef struct VAAPIEncodeType {
|
||||
@ -468,9 +371,6 @@ typedef struct VAAPIEncodeType {
|
||||
char *data, size_t *data_len);
|
||||
} VAAPIEncodeType;
|
||||
|
||||
|
||||
int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt);
|
||||
|
||||
int ff_vaapi_encode_init(AVCodecContext *avctx);
|
||||
int ff_vaapi_encode_close(AVCodecContext *avctx);
|
||||
|
||||
|
@ -360,6 +360,7 @@ static int vaapi_encode_av1_write_sequence_header(AVCodecContext *avctx,
|
||||
|
||||
static int vaapi_encode_av1_init_sequence_params(AVCodecContext *avctx)
|
||||
{
|
||||
FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
|
||||
VAAPIEncodeContext *ctx = avctx->priv_data;
|
||||
VAAPIEncodeAV1Context *priv = avctx->priv_data;
|
||||
AV1RawOBU *sh_obu = &priv->sh;
|
||||
@ -441,8 +442,8 @@ static int vaapi_encode_av1_init_sequence_params(AVCodecContext *avctx)
|
||||
vseq->seq_level_idx = sh->seq_level_idx[0];
|
||||
vseq->seq_tier = sh->seq_tier[0];
|
||||
vseq->order_hint_bits_minus_1 = sh->order_hint_bits_minus_1;
|
||||
vseq->intra_period = ctx->gop_size;
|
||||
vseq->ip_period = ctx->b_per_p + 1;
|
||||
vseq->intra_period = base_ctx->gop_size;
|
||||
vseq->ip_period = base_ctx->b_per_p + 1;
|
||||
|
||||
vseq->seq_fields.bits.enable_order_hint = sh->enable_order_hint;
|
||||
|
||||
@ -465,16 +466,17 @@ end:
|
||||
}
|
||||
|
||||
static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx,
|
||||
VAAPIEncodePicture *pic)
|
||||
VAAPIEncodePicture *vaapi_pic)
|
||||
{
|
||||
VAAPIEncodeContext *ctx = avctx->priv_data;
|
||||
VAAPIEncodeAV1Context *priv = avctx->priv_data;
|
||||
const FFHWBaseEncodePicture *pic = &vaapi_pic->base;
|
||||
VAAPIEncodeAV1Picture *hpic = pic->priv_data;
|
||||
AV1RawOBU *fh_obu = &priv->fh;
|
||||
AV1RawFrameHeader *fh = &fh_obu->obu.frame.header;
|
||||
VAEncPictureParameterBufferAV1 *vpic = pic->codec_picture_params;
|
||||
VAEncPictureParameterBufferAV1 *vpic = vaapi_pic->codec_picture_params;
|
||||
CodedBitstreamFragment *obu = &priv->current_obu;
|
||||
VAAPIEncodePicture *ref;
|
||||
FFHWBaseEncodePicture *ref;
|
||||
VAAPIEncodeAV1Picture *href;
|
||||
int slot, i;
|
||||
int ret;
|
||||
@ -482,8 +484,8 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx,
|
||||
{ 1, 0, 0, 0, -1, 0, -1, -1 };
|
||||
|
||||
memset(fh_obu, 0, sizeof(*fh_obu));
|
||||
pic->nb_slices = priv->tile_groups;
|
||||
pic->non_independent_frame = pic->encode_order < pic->display_order;
|
||||
vaapi_pic->nb_slices = priv->tile_groups;
|
||||
vaapi_pic->non_independent_frame = pic->encode_order < pic->display_order;
|
||||
fh_obu->header.obu_type = AV1_OBU_FRAME_HEADER;
|
||||
fh_obu->header.obu_has_size_field = 1;
|
||||
|
||||
@ -601,8 +603,8 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx,
|
||||
vpic->frame_width_minus_1 = fh->frame_width_minus_1;
|
||||
vpic->frame_height_minus_1 = fh->frame_height_minus_1;
|
||||
vpic->primary_ref_frame = fh->primary_ref_frame;
|
||||
vpic->reconstructed_frame = pic->recon_surface;
|
||||
vpic->coded_buf = pic->output_buffer;
|
||||
vpic->reconstructed_frame = vaapi_pic->recon_surface;
|
||||
vpic->coded_buf = vaapi_pic->output_buffer;
|
||||
vpic->tile_cols = fh->tile_cols;
|
||||
vpic->tile_rows = fh->tile_rows;
|
||||
vpic->order_hint = fh->order_hint;
|
||||
@ -630,12 +632,12 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx,
|
||||
|
||||
for (i = 0; i < MAX_REFERENCE_LIST_NUM; i++) {
|
||||
for (int j = 0; j < pic->nb_refs[i]; j++) {
|
||||
VAAPIEncodePicture *ref_pic = pic->refs[i][j];
|
||||
FFHWBaseEncodePicture *ref_pic = pic->refs[i][j];
|
||||
|
||||
slot = ((VAAPIEncodeAV1Picture*)ref_pic->priv_data)->slot;
|
||||
av_assert0(vpic->reference_frames[slot] == VA_INVALID_SURFACE);
|
||||
|
||||
vpic->reference_frames[slot] = ref_pic->recon_surface;
|
||||
vpic->reference_frames[slot] = ((VAAPIEncodePicture *)ref_pic)->recon_surface;
|
||||
}
|
||||
}
|
||||
|
||||
@ -752,7 +754,7 @@ static int vaapi_encode_av1_init_slice_params(AVCodecContext *avctx,
|
||||
}
|
||||
|
||||
static int vaapi_encode_av1_write_picture_header(AVCodecContext *avctx,
|
||||
VAAPIEncodePicture *pic,
|
||||
VAAPIEncodePicture *vaapi_pic,
|
||||
char *data, size_t *data_len)
|
||||
{
|
||||
VAAPIEncodeAV1Context *priv = avctx->priv_data;
|
||||
@ -760,10 +762,11 @@ static int vaapi_encode_av1_write_picture_header(AVCodecContext *avctx,
|
||||
CodedBitstreamAV1Context *cbctx = priv->cbc->priv_data;
|
||||
AV1RawOBU *fh_obu = &priv->fh;
|
||||
AV1RawFrameHeader *rep_fh = &fh_obu->obu.frame_header;
|
||||
const FFHWBaseEncodePicture *pic = &vaapi_pic->base;
|
||||
VAAPIEncodeAV1Picture *href;
|
||||
int ret = 0;
|
||||
|
||||
pic->tail_size = 0;
|
||||
vaapi_pic->tail_size = 0;
|
||||
/** Pack repeat frame header. */
|
||||
if (pic->display_order > pic->encode_order) {
|
||||
memset(fh_obu, 0, sizeof(*fh_obu));
|
||||
@ -785,11 +788,11 @@ static int vaapi_encode_av1_write_picture_header(AVCodecContext *avctx,
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
ret = vaapi_encode_av1_write_obu(avctx, pic->tail_data, &pic->tail_size, obu);
|
||||
ret = vaapi_encode_av1_write_obu(avctx, vaapi_pic->tail_data, &vaapi_pic->tail_size, obu);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
pic->tail_size /= 8;
|
||||
vaapi_pic->tail_size /= 8;
|
||||
}
|
||||
|
||||
memcpy(data, &priv->fh_data, MAX_PARAM_BUFFER_SIZE * sizeof(char));
|
||||
@ -1038,7 +1041,7 @@ const FFCodec ff_av1_vaapi_encoder = {
|
||||
.p.id = AV_CODEC_ID_AV1,
|
||||
.priv_data_size = sizeof(VAAPIEncodeAV1Context),
|
||||
.init = &vaapi_encode_av1_init,
|
||||
FF_CODEC_RECEIVE_PACKET_CB(&ff_vaapi_encode_receive_packet),
|
||||
FF_CODEC_RECEIVE_PACKET_CB(&ff_hw_base_encode_receive_packet),
|
||||
.close = &vaapi_encode_av1_close,
|
||||
.p.priv_class = &vaapi_encode_av1_class,
|
||||
.p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
|
||||
|
@ -233,7 +233,7 @@ static int vaapi_encode_h264_write_extra_header(AVCodecContext *avctx,
|
||||
goto fail;
|
||||
}
|
||||
if (priv->sei_needed & SEI_TIMING) {
|
||||
if (pic->type == FF_HW_PICTURE_TYPE_IDR) {
|
||||
if (pic->base.type == FF_HW_PICTURE_TYPE_IDR) {
|
||||
err = ff_cbs_sei_add_message(priv->cbc, au, 1,
|
||||
SEI_TYPE_BUFFERING_PERIOD,
|
||||
&priv->sei_buffering_period, NULL);
|
||||
@ -295,6 +295,7 @@ fail:
|
||||
|
||||
static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx)
|
||||
{
|
||||
FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
|
||||
VAAPIEncodeContext *ctx = avctx->priv_data;
|
||||
VAAPIEncodeH264Context *priv = avctx->priv_data;
|
||||
H264RawSPS *sps = &priv->raw_sps;
|
||||
@ -326,18 +327,18 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx)
|
||||
sps->constraint_set1_flag = 1;
|
||||
|
||||
if (avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile == AV_PROFILE_H264_HIGH_10)
|
||||
sps->constraint_set3_flag = ctx->gop_size == 1;
|
||||
sps->constraint_set3_flag = base_ctx->gop_size == 1;
|
||||
|
||||
if (avctx->profile == AV_PROFILE_H264_MAIN ||
|
||||
avctx->profile == AV_PROFILE_H264_HIGH || avctx->profile == AV_PROFILE_H264_HIGH_10) {
|
||||
sps->constraint_set4_flag = 1;
|
||||
sps->constraint_set5_flag = ctx->b_per_p == 0;
|
||||
sps->constraint_set5_flag = base_ctx->b_per_p == 0;
|
||||
}
|
||||
|
||||
if (ctx->gop_size == 1)
|
||||
if (base_ctx->gop_size == 1)
|
||||
priv->dpb_frames = 0;
|
||||
else
|
||||
priv->dpb_frames = 1 + ctx->max_b_depth;
|
||||
priv->dpb_frames = 1 + base_ctx->max_b_depth;
|
||||
|
||||
if (avctx->level != AV_LEVEL_UNKNOWN) {
|
||||
sps->level_idc = avctx->level;
|
||||
@ -374,7 +375,7 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx)
|
||||
sps->bit_depth_chroma_minus8 = bit_depth - 8;
|
||||
|
||||
sps->log2_max_frame_num_minus4 = 4;
|
||||
sps->pic_order_cnt_type = ctx->max_b_depth ? 0 : 2;
|
||||
sps->pic_order_cnt_type = base_ctx->max_b_depth ? 0 : 2;
|
||||
if (sps->pic_order_cnt_type == 0) {
|
||||
sps->log2_max_pic_order_cnt_lsb_minus4 = 4;
|
||||
}
|
||||
@ -501,8 +502,8 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx)
|
||||
sps->vui.motion_vectors_over_pic_boundaries_flag = 1;
|
||||
sps->vui.log2_max_mv_length_horizontal = 15;
|
||||
sps->vui.log2_max_mv_length_vertical = 15;
|
||||
sps->vui.max_num_reorder_frames = ctx->max_b_depth;
|
||||
sps->vui.max_dec_frame_buffering = ctx->max_b_depth + 1;
|
||||
sps->vui.max_num_reorder_frames = base_ctx->max_b_depth;
|
||||
sps->vui.max_dec_frame_buffering = base_ctx->max_b_depth + 1;
|
||||
|
||||
pps->nal_unit_header.nal_ref_idc = 3;
|
||||
pps->nal_unit_header.nal_unit_type = H264_NAL_PPS;
|
||||
@ -535,9 +536,9 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx)
|
||||
*vseq = (VAEncSequenceParameterBufferH264) {
|
||||
.seq_parameter_set_id = sps->seq_parameter_set_id,
|
||||
.level_idc = sps->level_idc,
|
||||
.intra_period = ctx->gop_size,
|
||||
.intra_idr_period = ctx->gop_size,
|
||||
.ip_period = ctx->b_per_p + 1,
|
||||
.intra_period = base_ctx->gop_size,
|
||||
.intra_idr_period = base_ctx->gop_size,
|
||||
.ip_period = base_ctx->b_per_p + 1,
|
||||
|
||||
.bits_per_second = ctx->va_bit_rate,
|
||||
.max_num_ref_frames = sps->max_num_ref_frames,
|
||||
@ -619,14 +620,15 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx)
|
||||
}
|
||||
|
||||
static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx,
|
||||
VAAPIEncodePicture *pic)
|
||||
VAAPIEncodePicture *vaapi_pic)
|
||||
{
|
||||
VAAPIEncodeContext *ctx = avctx->priv_data;
|
||||
FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
|
||||
VAAPIEncodeH264Context *priv = avctx->priv_data;
|
||||
const FFHWBaseEncodePicture *pic = &vaapi_pic->base;
|
||||
VAAPIEncodeH264Picture *hpic = pic->priv_data;
|
||||
VAAPIEncodePicture *prev = pic->prev;
|
||||
FFHWBaseEncodePicture *prev = pic->prev;
|
||||
VAAPIEncodeH264Picture *hprev = prev ? prev->priv_data : NULL;
|
||||
VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params;
|
||||
VAEncPictureParameterBufferH264 *vpic = vaapi_pic->codec_picture_params;
|
||||
int i, j = 0;
|
||||
|
||||
if (pic->type == FF_HW_PICTURE_TYPE_IDR) {
|
||||
@ -662,7 +664,7 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx,
|
||||
hpic->pic_order_cnt *= 2;
|
||||
}
|
||||
|
||||
hpic->dpb_delay = pic->display_order - pic->encode_order + ctx->max_b_depth;
|
||||
hpic->dpb_delay = pic->display_order - pic->encode_order + base_ctx->max_b_depth;
|
||||
hpic->cpb_delay = pic->encode_order - hpic->last_idr_frame;
|
||||
|
||||
if (priv->aud) {
|
||||
@ -699,7 +701,7 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx,
|
||||
priv->sei_recovery_point = (H264RawSEIRecoveryPoint) {
|
||||
.recovery_frame_cnt = 0,
|
||||
.exact_match_flag = 1,
|
||||
.broken_link_flag = ctx->b_per_p > 0,
|
||||
.broken_link_flag = base_ctx->b_per_p > 0,
|
||||
};
|
||||
|
||||
priv->sei_needed |= SEI_RECOVERY_POINT;
|
||||
@ -722,7 +724,7 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx,
|
||||
}
|
||||
|
||||
vpic->CurrPic = (VAPictureH264) {
|
||||
.picture_id = pic->recon_surface,
|
||||
.picture_id = vaapi_pic->recon_surface,
|
||||
.frame_idx = hpic->frame_num,
|
||||
.flags = 0,
|
||||
.TopFieldOrderCnt = hpic->pic_order_cnt,
|
||||
@ -730,14 +732,14 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx,
|
||||
};
|
||||
for (int k = 0; k < MAX_REFERENCE_LIST_NUM; k++) {
|
||||
for (i = 0; i < pic->nb_refs[k]; i++) {
|
||||
VAAPIEncodePicture *ref = pic->refs[k][i];
|
||||
FFHWBaseEncodePicture *ref = pic->refs[k][i];
|
||||
VAAPIEncodeH264Picture *href;
|
||||
|
||||
av_assert0(ref && ref->encode_order < pic->encode_order);
|
||||
href = ref->priv_data;
|
||||
|
||||
vpic->ReferenceFrames[j++] = (VAPictureH264) {
|
||||
.picture_id = ref->recon_surface,
|
||||
.picture_id = ((VAAPIEncodePicture *)ref)->recon_surface,
|
||||
.frame_idx = href->frame_num,
|
||||
.flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE,
|
||||
.TopFieldOrderCnt = href->pic_order_cnt,
|
||||
@ -753,7 +755,7 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx,
|
||||
};
|
||||
}
|
||||
|
||||
vpic->coded_buf = pic->output_buffer;
|
||||
vpic->coded_buf = vaapi_pic->output_buffer;
|
||||
|
||||
vpic->frame_num = hpic->frame_num;
|
||||
|
||||
@ -764,12 +766,13 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx,
|
||||
}
|
||||
|
||||
static void vaapi_encode_h264_default_ref_pic_list(AVCodecContext *avctx,
|
||||
VAAPIEncodePicture *pic,
|
||||
VAAPIEncodePicture *vaapi_pic,
|
||||
VAAPIEncodePicture **rpl0,
|
||||
VAAPIEncodePicture **rpl1,
|
||||
int *rpl_size)
|
||||
{
|
||||
VAAPIEncodePicture *prev;
|
||||
FFHWBaseEncodePicture *pic = &vaapi_pic->base;
|
||||
FFHWBaseEncodePicture *prev;
|
||||
VAAPIEncodeH264Picture *hp, *hn, *hc;
|
||||
int i, j, n = 0;
|
||||
|
||||
@ -783,17 +786,17 @@ static void vaapi_encode_h264_default_ref_pic_list(AVCodecContext *avctx,
|
||||
|
||||
if (pic->type == FF_HW_PICTURE_TYPE_P) {
|
||||
for (j = n; j > 0; j--) {
|
||||
hc = rpl0[j - 1]->priv_data;
|
||||
hc = rpl0[j - 1]->base.priv_data;
|
||||
av_assert0(hc->frame_num != hn->frame_num);
|
||||
if (hc->frame_num > hn->frame_num)
|
||||
break;
|
||||
rpl0[j] = rpl0[j - 1];
|
||||
}
|
||||
rpl0[j] = prev->dpb[i];
|
||||
rpl0[j] = (VAAPIEncodePicture *)prev->dpb[i];
|
||||
|
||||
} else if (pic->type == FF_HW_PICTURE_TYPE_B) {
|
||||
for (j = n; j > 0; j--) {
|
||||
hc = rpl0[j - 1]->priv_data;
|
||||
hc = rpl0[j - 1]->base.priv_data;
|
||||
av_assert0(hc->pic_order_cnt != hp->pic_order_cnt);
|
||||
if (hc->pic_order_cnt < hp->pic_order_cnt) {
|
||||
if (hn->pic_order_cnt > hp->pic_order_cnt ||
|
||||
@ -805,10 +808,10 @@ static void vaapi_encode_h264_default_ref_pic_list(AVCodecContext *avctx,
|
||||
}
|
||||
rpl0[j] = rpl0[j - 1];
|
||||
}
|
||||
rpl0[j] = prev->dpb[i];
|
||||
rpl0[j] = (VAAPIEncodePicture *)prev->dpb[i];
|
||||
|
||||
for (j = n; j > 0; j--) {
|
||||
hc = rpl1[j - 1]->priv_data;
|
||||
hc = rpl1[j - 1]->base.priv_data;
|
||||
av_assert0(hc->pic_order_cnt != hp->pic_order_cnt);
|
||||
if (hc->pic_order_cnt > hp->pic_order_cnt) {
|
||||
if (hn->pic_order_cnt < hp->pic_order_cnt ||
|
||||
@ -820,7 +823,7 @@ static void vaapi_encode_h264_default_ref_pic_list(AVCodecContext *avctx,
|
||||
}
|
||||
rpl1[j] = rpl1[j - 1];
|
||||
}
|
||||
rpl1[j] = prev->dpb[i];
|
||||
rpl1[j] = (VAAPIEncodePicture *)prev->dpb[i];
|
||||
}
|
||||
|
||||
++n;
|
||||
@ -840,7 +843,7 @@ static void vaapi_encode_h264_default_ref_pic_list(AVCodecContext *avctx,
|
||||
av_log(avctx, AV_LOG_DEBUG, "Default RefPicList0 for fn=%d/poc=%d:",
|
||||
hp->frame_num, hp->pic_order_cnt);
|
||||
for (i = 0; i < n; i++) {
|
||||
hn = rpl0[i]->priv_data;
|
||||
hn = rpl0[i]->base.priv_data;
|
||||
av_log(avctx, AV_LOG_DEBUG, " fn=%d/poc=%d",
|
||||
hn->frame_num, hn->pic_order_cnt);
|
||||
}
|
||||
@ -850,7 +853,7 @@ static void vaapi_encode_h264_default_ref_pic_list(AVCodecContext *avctx,
|
||||
av_log(avctx, AV_LOG_DEBUG, "Default RefPicList1 for fn=%d/poc=%d:",
|
||||
hp->frame_num, hp->pic_order_cnt);
|
||||
for (i = 0; i < n; i++) {
|
||||
hn = rpl1[i]->priv_data;
|
||||
hn = rpl1[i]->base.priv_data;
|
||||
av_log(avctx, AV_LOG_DEBUG, " fn=%d/poc=%d",
|
||||
hn->frame_num, hn->pic_order_cnt);
|
||||
}
|
||||
@ -861,16 +864,17 @@ static void vaapi_encode_h264_default_ref_pic_list(AVCodecContext *avctx,
|
||||
}
|
||||
|
||||
static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
|
||||
VAAPIEncodePicture *pic,
|
||||
VAAPIEncodePicture *vaapi_pic,
|
||||
VAAPIEncodeSlice *slice)
|
||||
{
|
||||
VAAPIEncodeH264Context *priv = avctx->priv_data;
|
||||
const FFHWBaseEncodePicture *pic = &vaapi_pic->base;
|
||||
VAAPIEncodeH264Picture *hpic = pic->priv_data;
|
||||
VAAPIEncodePicture *prev = pic->prev;
|
||||
FFHWBaseEncodePicture *prev = pic->prev;
|
||||
H264RawSPS *sps = &priv->raw_sps;
|
||||
H264RawPPS *pps = &priv->raw_pps;
|
||||
H264RawSliceHeader *sh = &priv->raw_slice.header;
|
||||
VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params;
|
||||
VAEncPictureParameterBufferH264 *vpic = vaapi_pic->codec_picture_params;
|
||||
VAEncSliceParameterBufferH264 *vslice = slice->codec_slice_params;
|
||||
int i, j;
|
||||
|
||||
@ -903,7 +907,7 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
|
||||
sh->slice_qp_delta = priv->fixed_qp_idr - (pps->pic_init_qp_minus26 + 26);
|
||||
|
||||
if (pic->is_reference && pic->type != FF_HW_PICTURE_TYPE_IDR) {
|
||||
VAAPIEncodePicture *discard_list[MAX_DPB_SIZE];
|
||||
FFHWBaseEncodePicture *discard_list[MAX_DPB_SIZE];
|
||||
int discard = 0, keep = 0;
|
||||
|
||||
// Discard everything which is in the DPB of the previous frame but
|
||||
@ -944,14 +948,14 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
|
||||
VAAPIEncodeH264Picture *href;
|
||||
int n;
|
||||
|
||||
vaapi_encode_h264_default_ref_pic_list(avctx, pic,
|
||||
vaapi_encode_h264_default_ref_pic_list(avctx, vaapi_pic,
|
||||
def_l0, def_l1, &n);
|
||||
|
||||
if (pic->type == FF_HW_PICTURE_TYPE_P) {
|
||||
int need_rplm = 0;
|
||||
for (i = 0; i < pic->nb_refs[0]; i++) {
|
||||
av_assert0(pic->refs[0][i]);
|
||||
if (pic->refs[0][i] != def_l0[i])
|
||||
if (pic->refs[0][i] != (FFHWBaseEncodePicture *)def_l0[i])
|
||||
need_rplm = 1;
|
||||
}
|
||||
|
||||
@ -982,7 +986,7 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
|
||||
av_assert0(pic->refs[0][i]);
|
||||
href = pic->refs[0][i]->priv_data;
|
||||
av_assert0(href->pic_order_cnt < hpic->pic_order_cnt);
|
||||
if (pic->refs[0][i] != def_l0[n0])
|
||||
if (pic->refs[0][i] != (FFHWBaseEncodePicture *)def_l0[n0])
|
||||
need_rplm_l0 = 1;
|
||||
++n0;
|
||||
}
|
||||
@ -991,7 +995,7 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx,
|
||||
av_assert0(pic->refs[1][i]);
|
||||
href = pic->refs[1][i]->priv_data;
|
||||
av_assert0(href->pic_order_cnt > hpic->pic_order_cnt);
|
||||
if (pic->refs[1][i] != def_l1[n1])
|
||||
if (pic->refs[1][i] != (FFHWBaseEncodePicture *)def_l1[n1])
|
||||
need_rplm_l1 = 1;
|
||||
++n1;
|
||||
}
|
||||
@ -1380,7 +1384,7 @@ const FFCodec ff_h264_vaapi_encoder = {
|
||||
.p.id = AV_CODEC_ID_H264,
|
||||
.priv_data_size = sizeof(VAAPIEncodeH264Context),
|
||||
.init = &vaapi_encode_h264_init,
|
||||
FF_CODEC_RECEIVE_PACKET_CB(&ff_vaapi_encode_receive_packet),
|
||||
FF_CODEC_RECEIVE_PACKET_CB(&ff_hw_base_encode_receive_packet),
|
||||
.close = &vaapi_encode_h264_close,
|
||||
.p.priv_class = &vaapi_encode_h264_class,
|
||||
.p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
|
||||
|
@ -260,6 +260,7 @@ fail:
|
||||
|
||||
static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx)
|
||||
{
|
||||
FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
|
||||
VAAPIEncodeContext *ctx = avctx->priv_data;
|
||||
VAAPIEncodeH265Context *priv = avctx->priv_data;
|
||||
H265RawVPS *vps = &priv->raw_vps;
|
||||
@ -341,7 +342,7 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx)
|
||||
ptl->general_max_420chroma_constraint_flag = chroma_format <= 1;
|
||||
ptl->general_max_monochrome_constraint_flag = chroma_format == 0;
|
||||
|
||||
ptl->general_intra_constraint_flag = ctx->gop_size == 1;
|
||||
ptl->general_intra_constraint_flag = base_ctx->gop_size == 1;
|
||||
ptl->general_one_picture_only_constraint_flag = 0;
|
||||
|
||||
ptl->general_lower_bit_rate_constraint_flag = 1;
|
||||
@ -354,7 +355,7 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx)
|
||||
level = ff_h265_guess_level(ptl, avctx->bit_rate,
|
||||
ctx->surface_width, ctx->surface_height,
|
||||
ctx->nb_slices, ctx->tile_rows, ctx->tile_cols,
|
||||
(ctx->b_per_p > 0) + 1);
|
||||
(base_ctx->b_per_p > 0) + 1);
|
||||
if (level) {
|
||||
av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);
|
||||
ptl->general_level_idc = level->level_idc;
|
||||
@ -368,8 +369,8 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx)
|
||||
}
|
||||
|
||||
vps->vps_sub_layer_ordering_info_present_flag = 0;
|
||||
vps->vps_max_dec_pic_buffering_minus1[0] = ctx->max_b_depth + 1;
|
||||
vps->vps_max_num_reorder_pics[0] = ctx->max_b_depth;
|
||||
vps->vps_max_dec_pic_buffering_minus1[0] = base_ctx->max_b_depth + 1;
|
||||
vps->vps_max_num_reorder_pics[0] = base_ctx->max_b_depth;
|
||||
vps->vps_max_latency_increase_plus1[0] = 0;
|
||||
|
||||
vps->vps_max_layer_id = 0;
|
||||
@ -643,9 +644,9 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx)
|
||||
.general_level_idc = vps->profile_tier_level.general_level_idc,
|
||||
.general_tier_flag = vps->profile_tier_level.general_tier_flag,
|
||||
|
||||
.intra_period = ctx->gop_size,
|
||||
.intra_idr_period = ctx->gop_size,
|
||||
.ip_period = ctx->b_per_p + 1,
|
||||
.intra_period = base_ctx->gop_size,
|
||||
.intra_idr_period = base_ctx->gop_size,
|
||||
.ip_period = base_ctx->b_per_p + 1,
|
||||
.bits_per_second = ctx->va_bit_rate,
|
||||
|
||||
.pic_width_in_luma_samples = sps->pic_width_in_luma_samples,
|
||||
@ -756,14 +757,15 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx)
|
||||
}
|
||||
|
||||
static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx,
|
||||
VAAPIEncodePicture *pic)
|
||||
VAAPIEncodePicture *vaapi_pic)
|
||||
{
|
||||
VAAPIEncodeContext *ctx = avctx->priv_data;
|
||||
FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
|
||||
VAAPIEncodeH265Context *priv = avctx->priv_data;
|
||||
FFHWBaseEncodePicture *pic = &vaapi_pic->base;
|
||||
VAAPIEncodeH265Picture *hpic = pic->priv_data;
|
||||
VAAPIEncodePicture *prev = pic->prev;
|
||||
FFHWBaseEncodePicture *prev = pic->prev;
|
||||
VAAPIEncodeH265Picture *hprev = prev ? prev->priv_data : NULL;
|
||||
VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params;
|
||||
VAEncPictureParameterBufferHEVC *vpic = vaapi_pic->codec_picture_params;
|
||||
int i, j = 0;
|
||||
|
||||
if (pic->type == FF_HW_PICTURE_TYPE_IDR) {
|
||||
@ -788,13 +790,13 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx,
|
||||
hpic->slice_type = HEVC_SLICE_P;
|
||||
hpic->pic_type = 1;
|
||||
} else {
|
||||
VAAPIEncodePicture *irap_ref;
|
||||
FFHWBaseEncodePicture *irap_ref;
|
||||
av_assert0(pic->refs[0][0] && pic->refs[1][0]);
|
||||
for (irap_ref = pic; irap_ref; irap_ref = irap_ref->refs[1][0]) {
|
||||
if (irap_ref->type == FF_HW_PICTURE_TYPE_I)
|
||||
break;
|
||||
}
|
||||
if (pic->b_depth == ctx->max_b_depth) {
|
||||
if (pic->b_depth == base_ctx->max_b_depth) {
|
||||
hpic->slice_nal_unit = irap_ref ? HEVC_NAL_RASL_N
|
||||
: HEVC_NAL_TRAIL_N;
|
||||
} else {
|
||||
@ -910,21 +912,21 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx,
|
||||
}
|
||||
|
||||
vpic->decoded_curr_pic = (VAPictureHEVC) {
|
||||
.picture_id = pic->recon_surface,
|
||||
.picture_id = vaapi_pic->recon_surface,
|
||||
.pic_order_cnt = hpic->pic_order_cnt,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
for (int k = 0; k < MAX_REFERENCE_LIST_NUM; k++) {
|
||||
for (i = 0; i < pic->nb_refs[k]; i++) {
|
||||
VAAPIEncodePicture *ref = pic->refs[k][i];
|
||||
FFHWBaseEncodePicture *ref = pic->refs[k][i];
|
||||
VAAPIEncodeH265Picture *href;
|
||||
|
||||
av_assert0(ref && ref->encode_order < pic->encode_order);
|
||||
href = ref->priv_data;
|
||||
|
||||
vpic->reference_frames[j++] = (VAPictureHEVC) {
|
||||
.picture_id = ref->recon_surface,
|
||||
.picture_id = ((VAAPIEncodePicture *)ref)->recon_surface,
|
||||
.pic_order_cnt = href->pic_order_cnt,
|
||||
.flags = (ref->display_order < pic->display_order ?
|
||||
VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE : 0) |
|
||||
@ -941,7 +943,7 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx,
|
||||
};
|
||||
}
|
||||
|
||||
vpic->coded_buf = pic->output_buffer;
|
||||
vpic->coded_buf = vaapi_pic->output_buffer;
|
||||
|
||||
vpic->nal_unit_type = hpic->slice_nal_unit;
|
||||
|
||||
@ -971,16 +973,17 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx,
|
||||
}
|
||||
|
||||
static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx,
|
||||
VAAPIEncodePicture *pic,
|
||||
VAAPIEncodePicture *vaapi_pic,
|
||||
VAAPIEncodeSlice *slice)
|
||||
{
|
||||
VAAPIEncodeContext *ctx = avctx->priv_data;
|
||||
FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
|
||||
VAAPIEncodeH265Context *priv = avctx->priv_data;
|
||||
const FFHWBaseEncodePicture *pic = &vaapi_pic->base;
|
||||
VAAPIEncodeH265Picture *hpic = pic->priv_data;
|
||||
const H265RawSPS *sps = &priv->raw_sps;
|
||||
const H265RawPPS *pps = &priv->raw_pps;
|
||||
H265RawSliceHeader *sh = &priv->raw_slice.header;
|
||||
VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params;
|
||||
VAEncPictureParameterBufferHEVC *vpic = vaapi_pic->codec_picture_params;
|
||||
VAEncSliceParameterBufferHEVC *vslice = slice->codec_slice_params;
|
||||
int i;
|
||||
|
||||
@ -997,7 +1000,7 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx,
|
||||
|
||||
sh->slice_type = hpic->slice_type;
|
||||
|
||||
if (sh->slice_type == HEVC_SLICE_P && ctx->p_to_gpb)
|
||||
if (sh->slice_type == HEVC_SLICE_P && base_ctx->p_to_gpb)
|
||||
sh->slice_type = HEVC_SLICE_B;
|
||||
|
||||
sh->slice_pic_order_cnt_lsb = hpic->pic_order_cnt &
|
||||
@ -1141,7 +1144,7 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx,
|
||||
.slice_tc_offset_div2 = sh->slice_tc_offset_div2,
|
||||
|
||||
.slice_fields.bits = {
|
||||
.last_slice_of_pic_flag = slice->index == pic->nb_slices - 1,
|
||||
.last_slice_of_pic_flag = slice->index == vaapi_pic->nb_slices - 1,
|
||||
.dependent_slice_segment_flag = sh->dependent_slice_segment_flag,
|
||||
.colour_plane_id = sh->colour_plane_id,
|
||||
.slice_temporal_mvp_enabled_flag =
|
||||
@ -1172,7 +1175,7 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx,
|
||||
av_assert0(pic->type == FF_HW_PICTURE_TYPE_P ||
|
||||
pic->type == FF_HW_PICTURE_TYPE_B);
|
||||
vslice->ref_pic_list0[0] = vpic->reference_frames[0];
|
||||
if (ctx->p_to_gpb && pic->type == FF_HW_PICTURE_TYPE_P)
|
||||
if (base_ctx->p_to_gpb && pic->type == FF_HW_PICTURE_TYPE_P)
|
||||
// Reference for GPB B-frame, L0 == L1
|
||||
vslice->ref_pic_list1[0] = vpic->reference_frames[0];
|
||||
}
|
||||
@ -1182,7 +1185,7 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx,
|
||||
vslice->ref_pic_list1[0] = vpic->reference_frames[1];
|
||||
}
|
||||
|
||||
if (pic->type == FF_HW_PICTURE_TYPE_P && ctx->p_to_gpb) {
|
||||
if (pic->type == FF_HW_PICTURE_TYPE_P && base_ctx->p_to_gpb) {
|
||||
vslice->slice_type = HEVC_SLICE_B;
|
||||
for (i = 0; i < FF_ARRAY_ELEMS(vslice->ref_pic_list0); i++) {
|
||||
vslice->ref_pic_list1[i].picture_id = vslice->ref_pic_list0[i].picture_id;
|
||||
@ -1495,7 +1498,7 @@ const FFCodec ff_hevc_vaapi_encoder = {
|
||||
.p.id = AV_CODEC_ID_HEVC,
|
||||
.priv_data_size = sizeof(VAAPIEncodeH265Context),
|
||||
.init = &vaapi_encode_h265_init,
|
||||
FF_CODEC_RECEIVE_PACKET_CB(&ff_vaapi_encode_receive_packet),
|
||||
FF_CODEC_RECEIVE_PACKET_CB(&ff_hw_base_encode_receive_packet),
|
||||
.close = &vaapi_encode_h265_close,
|
||||
.p.priv_class = &vaapi_encode_h265_class,
|
||||
.p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
|
||||
|
@ -220,12 +220,13 @@ static int vaapi_encode_mjpeg_write_extra_buffer(AVCodecContext *avctx,
|
||||
}
|
||||
|
||||
static int vaapi_encode_mjpeg_init_picture_params(AVCodecContext *avctx,
|
||||
VAAPIEncodePicture *pic)
|
||||
VAAPIEncodePicture *vaapi_pic)
|
||||
{
|
||||
VAAPIEncodeMJPEGContext *priv = avctx->priv_data;
|
||||
const FFHWBaseEncodePicture *pic = &vaapi_pic->base;
|
||||
JPEGRawFrameHeader *fh = &priv->frame_header;
|
||||
JPEGRawScanHeader *sh = &priv->scan.header;
|
||||
VAEncPictureParameterBufferJPEG *vpic = pic->codec_picture_params;
|
||||
VAEncPictureParameterBufferJPEG *vpic = vaapi_pic->codec_picture_params;
|
||||
const AVPixFmtDescriptor *desc;
|
||||
const uint8_t components_rgb[3] = { 'R', 'G', 'B' };
|
||||
const uint8_t components_yuv[3] = { 1, 2, 3 };
|
||||
@ -377,8 +378,8 @@ static int vaapi_encode_mjpeg_init_picture_params(AVCodecContext *avctx,
|
||||
|
||||
|
||||
*vpic = (VAEncPictureParameterBufferJPEG) {
|
||||
.reconstructed_picture = pic->recon_surface,
|
||||
.coded_buf = pic->output_buffer,
|
||||
.reconstructed_picture = vaapi_pic->recon_surface,
|
||||
.coded_buf = vaapi_pic->output_buffer,
|
||||
|
||||
.picture_width = fh->X,
|
||||
.picture_height = fh->Y,
|
||||
@ -406,7 +407,7 @@ static int vaapi_encode_mjpeg_init_picture_params(AVCodecContext *avctx,
|
||||
vpic->quantiser_table_selector[i] = fh->Tq[i];
|
||||
}
|
||||
|
||||
pic->nb_slices = 1;
|
||||
vaapi_pic->nb_slices = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -572,7 +573,7 @@ const FFCodec ff_mjpeg_vaapi_encoder = {
|
||||
.p.id = AV_CODEC_ID_MJPEG,
|
||||
.priv_data_size = sizeof(VAAPIEncodeMJPEGContext),
|
||||
.init = &vaapi_encode_mjpeg_init,
|
||||
FF_CODEC_RECEIVE_PACKET_CB(&ff_vaapi_encode_receive_packet),
|
||||
FF_CODEC_RECEIVE_PACKET_CB(&ff_hw_base_encode_receive_packet),
|
||||
.close = &vaapi_encode_mjpeg_close,
|
||||
.p.priv_class = &vaapi_encode_mjpeg_class,
|
||||
.p.capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DR1 |
|
||||
|
@ -166,6 +166,7 @@ fail:
|
||||
|
||||
static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx)
|
||||
{
|
||||
FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
|
||||
VAAPIEncodeContext *ctx = avctx->priv_data;
|
||||
VAAPIEncodeMPEG2Context *priv = avctx->priv_data;
|
||||
MPEG2RawSequenceHeader *sh = &priv->sequence_header;
|
||||
@ -281,7 +282,7 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx)
|
||||
|
||||
se->bit_rate_extension = priv->bit_rate >> 18;
|
||||
se->vbv_buffer_size_extension = priv->vbv_buffer_size >> 10;
|
||||
se->low_delay = ctx->b_per_p == 0;
|
||||
se->low_delay = base_ctx->b_per_p == 0;
|
||||
|
||||
se->frame_rate_extension_n = ext_n;
|
||||
se->frame_rate_extension_d = ext_d;
|
||||
@ -353,8 +354,8 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx)
|
||||
|
||||
|
||||
*vseq = (VAEncSequenceParameterBufferMPEG2) {
|
||||
.intra_period = ctx->gop_size,
|
||||
.ip_period = ctx->b_per_p + 1,
|
||||
.intra_period = base_ctx->gop_size,
|
||||
.ip_period = base_ctx->b_per_p + 1,
|
||||
|
||||
.picture_width = avctx->width,
|
||||
.picture_height = avctx->height,
|
||||
@ -417,12 +418,13 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx)
|
||||
}
|
||||
|
||||
static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx,
|
||||
VAAPIEncodePicture *pic)
|
||||
VAAPIEncodePicture *vaapi_pic)
|
||||
{
|
||||
VAAPIEncodeMPEG2Context *priv = avctx->priv_data;
|
||||
const FFHWBaseEncodePicture *pic = &vaapi_pic->base;
|
||||
MPEG2RawPictureHeader *ph = &priv->picture_header;
|
||||
MPEG2RawPictureCodingExtension *pce = &priv->picture_coding_extension.data.picture_coding;
|
||||
VAEncPictureParameterBufferMPEG2 *vpic = pic->codec_picture_params;
|
||||
VAEncPictureParameterBufferMPEG2 *vpic = vaapi_pic->codec_picture_params;
|
||||
|
||||
if (pic->type == FF_HW_PICTURE_TYPE_IDR || pic->type == FF_HW_PICTURE_TYPE_I) {
|
||||
ph->temporal_reference = 0;
|
||||
@ -448,8 +450,8 @@ static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx,
|
||||
pce->f_code[1][1] = 15;
|
||||
}
|
||||
|
||||
vpic->reconstructed_picture = pic->recon_surface;
|
||||
vpic->coded_buf = pic->output_buffer;
|
||||
vpic->reconstructed_picture = vaapi_pic->recon_surface;
|
||||
vpic->coded_buf = vaapi_pic->output_buffer;
|
||||
|
||||
switch (pic->type) {
|
||||
case FF_HW_PICTURE_TYPE_IDR:
|
||||
@ -458,12 +460,12 @@ static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx,
|
||||
break;
|
||||
case FF_HW_PICTURE_TYPE_P:
|
||||
vpic->picture_type = VAEncPictureTypePredictive;
|
||||
vpic->forward_reference_picture = pic->refs[0][0]->recon_surface;
|
||||
vpic->forward_reference_picture = ((VAAPIEncodePicture *)pic->refs[0][0])->recon_surface;
|
||||
break;
|
||||
case FF_HW_PICTURE_TYPE_B:
|
||||
vpic->picture_type = VAEncPictureTypeBidirectional;
|
||||
vpic->forward_reference_picture = pic->refs[0][0]->recon_surface;
|
||||
vpic->backward_reference_picture = pic->refs[1][0]->recon_surface;
|
||||
vpic->forward_reference_picture = ((VAAPIEncodePicture *)pic->refs[0][0])->recon_surface;
|
||||
vpic->backward_reference_picture = ((VAAPIEncodePicture *)pic->refs[1][0])->recon_surface;
|
||||
break;
|
||||
default:
|
||||
av_assert0(0 && "invalid picture type");
|
||||
@ -479,11 +481,12 @@ static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx,
|
||||
}
|
||||
|
||||
static int vaapi_encode_mpeg2_init_slice_params(AVCodecContext *avctx,
|
||||
VAAPIEncodePicture *pic,
|
||||
VAAPIEncodeSlice *slice)
|
||||
VAAPIEncodePicture *vaapi_pic,
|
||||
VAAPIEncodeSlice *slice)
|
||||
{
|
||||
VAAPIEncodeMPEG2Context *priv = avctx->priv_data;
|
||||
VAEncSliceParameterBufferMPEG2 *vslice = slice->codec_slice_params;
|
||||
const FFHWBaseEncodePicture *pic = &vaapi_pic->base;
|
||||
VAAPIEncodeMPEG2Context *priv = avctx->priv_data;
|
||||
VAEncSliceParameterBufferMPEG2 *vslice = slice->codec_slice_params;
|
||||
int qp;
|
||||
|
||||
vslice->macroblock_address = slice->block_start;
|
||||
@ -695,7 +698,7 @@ const FFCodec ff_mpeg2_vaapi_encoder = {
|
||||
.p.id = AV_CODEC_ID_MPEG2VIDEO,
|
||||
.priv_data_size = sizeof(VAAPIEncodeMPEG2Context),
|
||||
.init = &vaapi_encode_mpeg2_init,
|
||||
FF_CODEC_RECEIVE_PACKET_CB(&ff_vaapi_encode_receive_packet),
|
||||
FF_CODEC_RECEIVE_PACKET_CB(&ff_hw_base_encode_receive_packet),
|
||||
.close = &vaapi_encode_mpeg2_close,
|
||||
.p.priv_class = &vaapi_encode_mpeg2_class,
|
||||
.p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
|
||||
|
@ -52,6 +52,7 @@ typedef struct VAAPIEncodeVP8Context {
|
||||
|
||||
static int vaapi_encode_vp8_init_sequence_params(AVCodecContext *avctx)
|
||||
{
|
||||
FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
|
||||
VAAPIEncodeContext *ctx = avctx->priv_data;
|
||||
VAEncSequenceParameterBufferVP8 *vseq = ctx->codec_sequence_params;
|
||||
|
||||
@ -66,22 +67,23 @@ static int vaapi_encode_vp8_init_sequence_params(AVCodecContext *avctx)
|
||||
|
||||
if (!(ctx->va_rc_mode & VA_RC_CQP)) {
|
||||
vseq->bits_per_second = ctx->va_bit_rate;
|
||||
vseq->intra_period = ctx->gop_size;
|
||||
vseq->intra_period = base_ctx->gop_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vaapi_encode_vp8_init_picture_params(AVCodecContext *avctx,
|
||||
VAAPIEncodePicture *pic)
|
||||
VAAPIEncodePicture *vaapi_pic)
|
||||
{
|
||||
const FFHWBaseEncodePicture *pic = &vaapi_pic->base;
|
||||
VAAPIEncodeVP8Context *priv = avctx->priv_data;
|
||||
VAEncPictureParameterBufferVP8 *vpic = pic->codec_picture_params;
|
||||
VAEncPictureParameterBufferVP8 *vpic = vaapi_pic->codec_picture_params;
|
||||
int i;
|
||||
|
||||
vpic->reconstructed_frame = pic->recon_surface;
|
||||
vpic->reconstructed_frame = vaapi_pic->recon_surface;
|
||||
|
||||
vpic->coded_buf = pic->output_buffer;
|
||||
vpic->coded_buf = vaapi_pic->output_buffer;
|
||||
|
||||
switch (pic->type) {
|
||||
case FF_HW_PICTURE_TYPE_IDR:
|
||||
@ -101,7 +103,7 @@ static int vaapi_encode_vp8_init_picture_params(AVCodecContext *avctx,
|
||||
vpic->ref_last_frame =
|
||||
vpic->ref_gf_frame =
|
||||
vpic->ref_arf_frame =
|
||||
pic->refs[0][0]->recon_surface;
|
||||
((VAAPIEncodePicture *)pic->refs[0][0])->recon_surface;
|
||||
break;
|
||||
default:
|
||||
av_assert0(0 && "invalid picture type");
|
||||
@ -145,7 +147,7 @@ static int vaapi_encode_vp8_write_quant_table(AVCodecContext *avctx,
|
||||
|
||||
memset(&quant, 0, sizeof(quant));
|
||||
|
||||
if (pic->type == FF_HW_PICTURE_TYPE_P)
|
||||
if (pic->base.type == FF_HW_PICTURE_TYPE_P)
|
||||
q = priv->q_index_p;
|
||||
else
|
||||
q = priv->q_index_i;
|
||||
@ -250,7 +252,7 @@ const FFCodec ff_vp8_vaapi_encoder = {
|
||||
.p.id = AV_CODEC_ID_VP8,
|
||||
.priv_data_size = sizeof(VAAPIEncodeVP8Context),
|
||||
.init = &vaapi_encode_vp8_init,
|
||||
FF_CODEC_RECEIVE_PACKET_CB(&ff_vaapi_encode_receive_packet),
|
||||
FF_CODEC_RECEIVE_PACKET_CB(&ff_hw_base_encode_receive_packet),
|
||||
.close = &ff_vaapi_encode_close,
|
||||
.p.priv_class = &vaapi_encode_vp8_class,
|
||||
.p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
|
||||
|
@ -53,6 +53,7 @@ typedef struct VAAPIEncodeVP9Context {
|
||||
|
||||
static int vaapi_encode_vp9_init_sequence_params(AVCodecContext *avctx)
|
||||
{
|
||||
FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
|
||||
VAAPIEncodeContext *ctx = avctx->priv_data;
|
||||
VAEncSequenceParameterBufferVP9 *vseq = ctx->codec_sequence_params;
|
||||
VAEncPictureParameterBufferVP9 *vpic = ctx->codec_picture_params;
|
||||
@ -64,7 +65,7 @@ static int vaapi_encode_vp9_init_sequence_params(AVCodecContext *avctx)
|
||||
|
||||
if (!(ctx->va_rc_mode & VA_RC_CQP)) {
|
||||
vseq->bits_per_second = ctx->va_bit_rate;
|
||||
vseq->intra_period = ctx->gop_size;
|
||||
vseq->intra_period = base_ctx->gop_size;
|
||||
}
|
||||
|
||||
vpic->frame_width_src = avctx->width;
|
||||
@ -76,17 +77,18 @@ static int vaapi_encode_vp9_init_sequence_params(AVCodecContext *avctx)
|
||||
}
|
||||
|
||||
static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx,
|
||||
VAAPIEncodePicture *pic)
|
||||
VAAPIEncodePicture *vaapi_pic)
|
||||
{
|
||||
VAAPIEncodeContext *ctx = avctx->priv_data;
|
||||
FFHWBaseEncodeContext *base_ctx = avctx->priv_data;
|
||||
VAAPIEncodeVP9Context *priv = avctx->priv_data;
|
||||
const FFHWBaseEncodePicture *pic = &vaapi_pic->base;
|
||||
VAAPIEncodeVP9Picture *hpic = pic->priv_data;
|
||||
VAEncPictureParameterBufferVP9 *vpic = pic->codec_picture_params;
|
||||
VAEncPictureParameterBufferVP9 *vpic = vaapi_pic->codec_picture_params;
|
||||
int i;
|
||||
int num_tile_columns;
|
||||
|
||||
vpic->reconstructed_frame = pic->recon_surface;
|
||||
vpic->coded_buf = pic->output_buffer;
|
||||
vpic->reconstructed_frame = vaapi_pic->recon_surface;
|
||||
vpic->coded_buf = vaapi_pic->output_buffer;
|
||||
|
||||
// Maximum width of a tile in units of superblocks is MAX_TILE_WIDTH_B64(64)
|
||||
// So the number of tile columns is related to the width of the picture.
|
||||
@ -107,7 +109,7 @@ static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx,
|
||||
VAAPIEncodeVP9Picture *href = pic->refs[0][0]->priv_data;
|
||||
av_assert0(href->slot == 0 || href->slot == 1);
|
||||
|
||||
if (ctx->max_b_depth > 0) {
|
||||
if (base_ctx->max_b_depth > 0) {
|
||||
hpic->slot = !href->slot;
|
||||
vpic->refresh_frame_flags = 1 << hpic->slot | 0xfc;
|
||||
} else {
|
||||
@ -127,7 +129,7 @@ static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx,
|
||||
av_assert0(href0->slot < pic->b_depth + 1 &&
|
||||
href1->slot < pic->b_depth + 1);
|
||||
|
||||
if (pic->b_depth == ctx->max_b_depth) {
|
||||
if (pic->b_depth == base_ctx->max_b_depth) {
|
||||
// Unreferenced frame.
|
||||
vpic->refresh_frame_flags = 0x00;
|
||||
hpic->slot = 8;
|
||||
@ -159,11 +161,11 @@ static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx,
|
||||
|
||||
for (i = 0; i < MAX_REFERENCE_LIST_NUM; i++) {
|
||||
for (int j = 0; j < pic->nb_refs[i]; j++) {
|
||||
VAAPIEncodePicture *ref_pic = pic->refs[i][j];
|
||||
FFHWBaseEncodePicture *ref_pic = pic->refs[i][j];
|
||||
int slot;
|
||||
slot = ((VAAPIEncodeVP9Picture*)ref_pic->priv_data)->slot;
|
||||
av_assert0(vpic->reference_frames[slot] == VA_INVALID_SURFACE);
|
||||
vpic->reference_frames[slot] = ref_pic->recon_surface;
|
||||
vpic->reference_frames[slot] = ((VAAPIEncodePicture *)ref_pic)->recon_surface;
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,7 +309,7 @@ const FFCodec ff_vp9_vaapi_encoder = {
|
||||
.p.id = AV_CODEC_ID_VP9,
|
||||
.priv_data_size = sizeof(VAAPIEncodeVP9Context),
|
||||
.init = &vaapi_encode_vp9_init,
|
||||
FF_CODEC_RECEIVE_PACKET_CB(&ff_vaapi_encode_receive_packet),
|
||||
FF_CODEC_RECEIVE_PACKET_CB(&ff_hw_base_encode_receive_packet),
|
||||
.close = &ff_vaapi_encode_close,
|
||||
.p.priv_class = &vaapi_encode_vp9_class,
|
||||
.p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
|
||||
|
Loading…
Reference in New Issue
Block a user