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