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