1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Intel MediaSDK QSV based HEVC encoder
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * This file is part of FFmpeg.
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
10cabdff1aSopenharmony_ci *
11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14cabdff1aSopenharmony_ci * Lesser General Public License for more details.
15cabdff1aSopenharmony_ci *
16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19cabdff1aSopenharmony_ci */
20cabdff1aSopenharmony_ci
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci#include <stdint.h>
23cabdff1aSopenharmony_ci#include <sys/types.h>
24cabdff1aSopenharmony_ci
25cabdff1aSopenharmony_ci#include <mfx/mfxvideo.h>
26cabdff1aSopenharmony_ci
27cabdff1aSopenharmony_ci#include "libavutil/common.h"
28cabdff1aSopenharmony_ci#include "libavutil/opt.h"
29cabdff1aSopenharmony_ci
30cabdff1aSopenharmony_ci#include "avcodec.h"
31cabdff1aSopenharmony_ci#include "bytestream.h"
32cabdff1aSopenharmony_ci#include "codec_internal.h"
33cabdff1aSopenharmony_ci#include "get_bits.h"
34cabdff1aSopenharmony_ci#include "hevc.h"
35cabdff1aSopenharmony_ci#include "hevcdec.h"
36cabdff1aSopenharmony_ci#include "h2645_parse.h"
37cabdff1aSopenharmony_ci#include "qsv.h"
38cabdff1aSopenharmony_ci#include "qsv_internal.h"
39cabdff1aSopenharmony_ci#include "qsvenc.h"
40cabdff1aSopenharmony_ci
41cabdff1aSopenharmony_cienum LoadPlugin {
42cabdff1aSopenharmony_ci    LOAD_PLUGIN_NONE,
43cabdff1aSopenharmony_ci    LOAD_PLUGIN_HEVC_SW,
44cabdff1aSopenharmony_ci    LOAD_PLUGIN_HEVC_HW,
45cabdff1aSopenharmony_ci};
46cabdff1aSopenharmony_ci
47cabdff1aSopenharmony_citypedef struct QSVHEVCEncContext {
48cabdff1aSopenharmony_ci    AVClass *class;
49cabdff1aSopenharmony_ci    QSVEncContext qsv;
50cabdff1aSopenharmony_ci    int load_plugin;
51cabdff1aSopenharmony_ci} QSVHEVCEncContext;
52cabdff1aSopenharmony_ci
53cabdff1aSopenharmony_cistatic int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx)
54cabdff1aSopenharmony_ci{
55cabdff1aSopenharmony_ci    GetByteContext gbc;
56cabdff1aSopenharmony_ci    PutByteContext pbc;
57cabdff1aSopenharmony_ci
58cabdff1aSopenharmony_ci    GetBitContext gb;
59cabdff1aSopenharmony_ci    H2645RBSP sps_rbsp = { NULL };
60cabdff1aSopenharmony_ci    H2645NAL sps_nal = { NULL };
61cabdff1aSopenharmony_ci    HEVCSPS sps = { 0 };
62cabdff1aSopenharmony_ci    HEVCVPS vps = { 0 };
63cabdff1aSopenharmony_ci    uint8_t vps_buf[128], vps_rbsp_buf[128];
64cabdff1aSopenharmony_ci    uint8_t *new_extradata;
65cabdff1aSopenharmony_ci    unsigned int sps_id;
66cabdff1aSopenharmony_ci    int ret, i, type, vps_size;
67cabdff1aSopenharmony_ci
68cabdff1aSopenharmony_ci    if (!avctx->extradata_size) {
69cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "No extradata returned from libmfx\n");
70cabdff1aSopenharmony_ci        return AVERROR_UNKNOWN;
71cabdff1aSopenharmony_ci    }
72cabdff1aSopenharmony_ci
73cabdff1aSopenharmony_ci    av_fast_padded_malloc(&sps_rbsp.rbsp_buffer, &sps_rbsp.rbsp_buffer_alloc_size, avctx->extradata_size);
74cabdff1aSopenharmony_ci    if (!sps_rbsp.rbsp_buffer)
75cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
76cabdff1aSopenharmony_ci
77cabdff1aSopenharmony_ci    /* parse the SPS */
78cabdff1aSopenharmony_ci    ret = ff_h2645_extract_rbsp(avctx->extradata + 4, avctx->extradata_size - 4, &sps_rbsp, &sps_nal, 1);
79cabdff1aSopenharmony_ci    if (ret < 0) {
80cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Error unescaping the SPS buffer\n");
81cabdff1aSopenharmony_ci        return ret;
82cabdff1aSopenharmony_ci    }
83cabdff1aSopenharmony_ci
84cabdff1aSopenharmony_ci    ret = init_get_bits8(&gb, sps_nal.data, sps_nal.size);
85cabdff1aSopenharmony_ci    if (ret < 0) {
86cabdff1aSopenharmony_ci        av_freep(&sps_rbsp.rbsp_buffer);
87cabdff1aSopenharmony_ci        return ret;
88cabdff1aSopenharmony_ci    }
89cabdff1aSopenharmony_ci
90cabdff1aSopenharmony_ci    get_bits(&gb, 1);
91cabdff1aSopenharmony_ci    type = get_bits(&gb, 6);
92cabdff1aSopenharmony_ci    if (type != HEVC_NAL_SPS) {
93cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Unexpected NAL type in the extradata: %d\n",
94cabdff1aSopenharmony_ci               type);
95cabdff1aSopenharmony_ci        av_freep(&sps_rbsp.rbsp_buffer);
96cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
97cabdff1aSopenharmony_ci    }
98cabdff1aSopenharmony_ci    get_bits(&gb, 9);
99cabdff1aSopenharmony_ci
100cabdff1aSopenharmony_ci    ret = ff_hevc_parse_sps(&sps, &gb, &sps_id, 0, NULL, avctx);
101cabdff1aSopenharmony_ci    av_freep(&sps_rbsp.rbsp_buffer);
102cabdff1aSopenharmony_ci    if (ret < 0) {
103cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Error parsing the SPS\n");
104cabdff1aSopenharmony_ci        return ret;
105cabdff1aSopenharmony_ci    }
106cabdff1aSopenharmony_ci
107cabdff1aSopenharmony_ci    /* generate the VPS */
108cabdff1aSopenharmony_ci    vps.vps_max_layers     = 1;
109cabdff1aSopenharmony_ci    vps.vps_max_sub_layers = sps.max_sub_layers;
110cabdff1aSopenharmony_ci    vps.vps_temporal_id_nesting_flag = sps.temporal_id_nesting_flag;
111cabdff1aSopenharmony_ci    memcpy(&vps.ptl, &sps.ptl, sizeof(vps.ptl));
112cabdff1aSopenharmony_ci    vps.vps_sub_layer_ordering_info_present_flag = 1;
113cabdff1aSopenharmony_ci    for (i = 0; i < HEVC_MAX_SUB_LAYERS; i++) {
114cabdff1aSopenharmony_ci        vps.vps_max_dec_pic_buffering[i] = sps.temporal_layer[i].max_dec_pic_buffering;
115cabdff1aSopenharmony_ci        vps.vps_num_reorder_pics[i]      = sps.temporal_layer[i].num_reorder_pics;
116cabdff1aSopenharmony_ci        vps.vps_max_latency_increase[i]  = sps.temporal_layer[i].max_latency_increase;
117cabdff1aSopenharmony_ci    }
118cabdff1aSopenharmony_ci
119cabdff1aSopenharmony_ci    vps.vps_num_layer_sets                  = 1;
120cabdff1aSopenharmony_ci    vps.vps_timing_info_present_flag        = sps.vui.vui_timing_info_present_flag;
121cabdff1aSopenharmony_ci    vps.vps_num_units_in_tick               = sps.vui.vui_num_units_in_tick;
122cabdff1aSopenharmony_ci    vps.vps_time_scale                      = sps.vui.vui_time_scale;
123cabdff1aSopenharmony_ci    vps.vps_poc_proportional_to_timing_flag = sps.vui.vui_poc_proportional_to_timing_flag;
124cabdff1aSopenharmony_ci    vps.vps_num_ticks_poc_diff_one          = sps.vui.vui_num_ticks_poc_diff_one_minus1 + 1;
125cabdff1aSopenharmony_ci    vps.vps_num_hrd_parameters              = 0;
126cabdff1aSopenharmony_ci
127cabdff1aSopenharmony_ci    /* generate the encoded RBSP form of the VPS */
128cabdff1aSopenharmony_ci    ret = ff_hevc_encode_nal_vps(&vps, sps.vps_id, vps_rbsp_buf, sizeof(vps_rbsp_buf));
129cabdff1aSopenharmony_ci    if (ret < 0) {
130cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Error writing the VPS\n");
131cabdff1aSopenharmony_ci        return ret;
132cabdff1aSopenharmony_ci    }
133cabdff1aSopenharmony_ci
134cabdff1aSopenharmony_ci    /* escape and add the startcode */
135cabdff1aSopenharmony_ci    bytestream2_init(&gbc, vps_rbsp_buf, ret);
136cabdff1aSopenharmony_ci    bytestream2_init_writer(&pbc, vps_buf, sizeof(vps_buf));
137cabdff1aSopenharmony_ci
138cabdff1aSopenharmony_ci    bytestream2_put_be32(&pbc, 1);                 // startcode
139cabdff1aSopenharmony_ci    bytestream2_put_byte(&pbc, HEVC_NAL_VPS << 1); // NAL
140cabdff1aSopenharmony_ci    bytestream2_put_byte(&pbc, 1);                 // header
141cabdff1aSopenharmony_ci
142cabdff1aSopenharmony_ci    while (bytestream2_get_bytes_left(&gbc)) {
143cabdff1aSopenharmony_ci        if (bytestream2_get_bytes_left(&gbc) >= 3 && bytestream2_peek_be24(&gbc) <= 3) {
144cabdff1aSopenharmony_ci            bytestream2_put_be24(&pbc, 3);
145cabdff1aSopenharmony_ci            bytestream2_skip(&gbc, 2);
146cabdff1aSopenharmony_ci        } else
147cabdff1aSopenharmony_ci            bytestream2_put_byte(&pbc, bytestream2_get_byte(&gbc));
148cabdff1aSopenharmony_ci    }
149cabdff1aSopenharmony_ci
150cabdff1aSopenharmony_ci    vps_size = bytestream2_tell_p(&pbc);
151cabdff1aSopenharmony_ci    new_extradata = av_mallocz(vps_size + avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
152cabdff1aSopenharmony_ci    if (!new_extradata)
153cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
154cabdff1aSopenharmony_ci    memcpy(new_extradata, vps_buf, vps_size);
155cabdff1aSopenharmony_ci    memcpy(new_extradata + vps_size, avctx->extradata, avctx->extradata_size);
156cabdff1aSopenharmony_ci
157cabdff1aSopenharmony_ci    av_freep(&avctx->extradata);
158cabdff1aSopenharmony_ci    avctx->extradata       = new_extradata;
159cabdff1aSopenharmony_ci    avctx->extradata_size += vps_size;
160cabdff1aSopenharmony_ci
161cabdff1aSopenharmony_ci    return 0;
162cabdff1aSopenharmony_ci}
163cabdff1aSopenharmony_ci
164cabdff1aSopenharmony_cistatic av_cold int qsv_enc_init(AVCodecContext *avctx)
165cabdff1aSopenharmony_ci{
166cabdff1aSopenharmony_ci    QSVHEVCEncContext *q = avctx->priv_data;
167cabdff1aSopenharmony_ci    int ret;
168cabdff1aSopenharmony_ci
169cabdff1aSopenharmony_ci    if (q->load_plugin != LOAD_PLUGIN_NONE) {
170cabdff1aSopenharmony_ci        static const char * const uid_hevcenc_sw = "2fca99749fdb49aeb121a5b63ef568f7";
171cabdff1aSopenharmony_ci        static const char * const uid_hevcenc_hw = "6fadc791a0c2eb479ab6dcd5ea9da347";
172cabdff1aSopenharmony_ci
173cabdff1aSopenharmony_ci        if (q->qsv.load_plugins[0]) {
174cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_WARNING,
175cabdff1aSopenharmony_ci                   "load_plugins is not empty, but load_plugin is not set to 'none'."
176cabdff1aSopenharmony_ci                   "The load_plugin value will be ignored.\n");
177cabdff1aSopenharmony_ci        } else {
178cabdff1aSopenharmony_ci            av_freep(&q->qsv.load_plugins);
179cabdff1aSopenharmony_ci
180cabdff1aSopenharmony_ci            if (q->load_plugin == LOAD_PLUGIN_HEVC_SW)
181cabdff1aSopenharmony_ci                q->qsv.load_plugins = av_strdup(uid_hevcenc_sw);
182cabdff1aSopenharmony_ci            else
183cabdff1aSopenharmony_ci                q->qsv.load_plugins = av_strdup(uid_hevcenc_hw);
184cabdff1aSopenharmony_ci
185cabdff1aSopenharmony_ci            if (!q->qsv.load_plugins)
186cabdff1aSopenharmony_ci                return AVERROR(ENOMEM);
187cabdff1aSopenharmony_ci        }
188cabdff1aSopenharmony_ci    }
189cabdff1aSopenharmony_ci
190cabdff1aSopenharmony_ci    // HEVC and H264 meaning of the value is shifted by 1, make it consistent
191cabdff1aSopenharmony_ci    q->qsv.idr_interval++;
192cabdff1aSopenharmony_ci
193cabdff1aSopenharmony_ci    ret = ff_qsv_enc_init(avctx, &q->qsv);
194cabdff1aSopenharmony_ci    if (ret < 0)
195cabdff1aSopenharmony_ci        return ret;
196cabdff1aSopenharmony_ci
197cabdff1aSopenharmony_ci    if (!q->qsv.hevc_vps) {
198cabdff1aSopenharmony_ci        ret = generate_fake_vps(&q->qsv, avctx);
199cabdff1aSopenharmony_ci        if (ret < 0) {
200cabdff1aSopenharmony_ci            ff_qsv_enc_close(avctx, &q->qsv);
201cabdff1aSopenharmony_ci            return ret;
202cabdff1aSopenharmony_ci        }
203cabdff1aSopenharmony_ci    }
204cabdff1aSopenharmony_ci
205cabdff1aSopenharmony_ci    return 0;
206cabdff1aSopenharmony_ci}
207cabdff1aSopenharmony_ci
208cabdff1aSopenharmony_cistatic int qsv_enc_frame(AVCodecContext *avctx, AVPacket *pkt,
209cabdff1aSopenharmony_ci                         const AVFrame *frame, int *got_packet)
210cabdff1aSopenharmony_ci{
211cabdff1aSopenharmony_ci    QSVHEVCEncContext *q = avctx->priv_data;
212cabdff1aSopenharmony_ci
213cabdff1aSopenharmony_ci    return ff_qsv_encode(avctx, &q->qsv, pkt, frame, got_packet);
214cabdff1aSopenharmony_ci}
215cabdff1aSopenharmony_ci
216cabdff1aSopenharmony_cistatic av_cold int qsv_enc_close(AVCodecContext *avctx)
217cabdff1aSopenharmony_ci{
218cabdff1aSopenharmony_ci    QSVHEVCEncContext *q = avctx->priv_data;
219cabdff1aSopenharmony_ci
220cabdff1aSopenharmony_ci    return ff_qsv_enc_close(avctx, &q->qsv);
221cabdff1aSopenharmony_ci}
222cabdff1aSopenharmony_ci
223cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(QSVHEVCEncContext, x)
224cabdff1aSopenharmony_ci#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
225cabdff1aSopenharmony_cistatic const AVOption options[] = {
226cabdff1aSopenharmony_ci    QSV_COMMON_OPTS
227cabdff1aSopenharmony_ci    QSV_OPTION_RDO
228cabdff1aSopenharmony_ci    QSV_OPTION_MAX_FRAME_SIZE
229cabdff1aSopenharmony_ci    QSV_OPTION_MAX_SLICE_SIZE
230cabdff1aSopenharmony_ci    QSV_OPTION_MBBRC
231cabdff1aSopenharmony_ci    QSV_OPTION_EXTBRC
232cabdff1aSopenharmony_ci    QSV_OPTION_P_STRATEGY
233cabdff1aSopenharmony_ci    QSV_OPTION_B_STRATEGY
234cabdff1aSopenharmony_ci    QSV_OPTION_DBLK_IDC
235cabdff1aSopenharmony_ci    QSV_OPTION_LOW_DELAY_BRC
236cabdff1aSopenharmony_ci    QSV_OPTION_MAX_MIN_QP
237cabdff1aSopenharmony_ci
238cabdff1aSopenharmony_ci    { "idr_interval", "Distance (in I-frames) between IDR frames", OFFSET(qsv.idr_interval), AV_OPT_TYPE_INT, { .i64 = 0 }, -1, INT_MAX, VE, "idr_interval" },
239cabdff1aSopenharmony_ci    { "begin_only", "Output an IDR-frame only at the beginning of the stream", 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, 0, 0, VE, "idr_interval" },
240cabdff1aSopenharmony_ci    { "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_HEVC_HW }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VE, "load_plugin" },
241cabdff1aSopenharmony_ci    { "none",     NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_NONE },    0, 0, VE, "load_plugin" },
242cabdff1aSopenharmony_ci    { "hevc_sw",  NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_SW }, 0, 0, VE, "load_plugin" },
243cabdff1aSopenharmony_ci    { "hevc_hw",  NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_HW }, 0, 0, VE, "load_plugin" },
244cabdff1aSopenharmony_ci
245cabdff1aSopenharmony_ci    { "load_plugins", "A :-separate list of hexadecimal plugin UIDs to load in an internal session",
246cabdff1aSopenharmony_ci        OFFSET(qsv.load_plugins), AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, VE },
247cabdff1aSopenharmony_ci
248cabdff1aSopenharmony_ci    { "look_ahead_depth", "Depth of look ahead in number frames, available when extbrc option is enabled", OFFSET(qsv.look_ahead_depth), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, VE },
249cabdff1aSopenharmony_ci    { "profile", NULL, OFFSET(qsv.profile), AV_OPT_TYPE_INT, { .i64 = MFX_PROFILE_UNKNOWN }, 0, INT_MAX, VE, "profile" },
250cabdff1aSopenharmony_ci    { "unknown", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_UNKNOWN      }, INT_MIN, INT_MAX,     VE, "profile" },
251cabdff1aSopenharmony_ci    { "main",    NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_HEVC_MAIN    }, INT_MIN, INT_MAX,     VE, "profile" },
252cabdff1aSopenharmony_ci    { "main10",  NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_HEVC_MAIN10  }, INT_MIN, INT_MAX,     VE, "profile" },
253cabdff1aSopenharmony_ci    { "mainsp",  NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_HEVC_MAINSP  }, INT_MIN, INT_MAX,     VE, "profile" },
254cabdff1aSopenharmony_ci    { "rext",    NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_HEVC_REXT    }, INT_MIN, INT_MAX,     VE, "profile" },
255cabdff1aSopenharmony_ci#if QSV_VERSION_ATLEAST(1, 32)
256cabdff1aSopenharmony_ci    { "scc",     NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_HEVC_SCC     }, INT_MIN, INT_MAX,     VE, "profile" },
257cabdff1aSopenharmony_ci#endif
258cabdff1aSopenharmony_ci
259cabdff1aSopenharmony_ci    { "gpb", "1: GPB (generalized P/B frame); 0: regular P frame", OFFSET(qsv.gpb), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE},
260cabdff1aSopenharmony_ci
261cabdff1aSopenharmony_ci    { "tile_cols",  "Number of columns for tiled encoding",   OFFSET(qsv.tile_cols),    AV_OPT_TYPE_INT, { .i64 = 0 }, 0, UINT16_MAX, VE },
262cabdff1aSopenharmony_ci    { "tile_rows",  "Number of rows for tiled encoding",      OFFSET(qsv.tile_rows),    AV_OPT_TYPE_INT, { .i64 = 0 }, 0, UINT16_MAX, VE },
263cabdff1aSopenharmony_ci    { "recovery_point_sei", "Insert recovery point SEI messages",       OFFSET(qsv.recovery_point_sei),      AV_OPT_TYPE_INT, { .i64 = -1 },               -1,          1, VE },
264cabdff1aSopenharmony_ci    { "aud", "Insert the Access Unit Delimiter NAL", OFFSET(qsv.aud), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE},
265cabdff1aSopenharmony_ci    { "pic_timing_sei",    "Insert picture timing SEI with pic_struct_syntax element", OFFSET(qsv.pic_timing_sei), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE },
266cabdff1aSopenharmony_ci    { "transform_skip", "Turn this option ON to enable transformskip",   OFFSET(qsv.transform_skip),          AV_OPT_TYPE_INT,    { .i64 = -1},   -1, 1,  VE},
267cabdff1aSopenharmony_ci    { "int_ref_type", "Intra refresh type. B frames should be set to 0",         OFFSET(qsv.int_ref_type),            AV_OPT_TYPE_INT, { .i64 = -1 }, -1, UINT16_MAX, VE, "int_ref_type" },
268cabdff1aSopenharmony_ci        { "none",     NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, .flags = VE, "int_ref_type" },
269cabdff1aSopenharmony_ci        { "vertical", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, .flags = VE, "int_ref_type" },
270cabdff1aSopenharmony_ci        { "horizontal", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, .flags = VE, "int_ref_type" },
271cabdff1aSopenharmony_ci    { "int_ref_cycle_size", "Number of frames in the intra refresh cycle",       OFFSET(qsv.int_ref_cycle_size),      AV_OPT_TYPE_INT, { .i64 = -1 },               -1, UINT16_MAX, VE },
272cabdff1aSopenharmony_ci    { "int_ref_qp_delta",   "QP difference for the refresh MBs",                 OFFSET(qsv.int_ref_qp_delta),        AV_OPT_TYPE_INT, { .i64 = INT16_MIN }, INT16_MIN,  INT16_MAX, VE },
273cabdff1aSopenharmony_ci    { "int_ref_cycle_dist",   "Distance between the beginnings of the intra-refresh cycles in frames",  OFFSET(qsv.int_ref_cycle_dist),      AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT16_MAX, VE },
274cabdff1aSopenharmony_ci
275cabdff1aSopenharmony_ci    { NULL },
276cabdff1aSopenharmony_ci};
277cabdff1aSopenharmony_ci
278cabdff1aSopenharmony_cistatic const AVClass class = {
279cabdff1aSopenharmony_ci    .class_name = "hevc_qsv encoder",
280cabdff1aSopenharmony_ci    .item_name  = av_default_item_name,
281cabdff1aSopenharmony_ci    .option     = options,
282cabdff1aSopenharmony_ci    .version    = LIBAVUTIL_VERSION_INT,
283cabdff1aSopenharmony_ci};
284cabdff1aSopenharmony_ci
285cabdff1aSopenharmony_cistatic const FFCodecDefault qsv_enc_defaults[] = {
286cabdff1aSopenharmony_ci    { "b",         "1M"    },
287cabdff1aSopenharmony_ci    { "refs",      "0"     },
288cabdff1aSopenharmony_ci    // same as the x264 default
289cabdff1aSopenharmony_ci    { "g",         "248"   },
290cabdff1aSopenharmony_ci    { "bf",        "-1"    },
291cabdff1aSopenharmony_ci    { "qmin",      "-1"    },
292cabdff1aSopenharmony_ci    { "qmax",      "-1"    },
293cabdff1aSopenharmony_ci    { "trellis",   "-1"    },
294cabdff1aSopenharmony_ci    { "flags",     "+cgop" },
295cabdff1aSopenharmony_ci    { NULL },
296cabdff1aSopenharmony_ci};
297cabdff1aSopenharmony_ci
298cabdff1aSopenharmony_ciconst FFCodec ff_hevc_qsv_encoder = {
299cabdff1aSopenharmony_ci    .p.name         = "hevc_qsv",
300cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("HEVC (Intel Quick Sync Video acceleration)"),
301cabdff1aSopenharmony_ci    .priv_data_size = sizeof(QSVHEVCEncContext),
302cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
303cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_HEVC,
304cabdff1aSopenharmony_ci    .init           = qsv_enc_init,
305cabdff1aSopenharmony_ci    FF_CODEC_ENCODE_CB(qsv_enc_frame),
306cabdff1aSopenharmony_ci    .close          = qsv_enc_close,
307cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID,
308cabdff1aSopenharmony_ci    .p.pix_fmts     = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12,
309cabdff1aSopenharmony_ci                                                    AV_PIX_FMT_P010,
310cabdff1aSopenharmony_ci                                                    AV_PIX_FMT_YUYV422,
311cabdff1aSopenharmony_ci                                                    AV_PIX_FMT_Y210,
312cabdff1aSopenharmony_ci                                                    AV_PIX_FMT_QSV,
313cabdff1aSopenharmony_ci                                                    AV_PIX_FMT_BGRA,
314cabdff1aSopenharmony_ci                                                    AV_PIX_FMT_X2RGB10,
315cabdff1aSopenharmony_ci                                                    AV_PIX_FMT_NONE },
316cabdff1aSopenharmony_ci    .p.priv_class   = &class,
317cabdff1aSopenharmony_ci    .defaults       = qsv_enc_defaults,
318cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
319cabdff1aSopenharmony_ci    .p.wrapper_name = "qsv",
320cabdff1aSopenharmony_ci    .hw_configs     = ff_qsv_enc_hw_configs,
321cabdff1aSopenharmony_ci};
322