1/* 2 * librav1e encoder 3 * 4 * Copyright (c) 2019 Derek Buitenhuis 5 * 6 * This file is part of FFmpeg. 7 * 8 * FFmpeg is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * FFmpeg is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with FFmpeg; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 */ 22 23#include <rav1e.h> 24 25#include "libavutil/internal.h" 26#include "libavutil/avassert.h" 27#include "libavutil/base64.h" 28#include "libavutil/common.h" 29#include "libavutil/mathematics.h" 30#include "libavutil/opt.h" 31#include "libavutil/pixdesc.h" 32#include "avcodec.h" 33#include "bsf.h" 34#include "codec_internal.h" 35#include "encode.h" 36#include "internal.h" 37 38typedef struct librav1eContext { 39 const AVClass *class; 40 41 RaContext *ctx; 42 AVFrame *frame; 43 RaFrame *rframe; 44 AVBSFContext *bsf; 45 46 uint8_t *pass_data; 47 size_t pass_pos; 48 int pass_size; 49 50 AVDictionary *rav1e_opts; 51 int quantizer; 52 int speed; 53 int tiles; 54 int tile_rows; 55 int tile_cols; 56} librav1eContext; 57 58static inline RaPixelRange range_map(enum AVPixelFormat pix_fmt, enum AVColorRange range) 59{ 60 switch (pix_fmt) { 61 case AV_PIX_FMT_YUVJ420P: 62 case AV_PIX_FMT_YUVJ422P: 63 case AV_PIX_FMT_YUVJ444P: 64 return RA_PIXEL_RANGE_FULL; 65 } 66 67 switch (range) { 68 case AVCOL_RANGE_JPEG: 69 return RA_PIXEL_RANGE_FULL; 70 case AVCOL_RANGE_MPEG: 71 default: 72 return RA_PIXEL_RANGE_LIMITED; 73 } 74} 75 76static inline RaChromaSampling pix_fmt_map(enum AVPixelFormat pix_fmt) 77{ 78 switch (pix_fmt) { 79 case AV_PIX_FMT_YUV420P: 80 case AV_PIX_FMT_YUVJ420P: 81 case AV_PIX_FMT_YUV420P10: 82 case AV_PIX_FMT_YUV420P12: 83 return RA_CHROMA_SAMPLING_CS420; 84 case AV_PIX_FMT_YUV422P: 85 case AV_PIX_FMT_YUVJ422P: 86 case AV_PIX_FMT_YUV422P10: 87 case AV_PIX_FMT_YUV422P12: 88 return RA_CHROMA_SAMPLING_CS422; 89 case AV_PIX_FMT_YUV444P: 90 case AV_PIX_FMT_YUVJ444P: 91 case AV_PIX_FMT_YUV444P10: 92 case AV_PIX_FMT_YUV444P12: 93 return RA_CHROMA_SAMPLING_CS444; 94 default: 95 av_assert0(0); 96 } 97} 98 99static inline RaChromaSamplePosition chroma_loc_map(enum AVChromaLocation chroma_loc) 100{ 101 switch (chroma_loc) { 102 case AVCHROMA_LOC_LEFT: 103 return RA_CHROMA_SAMPLE_POSITION_VERTICAL; 104 case AVCHROMA_LOC_TOPLEFT: 105 return RA_CHROMA_SAMPLE_POSITION_COLOCATED; 106 default: 107 return RA_CHROMA_SAMPLE_POSITION_UNKNOWN; 108 } 109} 110 111static int get_stats(AVCodecContext *avctx, int eos) 112{ 113 librav1eContext *ctx = avctx->priv_data; 114 RaData* buf = rav1e_twopass_out(ctx->ctx); 115 if (!buf) 116 return 0; 117 118 if (!eos) { 119 uint8_t *tmp = av_fast_realloc(ctx->pass_data, &ctx->pass_size, 120 ctx->pass_pos + buf->len); 121 if (!tmp) { 122 rav1e_data_unref(buf); 123 return AVERROR(ENOMEM); 124 } 125 126 ctx->pass_data = tmp; 127 memcpy(ctx->pass_data + ctx->pass_pos, buf->data, buf->len); 128 ctx->pass_pos += buf->len; 129 } else { 130 size_t b64_size = AV_BASE64_SIZE(ctx->pass_pos); 131 132 memcpy(ctx->pass_data, buf->data, buf->len); 133 134 avctx->stats_out = av_malloc(b64_size); 135 if (!avctx->stats_out) { 136 rav1e_data_unref(buf); 137 return AVERROR(ENOMEM); 138 } 139 140 av_base64_encode(avctx->stats_out, b64_size, ctx->pass_data, ctx->pass_pos); 141 142 av_freep(&ctx->pass_data); 143 } 144 145 rav1e_data_unref(buf); 146 147 return 0; 148} 149 150static int set_stats(AVCodecContext *avctx) 151{ 152 librav1eContext *ctx = avctx->priv_data; 153 int ret = 1; 154 155 while (ret > 0 && ctx->pass_size - ctx->pass_pos > 0) { 156 ret = rav1e_twopass_in(ctx->ctx, ctx->pass_data + ctx->pass_pos, ctx->pass_size); 157 if (ret < 0) 158 return AVERROR_EXTERNAL; 159 ctx->pass_pos += ret; 160 } 161 162 return 0; 163} 164 165static av_cold int librav1e_encode_close(AVCodecContext *avctx) 166{ 167 librav1eContext *ctx = avctx->priv_data; 168 169 if (ctx->ctx) { 170 rav1e_context_unref(ctx->ctx); 171 ctx->ctx = NULL; 172 } 173 if (ctx->rframe) { 174 rav1e_frame_unref(ctx->rframe); 175 ctx->rframe = NULL; 176 } 177 178 av_frame_free(&ctx->frame); 179 av_bsf_free(&ctx->bsf); 180 av_freep(&ctx->pass_data); 181 182 return 0; 183} 184 185static av_cold int librav1e_encode_init(AVCodecContext *avctx) 186{ 187 librav1eContext *ctx = avctx->priv_data; 188 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt); 189 RaConfig *cfg = NULL; 190 int rret; 191 int ret = 0; 192 193 ctx->frame = av_frame_alloc(); 194 if (!ctx->frame) 195 return AVERROR(ENOMEM); 196 197 cfg = rav1e_config_default(); 198 if (!cfg) { 199 av_log(avctx, AV_LOG_ERROR, "Could not allocate rav1e config.\n"); 200 return AVERROR_EXTERNAL; 201 } 202 203 /* 204 * Rav1e currently uses the time base given to it only for ratecontrol... where 205 * the inverse is taken and used as a framerate. So, do what we do in other wrappers 206 * and use the framerate if we can. 207 */ 208 if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { 209 rav1e_config_set_time_base(cfg, (RaRational) { 210 avctx->framerate.den, avctx->framerate.num 211 }); 212 } else { 213 rav1e_config_set_time_base(cfg, (RaRational) { 214 avctx->time_base.num * avctx->ticks_per_frame, 215 avctx->time_base.den 216 }); 217 } 218 219 if ((avctx->flags & AV_CODEC_FLAG_PASS1 || avctx->flags & AV_CODEC_FLAG_PASS2) && !avctx->bit_rate) { 220 av_log(avctx, AV_LOG_ERROR, "A bitrate must be set to use two pass mode.\n"); 221 ret = AVERROR_INVALIDDATA; 222 goto end; 223 } 224 225 if (avctx->flags & AV_CODEC_FLAG_PASS2) { 226 if (!avctx->stats_in) { 227 av_log(avctx, AV_LOG_ERROR, "No stats file provided for second pass.\n"); 228 ret = AVERROR(EINVAL); 229 goto end; 230 } 231 232 ctx->pass_size = (strlen(avctx->stats_in) * 3) / 4; 233 ctx->pass_data = av_malloc(ctx->pass_size); 234 if (!ctx->pass_data) { 235 av_log(avctx, AV_LOG_ERROR, "Could not allocate stats buffer.\n"); 236 ret = AVERROR(ENOMEM); 237 goto end; 238 } 239 240 ctx->pass_size = av_base64_decode(ctx->pass_data, avctx->stats_in, ctx->pass_size); 241 if (ctx->pass_size < 0) { 242 av_log(avctx, AV_LOG_ERROR, "Invalid pass file.\n"); 243 ret = AVERROR(EINVAL); 244 goto end; 245 } 246 } 247 248 if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { 249 const AVBitStreamFilter *filter = av_bsf_get_by_name("extract_extradata"); 250 int bret; 251 252 if (!filter) { 253 av_log(avctx, AV_LOG_ERROR, "extract_extradata bitstream filter " 254 "not found. This is a bug, please report it.\n"); 255 ret = AVERROR_BUG; 256 goto end; 257 } 258 259 bret = av_bsf_alloc(filter, &ctx->bsf); 260 if (bret < 0) { 261 ret = bret; 262 goto end; 263 } 264 265 bret = avcodec_parameters_from_context(ctx->bsf->par_in, avctx); 266 if (bret < 0) { 267 ret = bret; 268 goto end; 269 } 270 271 bret = av_bsf_init(ctx->bsf); 272 if (bret < 0) { 273 ret = bret; 274 goto end; 275 } 276 } 277 278 { 279 AVDictionaryEntry *en = NULL; 280 while ((en = av_dict_get(ctx->rav1e_opts, "", en, AV_DICT_IGNORE_SUFFIX))) { 281 int parse_ret = rav1e_config_parse(cfg, en->key, en->value); 282 if (parse_ret < 0) 283 av_log(avctx, AV_LOG_WARNING, "Invalid value for %s: %s.\n", en->key, en->value); 284 } 285 } 286 287 rret = rav1e_config_parse_int(cfg, "width", avctx->width); 288 if (rret < 0) { 289 av_log(avctx, AV_LOG_ERROR, "Invalid width passed to rav1e.\n"); 290 ret = AVERROR_INVALIDDATA; 291 goto end; 292 } 293 294 rret = rav1e_config_parse_int(cfg, "height", avctx->height); 295 if (rret < 0) { 296 av_log(avctx, AV_LOG_ERROR, "Invalid height passed to rav1e.\n"); 297 ret = AVERROR_INVALIDDATA; 298 goto end; 299 } 300 301 rret = rav1e_config_parse_int(cfg, "threads", avctx->thread_count); 302 if (rret < 0) 303 av_log(avctx, AV_LOG_WARNING, "Invalid number of threads, defaulting to auto.\n"); 304 305 if (ctx->speed >= 0) { 306 rret = rav1e_config_parse_int(cfg, "speed", ctx->speed); 307 if (rret < 0) { 308 av_log(avctx, AV_LOG_ERROR, "Could not set speed preset.\n"); 309 ret = AVERROR_EXTERNAL; 310 goto end; 311 } 312 } 313 314 /* rav1e handles precedence between 'tiles' and cols/rows for us. */ 315 if (ctx->tiles > 0) { 316 rret = rav1e_config_parse_int(cfg, "tiles", ctx->tiles); 317 if (rret < 0) { 318 av_log(avctx, AV_LOG_ERROR, "Could not set number of tiles to encode with.\n"); 319 ret = AVERROR_EXTERNAL; 320 goto end; 321 } 322 } 323 if (ctx->tile_rows > 0) { 324 rret = rav1e_config_parse_int(cfg, "tile_rows", ctx->tile_rows); 325 if (rret < 0) { 326 av_log(avctx, AV_LOG_ERROR, "Could not set number of tile rows to encode with.\n"); 327 ret = AVERROR_EXTERNAL; 328 goto end; 329 } 330 } 331 if (ctx->tile_cols > 0) { 332 rret = rav1e_config_parse_int(cfg, "tile_cols", ctx->tile_cols); 333 if (rret < 0) { 334 av_log(avctx, AV_LOG_ERROR, "Could not set number of tile cols to encode with.\n"); 335 ret = AVERROR_EXTERNAL; 336 goto end; 337 } 338 } 339 340 if (avctx->gop_size > 0) { 341 rret = rav1e_config_parse_int(cfg, "key_frame_interval", avctx->gop_size); 342 if (rret < 0) { 343 av_log(avctx, AV_LOG_ERROR, "Could not set max keyint.\n"); 344 ret = AVERROR_EXTERNAL; 345 goto end; 346 } 347 } 348 349 if (avctx->keyint_min > 0) { 350 rret = rav1e_config_parse_int(cfg, "min_key_frame_interval", avctx->keyint_min); 351 if (rret < 0) { 352 av_log(avctx, AV_LOG_ERROR, "Could not set min keyint.\n"); 353 ret = AVERROR_EXTERNAL; 354 goto end; 355 } 356 } 357 358 if (avctx->bit_rate && ctx->quantizer < 0) { 359 int max_quantizer = avctx->qmax >= 0 ? avctx->qmax : 255; 360 361 rret = rav1e_config_parse_int(cfg, "quantizer", max_quantizer); 362 if (rret < 0) { 363 av_log(avctx, AV_LOG_ERROR, "Could not set max quantizer.\n"); 364 ret = AVERROR_EXTERNAL; 365 goto end; 366 } 367 368 if (avctx->qmin >= 0) { 369 rret = rav1e_config_parse_int(cfg, "min_quantizer", avctx->qmin); 370 if (rret < 0) { 371 av_log(avctx, AV_LOG_ERROR, "Could not set min quantizer.\n"); 372 ret = AVERROR_EXTERNAL; 373 goto end; 374 } 375 } 376 377 rret = rav1e_config_parse_int(cfg, "bitrate", avctx->bit_rate); 378 if (rret < 0) { 379 av_log(avctx, AV_LOG_ERROR, "Could not set bitrate.\n"); 380 ret = AVERROR_INVALIDDATA; 381 goto end; 382 } 383 } else if (ctx->quantizer >= 0) { 384 if (avctx->bit_rate) 385 av_log(avctx, AV_LOG_WARNING, "Both bitrate and quantizer specified. Using quantizer mode."); 386 387 rret = rav1e_config_parse_int(cfg, "quantizer", ctx->quantizer); 388 if (rret < 0) { 389 av_log(avctx, AV_LOG_ERROR, "Could not set quantizer.\n"); 390 ret = AVERROR_EXTERNAL; 391 goto end; 392 } 393 } 394 395 rret = rav1e_config_set_pixel_format(cfg, desc->comp[0].depth, 396 pix_fmt_map(avctx->pix_fmt), 397 chroma_loc_map(avctx->chroma_sample_location), 398 range_map(avctx->pix_fmt, avctx->color_range)); 399 if (rret < 0) { 400 av_log(avctx, AV_LOG_ERROR, "Failed to set pixel format properties.\n"); 401 ret = AVERROR_INVALIDDATA; 402 goto end; 403 } 404 405 /* rav1e's colorspace enums match standard values. */ 406 rret = rav1e_config_set_color_description(cfg, (RaMatrixCoefficients) avctx->colorspace, 407 (RaColorPrimaries) avctx->color_primaries, 408 (RaTransferCharacteristics) avctx->color_trc); 409 if (rret < 0) { 410 av_log(avctx, AV_LOG_WARNING, "Failed to set color properties.\n"); 411 if (avctx->err_recognition & AV_EF_EXPLODE) { 412 ret = AVERROR_INVALIDDATA; 413 goto end; 414 } 415 } 416 417 ctx->ctx = rav1e_context_new(cfg); 418 if (!ctx->ctx) { 419 av_log(avctx, AV_LOG_ERROR, "Failed to create rav1e encode context.\n"); 420 ret = AVERROR_EXTERNAL; 421 goto end; 422 } 423 424 ret = 0; 425 426end: 427 428 rav1e_config_unref(cfg); 429 430 return ret; 431} 432 433static int librav1e_receive_packet(AVCodecContext *avctx, AVPacket *pkt) 434{ 435 librav1eContext *ctx = avctx->priv_data; 436 RaFrame *rframe = ctx->rframe; 437 RaPacket *rpkt = NULL; 438 int ret; 439 440 if (!rframe) { 441 AVFrame *frame = ctx->frame; 442 443 ret = ff_encode_get_frame(avctx, frame); 444 if (ret < 0 && ret != AVERROR_EOF) 445 return ret; 446 447 if (frame->buf[0]) { 448 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); 449 450 int64_t *pts = av_malloc(sizeof(int64_t)); 451 if (!pts) { 452 av_log(avctx, AV_LOG_ERROR, "Could not allocate PTS buffer.\n"); 453 return AVERROR(ENOMEM); 454 } 455 *pts = frame->pts; 456 457 rframe = rav1e_frame_new(ctx->ctx); 458 if (!rframe) { 459 av_log(avctx, AV_LOG_ERROR, "Could not allocate new rav1e frame.\n"); 460 av_frame_unref(frame); 461 av_freep(&pts); 462 return AVERROR(ENOMEM); 463 } 464 465 for (int i = 0; i < desc->nb_components; i++) { 466 int shift = i ? desc->log2_chroma_h : 0; 467 int bytes = desc->comp[0].depth == 8 ? 1 : 2; 468 rav1e_frame_fill_plane(rframe, i, frame->data[i], 469 (frame->height >> shift) * frame->linesize[i], 470 frame->linesize[i], bytes); 471 } 472 av_frame_unref(frame); 473 rav1e_frame_set_opaque(rframe, pts, av_free); 474 } 475 } 476 477 ret = rav1e_send_frame(ctx->ctx, rframe); 478 if (rframe) 479 if (ret == RA_ENCODER_STATUS_ENOUGH_DATA) { 480 ctx->rframe = rframe; /* Queue is full. Store the RaFrame to retry next call */ 481 } else { 482 rav1e_frame_unref(rframe); /* No need to unref if flushing. */ 483 ctx->rframe = NULL; 484 } 485 486 switch (ret) { 487 case RA_ENCODER_STATUS_SUCCESS: 488 case RA_ENCODER_STATUS_ENOUGH_DATA: 489 break; 490 case RA_ENCODER_STATUS_FAILURE: 491 av_log(avctx, AV_LOG_ERROR, "Could not send frame: %s\n", rav1e_status_to_str(ret)); 492 return AVERROR_EXTERNAL; 493 default: 494 av_log(avctx, AV_LOG_ERROR, "Unknown return code %d from rav1e_send_frame: %s\n", ret, rav1e_status_to_str(ret)); 495 return AVERROR_UNKNOWN; 496 } 497 498retry: 499 500 if (avctx->flags & AV_CODEC_FLAG_PASS1) { 501 int sret = get_stats(avctx, 0); 502 if (sret < 0) 503 return sret; 504 } else if (avctx->flags & AV_CODEC_FLAG_PASS2) { 505 int sret = set_stats(avctx); 506 if (sret < 0) 507 return sret; 508 } 509 510 ret = rav1e_receive_packet(ctx->ctx, &rpkt); 511 switch (ret) { 512 case RA_ENCODER_STATUS_SUCCESS: 513 break; 514 case RA_ENCODER_STATUS_LIMIT_REACHED: 515 if (avctx->flags & AV_CODEC_FLAG_PASS1) { 516 int sret = get_stats(avctx, 1); 517 if (sret < 0) 518 return sret; 519 } 520 return AVERROR_EOF; 521 case RA_ENCODER_STATUS_ENCODED: 522 goto retry; 523 case RA_ENCODER_STATUS_NEED_MORE_DATA: 524 if (avctx->internal->draining) { 525 av_log(avctx, AV_LOG_ERROR, "Unexpected error when receiving packet after EOF.\n"); 526 return AVERROR_EXTERNAL; 527 } 528 return AVERROR(EAGAIN); 529 case RA_ENCODER_STATUS_FAILURE: 530 av_log(avctx, AV_LOG_ERROR, "Could not encode frame: %s\n", rav1e_status_to_str(ret)); 531 return AVERROR_EXTERNAL; 532 default: 533 av_log(avctx, AV_LOG_ERROR, "Unknown return code %d from rav1e_receive_packet: %s\n", ret, rav1e_status_to_str(ret)); 534 return AVERROR_UNKNOWN; 535 } 536 537 ret = ff_get_encode_buffer(avctx, pkt, rpkt->len, 0); 538 if (ret < 0) { 539 av_log(avctx, AV_LOG_ERROR, "Could not allocate packet.\n"); 540 rav1e_packet_unref(rpkt); 541 return ret; 542 } 543 544 memcpy(pkt->data, rpkt->data, rpkt->len); 545 546 if (rpkt->frame_type == RA_FRAME_TYPE_KEY) 547 pkt->flags |= AV_PKT_FLAG_KEY; 548 549 pkt->pts = pkt->dts = *((int64_t *) rpkt->opaque); 550 av_free(rpkt->opaque); 551 rav1e_packet_unref(rpkt); 552 553 if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { 554 int ret = av_bsf_send_packet(ctx->bsf, pkt); 555 if (ret < 0) { 556 av_log(avctx, AV_LOG_ERROR, "extradata extraction send failed.\n"); 557 av_packet_unref(pkt); 558 return ret; 559 } 560 561 ret = av_bsf_receive_packet(ctx->bsf, pkt); 562 if (ret < 0) { 563 av_log(avctx, AV_LOG_ERROR, "extradata extraction receive failed.\n"); 564 av_packet_unref(pkt); 565 return ret; 566 } 567 } 568 569 return 0; 570} 571 572#define OFFSET(x) offsetof(librav1eContext, x) 573#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM 574 575static const AVOption options[] = { 576 { "qp", "use constant quantizer mode", OFFSET(quantizer), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, VE }, 577 { "speed", "what speed preset to use", OFFSET(speed), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 10, VE }, 578 { "tiles", "number of tiles encode with", OFFSET(tiles), AV_OPT_TYPE_INT, { .i64 = 0 }, -1, INT64_MAX, VE }, 579 { "tile-rows", "number of tiles rows to encode with", OFFSET(tile_rows), AV_OPT_TYPE_INT, { .i64 = 0 }, -1, INT64_MAX, VE }, 580 { "tile-columns", "number of tiles columns to encode with", OFFSET(tile_cols), AV_OPT_TYPE_INT, { .i64 = 0 }, -1, INT64_MAX, VE }, 581 { "rav1e-params", "set the rav1e configuration using a :-separated list of key=value parameters", OFFSET(rav1e_opts), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE }, 582 { NULL } 583}; 584 585static const FFCodecDefault librav1e_defaults[] = { 586 { "b", "0" }, 587 { "g", "0" }, 588 { "keyint_min", "0" }, 589 { "qmax", "-1" }, 590 { "qmin", "-1" }, 591 { NULL } 592}; 593 594const enum AVPixelFormat librav1e_pix_fmts[] = { 595 AV_PIX_FMT_YUV420P, 596 AV_PIX_FMT_YUVJ420P, 597 AV_PIX_FMT_YUV420P10, 598 AV_PIX_FMT_YUV420P12, 599 AV_PIX_FMT_YUV422P, 600 AV_PIX_FMT_YUVJ422P, 601 AV_PIX_FMT_YUV422P10, 602 AV_PIX_FMT_YUV422P12, 603 AV_PIX_FMT_YUV444P, 604 AV_PIX_FMT_YUVJ444P, 605 AV_PIX_FMT_YUV444P10, 606 AV_PIX_FMT_YUV444P12, 607 AV_PIX_FMT_NONE 608}; 609 610static const AVClass class = { 611 .class_name = "librav1e", 612 .item_name = av_default_item_name, 613 .option = options, 614 .version = LIBAVUTIL_VERSION_INT, 615}; 616 617const FFCodec ff_librav1e_encoder = { 618 .p.name = "librav1e", 619 .p.long_name = NULL_IF_CONFIG_SMALL("librav1e AV1"), 620 .p.type = AVMEDIA_TYPE_VIDEO, 621 .p.id = AV_CODEC_ID_AV1, 622 .init = librav1e_encode_init, 623 FF_CODEC_RECEIVE_PACKET_CB(librav1e_receive_packet), 624 .close = librav1e_encode_close, 625 .priv_data_size = sizeof(librav1eContext), 626 .p.priv_class = &class, 627 .defaults = librav1e_defaults, 628 .p.pix_fmts = librav1e_pix_fmts, 629 .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS | 630 AV_CODEC_CAP_DR1, 631 .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS, 632 .p.wrapper_name = "librav1e", 633}; 634