]> git.sesse.net Git - ffmpeg/blob - libavcodec/h265_metadata_bsf.c
avcodec/options_table: make AVCodecContext->profile search for child constants
[ffmpeg] / libavcodec / h265_metadata_bsf.c
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 #include "libavutil/common.h"
20 #include "libavutil/opt.h"
21
22 #include "bsf.h"
23 #include "bsf_internal.h"
24 #include "cbs.h"
25 #include "cbs_h265.h"
26 #include "hevc.h"
27 #include "h265_profile_level.h"
28
29 enum {
30     PASS,
31     INSERT,
32     REMOVE,
33 };
34
35 enum {
36     LEVEL_UNSET = -2,
37     LEVEL_AUTO  = -1,
38 };
39
40 typedef struct H265MetadataContext {
41     const AVClass *class;
42
43     CodedBitstreamContext *cbc;
44     CodedBitstreamFragment access_unit;
45
46     H265RawAUD aud_nal;
47
48     int aud;
49
50     AVRational sample_aspect_ratio;
51
52     int video_format;
53     int video_full_range_flag;
54     int colour_primaries;
55     int transfer_characteristics;
56     int matrix_coefficients;
57
58     int chroma_sample_loc_type;
59
60     AVRational tick_rate;
61     int poc_proportional_to_timing_flag;
62     int num_ticks_poc_diff_one;
63
64     int crop_left;
65     int crop_right;
66     int crop_top;
67     int crop_bottom;
68
69     int level;
70     int level_guess;
71     int level_warned;
72 } H265MetadataContext;
73
74
75 static void h265_metadata_guess_level(AVBSFContext *bsf,
76                                       const CodedBitstreamFragment *au)
77 {
78     H265MetadataContext *ctx = bsf->priv_data;
79     const H265LevelDescriptor *desc;
80     const H265RawProfileTierLevel *ptl = NULL;
81     const H265RawHRDParameters    *hrd = NULL;
82     int64_t bit_rate = 0;
83     int width = 0, height = 0;
84     int tile_cols = 0, tile_rows = 0;
85     int max_dec_pic_buffering = 0;
86     int i;
87
88     for (i = 0; i < au->nb_units; i++) {
89         const CodedBitstreamUnit *unit = &au->units[i];
90
91         if (unit->type == HEVC_NAL_VPS) {
92             const H265RawVPS *vps = unit->content;
93
94             ptl = &vps->profile_tier_level;
95             max_dec_pic_buffering = vps->vps_max_dec_pic_buffering_minus1[0] + 1;
96
97             if (vps->vps_num_hrd_parameters > 0)
98                 hrd = &vps->hrd_parameters[0];
99
100         } else if (unit->type == HEVC_NAL_SPS) {
101             const H265RawSPS *sps = unit->content;
102
103             ptl = &sps->profile_tier_level;
104             max_dec_pic_buffering = sps->sps_max_dec_pic_buffering_minus1[0] + 1;
105
106             width  = sps->pic_width_in_luma_samples;
107             height = sps->pic_height_in_luma_samples;
108
109             if (sps->vui.vui_hrd_parameters_present_flag)
110                 hrd = &sps->vui.hrd_parameters;
111
112         } else if (unit->type == HEVC_NAL_PPS) {
113             const H265RawPPS *pps = unit->content;
114
115             if (pps->tiles_enabled_flag) {
116                 tile_cols = pps->num_tile_columns_minus1 + 1;
117                 tile_rows = pps->num_tile_rows_minus1 + 1;
118             }
119         }
120     }
121
122     if (hrd) {
123         if (hrd->nal_hrd_parameters_present_flag) {
124             bit_rate = (hrd->nal_sub_layer_hrd_parameters[0].bit_rate_value_minus1[0] + 1) *
125                        (INT64_C(1) << hrd->bit_rate_scale + 6);
126         } else if (hrd->vcl_hrd_parameters_present_flag) {
127             bit_rate = (hrd->vcl_sub_layer_hrd_parameters[0].bit_rate_value_minus1[0] + 1) *
128                        (INT64_C(1) << hrd->bit_rate_scale + 6);
129             // Adjust for VCL vs. NAL limits.
130             bit_rate = bit_rate * 11 / 10;
131         }
132     }
133
134     desc = ff_h265_guess_level(ptl, bit_rate, width, height,
135                                0, tile_rows, tile_cols,
136                                max_dec_pic_buffering);
137     if (desc) {
138         av_log(bsf, AV_LOG_DEBUG, "Stream appears to conform to "
139                "level %s.\n", desc->name);
140         ctx->level_guess = desc->level_idc;
141     }
142 }
143
144 static void h265_metadata_update_level(AVBSFContext *bsf,
145                                        uint8_t *level_idc)
146 {
147     H265MetadataContext *ctx = bsf->priv_data;
148
149     if (ctx->level != LEVEL_UNSET) {
150         if (ctx->level == LEVEL_AUTO) {
151             if (ctx->level_guess) {
152                 *level_idc = ctx->level_guess;
153             } else {
154                 if (!ctx->level_warned) {
155                     av_log(bsf, AV_LOG_WARNING, "Unable to determine level "
156                            "of stream: using level 8.5.\n");
157                     ctx->level_warned = 1;
158                 }
159                 *level_idc = 255;
160             }
161         } else {
162             *level_idc = ctx->level;
163         }
164     }
165 }
166
167 static int h265_metadata_update_vps(AVBSFContext *bsf,
168                                     H265RawVPS *vps)
169 {
170     H265MetadataContext *ctx = bsf->priv_data;
171
172     if (ctx->tick_rate.num && ctx->tick_rate.den) {
173         int num, den;
174
175         av_reduce(&num, &den, ctx->tick_rate.num, ctx->tick_rate.den,
176                   UINT32_MAX > INT_MAX ? UINT32_MAX : INT_MAX);
177
178         vps->vps_time_scale        = num;
179         vps->vps_num_units_in_tick = den;
180
181         vps->vps_timing_info_present_flag = 1;
182
183         if (ctx->num_ticks_poc_diff_one > 0) {
184             vps->vps_num_ticks_poc_diff_one_minus1 =
185                 ctx->num_ticks_poc_diff_one - 1;
186             vps->vps_poc_proportional_to_timing_flag = 1;
187         } else if (ctx->num_ticks_poc_diff_one == 0) {
188             vps->vps_poc_proportional_to_timing_flag = 0;
189         }
190     }
191
192     h265_metadata_update_level(bsf, &vps->profile_tier_level.general_level_idc);
193
194     return 0;
195 }
196
197 static int h265_metadata_update_sps(AVBSFContext *bsf,
198                                     H265RawSPS *sps)
199 {
200     H265MetadataContext *ctx = bsf->priv_data;
201     int need_vui = 0;
202     int crop_unit_x, crop_unit_y;
203
204     if (ctx->sample_aspect_ratio.num && ctx->sample_aspect_ratio.den) {
205         // Table E-1.
206         static const AVRational sar_idc[] = {
207             {   0,  0 }, // Unspecified (never written here).
208             {   1,  1 }, {  12, 11 }, {  10, 11 }, {  16, 11 },
209             {  40, 33 }, {  24, 11 }, {  20, 11 }, {  32, 11 },
210             {  80, 33 }, {  18, 11 }, {  15, 11 }, {  64, 33 },
211             { 160, 99 }, {   4,  3 }, {   3,  2 }, {   2,  1 },
212         };
213         int num, den, i;
214
215         av_reduce(&num, &den, ctx->sample_aspect_ratio.num,
216                   ctx->sample_aspect_ratio.den, 65535);
217
218         for (i = 1; i < FF_ARRAY_ELEMS(sar_idc); i++) {
219             if (num == sar_idc[i].num &&
220                 den == sar_idc[i].den)
221                 break;
222         }
223         if (i == FF_ARRAY_ELEMS(sar_idc)) {
224             sps->vui.aspect_ratio_idc = 255;
225             sps->vui.sar_width  = num;
226             sps->vui.sar_height = den;
227         } else {
228             sps->vui.aspect_ratio_idc = i;
229         }
230         sps->vui.aspect_ratio_info_present_flag = 1;
231         need_vui = 1;
232     }
233
234 #define SET_OR_INFER(field, value, present_flag, infer) do { \
235         if (value >= 0) { \
236             field = value; \
237             need_vui = 1; \
238         } else if (!present_flag) \
239             field = infer; \
240     } while (0)
241
242     if (ctx->video_format             >= 0 ||
243         ctx->video_full_range_flag    >= 0 ||
244         ctx->colour_primaries         >= 0 ||
245         ctx->transfer_characteristics >= 0 ||
246         ctx->matrix_coefficients      >= 0) {
247
248         SET_OR_INFER(sps->vui.video_format, ctx->video_format,
249                      sps->vui.video_signal_type_present_flag, 5);
250
251         SET_OR_INFER(sps->vui.video_full_range_flag,
252                      ctx->video_full_range_flag,
253                      sps->vui.video_signal_type_present_flag, 0);
254
255         if (ctx->colour_primaries         >= 0 ||
256             ctx->transfer_characteristics >= 0 ||
257             ctx->matrix_coefficients      >= 0) {
258
259             SET_OR_INFER(sps->vui.colour_primaries,
260                          ctx->colour_primaries,
261                          sps->vui.colour_description_present_flag, 2);
262
263             SET_OR_INFER(sps->vui.transfer_characteristics,
264                          ctx->transfer_characteristics,
265                          sps->vui.colour_description_present_flag, 2);
266
267             SET_OR_INFER(sps->vui.matrix_coefficients,
268                          ctx->matrix_coefficients,
269                          sps->vui.colour_description_present_flag, 2);
270
271             sps->vui.colour_description_present_flag = 1;
272         }
273         sps->vui.video_signal_type_present_flag = 1;
274         need_vui = 1;
275     }
276
277     if (ctx->chroma_sample_loc_type >= 0) {
278         sps->vui.chroma_sample_loc_type_top_field =
279             ctx->chroma_sample_loc_type;
280         sps->vui.chroma_sample_loc_type_bottom_field =
281             ctx->chroma_sample_loc_type;
282         sps->vui.chroma_loc_info_present_flag = 1;
283         need_vui = 1;
284     }
285
286     if (ctx->tick_rate.num && ctx->tick_rate.den) {
287         int num, den;
288
289         av_reduce(&num, &den, ctx->tick_rate.num, ctx->tick_rate.den,
290                   UINT32_MAX > INT_MAX ? UINT32_MAX : INT_MAX);
291
292         sps->vui.vui_time_scale        = num;
293         sps->vui.vui_num_units_in_tick = den;
294
295         sps->vui.vui_timing_info_present_flag = 1;
296         need_vui = 1;
297
298         if (ctx->num_ticks_poc_diff_one > 0) {
299             sps->vui.vui_num_ticks_poc_diff_one_minus1 =
300                 ctx->num_ticks_poc_diff_one - 1;
301             sps->vui.vui_poc_proportional_to_timing_flag = 1;
302         } else if (ctx->num_ticks_poc_diff_one == 0) {
303             sps->vui.vui_poc_proportional_to_timing_flag = 0;
304         }
305     }
306
307     if (sps->separate_colour_plane_flag || sps->chroma_format_idc == 0) {
308         crop_unit_x = 1;
309         crop_unit_y = 1;
310     } else {
311         crop_unit_x = 1 + (sps->chroma_format_idc < 3);
312         crop_unit_y = 1 + (sps->chroma_format_idc < 2);
313     }
314 #define CROP(border, unit) do { \
315         if (ctx->crop_ ## border >= 0) { \
316             if (ctx->crop_ ## border % unit != 0) { \
317                 av_log(bsf, AV_LOG_ERROR, "Invalid value for crop_%s: " \
318                        "must be a multiple of %d.\n", #border, unit); \
319                 return AVERROR(EINVAL); \
320             } \
321             sps->conf_win_ ## border ## _offset = \
322                 ctx->crop_ ## border / unit; \
323             sps->conformance_window_flag = 1; \
324         } \
325     } while (0)
326     CROP(left,   crop_unit_x);
327     CROP(right,  crop_unit_x);
328     CROP(top,    crop_unit_y);
329     CROP(bottom, crop_unit_y);
330 #undef CROP
331
332     if (need_vui)
333         sps->vui_parameters_present_flag = 1;
334
335     h265_metadata_update_level(bsf, &sps->profile_tier_level.general_level_idc);
336
337     return 0;
338 }
339
340 static int h265_metadata_update_side_data(AVBSFContext *bsf, AVPacket *pkt)
341 {
342     H265MetadataContext *ctx = bsf->priv_data;
343     CodedBitstreamFragment *au = &ctx->access_unit;
344     uint8_t *side_data;
345     int side_data_size;
346     int err, i;
347
348     side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
349                                         &side_data_size);
350     if (!side_data_size)
351         return 0;
352
353     err = ff_cbs_read(ctx->cbc, au, side_data, side_data_size);
354     if (err < 0) {
355         av_log(bsf, AV_LOG_ERROR, "Failed to read extradata from packet side data.\n");
356         return err;
357     }
358
359     if (ctx->level == LEVEL_AUTO && !ctx->level_guess)
360         h265_metadata_guess_level(bsf, au);
361
362     for (i = 0; i < au->nb_units; i++) {
363         if (au->units[i].type == HEVC_NAL_VPS) {
364             err = h265_metadata_update_vps(bsf, au->units[i].content);
365             if (err < 0)
366                 return err;
367         }
368         if (au->units[i].type == HEVC_NAL_SPS) {
369             err = h265_metadata_update_sps(bsf, au->units[i].content);
370             if (err < 0)
371                 return err;
372         }
373     }
374
375     err = ff_cbs_write_fragment_data(ctx->cbc, au);
376     if (err < 0) {
377         av_log(bsf, AV_LOG_ERROR, "Failed to write extradata into packet side data.\n");
378         return err;
379     }
380
381     side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, au->data_size);
382     if (!side_data)
383         return AVERROR(ENOMEM);
384     memcpy(side_data, au->data, au->data_size);
385
386     ff_cbs_fragment_reset(ctx->cbc, au);
387
388     return 0;
389 }
390
391 static int h265_metadata_filter(AVBSFContext *bsf, AVPacket *pkt)
392 {
393     H265MetadataContext *ctx = bsf->priv_data;
394     CodedBitstreamFragment *au = &ctx->access_unit;
395     int err, i;
396
397     err = ff_bsf_get_packet_ref(bsf, pkt);
398     if (err < 0)
399         return err;
400
401     err = h265_metadata_update_side_data(bsf, pkt);
402     if (err < 0)
403         goto fail;
404
405     err = ff_cbs_read_packet(ctx->cbc, au, pkt);
406     if (err < 0) {
407         av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n");
408         goto fail;
409     }
410
411     if (au->nb_units == 0) {
412         av_log(bsf, AV_LOG_ERROR, "No NAL units in packet.\n");
413         err = AVERROR_INVALIDDATA;
414         goto fail;
415     }
416
417     // If an AUD is present, it must be the first NAL unit.
418     if (au->units[0].type == HEVC_NAL_AUD) {
419         if (ctx->aud == REMOVE)
420             ff_cbs_delete_unit(ctx->cbc, au, 0);
421     } else {
422         if (ctx->aud == INSERT) {
423             H265RawAUD *aud = &ctx->aud_nal;
424             int pic_type = 0, temporal_id = 8, layer_id = 0;
425
426             for (i = 0; i < au->nb_units; i++) {
427                 const H265RawNALUnitHeader *nal = au->units[i].content;
428                 if (!nal)
429                     continue;
430                 if (nal->nuh_temporal_id_plus1 < temporal_id + 1)
431                     temporal_id = nal->nuh_temporal_id_plus1 - 1;
432
433                 if (au->units[i].type <= HEVC_NAL_RSV_VCL31) {
434                     const H265RawSlice *slice = au->units[i].content;
435                     layer_id = nal->nuh_layer_id;
436                     if (slice->header.slice_type == HEVC_SLICE_B &&
437                         pic_type < 2)
438                         pic_type = 2;
439                     if (slice->header.slice_type == HEVC_SLICE_P &&
440                         pic_type < 1)
441                         pic_type = 1;
442                 }
443             }
444
445             aud->nal_unit_header = (H265RawNALUnitHeader) {
446                 .nal_unit_type         = HEVC_NAL_AUD,
447                 .nuh_layer_id          = layer_id,
448                 .nuh_temporal_id_plus1 = temporal_id + 1,
449             };
450             aud->pic_type = pic_type;
451
452             err = ff_cbs_insert_unit_content(ctx->cbc, au,
453                                              0, HEVC_NAL_AUD, aud, NULL);
454             if (err < 0) {
455                 av_log(bsf, AV_LOG_ERROR, "Failed to insert AUD.\n");
456                 goto fail;
457             }
458         }
459     }
460
461     if (ctx->level == LEVEL_AUTO && !ctx->level_guess)
462         h265_metadata_guess_level(bsf, au);
463
464     for (i = 0; i < au->nb_units; i++) {
465         if (au->units[i].type == HEVC_NAL_VPS) {
466             err = h265_metadata_update_vps(bsf, au->units[i].content);
467             if (err < 0)
468                 goto fail;
469         }
470         if (au->units[i].type == HEVC_NAL_SPS) {
471             err = h265_metadata_update_sps(bsf, au->units[i].content);
472             if (err < 0)
473                 goto fail;
474         }
475     }
476
477     err = ff_cbs_write_packet(ctx->cbc, pkt, au);
478     if (err < 0) {
479         av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n");
480         goto fail;
481     }
482
483     err = 0;
484 fail:
485     ff_cbs_fragment_reset(ctx->cbc, au);
486
487     if (err < 0)
488         av_packet_unref(pkt);
489
490     return err;
491 }
492
493 static int h265_metadata_init(AVBSFContext *bsf)
494 {
495     H265MetadataContext *ctx = bsf->priv_data;
496     CodedBitstreamFragment *au = &ctx->access_unit;
497     int err, i;
498
499     err = ff_cbs_init(&ctx->cbc, AV_CODEC_ID_HEVC, bsf);
500     if (err < 0)
501         return err;
502
503     if (bsf->par_in->extradata) {
504         err = ff_cbs_read_extradata(ctx->cbc, au, bsf->par_in);
505         if (err < 0) {
506             av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n");
507             goto fail;
508         }
509
510         if (ctx->level == LEVEL_AUTO)
511             h265_metadata_guess_level(bsf, au);
512
513         for (i = 0; i < au->nb_units; i++) {
514             if (au->units[i].type == HEVC_NAL_VPS) {
515                 err = h265_metadata_update_vps(bsf, au->units[i].content);
516                 if (err < 0)
517                     goto fail;
518             }
519             if (au->units[i].type == HEVC_NAL_SPS) {
520                 err = h265_metadata_update_sps(bsf, au->units[i].content);
521                 if (err < 0)
522                     goto fail;
523             }
524         }
525
526         err = ff_cbs_write_extradata(ctx->cbc, bsf->par_out, au);
527         if (err < 0) {
528             av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n");
529             goto fail;
530         }
531     }
532
533     err = 0;
534 fail:
535     ff_cbs_fragment_reset(ctx->cbc, au);
536     return err;
537 }
538
539 static void h265_metadata_close(AVBSFContext *bsf)
540 {
541     H265MetadataContext *ctx = bsf->priv_data;
542
543     ff_cbs_fragment_free(ctx->cbc, &ctx->access_unit);
544     ff_cbs_close(&ctx->cbc);
545 }
546
547 #define OFFSET(x) offsetof(H265MetadataContext, x)
548 #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM)
549 static const AVOption h265_metadata_options[] = {
550     { "aud", "Access Unit Delimiter NAL units",
551         OFFSET(aud), AV_OPT_TYPE_INT,
552         { .i64 = PASS }, PASS, REMOVE, FLAGS, "aud" },
553     { "pass",   NULL, 0, AV_OPT_TYPE_CONST,
554         { .i64 = PASS   }, .flags = FLAGS, .unit = "aud" },
555     { "insert", NULL, 0, AV_OPT_TYPE_CONST,
556         { .i64 = INSERT }, .flags = FLAGS, .unit = "aud" },
557     { "remove", NULL, 0, AV_OPT_TYPE_CONST,
558         { .i64 = REMOVE }, .flags = FLAGS, .unit = "aud" },
559
560     { "sample_aspect_ratio", "Set sample aspect ratio (table E-1)",
561         OFFSET(sample_aspect_ratio), AV_OPT_TYPE_RATIONAL,
562         { .dbl = 0.0 }, 0, 65535, FLAGS },
563
564     { "video_format", "Set video format (table E-2)",
565         OFFSET(video_format), AV_OPT_TYPE_INT,
566         { .i64 = -1 }, -1, 7, FLAGS },
567     { "video_full_range_flag", "Set video full range flag",
568         OFFSET(video_full_range_flag), AV_OPT_TYPE_INT,
569         { .i64 = -1 }, -1, 1, FLAGS },
570     { "colour_primaries", "Set colour primaries (table E-3)",
571         OFFSET(colour_primaries), AV_OPT_TYPE_INT,
572         { .i64 = -1 }, -1, 255, FLAGS },
573     { "transfer_characteristics", "Set transfer characteristics (table E-4)",
574         OFFSET(transfer_characteristics), AV_OPT_TYPE_INT,
575         { .i64 = -1 }, -1, 255, FLAGS },
576     { "matrix_coefficients", "Set matrix coefficients (table E-5)",
577         OFFSET(matrix_coefficients), AV_OPT_TYPE_INT,
578         { .i64 = -1 }, -1, 255, FLAGS },
579
580     { "chroma_sample_loc_type", "Set chroma sample location type (figure E-1)",
581         OFFSET(chroma_sample_loc_type), AV_OPT_TYPE_INT,
582         { .i64 = -1 }, -1, 6, FLAGS },
583
584     { "tick_rate",
585         "Set VPS and VUI tick rate (num_units_in_tick / time_scale)",
586         OFFSET(tick_rate), AV_OPT_TYPE_RATIONAL,
587         { .dbl = 0.0 }, 0, UINT_MAX, FLAGS },
588     { "num_ticks_poc_diff_one",
589         "Set VPS and VUI number of ticks per POC increment",
590         OFFSET(num_ticks_poc_diff_one), AV_OPT_TYPE_INT,
591         { .i64 = -1 }, -1, INT_MAX, FLAGS },
592
593     { "crop_left", "Set left border crop offset",
594         OFFSET(crop_left), AV_OPT_TYPE_INT,
595         { .i64 = -1 }, -1, HEVC_MAX_WIDTH, FLAGS },
596     { "crop_right", "Set right border crop offset",
597         OFFSET(crop_right), AV_OPT_TYPE_INT,
598         { .i64 = -1 }, -1, HEVC_MAX_WIDTH, FLAGS },
599     { "crop_top", "Set top border crop offset",
600         OFFSET(crop_top), AV_OPT_TYPE_INT,
601         { .i64 = -1 }, -1, HEVC_MAX_HEIGHT, FLAGS },
602     { "crop_bottom", "Set bottom border crop offset",
603         OFFSET(crop_bottom), AV_OPT_TYPE_INT,
604         { .i64 = -1 }, -1, HEVC_MAX_HEIGHT, FLAGS },
605
606     { "level", "Set level (tables A.6 and A.7)",
607         OFFSET(level), AV_OPT_TYPE_INT,
608         { .i64 = LEVEL_UNSET }, LEVEL_UNSET, 0xff, FLAGS, "level" },
609     { "auto", "Attempt to guess level from stream properties",
610         0, AV_OPT_TYPE_CONST,
611         { .i64 = LEVEL_AUTO }, .flags = FLAGS, .unit = "level" },
612 #define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \
613         { .i64 = value },      .flags = FLAGS, .unit = "level"
614     { LEVEL("1",    30) },
615     { LEVEL("2",    60) },
616     { LEVEL("2.1",  63) },
617     { LEVEL("3",    90) },
618     { LEVEL("3.1",  93) },
619     { LEVEL("4",   120) },
620     { LEVEL("4.1", 123) },
621     { LEVEL("5",   150) },
622     { LEVEL("5.1", 153) },
623     { LEVEL("5.2", 156) },
624     { LEVEL("6",   180) },
625     { LEVEL("6.1", 183) },
626     { LEVEL("6.2", 186) },
627     { LEVEL("8.5", 255) },
628 #undef LEVEL
629
630     { NULL }
631 };
632
633 static const AVClass h265_metadata_class = {
634     .class_name = "h265_metadata_bsf",
635     .item_name  = av_default_item_name,
636     .option     = h265_metadata_options,
637     .version    = LIBAVUTIL_VERSION_INT,
638 };
639
640 static const enum AVCodecID h265_metadata_codec_ids[] = {
641     AV_CODEC_ID_HEVC, AV_CODEC_ID_NONE,
642 };
643
644 const AVBitStreamFilter ff_hevc_metadata_bsf = {
645     .name           = "hevc_metadata",
646     .priv_data_size = sizeof(H265MetadataContext),
647     .priv_class     = &h265_metadata_class,
648     .init           = &h265_metadata_init,
649     .close          = &h265_metadata_close,
650     .filter         = &h265_metadata_filter,
651     .codec_ids      = h265_metadata_codec_ids,
652 };