History

lavc/vaapi_encode: Add VAAPI AV1 encoder

Fei Wang committed 3 years ago

Commit 3be81e31 parent 254c5a811 files · +1311 −33Browse files

Unified · Split

11 files
  1. Changelog +1 −0
  2. configure +3 −0
  3. doc/encoders.texi +14 −0
  4. libavcodec/Makefile +2 −0
  5. libavcodec/allcodecs.c +1 −0
  6. libavcodec/av1_levels.c +92 −0
  7. libavcodec/av1_levels.h +58 −0
  8. libavcodec/vaapi_encode.c +166 −32
  9. libavcodec/vaapi_encode.h +24 −0
  10. libavcodec/vaapi_encode_av1.c +949 −0
  11. libavcodec/version.h +1 −1
Changelog+1−0
@@ -34,6 +34,7 @@ version <next>: · 33 unmodified lines
3434 - Support HEVC,VP9,AV1 codec fourcclist in enhanced rtmp protocol
3535 - CRI USM demuxer
3636 - ffmpeg CLI '-top' option deprecated in favor of the setfield filter
37+- VAAPI AV1 encoder
3738
3839
3940 version 6.0:
configure+3−0
@@ -3323,6 +3323,8 @@ av1_qsv_decoder_select="qsvdec" · 3322 unmodified lines
33233323 av1_qsv_encoder_select="qsvenc"
33243324 av1_qsv_encoder_deps="libvpl"
33253325 av1_amf_encoder_deps="amf"
3326+av1_vaapi_encoder_deps="VAEncPictureParameterBufferAV1"
3327+av1_vaapi_encoder_select="cbs_av1 vaapi_encode"
33263328
33273329 # parsers
33283330 aac_parser_select="adts_header mpeg4audio"
@@ -7108,6 +7110,7 @@ if enabled vaapi; then · 3779 unmodified lines
71087110 check_type "va/va.h va/va_enc_jpeg.h" "VAEncPictureParameterBufferJPEG"
71097111 check_type "va/va.h va/va_enc_vp8.h" "VAEncPictureParameterBufferVP8"
71107112 check_type "va/va.h va/va_enc_vp9.h" "VAEncPictureParameterBufferVP9"
7113+ check_type "va/va.h va/va_enc_av1.h" "VAEncPictureParameterBufferAV1"
71117114 fi
71127115
71137116 if enabled_all opencl libdrm ; then
doc/encoders.texi+14−0
@@ -3995,6 +3995,20 @@ Average variable bitrate. · 3994 unmodified lines
39953995 Each encoder also has its own specific options:
39963996 @table @option
39973997
3998+@item av1_vaapi
3999+@option{profile} sets the value of @emph{seq_profile}.
4000+@option{tier} sets the value of @emph{seq_tier}.
4001+@option{level} sets the value of @emph{seq_level_idx}.
4002+
4003+@table @option
4004+@item tiles
4005+Set the number of tiles to encode the input video with, as columns x rows.
4006+(default is auto, which means use minimal tile column/row number).
4007+@item tile_groups
4008+Set tile groups number. All the tiles will be distributed as evenly as possible to
4009+each tile group. (default is 1).
4010+@end table
4011+
39984012 @item h264_vaapi
39994013 @option{profile} sets the value of @emph{profile_idc} and the @emph{constraint_set*_flag}s.
40004014 @option{level} sets the value of @emph{level_idc}.
libavcodec/Makefile+2−0
@@ -258,6 +258,7 @@ OBJS-$(CONFIG_AV1_MEDIACODEC_DECODER) += mediacodecdec.o · 257 unmodified lines
258258 OBJS-$(CONFIG_AV1_MEDIACODEC_ENCODER) += mediacodecenc.o
259259 OBJS-$(CONFIG_AV1_NVENC_ENCODER) += nvenc_av1.o nvenc.o
260260 OBJS-$(CONFIG_AV1_QSV_ENCODER) += qsvenc_av1.o
261+OBJS-$(CONFIG_AV1_VAAPI_ENCODER) += vaapi_encode_av1.o av1_levels.o
261262 OBJS-$(CONFIG_AVRN_DECODER) += avrndec.o
262263 OBJS-$(CONFIG_AVRP_DECODER) += r210dec.o
263264 OBJS-$(CONFIG_AVRP_ENCODER) += r210enc.o
@@ -1322,6 +1323,7 @@ TESTPROGS = avcodec \ · 1058 unmodified lines
13221323 jpeg2000dwt \
13231324 mathops \
13241325
1326+TESTPROGS-$(CONFIG_AV1_VAAPI_ENCODER) += av1_levels
13251327 TESTPROGS-$(CONFIG_CABAC) += cabac
13261328 TESTPROGS-$(CONFIG_DCT) += avfft
13271329 TESTPROGS-$(CONFIG_FFT) += fft fft-fixed32
libavcodec/allcodecs.c+1−0
@@ -845,6 +845,7 @@ extern const FFCodec ff_av1_nvenc_encoder; · 844 unmodified lines
845845 extern const FFCodec ff_av1_qsv_decoder;
846846 extern const FFCodec ff_av1_qsv_encoder;
847847 extern const FFCodec ff_av1_amf_encoder;
848+extern const FFCodec ff_av1_vaapi_encoder;
848849 extern const FFCodec ff_libopenh264_encoder;
849850 extern const FFCodec ff_libopenh264_decoder;
850851 extern const FFCodec ff_h264_amf_encoder;
libavcodec/av1_levels.c+92−0
@@ -0,0 +1,92 @@
1+/*
2+ * Copyright (c) 2023 Intel Corporation
3+ *
4+ * This file is part of FFmpeg.
5+ *
6+ * FFmpeg is free software; you can redistribute it and/or
7+ * modify it under the terms of the GNU Lesser General Public
8+ * License as published by the Free Software Foundation; either
9+ * version 2.1 of the License, or (at your option) any later version.
10+ *
11+ * FFmpeg is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+ * Lesser General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU Lesser General Public
17+ * License along with FFmpeg; if not, write to the Free Software
18+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19+ */
20+
21+#include <stddef.h>
22+#include "libavutil/macros.h"
23+#include "av1_levels.h"
24+
25+/** ignore entries which named in spec but no details. Like level 2.2 and 7.0. */
26+static const AV1LevelDescriptor av1_levels[] = {
27+ // Name MaxVSize MainMbps MaxTiles
28+ // | level_idx | MaxDisplayRate | HighMbps | MaxTileCols
29+ // | | MaxPicSize | | MaxDecodeRate | | MainCR | |
30+ // | | | MaxHSize | | | MaxHeaderRate | | | HighCR| |
31+ // | | | | | | | | | | | | | |
32+ { "2.0", 0, 147456, 2048, 1152, 4423680, 5529600, 150, 1.5, 0, 2, 0, 8, 4 },
33+ { "2.1", 1, 278784, 2816, 1584, 8363520, 10454400, 150, 3.0, 0, 2, 0, 8, 4 },
34+ { "3.0", 4, 665856, 4352, 2448, 19975680, 24969600, 150, 6.0, 0, 2, 0, 16, 6 },
35+ { "3.1", 5, 1065024, 5504, 3096, 31950720, 39938400, 150, 10.0, 0, 2, 0, 16, 6 },
36+ { "4.0", 8, 2359296, 6144, 3456, 70778880, 77856768, 300, 12.0, 30.0, 4, 4, 32, 8 },
37+ { "4.1", 9, 2359296, 6144, 3456, 141557760, 155713536, 300, 20.0, 50.0, 4, 4, 32, 8 },
38+ { "5.0", 12, 8912896, 8192, 4352, 267386880, 273715200, 300, 30.0, 100.0, 6, 4, 64, 8 },
39+ { "5.1", 13, 8912896, 8192, 4352, 534773760, 547430400, 300, 40.0, 160.0, 8, 4, 64, 8 },
40+ { "5.2", 14, 8912896, 8192, 4352, 1069547520, 1094860800, 300, 60.0, 240.0, 8, 4, 64, 8 },
41+ { "5.3", 15, 8912896, 8192, 4352, 1069547520, 1176502272, 300, 60.0, 240.0, 8, 4, 64, 8 },
42+ { "6.0", 16, 35651584, 16384, 8704, 1069547520, 1176502272, 300, 60.0, 240.0, 8, 4, 128, 16 },
43+ { "6.1", 17, 35651584, 16384, 8704, 2139095040, 2189721600, 300, 100.0, 480.0, 8, 4, 128, 16 },
44+ { "6.2", 18, 35651584, 16384, 8704, 4278190080, 4379443200, 300, 160.0, 800.0, 8, 4, 128, 16 },
45+ { "6.3", 19, 35651584, 16384, 8704, 4278190080, 4706009088, 300, 160.0, 800.0, 8, 4, 128, 16 },
46+};
47+
48+const AV1LevelDescriptor *ff_av1_guess_level(int64_t bitrate,
49+ int tier,
50+ int width,
51+ int height,
52+ int tiles,
53+ int tile_cols,
54+ float fps)
55+{
56+ int pic_size;
57+ uint64_t display_rate;
58+ float max_br;
59+
60+ pic_size = width * height;
61+ display_rate = (uint64_t)pic_size * fps;
62+
63+ for (int i = 0; i < FF_ARRAY_ELEMS(av1_levels); i++) {
64+ const AV1LevelDescriptor *level = &av1_levels[i];
65+ // Limitation: decode rate, header rate, compress rate, etc. are not considered.
66+ if (pic_size > level->max_pic_size)
67+ continue;
68+ if (width > level->max_h_size)
69+ continue;
70+ if (height > level->max_v_size)
71+ continue;
72+ if (display_rate > level->max_display_rate)
73+ continue;
74+
75+ if (tier)
76+ max_br = level->high_mbps;
77+ else
78+ max_br = level->main_mbps;
79+ if (!max_br)
80+ continue;
81+ if (bitrate > (int64_t)(1000000.0 * max_br))
82+ continue;
83+
84+ if (tiles > level->max_tiles)
85+ continue;
86+ if (tile_cols > level->max_tile_cols)
87+ continue;
88+ return level;
89+ }
90+
91+ return NULL;
92+}
libavcodec/av1_levels.h+58−0
@@ -0,0 +1,58 @@
1+/*
2+ * Copyright (c) 2023 Intel Corporation
3+ *
4+ * This file is part of FFmpeg.
5+ *
6+ * FFmpeg is free software; you can redistribute it and/or
7+ * modify it under the terms of the GNU Lesser General Public
8+ * License as published by the Free Software Foundation; either
9+ * version 2.1 of the License, or (at your option) any later version.
10+ *
11+ * FFmpeg is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+ * Lesser General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU Lesser General Public
17+ * License along with FFmpeg; if not, write to the Free Software
18+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19+ */
20+
21+#ifndef AVCODEC_AV1_LEVELS_H
22+#define AVCODEC_AV1_LEVELS_H
23+
24+#include <stdint.h>
25+
26+typedef struct AV1LevelDescriptor {
27+ char name[4];
28+ uint8_t level_idx;
29+
30+ uint32_t max_pic_size;
31+ uint32_t max_h_size;
32+ uint32_t max_v_size;
33+ uint64_t max_display_rate;
34+ uint64_t max_decode_rate;
35+
36+ uint32_t max_header_rate;
37+ float main_mbps;
38+ float high_mbps;
39+ uint32_t main_cr;
40+ uint32_t high_cr;
41+ uint32_t max_tiles;
42+ uint32_t max_tile_cols;
43+} AV1LevelDescriptor;
44+
45+/**
46+ * Guess the level of a stream from some parameters.
47+ *
48+ * Unknown parameters may be zero, in which case they will be ignored.
49+ */
50+const AV1LevelDescriptor *ff_av1_guess_level(int64_t bitrate,
51+ int tier,
52+ int width,
53+ int height,
54+ int tile_rows,
55+ int tile_cols,
56+ float fps);
57+
58+#endif /* AVCODEC_AV1_LEVELS_H */
libavcodec/vaapi_encode.c+166−32
@@ -683,6 +683,11 @@ static int vaapi_encode_set_output_property(AVCodecContext *avctx, · 682 unmodified lines
683683 pic->opaque_ref = NULL;
684684 }
685685
686+ if (ctx->codec->flags & FLAG_TIMESTAMP_NO_DELAY) {
687+ pkt->dts = pkt->pts;
688+ return 0;
689+ }
690+
686691 if (ctx->output_delay == 0) {
687692 pkt->dts = pkt->pts;
688693 } else if (pic->encode_order < ctx->decode_delay) {
@@ -698,65 +703,160 @@ static int vaapi_encode_set_output_property(AVCodecContext *avctx, · 9 unmodified lines
698703 return 0;
699704 }
700705
701−static int vaapi_encode_output(AVCodecContext *avctx,
702− VAAPIEncodePicture *pic, AVPacket *pkt)
706+static int vaapi_encode_get_coded_buffer_size(AVCodecContext *avctx, VABufferID buf_id)
703707 {
704708 VAAPIEncodeContext *ctx = avctx->priv_data;
705709 VACodedBufferSegment *buf_list, *buf;
710+ int size = 0;
706711 VAStatus vas;
707− int total_size = 0;
708− uint8_t *ptr;
709712 int err;
710713
711− err = vaapi_encode_wait(avctx, pic);
712− if (err < 0)
713− return err;
714−
715− buf_list = NULL;
716− vas = vaMapBuffer(ctx->hwctx->display, pic->output_buffer,
714+ vas = vaMapBuffer(ctx->hwctx->display, buf_id,
717715 (void**)&buf_list);
718716 if (vas != VA_STATUS_SUCCESS) {
719717 av_log(avctx, AV_LOG_ERROR, "Failed to map output buffers: "
720718 "%d (%s).\n", vas, vaErrorStr(vas));
721719 err = AVERROR(EIO);
722− goto fail;
720+ return err;
723721 }
724722
725723 for (buf = buf_list; buf; buf = buf->next)
726− total_size += buf->size;
724+ size += buf->size;
727725
728− err = ff_get_encode_buffer(avctx, pkt, total_size, 0);
729− ptr = pkt->data;
726+ vas = vaUnmapBuffer(ctx->hwctx->display, buf_id);
727+ if (vas != VA_STATUS_SUCCESS) {
728+ av_log(avctx, AV_LOG_ERROR, "Failed to unmap output buffers: "
729+ "%d (%s).\n", vas, vaErrorStr(vas));
730+ err = AVERROR(EIO);
731+ return err;
732+ }
730733
731− if (err < 0)
732− goto fail_mapped;
734+ return size;
735+}
736+
737+static int vaapi_encode_get_coded_buffer_data(AVCodecContext *avctx,
738+ VABufferID buf_id, uint8_t **dst)
739+{
740+ VAAPIEncodeContext *ctx = avctx->priv_data;
741+ VACodedBufferSegment *buf_list, *buf;
742+ VAStatus vas;
743+ int err;
744+
745+ vas = vaMapBuffer(ctx->hwctx->display, buf_id,
746+ (void**)&buf_list);
747+ if (vas != VA_STATUS_SUCCESS) {
748+ av_log(avctx, AV_LOG_ERROR, "Failed to map output buffers: "
749+ "%d (%s).\n", vas, vaErrorStr(vas));
750+ err = AVERROR(EIO);
751+ return err;
752+ }
733753
734754 for (buf = buf_list; buf; buf = buf->next) {
735755 av_log(avctx, AV_LOG_DEBUG, "Output buffer: %u bytes "
736756 "(status %08x).\n", buf->size, buf->status);
737757
738− memcpy(ptr, buf->buf, buf->size);
739− ptr += buf->size;
758+ memcpy(*dst, buf->buf, buf->size);
759+ *dst += buf->size;
740760 }
741761
742− vas = vaUnmapBuffer(ctx->hwctx->display, pic->output_buffer);
762+ vas = vaUnmapBuffer(ctx->hwctx->display, buf_id);
743763 if (vas != VA_STATUS_SUCCESS) {
744764 av_log(avctx, AV_LOG_ERROR, "Failed to unmap output buffers: "
745765 "%d (%s).\n", vas, vaErrorStr(vas));
746766 err = AVERROR(EIO);
747− goto fail;
767+ return err;
768+ }
769+
770+ return 0;
771+}
772+
773+static int vaapi_encode_get_coded_data(AVCodecContext *avctx,
774+ VAAPIEncodePicture *pic, AVPacket *pkt)
775+{
776+ VAAPIEncodeContext *ctx = avctx->priv_data;
777+ VABufferID output_buffer_prev;
778+ int total_size = 0;
779+ uint8_t *ptr;
780+ int ret;
781+
782+ if (ctx->coded_buffer_ref) {
783+ output_buffer_prev = (VABufferID)(uintptr_t)ctx->coded_buffer_ref->data;
784+ ret = vaapi_encode_get_coded_buffer_size(avctx, output_buffer_prev);
785+ if (ret < 0)
786+ goto end;
787+ total_size += ret;
748788 }
749789
790+ ret = vaapi_encode_get_coded_buffer_size(avctx, pic->output_buffer);
791+ if (ret < 0)
792+ goto end;
793+ total_size += ret;
794+
795+ ret = ff_get_encode_buffer(avctx, pkt, total_size, 0);
796+ if (ret < 0)
797+ goto end;
798+ ptr = pkt->data;
799+
800+ if (ctx->coded_buffer_ref) {
801+ ret = vaapi_encode_get_coded_buffer_data(avctx, output_buffer_prev, &ptr);
802+ if (ret < 0)
803+ goto end;
804+ }
805+
806+ ret = vaapi_encode_get_coded_buffer_data(avctx, pic->output_buffer, &ptr);
807+ if (ret < 0)
808+ goto end;
809+
810+end:
811+ if (ctx->coded_buffer_ref) {
812+ av_buffer_unref(&ctx->coded_buffer_ref);
813+ }
750814 av_buffer_unref(&pic->output_buffer_ref);
751815 pic->output_buffer = VA_INVALID_ID;
752816
817+ return ret;
818+}
819+
820+static int vaapi_encode_output(AVCodecContext *avctx,
821+ VAAPIEncodePicture *pic, AVPacket *pkt)
822+{
823+ VAAPIEncodeContext *ctx = avctx->priv_data;
824+ AVPacket *pkt_ptr = pkt;
825+ int err;
826+
827+ err = vaapi_encode_wait(avctx, pic);
828+ if (err < 0)
829+ return err;
830+
831+ if (pic->non_independent_frame) {
832+ av_assert0(!ctx->coded_buffer_ref);
833+ ctx->coded_buffer_ref = av_buffer_ref(pic->output_buffer_ref);
834+
835+ if (pic->tail_size) {
836+ if (ctx->tail_pkt->size) {
837+ err = AVERROR(AVERROR_BUG);
838+ goto end;
839+ }
840+
841+ err = ff_get_encode_buffer(avctx, ctx->tail_pkt, pic->tail_size, 0);
842+ if (err < 0)
843+ goto end;
844+
845+ memcpy(ctx->tail_pkt->data, pic->tail_data, pic->tail_size);
846+ pkt_ptr = ctx->tail_pkt;
847+ }
848+ } else {
849+ err = vaapi_encode_get_coded_data(avctx, pic, pkt);
850+ if (err < 0)
851+ goto end;
852+ }
853+
753854 av_log(avctx, AV_LOG_DEBUG, "Output read for pic %"PRId64"/%"PRId64".\n",
754855 pic->display_order, pic->encode_order);
755− return 0;
756856
757−fail_mapped:
758− vaUnmapBuffer(ctx->hwctx->display, pic->output_buffer);
759−fail:
857+ vaapi_encode_set_output_property(avctx, pic, pkt_ptr);
858+
859+end:
760860 av_buffer_unref(&pic->output_buffer_ref);
761861 pic->output_buffer = VA_INVALID_ID;
762862 return err;
@@ -1128,9 +1228,19 @@ static int vaapi_encode_pick_next(AVCodecContext *avctx, · 365 unmodified lines
11281228
11291229 vaapi_encode_add_ref(avctx, pic, pic, 0, 1, 0);
11301230 if (pic->type != PICTURE_TYPE_IDR) {
1131− vaapi_encode_add_ref(avctx, pic, start,
1132− pic->type == PICTURE_TYPE_P,
1133− b_counter > 0, 0);
1231+ // TODO: apply both previous and forward multi reference for all vaapi encoders.
1232+ // And L0/L1 reference frame number can be set dynamically through query
1233+ // VAConfigAttribEncMaxRefFrames attribute.
1234+ if (avctx->codec_id == AV_CODEC_ID_AV1) {
1235+ for (i = 0; i < ctx->nb_next_prev; i++)
1236+ vaapi_encode_add_ref(avctx, pic, ctx->next_prev[i],
1237+ pic->type == PICTURE_TYPE_P,
1238+ b_counter > 0, 0);
1239+ } else
1240+ vaapi_encode_add_ref(avctx, pic, start,
1241+ pic->type == PICTURE_TYPE_P,
1242+ b_counter > 0, 0);
1243+
11341244 vaapi_encode_add_ref(avctx, pic, ctx->next_prev[ctx->nb_next_prev - 1], 0, 0, 1);
11351245 }
11361246
@@ -1292,6 +1402,19 @@ int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt) · 155 unmodified lines
12921402 AVFrame *frame = ctx->frame;
12931403 int err;
12941404
1405+start:
1406+ /** if no B frame before repeat P frame, sent repeat P frame out. */
1407+ if (ctx->tail_pkt->size) {
1408+ for (VAAPIEncodePicture *tmp = ctx->pic_start; tmp; tmp = tmp->next) {
1409+ if (tmp->type == PICTURE_TYPE_B && tmp->pts < ctx->tail_pkt->pts)
1410+ break;
1411+ else if (!tmp->next) {
1412+ av_packet_move_ref(pkt, ctx->tail_pkt);
1413+ goto end;
1414+ }
1415+ }
1416+ }
1417+
12951418 err = ff_encode_get_frame(avctx, frame);
12961419 if (err < 0 && err != AVERROR_EOF)
12971420 return err;
@@ -1356,17 +1479,21 @@ int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt) · 58 unmodified lines
13561479 return err;
13571480 }
13581481
1359− vaapi_encode_set_output_property(avctx, pic, pkt);
1360− av_log(avctx, AV_LOG_DEBUG, "Output packet: pts %"PRId64", dts %"PRId64", "
1361− "size %d bytes.\n", pkt->pts, pkt->dts, pkt->size);
1362−
13631482 ctx->output_order = pic->encode_order;
13641483 vaapi_encode_clear_old(avctx);
13651484
1485+ /** loop to get an available pkt in encoder flushing. */
1486+ if (ctx->end_of_stream && !pkt->size)
1487+ goto start;
1488+
1489+end:
1490+ if (pkt->size)
1491+ av_log(avctx, AV_LOG_DEBUG, "Output packet: pts %"PRId64", dts %"PRId64", "
1492+ "size %d bytes.\n", pkt->pts, pkt->dts, pkt->size);
1493+
13661494 return 0;
13671495 }
13681496
1369−
13701497 static av_cold void vaapi_encode_add_global_param(AVCodecContext *avctx, int type,
13711498 void *buffer, size_t size)
13721499 {
@@ -2667,6 +2794,12 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) · 1294 unmodified lines
26672794 ctx->device = (AVHWDeviceContext*)ctx->device_ref->data;
26682795 ctx->hwctx = ctx->device->hwctx;
26692796
2797+ ctx->tail_pkt = av_packet_alloc();
2798+ if (!ctx->tail_pkt) {
2799+ err = AVERROR(ENOMEM);
2800+ goto fail;
2801+ }
2802+
26702803 err = vaapi_encode_profile_entrypoint(avctx);
26712804 if (err < 0)
26722805 goto fail;
@@ -2859,6 +2992,7 @@ av_cold int ff_vaapi_encode_close(AVCodecContext *avctx) · 186 unmodified lines
28592992 }
28602993
28612994 av_frame_free(&ctx->frame);
2995+ av_packet_free(&ctx->tail_pkt);
28622996
28632997 av_freep(&ctx->codec_sequence_params);
28642998 av_freep(&ctx->codec_picture_params);
libavcodec/vaapi_encode.h+24−0
@@ -133,6 +133,17 @@ typedef struct VAAPIEncodePicture { · 132 unmodified lines
133133
134134 int nb_slices;
135135 VAAPIEncodeSlice *slices;
136+
137+ /**
138+ * indicate if current frame is an independent frame that the coded data
139+ * can be pushed to downstream directly. Coded of non-independent frame
140+ * data will be concatenated into next independent frame.
141+ */
142+ int non_independent_frame;
143+ /** Tail data of current pic, used only for repeat header of AV1. */
144+ char tail_data[MAX_PARAM_BUFFER_SIZE];
145+ /** Byte length of tail_data. */
146+ size_t tail_size;
136147 } VAAPIEncodePicture;
137148
138149 typedef struct VAAPIEncodeProfile {
@@ -367,6 +378,16 @@ typedef struct VAAPIEncodeContext { · 228 unmodified lines
367378 AVFifo *encode_fifo;
368379 // Max number of frame buffered in encoder.
369380 int async_depth;
381+
382+ /** Head data for current output pkt, used only for AV1. */
383+ //void *header_data;
384+ //size_t header_data_size;
385+
386+ /** Buffered coded data of a pic if it is an non-independent frame. */
387+ AVBufferRef *coded_buffer_ref;
388+
389+ /** Tail data of a pic, now only used for av1 repeat frame header. */
390+ AVPacket *tail_pkt;
370391 } VAAPIEncodeContext;
371392
372393 enum {
@@ -383,6 +404,9 @@ enum { · 10 unmodified lines
383404 // Codec supports non-IDR key pictures (that is, key pictures do
384405 // not necessarily empty the DPB).
385406 FLAG_NON_IDR_KEY_PICTURES = 1 << 5,
407+ // Codec output packet without timestamp delay, which means the
408+ // output packet has same PTS and DTS.
409+ FLAG_TIMESTAMP_NO_DELAY = 1 << 6,
386410 };
387411
388412 typedef struct VAAPIEncodeType {
libavcodec/vaapi_encode_av1.c+949−0
@@ -0,0 +1,949 @@
1+/*
2+ * Copyright (c) 2023 Intel Corporation
3+ *
4+ * This file is part of FFmpeg.
5+ *
6+ * FFmpeg is free software; you can redistribute it and/or
7+ * modify it under the terms of the GNU Lesser General Public
8+ * License as published by the Free Software Foundation; either
9+ * version 2.1 of the License, or (at your option) any later version.
10+ *
11+ * FFmpeg is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+ * Lesser General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU Lesser General Public
17+ * License along with FFmpeg; if not, write to the Free Software
18+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19+ */
20+
21+#include <va/va.h>
22+#include <va/va_enc_av1.h>
23+
24+#include "libavutil/pixdesc.h"
25+#include "libavutil/opt.h"
26+
27+#include "cbs_av1.h"
28+#include "put_bits.h"
29+#include "codec_internal.h"
30+#include "av1_levels.h"
31+#include "vaapi_encode.h"
32+
33+#define AV1_MAX_QUANT 255
34+
35+typedef struct VAAPIEncodeAV1Picture {
36+ int64_t last_idr_frame;
37+ int slot;
38+} VAAPIEncodeAV1Picture;
39+
40+typedef struct VAAPIEncodeAV1Context {
41+ VAAPIEncodeContext common;
42+ AV1RawOBU sh; /**< sequence header.*/
43+ AV1RawOBU fh; /**< frame header.*/
44+ CodedBitstreamContext *cbc;
45+ CodedBitstreamFragment current_obu;
46+ VAConfigAttribValEncAV1 attr;
47+ VAConfigAttribValEncAV1Ext1 attr_ext1;
48+ VAConfigAttribValEncAV1Ext2 attr_ext2;
49+
50+ char sh_data[MAX_PARAM_BUFFER_SIZE]; /**< coded sequence header data. */
51+ size_t sh_data_len; /**< bit length of sh_data. */
52+ char fh_data[MAX_PARAM_BUFFER_SIZE]; /**< coded frame header data. */
53+ size_t fh_data_len; /**< bit length of fh_data. */
54+
55+ uint8_t uniform_tile;
56+ uint8_t use_128x128_superblock;
57+ int sb_cols;
58+ int sb_rows;
59+ int tile_cols_log2;
60+ int tile_rows_log2;
61+ int max_tile_width_sb;
62+ int max_tile_height_sb;
63+ uint8_t width_in_sbs_minus_1[AV1_MAX_TILE_COLS];
64+ uint8_t height_in_sbs_minus_1[AV1_MAX_TILE_ROWS];
65+
66+ int min_log2_tile_cols;
67+ int max_log2_tile_cols;
68+ int min_log2_tile_rows;
69+ int max_log2_tile_rows;
70+
71+ int q_idx_idr;
72+ int q_idx_p;
73+ int q_idx_b;
74+
75+ /** bit positions in current frame header */
76+ int qindex_offset;
77+ int loopfilter_offset;
78+ int cdef_start_offset;
79+ int cdef_param_size;
80+
81+ /** user options */
82+ int profile;
83+ int level;
84+ int tier;
85+ int tile_cols, tile_rows;
86+ int tile_groups;
87+} VAAPIEncodeAV1Context;
88+
89+static void vaapi_encode_av1_trace_write_log(void *ctx,
90+ PutBitContext *pbc, int length,
91+ const char *str, const int *subscripts,
92+ int64_t value)
93+{
94+ VAAPIEncodeAV1Context *priv = ctx;
95+ int position;
96+
97+ position = put_bits_count(pbc);
98+ av_assert0(position >= length);
99+
100+ if (!strcmp(str, "base_q_idx"))
101+ priv->qindex_offset = position - length;
102+ else if (!strcmp(str, "loop_filter_level[0]"))
103+ priv->loopfilter_offset = position - length;
104+ else if (!strcmp(str, "cdef_damping_minus_3"))
105+ priv->cdef_start_offset = position - length;
106+ else if (!strcmp(str, "cdef_uv_sec_strength[i]"))
107+ priv->cdef_param_size = position - priv->cdef_start_offset;
108+}
109+
110+static av_cold int vaapi_encode_av1_get_encoder_caps(AVCodecContext *avctx)
111+{
112+ VAAPIEncodeContext *ctx = avctx->priv_data;
113+ VAAPIEncodeAV1Context *priv = avctx->priv_data;
114+
115+ // Surfaces must be aligned to superblock boundaries.
116+ ctx->surface_width = FFALIGN(avctx->width, priv->use_128x128_superblock ? 128 : 64);
117+ ctx->surface_height = FFALIGN(avctx->height, priv->use_128x128_superblock ? 128 : 64);
118+
119+ return 0;
120+}
121+
122+static av_cold int vaapi_encode_av1_configure(AVCodecContext *avctx)
123+{
124+ VAAPIEncodeContext *ctx = avctx->priv_data;
125+ VAAPIEncodeAV1Context *priv = avctx->priv_data;
126+ int ret;
127+
128+ ret = ff_cbs_init(&priv->cbc, AV_CODEC_ID_AV1, avctx);
129+ if (ret < 0)
130+ return ret;
131+ priv->cbc->trace_enable = 1;
132+ priv->cbc->trace_level = AV_LOG_DEBUG;
133+ priv->cbc->trace_context = ctx;
134+ priv->cbc->trace_write_callback = vaapi_encode_av1_trace_write_log;
135+
136+ if (ctx->rc_mode->quality) {
137+ priv->q_idx_p = av_clip(ctx->rc_quality, 0, AV1_MAX_QUANT);
138+ if (fabs(avctx->i_quant_factor) > 0.0)
139+ priv->q_idx_idr =
140+ av_clip((fabs(avctx->i_quant_factor) * priv->q_idx_p +
141+ avctx->i_quant_offset) + 0.5,
142+ 0, AV1_MAX_QUANT);
143+ else
144+ priv->q_idx_idr = priv->q_idx_p;
145+
146+ if (fabs(avctx->b_quant_factor) > 0.0)
147+ priv->q_idx_b =
148+ av_clip((fabs(avctx->b_quant_factor) * priv->q_idx_p +
149+ avctx->b_quant_offset) + 0.5,
150+ 0, AV1_MAX_QUANT);
151+ else
152+ priv->q_idx_b = priv->q_idx_p;
153+ } else {
154+ /** Arbitrary value */
155+ priv->q_idx_idr = priv->q_idx_p = priv->q_idx_b = 128;
156+ }
157+
158+ return 0;
159+}
160+
161+static int vaapi_encode_av1_add_obu(AVCodecContext *avctx,
162+ CodedBitstreamFragment *au,
163+ uint8_t type,
164+ void *obu_unit)
165+{
166+ int ret;
167+
168+ ret = ff_cbs_insert_unit_content(au, -1,
169+ type, obu_unit, NULL);
170+ if (ret < 0) {
171+ av_log(avctx, AV_LOG_ERROR, "Failed to add OBU unit: "
172+ "type = %d.\n", type);
173+ return ret;
174+ }
175+
176+ return 0;
177+}
178+
179+static int vaapi_encode_av1_write_obu(AVCodecContext *avctx,
180+ char *data, size_t *data_len,
181+ CodedBitstreamFragment *bs)
182+{
183+ VAAPIEncodeAV1Context *priv = avctx->priv_data;
184+ int ret;
185+
186+ ret = ff_cbs_write_fragment_data(priv->cbc, bs);
187+ if (ret < 0) {
188+ av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n");
189+ return ret;
190+ }
191+
192+ if ((size_t)8 * MAX_PARAM_BUFFER_SIZE < 8 * bs->data_size - bs->data_bit_padding) {
193+ av_log(avctx, AV_LOG_ERROR, "Access unit too large: "
194+ "%zu < %zu.\n", (size_t)8 * MAX_PARAM_BUFFER_SIZE,
195+ 8 * bs->data_size - bs->data_bit_padding);
196+ return AVERROR(ENOSPC);
197+ }
198+
199+ memcpy(data, bs->data, bs->data_size);
200+ *data_len = 8 * bs->data_size - bs->data_bit_padding;
201+
202+ return 0;
203+}
204+
205+static int tile_log2(int blkSize, int target) {
206+ int k;
207+ for (k = 0; (blkSize << k) < target; k++);
208+ return k;
209+}
210+
211+static int vaapi_encode_av1_set_tile(AVCodecContext *avctx)
212+{
213+ VAAPIEncodeAV1Context *priv = avctx->priv_data;
214+ int mi_cols, mi_rows, sb_shift, sb_size;
215+ int max_tile_area_sb, max_tile_area_sb_varied;
216+ int tile_width_sb, tile_height_sb, widest_tile_sb;
217+ int tile_cols, tile_rows;
218+ int min_log2_tiles;
219+ int i;
220+
221+ if (priv->tile_cols > AV1_MAX_TILE_COLS ||
222+ priv->tile_rows > AV1_MAX_TILE_ROWS) {
223+ av_log(avctx, AV_LOG_ERROR, "Invalid tile number %dx%d, should less than %dx%d.\n",
224+ priv->tile_cols, priv->tile_rows, AV1_MAX_TILE_COLS, AV1_MAX_TILE_ROWS);
225+ return AVERROR(EINVAL);
226+ }
227+
228+ mi_cols = 2 * ((avctx->width + 7) >> 3);
229+ mi_rows = 2 * ((avctx->height + 7) >> 3);
230+ priv->sb_cols = priv->use_128x128_superblock ?
231+ ((mi_cols + 31) >> 5) : ((mi_cols + 15) >> 4);
232+ priv->sb_rows = priv->use_128x128_superblock ?
233+ ((mi_rows + 31) >> 5) : ((mi_rows + 15) >> 4);
234+ sb_shift = priv->use_128x128_superblock ? 5 : 4;
235+ sb_size = sb_shift + 2;
236+ priv->max_tile_width_sb = AV1_MAX_TILE_WIDTH >> sb_size;
237+ max_tile_area_sb = AV1_MAX_TILE_AREA >> (2 * sb_size);
238+
239+ priv->min_log2_tile_cols = tile_log2(priv->max_tile_width_sb, priv->sb_cols);
240+ priv->max_log2_tile_cols = tile_log2(1, FFMIN(priv->sb_cols, AV1_MAX_TILE_COLS));
241+ priv->max_log2_tile_rows = tile_log2(1, FFMIN(priv->sb_rows, AV1_MAX_TILE_ROWS));
242+ min_log2_tiles = FFMAX(priv->min_log2_tile_cols,
243+ tile_log2(max_tile_area_sb, priv->sb_rows * priv->sb_cols));
244+
245+ tile_cols = av_clip(priv->tile_cols, (priv->sb_cols + priv->max_tile_width_sb - 1) / priv->max_tile_width_sb, priv->sb_cols);
246+
247+ if (!priv->tile_cols)
248+ priv->tile_cols = tile_cols;
249+ else if (priv->tile_cols != tile_cols){
250+ av_log(avctx, AV_LOG_ERROR, "Invalid tile cols %d, should be in range of %d~%d\n",
251+ priv->tile_cols,
252+ (priv->sb_cols + priv->max_tile_width_sb - 1) / priv->max_tile_width_sb,
253+ priv->sb_cols);
254+ return AVERROR(EINVAL);
255+ }
256+
257+ priv->tile_cols_log2 = tile_log2(1, priv->tile_cols);
258+ tile_width_sb = (priv->sb_cols + (1 << priv->tile_cols_log2) - 1) >>
259+ priv->tile_cols_log2;
260+
261+ if (priv->tile_rows > priv->sb_rows) {
262+ av_log(avctx, AV_LOG_ERROR, "Invalid tile rows %d, should be less than %d.\n",
263+ priv->tile_rows, priv->sb_rows);
264+ return AVERROR(EINVAL);
265+ }
266+
267+ /** Try user setting tile rows number first. */
268+ tile_rows = priv->tile_rows ? priv->tile_rows : 1;
269+ for (; tile_rows <= priv->sb_rows && tile_rows <= AV1_MAX_TILE_ROWS; tile_rows++) {
270+ /** try uniformed tile. */
271+ priv->tile_rows_log2 = tile_log2(1, tile_rows);
272+ if ((priv->sb_cols + tile_width_sb - 1) / tile_width_sb == priv->tile_cols) {
273+ for (i = 0; i < priv->tile_cols - 1; i++)
274+ priv->width_in_sbs_minus_1[i] = tile_width_sb - 1;
275+ priv->width_in_sbs_minus_1[i] = priv->sb_cols - (priv->tile_cols - 1) * tile_width_sb - 1;
276+
277+ tile_height_sb = (priv->sb_rows + (1 << priv->tile_rows_log2) - 1) >>
278+ priv->tile_rows_log2;
279+
280+ if ((priv->sb_rows + tile_height_sb - 1) / tile_height_sb == tile_rows &&
281+ tile_height_sb <= max_tile_area_sb / tile_width_sb) {
282+ for (i = 0; i < tile_rows - 1; i++)
283+ priv->height_in_sbs_minus_1[i] = tile_height_sb - 1;
284+ priv->height_in_sbs_minus_1[i] = priv->sb_rows - (tile_rows - 1) * tile_height_sb - 1;
285+
286+ priv->uniform_tile = 1;
287+ priv->min_log2_tile_rows = FFMAX(min_log2_tiles - priv->tile_cols_log2, 0);
288+
289+ break;
290+ }
291+ }
292+
293+ /** try non-uniformed tile. */
294+ widest_tile_sb = 0;
295+ for (i = 0; i < priv->tile_cols; i++) {
296+ priv->width_in_sbs_minus_1[i] = (i + 1) * priv->sb_cols / priv->tile_cols - i * priv->sb_cols / priv->tile_cols - 1;
297+ widest_tile_sb = FFMAX(widest_tile_sb, priv->width_in_sbs_minus_1[i] + 1);
298+ }
299+
300+ if (min_log2_tiles)
301+ max_tile_area_sb_varied = (priv->sb_rows * priv->sb_cols) >> (min_log2_tiles + 1);
302+ else
303+ max_tile_area_sb_varied = priv->sb_rows * priv->sb_cols;
304+ priv->max_tile_height_sb = FFMAX(1, max_tile_area_sb_varied / widest_tile_sb);
305+
306+ if (tile_rows == av_clip(tile_rows, (priv->sb_rows + priv->max_tile_height_sb - 1) / priv->max_tile_height_sb, priv->sb_rows)) {
307+ for (i = 0; i < tile_rows; i++)
308+ priv->height_in_sbs_minus_1[i] = (i + 1) * priv->sb_rows / tile_rows - i * priv->sb_rows / tile_rows - 1;
309+
310+ break;
311+ }
312+
313+ /** Return invalid parameter if explicit tile rows is set. */
314+ if (priv->tile_rows) {
315+ av_log(avctx, AV_LOG_ERROR, "Invalid tile rows %d.\n", priv->tile_rows);
316+ return AVERROR(EINVAL);
317+ }
318+ }
319+
320+ priv->tile_rows = tile_rows;
321+ av_log(avctx, AV_LOG_DEBUG, "Setting tile cols/rows to %d/%d.\n",
322+ priv->tile_cols, priv->tile_rows);
323+
324+ /** check if tile cols/rows is supported by driver. */
325+ if (priv->attr_ext2.bits.max_tile_num_minus1) {
326+ if ((priv->tile_cols * priv->tile_rows - 1) > priv->attr_ext2.bits.max_tile_num_minus1) {
327+ av_log(avctx, AV_LOG_ERROR, "Unsupported tile num %d * %d = %d by driver, "
328+ "should be at most %d.\n", priv->tile_cols, priv->tile_rows,
329+ priv->tile_cols * priv->tile_rows,
330+ priv->attr_ext2.bits.max_tile_num_minus1 + 1);
331+ return AVERROR(EINVAL);
332+ }
333+ }
334+
335+ /** check if tile group numbers is valid. */
336+ if (priv->tile_groups > priv->tile_cols * priv->tile_rows) {
337+ av_log(avctx, AV_LOG_WARNING, "Invalid tile groups number %d, "
338+ "correct to %d.\n", priv->tile_groups, priv->tile_cols * priv->tile_rows);
339+ priv->tile_groups = priv->tile_cols * priv->tile_rows;
340+ }
341+
342+ return 0;
343+}
344+
345+static int vaapi_encode_av1_write_sequence_header(AVCodecContext *avctx,
346+ char *data, size_t *data_len)
347+{
348+ VAAPIEncodeAV1Context *priv = avctx->priv_data;
349+
350+ memcpy(data, &priv->sh_data, MAX_PARAM_BUFFER_SIZE * sizeof(char));
351+ *data_len = priv->sh_data_len;
352+
353+ return 0;
354+}
355+
356+static int vaapi_encode_av1_init_sequence_params(AVCodecContext *avctx)
357+{
358+ VAAPIEncodeContext *ctx = avctx->priv_data;
359+ VAAPIEncodeAV1Context *priv = avctx->priv_data;
360+ AV1RawOBU *sh_obu = &priv->sh;
361+ AV1RawSequenceHeader *sh = &sh_obu->obu.sequence_header;
362+ VAEncSequenceParameterBufferAV1 *vseq = ctx->codec_sequence_params;
363+ CodedBitstreamFragment *obu = &priv->current_obu;
364+ const AVPixFmtDescriptor *desc;
365+ int ret;
366+
367+ memset(sh_obu, 0, sizeof(*sh_obu));
368+ sh_obu->header.obu_type = AV1_OBU_SEQUENCE_HEADER;
369+
370+ desc = av_pix_fmt_desc_get(priv->common.input_frames->sw_format);
371+ av_assert0(desc);
372+
373+ sh->seq_profile = avctx->profile;
374+ if (!sh->seq_force_screen_content_tools)
375+ sh->seq_force_integer_mv = AV1_SELECT_INTEGER_MV;
376+ sh->frame_width_bits_minus_1 = av_log2(avctx->width);
377+ sh->frame_height_bits_minus_1 = av_log2(avctx->height);
378+ sh->max_frame_width_minus_1 = avctx->width - 1;
379+ sh->max_frame_height_minus_1 = avctx->height - 1;
380+ sh->seq_tier[0] = priv->tier;
381+ /** enable order hint and reserve maximum 8 bits for it by default. */
382+ sh->enable_order_hint = 1;
383+ sh->order_hint_bits_minus_1 = 7;
384+
385+ sh->color_config = (AV1RawColorConfig) {
386+ .high_bitdepth = desc->comp[0].depth == 8 ? 0 : 1,
387+ .color_primaries = avctx->color_primaries,
388+ .transfer_characteristics = avctx->color_trc,
389+ .matrix_coefficients = avctx->colorspace,
390+ .color_description_present_flag = (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||
391+ avctx->color_trc != AVCOL_TRC_UNSPECIFIED ||
392+ avctx->colorspace != AVCOL_SPC_UNSPECIFIED),
393+ .color_range = avctx->color_range == AVCOL_RANGE_JPEG,
394+ .subsampling_x = desc->log2_chroma_w,
395+ .subsampling_y = desc->log2_chroma_h,
396+ };
397+
398+ switch (avctx->chroma_sample_location) {
399+ case AVCHROMA_LOC_LEFT:
400+ sh->color_config.chroma_sample_position = AV1_CSP_VERTICAL;
401+ break;
402+ case AVCHROMA_LOC_TOPLEFT:
403+ sh->color_config.chroma_sample_position = AV1_CSP_COLOCATED;
404+ break;
405+ default:
406+ sh->color_config.chroma_sample_position = AV1_CSP_UNKNOWN;
407+ break;
408+ }
409+
410+ if (avctx->level != AV_LEVEL_UNKNOWN) {
411+ sh->seq_level_idx[0] = avctx->level;
412+ } else {
413+ const AV1LevelDescriptor *level;
414+ float framerate;
415+
416+ if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
417+ framerate = avctx->framerate.num / avctx->framerate.den;
418+ else
419+ framerate = 0;
420+
421+ level = ff_av1_guess_level(avctx->bit_rate, priv->tier,
422+ ctx->surface_width, ctx->surface_height,
423+ priv->tile_rows * priv->tile_cols,
424+ priv->tile_cols, framerate);
425+ if (level) {
426+ av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name);
427+ sh->seq_level_idx[0] = level->level_idx;
428+ } else {
429+ av_log(avctx, AV_LOG_VERBOSE, "Stream will not conform to "
430+ "any normal level, using maximum parameters level by default.\n");
431+ sh->seq_level_idx[0] = 31;
432+ sh->seq_tier[0] = 1;
433+ }
434+ }
435+ vseq->seq_profile = sh->seq_profile;
436+ vseq->seq_level_idx = sh->seq_level_idx[0];
437+ vseq->seq_tier = sh->seq_tier[0];
438+ vseq->order_hint_bits_minus_1 = sh->order_hint_bits_minus_1;
439+ vseq->intra_period = ctx->gop_size;
440+ vseq->ip_period = ctx->b_per_p + 1;
441+
442+ vseq->seq_fields.bits.enable_order_hint = sh->enable_order_hint;
443+
444+ if (!(ctx->va_rc_mode & VA_RC_CQP)) {
445+ vseq->bits_per_second = ctx->va_bit_rate;
446+ vseq->seq_fields.bits.enable_cdef = sh->enable_cdef = 1;
447+ }
448+
449+ ret = vaapi_encode_av1_add_obu(avctx, obu, AV1_OBU_SEQUENCE_HEADER, &priv->sh);
450+ if (ret < 0)
451+ goto end;
452+
453+ ret = vaapi_encode_av1_write_obu(avctx, priv->sh_data, &priv->sh_data_len, obu);
454+ if (ret < 0)
455+ goto end;
456+
457+end:
458+ ff_cbs_fragment_reset(obu);
459+ return ret;
460+}
461+
462+static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx,
463+ VAAPIEncodePicture *pic)
464+{
465+ VAAPIEncodeContext *ctx = avctx->priv_data;
466+ VAAPIEncodeAV1Context *priv = avctx->priv_data;
467+ VAAPIEncodeAV1Picture *hpic = pic->priv_data;
468+ AV1RawOBU *fh_obu = &priv->fh;
469+ AV1RawFrameHeader *fh = &fh_obu->obu.frame.header;
470+ VAEncPictureParameterBufferAV1 *vpic = pic->codec_picture_params;
471+ CodedBitstreamFragment *obu = &priv->current_obu;
472+ VAAPIEncodePicture *ref;
473+ VAAPIEncodeAV1Picture *href;
474+ int slot, i;
475+ int ret;
476+ static const int8_t default_loop_filter_ref_deltas[AV1_TOTAL_REFS_PER_FRAME] =
477+ { 1, 0, 0, 0, -1, 0, -1, -1 };
478+
479+ memset(fh_obu, 0, sizeof(*fh_obu));
480+ pic->nb_slices = priv->tile_groups;
481+ pic->non_independent_frame = pic->encode_order < pic->display_order;
482+ fh_obu->header.obu_type = AV1_OBU_FRAME_HEADER;
483+ fh_obu->header.obu_has_size_field = 1;
484+
485+ switch (pic->type) {
486+ case PICTURE_TYPE_IDR:
487+ av_assert0(pic->nb_refs[0] == 0 || pic->nb_refs[1]);
488+ fh->frame_type = AV1_FRAME_KEY;
489+ fh->refresh_frame_flags = 0xFF;
490+ fh->base_q_idx = priv->q_idx_idr;
491+ hpic->slot = 0;
492+ hpic->last_idr_frame = pic->display_order;
493+ break;
494+ case PICTURE_TYPE_P:
495+ av_assert0(pic->nb_refs[0]);
496+ fh->frame_type = AV1_FRAME_INTER;
497+ fh->base_q_idx = priv->q_idx_p;
498+ ref = pic->refs[0][pic->nb_refs[0] - 1];
499+ href = ref->priv_data;
500+ hpic->slot = !href->slot;
501+ hpic->last_idr_frame = href->last_idr_frame;
502+ fh->refresh_frame_flags = 1 << hpic->slot;
503+
504+ /** set the nearest frame in L0 as all reference frame. */
505+ for (i = 0; i < AV1_REFS_PER_FRAME; i++) {
506+ fh->ref_frame_idx[i] = href->slot;
507+ }
508+ fh->primary_ref_frame = href->slot;
509+ fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame;
510+ vpic->ref_frame_ctrl_l0.fields.search_idx0 = AV1_REF_FRAME_LAST;
511+
512+ /** set the 2nd nearest frame in L0 as Golden frame. */
513+ if (pic->nb_refs[0] > 1) {
514+ ref = pic->refs[0][pic->nb_refs[0] - 2];
515+ href = ref->priv_data;
516+ fh->ref_frame_idx[3] = href->slot;
517+ fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame;
518+ vpic->ref_frame_ctrl_l0.fields.search_idx1 = AV1_REF_FRAME_GOLDEN;
519+ }
520+ break;
521+ case PICTURE_TYPE_B:
522+ av_assert0(pic->nb_refs[0] && pic->nb_refs[1]);
523+ fh->frame_type = AV1_FRAME_INTER;
524+ fh->base_q_idx = priv->q_idx_b;
525+ fh->refresh_frame_flags = 0x0;
526+ fh->reference_select = 1;
527+
528+ /** B frame will not be referenced, disable its recon frame. */
529+ vpic->picture_flags.bits.disable_frame_recon = 1;
530+
531+ /** Use LAST_FRAME and BWDREF_FRAME for reference. */
532+ vpic->ref_frame_ctrl_l0.fields.search_idx0 = AV1_REF_FRAME_LAST;
533+ vpic->ref_frame_ctrl_l1.fields.search_idx0 = AV1_REF_FRAME_BWDREF;
534+
535+ ref = pic->refs[0][pic->nb_refs[0] - 1];
536+ href = ref->priv_data;
537+ hpic->last_idr_frame = href->last_idr_frame;
538+ fh->primary_ref_frame = href->slot;
539+ fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame;
540+ for (i = 0; i < AV1_REF_FRAME_GOLDEN; i++) {
541+ fh->ref_frame_idx[i] = href->slot;
542+ }
543+
544+ ref = pic->refs[1][pic->nb_refs[1] - 1];
545+ href = ref->priv_data;
546+ fh->ref_order_hint[href->slot] = ref->display_order - href->last_idr_frame;
547+ for (i = AV1_REF_FRAME_GOLDEN; i < AV1_REFS_PER_FRAME; i++) {
548+ fh->ref_frame_idx[i] = href->slot;
549+ }
550+ break;
551+ default:
552+ av_assert0(0 && "invalid picture type");
553+ }
554+
555+ fh->show_frame = pic->display_order <= pic->encode_order;
556+ fh->showable_frame = fh->frame_type != AV1_FRAME_KEY;
557+ fh->frame_width_minus_1 = avctx->width - 1;
558+ fh->frame_height_minus_1 = avctx->height - 1;
559+ fh->render_width_minus_1 = fh->frame_width_minus_1;
560+ fh->render_height_minus_1 = fh->frame_height_minus_1;
561+ fh->order_hint = pic->display_order - hpic->last_idr_frame;
562+ fh->tile_cols = priv->tile_cols;
563+ fh->tile_rows = priv->tile_rows;
564+ fh->tile_cols_log2 = priv->tile_cols_log2;
565+ fh->tile_rows_log2 = priv->tile_rows_log2;
566+ fh->uniform_tile_spacing_flag = priv->uniform_tile;
567+ fh->tile_size_bytes_minus1 = priv->attr_ext2.bits.tile_size_bytes_minus1;
568+
569+ /** ignore ONLY_4x4 mode for codedlossless is not fully implemented. */
570+ if (priv->attr_ext2.bits.tx_mode_support & 0x04)
571+ fh->tx_mode = AV1_TX_MODE_SELECT;
572+ else if (priv->attr_ext2.bits.tx_mode_support & 0x02)
573+ fh->tx_mode = AV1_TX_MODE_LARGEST;
574+ else {
575+ av_log(avctx, AV_LOG_ERROR, "No available tx mode found.\n");
576+ return AVERROR(EINVAL);
577+ }
578+
579+ for (i = 0; i < fh->tile_cols; i++)
580+ fh->width_in_sbs_minus_1[i] = vpic->width_in_sbs_minus_1[i] = priv->width_in_sbs_minus_1[i];
581+
582+ for (i = 0; i < fh->tile_rows; i++)
583+ fh->height_in_sbs_minus_1[i] = vpic->height_in_sbs_minus_1[i] = priv->height_in_sbs_minus_1[i];
584+
585+ memcpy(fh->loop_filter_ref_deltas, default_loop_filter_ref_deltas,
586+ AV1_TOTAL_REFS_PER_FRAME * sizeof(int8_t));
587+
588+ if (fh->frame_type == AV1_FRAME_KEY && fh->show_frame) {
589+ fh->error_resilient_mode = 1;
590+ }
591+
592+ if (fh->frame_type == AV1_FRAME_KEY || fh->error_resilient_mode)
593+ fh->primary_ref_frame = AV1_PRIMARY_REF_NONE;
594+
595+ vpic->base_qindex = fh->base_q_idx;
596+ vpic->frame_width_minus_1 = fh->frame_width_minus_1;
597+ vpic->frame_height_minus_1 = fh->frame_height_minus_1;
598+ vpic->primary_ref_frame = fh->primary_ref_frame;
599+ vpic->reconstructed_frame = pic->recon_surface;
600+ vpic->coded_buf = pic->output_buffer;
601+ vpic->tile_cols = fh->tile_cols;
602+ vpic->tile_rows = fh->tile_rows;
603+ vpic->order_hint = fh->order_hint;
604+#if VA_CHECK_VERSION(1, 15, 0)
605+ vpic->refresh_frame_flags = fh->refresh_frame_flags;
606+#endif
607+
608+ vpic->picture_flags.bits.enable_frame_obu = 0;
609+ vpic->picture_flags.bits.frame_type = fh->frame_type;
610+ vpic->picture_flags.bits.reduced_tx_set = fh->reduced_tx_set;
611+ vpic->picture_flags.bits.error_resilient_mode = fh->error_resilient_mode;
612+
613+ /** let driver decide to use single or compound reference prediction mode. */
614+ vpic->mode_control_flags.bits.reference_mode = fh->reference_select ? 2 : 0;
615+ vpic->mode_control_flags.bits.tx_mode = fh->tx_mode;
616+
617+ vpic->tile_group_obu_hdr_info.bits.obu_has_size_field = 1;
618+
619+ /** set reference. */
620+ for (i = 0; i < AV1_REFS_PER_FRAME; i++)
621+ vpic->ref_frame_idx[i] = fh->ref_frame_idx[i];
622+
623+ for (i = 0; i < FF_ARRAY_ELEMS(vpic->reference_frames); i++)
624+ vpic->reference_frames[i] = VA_INVALID_SURFACE;
625+
626+ for (i = 0; i < MAX_REFERENCE_LIST_NUM; i++) {
627+ for (int j = 0; j < pic->nb_refs[i]; j++) {
628+ VAAPIEncodePicture *ref_pic = pic->refs[i][j];
629+
630+ slot = ((VAAPIEncodeAV1Picture*)ref_pic->priv_data)->slot;
631+ av_assert0(vpic->reference_frames[slot] == VA_INVALID_SURFACE);
632+
633+ vpic->reference_frames[slot] = ref_pic->recon_surface;
634+ }
635+ }
636+
637+ fh_obu->obu_size_byte_len = priv->attr_ext2.bits.obu_size_bytes_minus1 + 1;
638+ ret = vaapi_encode_av1_add_obu(avctx, obu, AV1_OBU_FRAME_HEADER, &priv->fh);
639+ if (ret < 0)
640+ goto end;
641+
642+ ret = vaapi_encode_av1_write_obu(avctx, priv->fh_data, &priv->fh_data_len, obu);
643+ if (ret < 0)
644+ goto end;
645+
646+ if (!(ctx->va_rc_mode & VA_RC_CQP)) {
647+ vpic->min_base_qindex = av_clip(avctx->qmin, 1, AV1_MAX_QUANT);
648+ vpic->max_base_qindex = av_clip(avctx->qmax, 1, AV1_MAX_QUANT);
649+
650+ vpic->bit_offset_qindex = priv->qindex_offset;
651+ vpic->bit_offset_loopfilter_params = priv->loopfilter_offset;
652+ vpic->bit_offset_cdef_params = priv->cdef_start_offset;
653+ vpic->size_in_bits_cdef_params = priv->cdef_param_size;
654+ vpic->size_in_bits_frame_hdr_obu = priv->fh_data_len;
655+ vpic->byte_offset_frame_hdr_obu_size = (((pic->type == PICTURE_TYPE_IDR) ?
656+ priv->sh_data_len / 8 : 0) +
657+ (fh_obu->header.obu_extension_flag ?
658+ 2 : 1));
659+ }
660+
661+end:
662+ ff_cbs_fragment_reset(obu);
663+ return ret;
664+}
665+
666+static int vaapi_encode_av1_init_slice_params(AVCodecContext *avctx,
667+ VAAPIEncodePicture *pic,
668+ VAAPIEncodeSlice *slice)
669+{
670+ VAAPIEncodeAV1Context *priv = avctx->priv_data;
671+ VAEncTileGroupBufferAV1 *vslice = slice->codec_slice_params;
672+ CodedBitstreamAV1Context *cbctx = priv->cbc->priv_data;
673+ int div;
674+
675+ /** Set tile group info. */
676+ div = priv->tile_cols * priv->tile_rows / priv->tile_groups;
677+ vslice->tg_start = slice->index * div;
678+ if (slice->index == (priv->tile_groups - 1)) {
679+ vslice->tg_end = priv->tile_cols * priv->tile_rows - 1;
680+ cbctx->seen_frame_header = 0;
681+ } else {
682+ vslice->tg_end = (slice->index + 1) * div - 1;
683+ }
684+
685+ return 0;
686+}
687+
688+static int vaapi_encode_av1_write_picture_header(AVCodecContext *avctx,
689+ VAAPIEncodePicture *pic,
690+ char *data, size_t *data_len)
691+{
692+ VAAPIEncodeAV1Context *priv = avctx->priv_data;
693+ CodedBitstreamFragment *obu = &priv->current_obu;
694+ CodedBitstreamAV1Context *cbctx = priv->cbc->priv_data;
695+ AV1RawOBU *fh_obu = &priv->fh;
696+ AV1RawFrameHeader *rep_fh = &fh_obu->obu.frame_header;
697+ VAAPIEncodeAV1Picture *href;
698+ int ret = 0;
699+
700+ pic->tail_size = 0;
701+ /** Pack repeat frame header. */
702+ if (pic->display_order > pic->encode_order) {
703+ memset(fh_obu, 0, sizeof(*fh_obu));
704+ href = pic->refs[0][pic->nb_refs[0] - 1]->priv_data;
705+ fh_obu->header.obu_type = AV1_OBU_FRAME_HEADER;
706+ fh_obu->header.obu_has_size_field = 1;
707+
708+ rep_fh->show_existing_frame = 1;
709+ rep_fh->frame_to_show_map_idx = href->slot == 0;
710+ rep_fh->frame_type = AV1_FRAME_INTER;
711+ rep_fh->frame_width_minus_1 = avctx->width - 1;
712+ rep_fh->frame_height_minus_1 = avctx->height - 1;
713+ rep_fh->render_width_minus_1 = rep_fh->frame_width_minus_1;
714+ rep_fh->render_height_minus_1 = rep_fh->frame_height_minus_1;
715+
716+ cbctx->seen_frame_header = 0;
717+
718+ ret = vaapi_encode_av1_add_obu(avctx, obu, AV1_OBU_FRAME_HEADER, &priv->fh);
719+ if (ret < 0)
720+ goto end;
721+
722+ ret = vaapi_encode_av1_write_obu(avctx, pic->tail_data, &pic->tail_size, obu);
723+ if (ret < 0)
724+ goto end;
725+
726+ pic->tail_size /= 8;
727+ }
728+
729+ memcpy(data, &priv->fh_data, MAX_PARAM_BUFFER_SIZE * sizeof(char));
730+ *data_len = priv->fh_data_len;
731+
732+end:
733+ ff_cbs_fragment_reset(obu);
734+ return ret;
735+}
736+
737+static const VAAPIEncodeProfile vaapi_encode_av1_profiles[] = {
738+ { AV_PROFILE_AV1_MAIN, 8, 3, 1, 1, VAProfileAV1Profile0 },
739+ { AV_PROFILE_AV1_MAIN, 10, 3, 1, 1, VAProfileAV1Profile0 },
740+ { AV_PROFILE_UNKNOWN }
741+};
742+
743+static const VAAPIEncodeType vaapi_encode_type_av1 = {
744+ .profiles = vaapi_encode_av1_profiles,
745+ .flags = FLAG_B_PICTURES | FLAG_TIMESTAMP_NO_DELAY,
746+ .default_quality = 25,
747+
748+ .get_encoder_caps = &vaapi_encode_av1_get_encoder_caps,
749+ .configure = &vaapi_encode_av1_configure,
750+
751+ .sequence_header_type = VAEncPackedHeaderSequence,
752+ .sequence_params_size = sizeof(VAEncSequenceParameterBufferAV1),
753+ .init_sequence_params = &vaapi_encode_av1_init_sequence_params,
754+ .write_sequence_header = &vaapi_encode_av1_write_sequence_header,
755+
756+ .picture_priv_data_size = sizeof(VAAPIEncodeAV1Picture),
757+ .picture_header_type = VAEncPackedHeaderPicture,
758+ .picture_params_size = sizeof(VAEncPictureParameterBufferAV1),
759+ .init_picture_params = &vaapi_encode_av1_init_picture_params,
760+ .write_picture_header = &vaapi_encode_av1_write_picture_header,
761+
762+ .slice_params_size = sizeof(VAEncTileGroupBufferAV1),
763+ .init_slice_params = &vaapi_encode_av1_init_slice_params,
764+};
765+
766+static av_cold int vaapi_encode_av1_init(AVCodecContext *avctx)
767+{
768+ VAAPIEncodeContext *ctx = avctx->priv_data;
769+ VAAPIEncodeAV1Context *priv = avctx->priv_data;
770+ VAConfigAttrib attr;
771+ VAStatus vas;
772+ int ret;
773+
774+ ctx->codec = &vaapi_encode_type_av1;
775+
776+ ctx->desired_packed_headers =
777+ VA_ENC_PACKED_HEADER_SEQUENCE |
778+ VA_ENC_PACKED_HEADER_PICTURE;
779+
780+ if (avctx->profile == AV_PROFILE_UNKNOWN)
781+ avctx->profile = priv->profile;
782+ if (avctx->level == AV_LEVEL_UNKNOWN)
783+ avctx->level = priv->level;
784+
785+ if (avctx->level != AV_LEVEL_UNKNOWN && avctx->level & ~0x1f) {
786+ av_log(avctx, AV_LOG_ERROR, "Invalid level %d\n", avctx->level);
787+ return AVERROR(EINVAL);
788+ }
789+
790+ ret = ff_vaapi_encode_init(avctx);
791+ if (ret < 0)
792+ return ret;
793+
794+ attr.type = VAConfigAttribEncAV1;
795+ vas = vaGetConfigAttributes(ctx->hwctx->display,
796+ ctx->va_profile,
797+ ctx->va_entrypoint,
798+ &attr, 1);
799+ if (vas != VA_STATUS_SUCCESS) {
800+ av_log(avctx, AV_LOG_ERROR, "Failed to query "
801+ "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
802+ return AVERROR_EXTERNAL;
803+ } else if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
804+ priv->attr.value = 0;
805+ av_log(avctx, AV_LOG_WARNING, "Attribute type:%d is not "
806+ "supported.\n", attr.type);
807+ } else {
808+ priv->attr.value = attr.value;
809+ }
810+
811+ attr.type = VAConfigAttribEncAV1Ext1;
812+ vas = vaGetConfigAttributes(ctx->hwctx->display,
813+ ctx->va_profile,
814+ ctx->va_entrypoint,
815+ &attr, 1);
816+ if (vas != VA_STATUS_SUCCESS) {
817+ av_log(avctx, AV_LOG_ERROR, "Failed to query "
818+ "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
819+ return AVERROR_EXTERNAL;
820+ } else if (attr.value == VA_ATTRIB_NOT_SUPPORTED) {
821+ priv->attr_ext1.value = 0;
822+ av_log(avctx, AV_LOG_WARNING, "Attribute type:%d is not "
823+ "supported.\n", attr.type);
824+ } else {
825+ priv->attr_ext1.value = attr.value;
826+ }
827+
828+ /** This attr provides essential indicators, return error if not support. */
829+ attr.type = VAConfigAttribEncAV1Ext2;
830+ vas = vaGetConfigAttributes(ctx->hwctx->display,
831+ ctx->va_profile,
832+ ctx->va_entrypoint,
833+ &attr, 1);
834+ if (vas != VA_STATUS_SUCCESS || attr.value == VA_ATTRIB_NOT_SUPPORTED) {
835+ av_log(avctx, AV_LOG_ERROR, "Failed to query "
836+ "config attribute: %d (%s).\n", vas, vaErrorStr(vas));
837+ return AVERROR_EXTERNAL;
838+ } else {
839+ priv->attr_ext2.value = attr.value;
840+ }
841+
842+ ret = vaapi_encode_av1_set_tile(avctx);
843+ if (ret < 0)
844+ return ret;
845+
846+ return 0;
847+}
848+
849+static av_cold int vaapi_encode_av1_close(AVCodecContext *avctx)
850+{
851+ VAAPIEncodeAV1Context *priv = avctx->priv_data;
852+
853+ ff_cbs_fragment_free(&priv->current_obu);
854+ ff_cbs_close(&priv->cbc);
855+
856+ return ff_vaapi_encode_close(avctx);
857+}
858+
859+#define OFFSET(x) offsetof(VAAPIEncodeAV1Context, x)
860+#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM)
861+
862+static const AVOption vaapi_encode_av1_options[] = {
863+ VAAPI_ENCODE_COMMON_OPTIONS,
864+ VAAPI_ENCODE_RC_OPTIONS,
865+ { "profile", "Set profile (seq_profile)",
866+ OFFSET(profile), AV_OPT_TYPE_INT,
867+ { .i64 = AV_PROFILE_UNKNOWN }, AV_PROFILE_UNKNOWN, 0xff, FLAGS, "profile" },
868+
869+#define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \
870+ { .i64 = value }, 0, 0, FLAGS, "profile"
871+ { PROFILE("main", AV_PROFILE_AV1_MAIN) },
872+ { PROFILE("high", AV_PROFILE_AV1_HIGH) },
873+ { PROFILE("professional", AV_PROFILE_AV1_PROFESSIONAL) },
874+#undef PROFILE
875+
876+ { "tier", "Set tier (seq_tier)",
877+ OFFSET(tier), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS, "tier" },
878+ { "main", NULL, 0, AV_OPT_TYPE_CONST,
879+ { .i64 = 0 }, 0, 0, FLAGS, "tier" },
880+ { "high", NULL, 0, AV_OPT_TYPE_CONST,
881+ { .i64 = 1 }, 0, 0, FLAGS, "tier" },
882+ { "level", "Set level (seq_level_idx)",
883+ OFFSET(level), AV_OPT_TYPE_INT,
884+ { .i64 = AV_LEVEL_UNKNOWN }, AV_LEVEL_UNKNOWN, 0x1f, FLAGS, "level" },
885+
886+#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \
887+ { .i64 = value }, 0, 0, FLAGS, "level"
888+ { LEVEL("2.0", 0) },
889+ { LEVEL("2.1", 1) },
890+ { LEVEL("3.0", 4) },
891+ { LEVEL("3.1", 5) },
892+ { LEVEL("4.0", 8) },
893+ { LEVEL("4.1", 9) },
894+ { LEVEL("5.0", 12) },
895+ { LEVEL("5.1", 13) },
896+ { LEVEL("5.2", 14) },
897+ { LEVEL("5.3", 15) },
898+ { LEVEL("6.0", 16) },
899+ { LEVEL("6.1", 17) },
900+ { LEVEL("6.2", 18) },
901+ { LEVEL("6.3", 19) },
902+#undef LEVEL
903+
904+ { "tiles", "Tile columns x rows (Use minimal tile column/row number automatically by default)",
905+ OFFSET(tile_cols), AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS },
906+ { "tile_groups", "Number of tile groups for encoding",
907+ OFFSET(tile_groups), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, AV1_MAX_TILE_ROWS * AV1_MAX_TILE_COLS, FLAGS },
908+
909+ { NULL },
910+};
911+
912+static const FFCodecDefault vaapi_encode_av1_defaults[] = {
913+ { "b", "0" },
914+ { "bf", "2" },
915+ { "g", "120" },
916+ { "qmin", "1" },
917+ { "qmax", "255" },
918+ { NULL },
919+};
920+
921+static const AVClass vaapi_encode_av1_class = {
922+ .class_name = "av1_vaapi",
923+ .item_name = av_default_item_name,
924+ .option = vaapi_encode_av1_options,
925+ .version = LIBAVUTIL_VERSION_INT,
926+};
927+
928+const FFCodec ff_av1_vaapi_encoder = {
929+ .p.name = "av1_vaapi",
930+ CODEC_LONG_NAME("AV1 (VAAPI)"),
931+ .p.type = AVMEDIA_TYPE_VIDEO,
932+ .p.id = AV_CODEC_ID_AV1,
933+ .priv_data_size = sizeof(VAAPIEncodeAV1Context),
934+ .init = &vaapi_encode_av1_init,
935+ FF_CODEC_RECEIVE_PACKET_CB(&ff_vaapi_encode_receive_packet),
936+ .close = &vaapi_encode_av1_close,
937+ .p.priv_class = &vaapi_encode_av1_class,
938+ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
939+ AV_CODEC_CAP_DR1 | AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
940+ .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE |
941+ FF_CODEC_CAP_INIT_CLEANUP,
942+ .defaults = vaapi_encode_av1_defaults,
943+ .p.pix_fmts = (const enum AVPixelFormat[]) {
944+ AV_PIX_FMT_VAAPI,
945+ AV_PIX_FMT_NONE,
946+ },
947+ .hw_configs = ff_vaapi_encode_hw_configs,
948+ .p.wrapper_name = "vaapi",
949+};
libavcodec/version.h+1−1
@@ -29,7 +29,7 @@ · 28 unmodified lines
2929
3030 #include "version_major.h"
3131
32−#define LIBAVCODEC_VERSION_MINOR 26
32+#define LIBAVCODEC_VERSION_MINOR 27
3333 #define LIBAVCODEC_VERSION_MICRO 100
3434
3535 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t