| @@ -0,0 +1,483 @@ |
| | 1 | /* |
| | 2 | * liboapv encoder |
| | 3 | * Advanced Professional Video codec library |
| | 4 | * |
| | 5 | * Copyright (C) 2025 Dawid Kozinski <d.kozinski@samsung.com> |
| | 6 | * |
| | 7 | * This file is part of FFmpeg. |
| | 8 | * |
| | 9 | * FFmpeg is free software; you can redistribute it and/or |
| | 10 | * modify it under the terms of the GNU Lesser General Public |
| | 11 | * License as published by the Free Software Foundation; either |
| | 12 | * version 2.1 of the License, or (at your option) any later version. |
| | 13 | * |
| | 14 | * FFmpeg is distributed in the hope that it will be useful, |
| | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| | 17 | * Lesser General Public License for more details. |
| | 18 | * |
| | 19 | * You should have received a copy of the GNU Lesser General Public |
| | 20 | * License along with FFmpeg; if not, write to the Free Software |
| | 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| | 22 | */ |
| | 23 | |
| | 24 | #include <stdint.h> |
| | 25 | #include <stdlib.h> |
| | 26 | |
| | 27 | #include <oapv/oapv.h> |
| | 28 | |
| | 29 | #include "libavutil/avassert.h" |
| | 30 | #include "libavutil/intreadwrite.h" |
| | 31 | #include "libavutil/imgutils.h" |
| | 32 | #include "libavutil/mem.h" |
| | 33 | #include "libavutil/opt.h" |
| | 34 | #include "libavutil/pixdesc.h" |
| | 35 | #include "libavutil/pixfmt.h" |
| | 36 | |
| | 37 | #include "avcodec.h" |
| | 38 | #include "apv.h" |
| | 39 | #include "codec_internal.h" |
| | 40 | #include "encode.h" |
| | 41 | #include "packet_internal.h" |
| | 42 | #include "profiles.h" |
| | 43 | |
| | 44 | #define MAX_BS_BUF (128 * 1024 * 1024) |
| | 45 | #define MAX_NUM_FRMS (1) // supports only 1-frame in an access unit |
| | 46 | #define FRM_IDX (0) // supports only 1-frame in an access unit |
| | 47 | #define MAX_NUM_CC (OAPV_MAX_CC) // Max number of color componets (upto 4:4:4:4) |
| | 48 | |
| | 49 | /** |
| | 50 | * The structure stores all the states associated with the instance of APV encoder |
| | 51 | */ |
| | 52 | typedef struct ApvEncContext { |
| | 53 | const AVClass *class; |
| | 54 | |
| | 55 | oapve_t id; // APV instance identifier |
| | 56 | oapvm_t mid; |
| | 57 | oapve_cdesc_t cdsc; // coding parameters i.e profile, width & height of input frame, num of therads, frame rate ... |
| | 58 | oapv_bitb_t bitb; // bitstream buffer (output) |
| | 59 | oapve_stat_t stat; // encoding status (output) |
| | 60 | |
| | 61 | oapv_frms_t ifrms; // frames for input |
| | 62 | |
| | 63 | int num_frames; // number of frames in an access unit |
| | 64 | |
| | 65 | int preset_id; // preset of apv ( fastest, fast, medium, slow, placebo) |
| | 66 | |
| | 67 | int qp; // quantization parameter (QP) [0,63] |
| | 68 | |
| | 69 | AVDictionary *oapv_params; |
| | 70 | } ApvEncContext; |
| | 71 | |
| | 72 | static int apv_imgb_release(oapv_imgb_t *imgb) |
| | 73 | { |
| | 74 | int refcnt = --imgb->refcnt; |
| | 75 | if (refcnt == 0) { |
| | 76 | for (int i = 0; i < imgb->np; i++) |
| | 77 | av_freep(&imgb->baddr[i]); |
| | 78 | av_free(imgb); |
| | 79 | } |
| | 80 | |
| | 81 | return refcnt; |
| | 82 | } |
| | 83 | |
| | 84 | static int apv_imgb_addref(oapv_imgb_t * imgb) |
| | 85 | { |
| | 86 | int refcnt = ++imgb->refcnt; |
| | 87 | return refcnt; |
| | 88 | } |
| | 89 | |
| | 90 | static int apv_imgb_getref(oapv_imgb_t * imgb) |
| | 91 | { |
| | 92 | return imgb->refcnt; |
| | 93 | } |
| | 94 | |
| | 95 | /** |
| | 96 | * Convert FFmpeg pixel format (AVPixelFormat) into APV pre-defined color format |
| | 97 | * |
| | 98 | * @return APV pre-defined color format (@see oapv.h) on success, OAPV_CF_UNKNOWN on failure |
| | 99 | */ |
| | 100 | static inline int get_color_format(enum AVPixelFormat pix_fmt) |
| | 101 | { |
| | 102 | int cf = OAPV_CF_UNKNOWN; |
| | 103 | |
| | 104 | switch (pix_fmt) { |
| | 105 | case AV_PIX_FMT_YUV422P10: |
| | 106 | cf = OAPV_CF_YCBCR422; |
| | 107 | break; |
| | 108 | case AV_PIX_FMT_YUV444P10: |
| | 109 | cf = OAPV_CF_YCBCR444; |
| | 110 | break; |
| | 111 | default: |
| | 112 | av_assert0(cf != OAPV_CF_UNKNOWN); |
| | 113 | } |
| | 114 | |
| | 115 | return cf; |
| | 116 | } |
| | 117 | |
| | 118 | static oapv_imgb_t *apv_imgb_create(AVCodecContext *avctx) |
| | 119 | { |
| | 120 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); |
| | 121 | oapv_imgb_t *imgb; |
| | 122 | int input_depth; |
| | 123 | int cfmt; // color format |
| | 124 | int cs; |
| | 125 | |
| | 126 | av_assert0(desc); |
| | 127 | |
| | 128 | imgb = av_mallocz(sizeof(oapv_imgb_t)); |
| | 129 | if (!imgb) |
| | 130 | goto fail; |
| | 131 | |
| | 132 | input_depth = desc->comp[0].depth; |
| | 133 | cfmt = get_color_format(avctx->pix_fmt); |
| | 134 | cs = OAPV_CS_SET(cfmt, input_depth, AV_HAVE_BIGENDIAN); |
| | 135 | |
| | 136 | imgb->np = desc->nb_components; |
| | 137 | |
| | 138 | for (int i = 0; i < imgb->np; i++) { |
| | 139 | imgb->w[i] = avctx->width >> ((i == 1 || i == 2) ? desc->log2_chroma_w : 0); |
| | 140 | imgb->h[i] = avctx->height; |
| | 141 | imgb->aw[i] = FFALIGN(imgb->w[i], OAPV_MB_W); |
| | 142 | imgb->ah[i] = FFALIGN(imgb->h[i], OAPV_MB_H); |
| | 143 | imgb->s[i] = imgb->aw[i] * OAPV_CS_GET_BYTE_DEPTH(cs); |
| | 144 | |
| | 145 | imgb->bsize[i] = imgb->e[i] = imgb->s[i] * imgb->ah[i]; |
| | 146 | imgb->a[i] = imgb->baddr[i] = av_mallocz(imgb->bsize[i]); |
| | 147 | if (imgb->a[i] == NULL) |
| | 148 | goto fail; |
| | 149 | } |
| | 150 | |
| | 151 | imgb->cs = cs; |
| | 152 | imgb->addref = apv_imgb_addref; |
| | 153 | imgb->getref = apv_imgb_getref; |
| | 154 | imgb->release = apv_imgb_release; |
| | 155 | imgb->refcnt = 1; |
| | 156 | |
| | 157 | return imgb; |
| | 158 | fail: |
| | 159 | av_log(avctx, AV_LOG_ERROR, "cannot create image buffer\n"); |
| | 160 | if (imgb) { |
| | 161 | for (int i = 0; i < imgb->np; i++) |
| | 162 | av_freep(&imgb->a[i]); |
| | 163 | av_freep(&imgb); |
| | 164 | } |
| | 165 | return NULL; |
| | 166 | } |
| | 167 | |
| | 168 | /** |
| | 169 | * The function returns a pointer to the object of the oapve_cdesc_t type. |
| | 170 | * oapve_cdesc_t contains all encoder parameters that should be initialized before the encoder is used. |
| | 171 | * |
| | 172 | * The field values of the oapve_cdesc_t structure are populated based on: |
| | 173 | * - the corresponding field values of the AvCodecConetxt structure, |
| | 174 | * - the apv encoder specific option values, |
| | 175 | * |
| | 176 | * The order of processing input data and populating the apve_cdsc structure |
| | 177 | * 1) first, the fields of the AVCodecContext structure corresponding to the provided input options are processed, |
| | 178 | * (i.e -pix_fmt yuv422p -s:v 1920x1080 -r 30 -profile:v 0) |
| | 179 | * 2) then apve-specific options added as AVOption to the apv AVCodec implementation |
| | 180 | * (i.e -preset 0) |
| | 181 | * |
| | 182 | * Keep in mind that, there are options that can be set in different ways. |
| | 183 | * In this case, please follow the above-mentioned order of processing. |
| | 184 | * The most recent assignments overwrite the previous values. |
| | 185 | * |
| | 186 | * @param[in] avctx codec context (AVCodecContext) |
| | 187 | * @param[out] cdsc contains all APV encoder encoder parameters that should be initialized before the encoder is use |
| | 188 | * |
| | 189 | * @return 0 on success, negative error code on failure |
| | 190 | */ |
| | 191 | static int get_conf(AVCodecContext *avctx, oapve_cdesc_t *cdsc) |
| | 192 | { |
| | 193 | ApvEncContext *apv = avctx->priv_data; |
| | 194 | |
| | 195 | /* initialize apv_param struct with default values */ |
| | 196 | int ret = oapve_param_default(&cdsc->param[FRM_IDX]); |
| | 197 | if (OAPV_FAILED(ret)) { |
| | 198 | av_log(avctx, AV_LOG_ERROR, "Cannot set default parameter\n"); |
| | 199 | return AVERROR_EXTERNAL; |
| | 200 | } |
| | 201 | |
| | 202 | /* read options from AVCodecContext */ |
| | 203 | if (avctx->width > 0) |
| | 204 | cdsc->param[FRM_IDX].w = avctx->width; |
| | 205 | |
| | 206 | if (avctx->height > 0) |
| | 207 | cdsc->param[FRM_IDX].h = avctx->height; |
| | 208 | |
| | 209 | if (avctx->framerate.num > 0) { |
| | 210 | cdsc->param[FRM_IDX].fps_num = avctx->framerate.num; |
| | 211 | cdsc->param[FRM_IDX].fps_den = avctx->framerate.den; |
| | 212 | } else if (avctx->time_base.num > 0) { |
| | 213 | cdsc->param[FRM_IDX].fps_num = avctx->time_base.den; |
| | 214 | cdsc->param[FRM_IDX].fps_den = avctx->time_base.num; |
| | 215 | } |
| | 216 | |
| | 217 | cdsc->param[FRM_IDX].preset = apv->preset_id; |
| | 218 | cdsc->param[FRM_IDX].qp = apv->qp; |
| | 219 | if (avctx->bit_rate / 1000 > INT_MAX || avctx->rc_max_rate / 1000 > INT_MAX) { |
| | 220 | av_log(avctx, AV_LOG_ERROR, "bit_rate and rc_max_rate > %d000 is not supported\n", INT_MAX); |
| | 221 | return AVERROR(EINVAL); |
| | 222 | } |
| | 223 | cdsc->param[FRM_IDX].bitrate = (int)(avctx->bit_rate / 1000); |
| | 224 | if (cdsc->param[FRM_IDX].bitrate) { |
| | 225 | if (cdsc->param[FRM_IDX].qp) { |
| | 226 | av_log(avctx, AV_LOG_WARNING, "You cannot set both the bitrate and the QP parameter at the same time.\n" |
| | 227 | "If the bitrate is set, the rate control type is set to ABR, which means that the QP value is ignored.\n"); |
| | 228 | } |
| | 229 | cdsc->param[FRM_IDX].rc_type = OAPV_RC_ABR; |
| | 230 | } |
| | 231 | |
| | 232 | cdsc->threads = avctx->thread_count; |
| | 233 | |
| | 234 | if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED) { |
| | 235 | cdsc->param[FRM_IDX].color_primaries = avctx->color_primaries; |
| | 236 | cdsc->param[FRM_IDX].color_description_present_flag = 1; |
| | 237 | } |
| | 238 | |
| | 239 | if (avctx->color_trc != AVCOL_TRC_UNSPECIFIED) { |
| | 240 | cdsc->param[FRM_IDX].transfer_characteristics = avctx->color_trc; |
| | 241 | cdsc->param[FRM_IDX].color_description_present_flag = 1; |
| | 242 | } |
| | 243 | |
| | 244 | if (avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { |
| | 245 | cdsc->param[FRM_IDX].matrix_coefficients = avctx->colorspace; |
| | 246 | cdsc->param[FRM_IDX].color_description_present_flag = 1; |
| | 247 | } |
| | 248 | |
| | 249 | if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED) { |
| | 250 | cdsc->param[FRM_IDX].full_range_flag = (avctx->color_range == AVCOL_RANGE_JPEG); |
| | 251 | cdsc->param[FRM_IDX].color_description_present_flag = 1; |
| | 252 | } |
| | 253 | |
| | 254 | cdsc->max_bs_buf_size = MAX_BS_BUF; /* maximum bitstream buffer size */ |
| | 255 | cdsc->max_num_frms = MAX_NUM_FRMS; |
| | 256 | |
| | 257 | const AVDictionaryEntry *en = NULL; |
| | 258 | while (en = av_dict_iterate(apv->oapv_params, en)) { |
| | 259 | ret = oapve_param_parse(&cdsc->param[FRM_IDX], en->key, en->value); |
| | 260 | if (ret < 0) |
| | 261 | av_log(avctx, AV_LOG_WARNING, "Error parsing option '%s = %s'.\n", en->key, en->value); |
| | 262 | } |
| | 263 | |
| | 264 | return 0; |
| | 265 | } |
| | 266 | |
| | 267 | /** |
| | 268 | * @brief Initialize APV codec |
| | 269 | * Create an encoder instance and allocate all the needed resources |
| | 270 | * |
| | 271 | * @param avctx codec context |
| | 272 | * @return 0 on success, negative error code on failure |
| | 273 | */ |
| | 274 | static av_cold int liboapve_init(AVCodecContext *avctx) |
| | 275 | { |
| | 276 | ApvEncContext *apv = avctx->priv_data; |
| | 277 | oapve_cdesc_t *cdsc = &apv->cdsc; |
| | 278 | unsigned char *bs_buf; |
| | 279 | int ret; |
| | 280 | |
| | 281 | /* allocate bitstream buffer */ |
| | 282 | bs_buf = (unsigned char *)av_malloc(MAX_BS_BUF); |
| | 283 | if (bs_buf == NULL) { |
| | 284 | av_log(avctx, AV_LOG_ERROR, "Cannot allocate bitstream buffer, size=%d\n", MAX_BS_BUF); |
| | 285 | return AVERROR(ENOMEM); |
| | 286 | } |
| | 287 | apv->bitb.addr = bs_buf; |
| | 288 | apv->bitb.bsize = MAX_BS_BUF; |
| | 289 | |
| | 290 | /* read configurations and set values for created descriptor (APV_CDSC) */ |
| | 291 | ret = get_conf(avctx, cdsc); |
| | 292 | if (ret < 0) { |
| | 293 | av_log(avctx, AV_LOG_ERROR, "Cannot get OAPV configuration\n"); |
| | 294 | return ret; |
| | 295 | } |
| | 296 | |
| | 297 | /* create encoder */ |
| | 298 | apv->id = oapve_create(cdsc, &ret); |
| | 299 | if (apv->id == NULL) { |
| | 300 | av_log(avctx, AV_LOG_ERROR, "Cannot create OAPV encoder\n"); |
| | 301 | if (ret == OAPV_ERR_INVALID_LEVEL) |
| | 302 | av_log(avctx, AV_LOG_ERROR, "Invalid level idc: %d\n", cdsc->param[0].level_idc); |
| | 303 | return AVERROR_EXTERNAL; |
| | 304 | } |
| | 305 | |
| | 306 | /* create metadata handler */ |
| | 307 | apv->mid = oapvm_create(&ret); |
| | 308 | if (apv->mid == NULL || OAPV_FAILED(ret)) { |
| | 309 | av_log(avctx, AV_LOG_ERROR, "cannot create OAPV metadata handler\n"); |
| | 310 | return AVERROR_EXTERNAL; |
| | 311 | } |
| | 312 | |
| | 313 | apv->ifrms.frm[FRM_IDX].imgb = apv_imgb_create(avctx); |
| | 314 | if (apv->ifrms.frm[FRM_IDX].imgb == NULL) |
| | 315 | return AVERROR(ENOMEM); |
| | 316 | apv->ifrms.num_frms++; |
| | 317 | |
| | 318 | /* color description values */ |
| | 319 | if (cdsc->param[FRM_IDX].color_description_present_flag) { |
| | 320 | avctx->color_primaries = cdsc->param[FRM_IDX].color_primaries; |
| | 321 | avctx->color_trc = cdsc->param[FRM_IDX].transfer_characteristics; |
| | 322 | avctx->colorspace = cdsc->param[FRM_IDX].matrix_coefficients; |
| | 323 | avctx->color_range = (cdsc->param[FRM_IDX].full_range_flag) ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; |
| | 324 | } |
| | 325 | |
| | 326 | return 0; |
| | 327 | } |
| | 328 | |
| | 329 | /** |
| | 330 | * Encode raw data frame into APV packet |
| | 331 | * |
| | 332 | * @param[in] avctx codec context |
| | 333 | * @param[out] avpkt output AVPacket containing encoded data |
| | 334 | * @param[in] frame AVFrame containing the raw data to be encoded |
| | 335 | * @param[out] got_packet encoder sets to 0 or 1 to indicate that a |
| | 336 | * non-empty packet was returned in pkt |
| | 337 | * |
| | 338 | * @return 0 on success, negative error code on failure |
| | 339 | */ |
| | 340 | static int liboapve_encode(AVCodecContext *avctx, AVPacket *avpkt, |
| | 341 | const AVFrame *frame, int *got_packet) |
| | 342 | { |
| | 343 | ApvEncContext *apv = avctx->priv_data; |
| | 344 | const oapve_cdesc_t *cdsc = &apv->cdsc; |
| | 345 | oapv_frm_t *frm = &apv->ifrms.frm[FRM_IDX]; |
| | 346 | oapv_imgb_t *imgb = frm->imgb; |
| | 347 | int ret; |
| | 348 | |
| | 349 | if (avctx->width != frame->width || avctx->height != frame->height || avctx->pix_fmt != frame->format) { |
| | 350 | av_log(avctx, AV_LOG_ERROR, "Dimension changes are not supported\n"); |
| | 351 | return AVERROR(EINVAL); |
| | 352 | } |
| | 353 | |
| | 354 | av_image_copy((uint8_t **)imgb->a, imgb->s, (const uint8_t **)frame->data, frame->linesize, |
| | 355 | frame->format, frame->width, frame->height); |
| | 356 | |
| | 357 | imgb->ts[0] = frame->pts; |
| | 358 | |
| | 359 | frm->group_id = 1; // @todo FIX-ME : need to set properly in case of multi-frame |
| | 360 | frm->pbu_type = OAPV_PBU_TYPE_PRIMARY_FRAME; |
| | 361 | |
| | 362 | ret = oapve_encode(apv->id, &apv->ifrms, apv->mid, &apv->bitb, &apv->stat, NULL); |
| | 363 | if (OAPV_FAILED(ret)) { |
| | 364 | av_log(avctx, AV_LOG_ERROR, "oapve_encode() failed\n"); |
| | 365 | return AVERROR_EXTERNAL; |
| | 366 | } |
| | 367 | |
| | 368 | /* store bitstream */ |
| | 369 | if (OAPV_SUCCEEDED(ret) && apv->stat.write > 0) { |
| | 370 | uint8_t *data = apv->bitb.addr; |
| | 371 | int size = apv->stat.write; |
| | 372 | |
| | 373 | // The encoder may return a "Raw bitstream" formated AU, including au_size. |
| | 374 | // Discard it as we only need the access_unit() structure. |
| | 375 | if (size > 4 && AV_RB32(data) != APV_SIGNATURE) { |
| | 376 | data += 4; |
| | 377 | size -= 4; |
| | 378 | } |
| | 379 | |
| | 380 | ret = ff_get_encode_buffer(avctx, avpkt, size, 0); |
| | 381 | if (ret < 0) |
| | 382 | return ret; |
| | 383 | |
| | 384 | memcpy(avpkt->data, data, size); |
| | 385 | avpkt->pts = avpkt->dts = frame->pts; |
| | 386 | avpkt->flags |= AV_PKT_FLAG_KEY; |
| | 387 | |
| | 388 | if (cdsc->param[FRM_IDX].qp) |
| | 389 | ff_side_data_set_encoder_stats(avpkt, cdsc->param[FRM_IDX].qp * FF_QP2LAMBDA, NULL, 0, AV_PICTURE_TYPE_I); |
| | 390 | |
| | 391 | *got_packet = 1; |
| | 392 | } |
| | 393 | |
| | 394 | return 0; |
| | 395 | } |
| | 396 | |
| | 397 | /** |
| | 398 | * Destroy the encoder and release all the allocated resources |
| | 399 | * |
| | 400 | * @param avctx codec context |
| | 401 | * @return 0 on success, negative error code on failure |
| | 402 | */ |
| | 403 | static av_cold int liboapve_close(AVCodecContext *avctx) |
| | 404 | { |
| | 405 | ApvEncContext *apv = avctx->priv_data; |
| | 406 | |
| | 407 | for (int i = 0; i < apv->num_frames; i++) { |
| | 408 | if (apv->ifrms.frm[i].imgb != NULL) |
| | 409 | apv->ifrms.frm[i].imgb->release(apv->ifrms.frm[i].imgb); |
| | 410 | apv->ifrms.frm[i].imgb = NULL; |
| | 411 | } |
| | 412 | |
| | 413 | if (apv->mid) { |
| | 414 | oapvm_rem_all(apv->mid); |
| | 415 | } |
| | 416 | |
| | 417 | if (apv->id) { |
| | 418 | oapve_delete(apv->id); |
| | 419 | apv->id = NULL; |
| | 420 | } |
| | 421 | |
| | 422 | if (apv->mid) { |
| | 423 | oapvm_delete(apv->mid); |
| | 424 | apv->mid = NULL; |
| | 425 | } |
| | 426 | |
| | 427 | av_freep(&apv->bitb.addr); /* release bitstream buffer */ |
| | 428 | |
| | 429 | return 0; |
| | 430 | } |
| | 431 | |
| | 432 | #define OFFSET(x) offsetof(ApvEncContext, x) |
| | 433 | #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM |
| | 434 | |
| | 435 | static const enum AVPixelFormat supported_pixel_formats[] = { |
| | 436 | AV_PIX_FMT_YUV422P10, |
| | 437 | AV_PIX_FMT_YUV444P10, |
| | 438 | AV_PIX_FMT_NONE |
| | 439 | }; |
| | 440 | |
| | 441 | static const AVOption liboapv_options[] = { |
| | 442 | { "preset", "Encoding preset for setting encoding speed (optimization level control)", OFFSET(preset_id), AV_OPT_TYPE_INT, { .i64 = OAPV_PRESET_DEFAULT }, OAPV_PRESET_FASTEST, OAPV_PRESET_PLACEBO, VE, .unit = "preset" }, |
| | 443 | { "fastest", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_FASTEST }, INT_MIN, INT_MAX, VE, .unit = "preset" }, |
| | 444 | { "fast", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_FAST }, INT_MIN, INT_MAX, VE, .unit = "preset" }, |
| | 445 | { "medium", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_MEDIUM }, INT_MIN, INT_MAX, VE, .unit = "preset" }, |
| | 446 | { "slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_SLOW }, INT_MIN, INT_MAX, VE, .unit = "preset" }, |
| | 447 | { "placebo", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_PLACEBO }, INT_MIN, INT_MAX, VE, .unit = "preset" }, |
| | 448 | { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_DEFAULT }, INT_MIN, INT_MAX, VE, .unit = "preset" }, |
| | 449 | |
| | 450 | { "qp", "Quantization parameter value for CQP rate control mode", OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 32 }, 0, 63, VE }, |
| | 451 | { "oapv-params", "Override the apv configuration using a :-separated list of key=value parameters", OFFSET(oapv_params), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE }, |
| | 452 | { NULL } |
| | 453 | }; |
| | 454 | |
| | 455 | static const AVClass liboapve_class = { |
| | 456 | .class_name = "liboapv", |
| | 457 | .item_name = av_default_item_name, |
| | 458 | .option = liboapv_options, |
| | 459 | .version = LIBAVUTIL_VERSION_INT, |
| | 460 | }; |
| | 461 | |
| | 462 | static const FFCodecDefault liboapve_defaults[] = { |
| | 463 | { "b", "0" }, // bitrate in terms of kilo-bits per second (support for bit-rates from a few hundred Mbps to a few Gbps for 2K, 4K and 8K resolution content) |
| | 464 | { NULL }, |
| | 465 | }; |
| | 466 | |
| | 467 | const FFCodec ff_liboapv_encoder = { |
| | 468 | .p.name = "liboapv", |
| | 469 | .p.long_name = NULL_IF_CONFIG_SMALL("liboapv APV"), |
| | 470 | .p.type = AVMEDIA_TYPE_VIDEO, |
| | 471 | .p.id = AV_CODEC_ID_APV, |
| | 472 | .init = liboapve_init, |
| | 473 | FF_CODEC_ENCODE_CB(liboapve_encode), |
| | 474 | .close = liboapve_close, |
| | 475 | .priv_data_size = sizeof(ApvEncContext), |
| | 476 | .p.priv_class = &liboapve_class, |
| | 477 | .defaults = liboapve_defaults, |
| | 478 | .p.capabilities = AV_CODEC_CAP_OTHER_THREADS | AV_CODEC_CAP_DR1, |
| | 479 | .p.wrapper_name = "liboapv", |
| | 480 | .p.pix_fmts = supported_pixel_formats, |
| | 481 | .p.profiles = NULL_IF_CONFIG_SMALL(ff_apv_profiles), |
| | 482 | .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_NOT_INIT_THREADSAFE, |
| | 483 | }; |