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/avstring.h"
20#include "libavutil/display.h"
21#include "libavutil/common.h"
22#include "libavutil/opt.h"
23
24#include "bsf.h"
25#include "bsf_internal.h"
26#include "cbs.h"
27#include "cbs_bsf.h"
28#include "cbs_h264.h"
29#include "h264.h"
30#include "h264_levels.h"
31#include "h264_sei.h"
32
33enum {
34    FLIP_HORIZONTAL = 1,
35    FLIP_VERTICAL   = 2,
36};
37
38enum {
39    LEVEL_UNSET = -2,
40    LEVEL_AUTO  = -1,
41};
42
43typedef struct H264MetadataContext {
44    CBSBSFContext common;
45
46    int done_first_au;
47
48    int aud;
49    H264RawAUD aud_nal;
50
51    AVRational sample_aspect_ratio;
52
53    int overscan_appropriate_flag;
54
55    int video_format;
56    int video_full_range_flag;
57    int colour_primaries;
58    int transfer_characteristics;
59    int matrix_coefficients;
60
61    int chroma_sample_loc_type;
62
63    AVRational tick_rate;
64    int fixed_frame_rate_flag;
65    int zero_new_constraint_set_flags;
66
67    int crop_left;
68    int crop_right;
69    int crop_top;
70    int crop_bottom;
71
72    const char *sei_user_data;
73    SEIRawUserDataUnregistered sei_user_data_payload;
74
75    int delete_filler;
76
77    int display_orientation;
78    double rotate;
79    int flip;
80    H264RawSEIDisplayOrientation display_orientation_payload;
81
82    int level;
83} H264MetadataContext;
84
85
86static int h264_metadata_insert_aud(AVBSFContext *bsf,
87                                    CodedBitstreamFragment *au)
88{
89    H264MetadataContext *ctx = bsf->priv_data;
90    int primary_pic_type_mask = 0xff;
91    int err, i, j;
92
93    static const int primary_pic_type_table[] = {
94        0x084, // 2, 7
95        0x0a5, // 0, 2, 5, 7
96        0x0e7, // 0, 1, 2, 5, 6, 7
97        0x210, // 4, 9
98        0x318, // 3, 4, 8, 9
99        0x294, // 2, 4, 7, 9
100        0x3bd, // 0, 2, 3, 4, 5, 7, 8, 9
101        0x3ff, // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
102    };
103
104    for (i = 0; i < au->nb_units; i++) {
105        if (au->units[i].type == H264_NAL_SLICE ||
106            au->units[i].type == H264_NAL_IDR_SLICE) {
107            H264RawSlice *slice = au->units[i].content;
108            for (j = 0; j < FF_ARRAY_ELEMS(primary_pic_type_table); j++) {
109                if (!(primary_pic_type_table[j] &
110                      (1 << slice->header.slice_type)))
111                    primary_pic_type_mask &= ~(1 << j);
112            }
113        }
114    }
115    for (j = 0; j < FF_ARRAY_ELEMS(primary_pic_type_table); j++)
116        if (primary_pic_type_mask & (1 << j))
117            break;
118    if (j >= FF_ARRAY_ELEMS(primary_pic_type_table)) {
119        av_log(bsf, AV_LOG_ERROR, "No usable primary_pic_type: "
120               "invalid slice types?\n");
121        return AVERROR_INVALIDDATA;
122    }
123
124    ctx->aud_nal = (H264RawAUD) {
125        .nal_unit_header.nal_unit_type = H264_NAL_AUD,
126        .primary_pic_type = j,
127    };
128
129    err = ff_cbs_insert_unit_content(au, 0, H264_NAL_AUD,
130                                     &ctx->aud_nal, NULL);
131    if (err < 0) {
132        av_log(bsf, AV_LOG_ERROR, "Failed to insert AUD.\n");
133        return err;
134    }
135
136    return 0;
137}
138
139static int h264_metadata_update_sps(AVBSFContext *bsf,
140                                    H264RawSPS *sps)
141{
142    H264MetadataContext *ctx = bsf->priv_data;
143    int need_vui = 0;
144    int crop_unit_x, crop_unit_y;
145
146    if (ctx->sample_aspect_ratio.num && ctx->sample_aspect_ratio.den) {
147        // Table E-1.
148        static const AVRational sar_idc[] = {
149            {   0,  0 }, // Unspecified (never written here).
150            {   1,  1 }, {  12, 11 }, {  10, 11 }, {  16, 11 },
151            {  40, 33 }, {  24, 11 }, {  20, 11 }, {  32, 11 },
152            {  80, 33 }, {  18, 11 }, {  15, 11 }, {  64, 33 },
153            { 160, 99 }, {   4,  3 }, {   3,  2 }, {   2,  1 },
154        };
155        int num, den, i;
156
157        av_reduce(&num, &den, ctx->sample_aspect_ratio.num,
158                  ctx->sample_aspect_ratio.den, 65535);
159
160        for (i = 1; i < FF_ARRAY_ELEMS(sar_idc); i++) {
161            if (num == sar_idc[i].num &&
162                den == sar_idc[i].den)
163                break;
164        }
165        if (i == FF_ARRAY_ELEMS(sar_idc)) {
166            sps->vui.aspect_ratio_idc = 255;
167            sps->vui.sar_width  = num;
168            sps->vui.sar_height = den;
169        } else {
170            sps->vui.aspect_ratio_idc = i;
171        }
172        sps->vui.aspect_ratio_info_present_flag = 1;
173        need_vui = 1;
174    }
175
176#define SET_VUI_FIELD(field) do { \
177        if (ctx->field >= 0) { \
178            sps->vui.field = ctx->field; \
179            need_vui = 1; \
180        } \
181    } while (0)
182
183    if (ctx->overscan_appropriate_flag >= 0) {
184        SET_VUI_FIELD(overscan_appropriate_flag);
185        sps->vui.overscan_info_present_flag = 1;
186    }
187
188    if (ctx->video_format             >= 0 ||
189        ctx->video_full_range_flag    >= 0 ||
190        ctx->colour_primaries         >= 0 ||
191        ctx->transfer_characteristics >= 0 ||
192        ctx->matrix_coefficients      >= 0) {
193
194        SET_VUI_FIELD(video_format);
195
196        SET_VUI_FIELD(video_full_range_flag);
197
198        if (ctx->colour_primaries         >= 0 ||
199            ctx->transfer_characteristics >= 0 ||
200            ctx->matrix_coefficients      >= 0) {
201
202            SET_VUI_FIELD(colour_primaries);
203            SET_VUI_FIELD(transfer_characteristics);
204            SET_VUI_FIELD(matrix_coefficients);
205
206            sps->vui.colour_description_present_flag = 1;
207        }
208        sps->vui.video_signal_type_present_flag = 1;
209    }
210
211    if (ctx->chroma_sample_loc_type >= 0) {
212        sps->vui.chroma_sample_loc_type_top_field =
213            ctx->chroma_sample_loc_type;
214        sps->vui.chroma_sample_loc_type_bottom_field =
215            ctx->chroma_sample_loc_type;
216        sps->vui.chroma_loc_info_present_flag = 1;
217        need_vui = 1;
218    }
219
220    if (ctx->tick_rate.num && ctx->tick_rate.den) {
221        int num, den;
222
223        av_reduce(&num, &den, ctx->tick_rate.num, ctx->tick_rate.den,
224                  UINT32_MAX > INT_MAX ? UINT32_MAX : INT_MAX);
225
226        sps->vui.time_scale        = num;
227        sps->vui.num_units_in_tick = den;
228
229        sps->vui.timing_info_present_flag = 1;
230        need_vui = 1;
231    }
232    SET_VUI_FIELD(fixed_frame_rate_flag);
233    if (ctx->zero_new_constraint_set_flags) {
234        sps->constraint_set4_flag = 0;
235        sps->constraint_set5_flag = 0;
236    }
237
238    if (sps->separate_colour_plane_flag || sps->chroma_format_idc == 0) {
239        crop_unit_x = 1;
240        crop_unit_y = 2 - sps->frame_mbs_only_flag;
241    } else {
242        crop_unit_x = 1 + (sps->chroma_format_idc < 3);
243        crop_unit_y = (1 + (sps->chroma_format_idc < 2)) *
244                       (2 - sps->frame_mbs_only_flag);
245    }
246#define CROP(border, unit) do { \
247        if (ctx->crop_ ## border >= 0) { \
248            if (ctx->crop_ ## border % unit != 0) { \
249                av_log(bsf, AV_LOG_ERROR, "Invalid value for crop_%s: " \
250                       "must be a multiple of %d.\n", #border, unit); \
251                return AVERROR(EINVAL); \
252            } \
253            sps->frame_crop_ ## border ## _offset = \
254                  ctx->crop_ ## border / unit; \
255            sps->frame_cropping_flag = 1; \
256        } \
257    } while (0)
258    CROP(left,   crop_unit_x);
259    CROP(right,  crop_unit_x);
260    CROP(top,    crop_unit_y);
261    CROP(bottom, crop_unit_y);
262#undef CROP
263
264    if (ctx->level != LEVEL_UNSET) {
265        int level_idc;
266
267        if (ctx->level == LEVEL_AUTO) {
268            const H264LevelDescriptor *desc;
269            int64_t bit_rate;
270            int width, height, dpb_frames;
271            int framerate;
272
273            if (sps->vui.nal_hrd_parameters_present_flag) {
274                bit_rate = (sps->vui.nal_hrd_parameters.bit_rate_value_minus1[0] + 1) *
275                    (INT64_C(1) << (sps->vui.nal_hrd_parameters.bit_rate_scale + 6));
276            } else if (sps->vui.vcl_hrd_parameters_present_flag) {
277                bit_rate = (sps->vui.vcl_hrd_parameters.bit_rate_value_minus1[0] + 1) *
278                    (INT64_C(1) << (sps->vui.vcl_hrd_parameters.bit_rate_scale + 6));
279                // Adjust for VCL vs. NAL limits.
280                bit_rate = bit_rate * 6 / 5;
281            } else {
282                bit_rate = 0;
283            }
284
285            // Don't use max_dec_frame_buffering if it is only inferred.
286            dpb_frames = sps->vui.bitstream_restriction_flag ?
287                sps->vui.max_dec_frame_buffering : H264_MAX_DPB_FRAMES;
288
289            width  = 16 * (sps->pic_width_in_mbs_minus1 + 1);
290            height = 16 * (sps->pic_height_in_map_units_minus1 + 1) *
291                (2 - sps->frame_mbs_only_flag);
292
293            if (sps->vui.timing_info_present_flag)
294                framerate = sps->vui.time_scale / sps->vui.num_units_in_tick / 2;
295            else
296                framerate = 0;
297
298            desc = ff_h264_guess_level(sps->profile_idc, bit_rate, framerate,
299                                       width, height, dpb_frames);
300            if (desc) {
301                level_idc = desc->level_idc;
302            } else {
303                av_log(bsf, AV_LOG_WARNING, "Stream does not appear to "
304                       "conform to any level: using level 6.2.\n");
305                level_idc = 62;
306            }
307        } else {
308            level_idc = ctx->level;
309        }
310
311        if (level_idc == 9) {
312            if (sps->profile_idc == 66 ||
313                sps->profile_idc == 77 ||
314                sps->profile_idc == 88) {
315                sps->level_idc = 11;
316                sps->constraint_set3_flag = 1;
317            } else {
318                sps->level_idc = 9;
319            }
320        } else {
321            sps->level_idc = level_idc;
322        }
323    }
324
325    if (need_vui)
326        sps->vui_parameters_present_flag = 1;
327
328    return 0;
329}
330
331static int h264_metadata_handle_display_orientation(AVBSFContext *bsf,
332                                                    AVPacket *pkt,
333                                                    CodedBitstreamFragment *au,
334                                                    int seek_point)
335{
336    H264MetadataContext *ctx = bsf->priv_data;
337    SEIRawMessage *message;
338    int err;
339
340    message = NULL;
341    while (ff_cbs_sei_find_message(ctx->common.output, au,
342                                   SEI_TYPE_DISPLAY_ORIENTATION,
343                                   &message) == 0) {
344        H264RawSEIDisplayOrientation *disp = message->payload;
345        double angle = disp->anticlockwise_rotation * 180.0 / 65536.0;
346        int32_t *matrix;
347
348        matrix = av_malloc(9 * sizeof(int32_t));
349        if (!matrix)
350            return AVERROR(ENOMEM);
351
352        /* av_display_rotation_set() expects the angle in the clockwise
353         * direction, hence the first minus.
354         * The below code applies the flips after the rotation, yet
355         * the H.2645 specs require flipping to be applied first.
356         * Because of R O(phi) = O(-phi) R (where R is flipping around
357         * an arbitatry axis and O(phi) is the proper rotation by phi)
358         * we can create display matrices as desired by negating
359         * the degree once for every flip applied. */
360        angle = -angle * (1 - 2 * !!disp->hor_flip) * (1 - 2 * !!disp->ver_flip);
361
362        av_display_rotation_set(matrix, angle);
363        av_display_matrix_flip(matrix, disp->hor_flip, disp->ver_flip);
364
365        // If there are multiple display orientation messages in an
366        // access unit, then the last one added to the packet (i.e.
367        // the first one in the access unit) will prevail.
368        err = av_packet_add_side_data(pkt, AV_PKT_DATA_DISPLAYMATRIX,
369                                      (uint8_t*)matrix,
370                                      9 * sizeof(int32_t));
371        if (err < 0) {
372            av_log(bsf, AV_LOG_ERROR, "Failed to attach extracted "
373                   "displaymatrix side data to packet.\n");
374            av_free(matrix);
375            return AVERROR(ENOMEM);
376        }
377    }
378
379    if (ctx->display_orientation == BSF_ELEMENT_REMOVE ||
380        ctx->display_orientation == BSF_ELEMENT_INSERT) {
381        ff_cbs_sei_delete_message_type(ctx->common.output, au,
382                                       SEI_TYPE_DISPLAY_ORIENTATION);
383    }
384
385    if (ctx->display_orientation == BSF_ELEMENT_INSERT) {
386        H264RawSEIDisplayOrientation *disp =
387            &ctx->display_orientation_payload;
388        uint8_t *data;
389        size_t size;
390        int write = 0;
391
392        data = av_packet_get_side_data(pkt, AV_PKT_DATA_DISPLAYMATRIX, &size);
393        if (data && size >= 9 * sizeof(int32_t)) {
394            int32_t matrix[9];
395            double dmatrix[9];
396            int hflip, vflip, i;
397            double scale_x, scale_y, angle;
398
399            memcpy(matrix, data, sizeof(matrix));
400
401            for (i = 0; i < 9; i++)
402                dmatrix[i] = matrix[i] / 65536.0;
403
404            // Extract scale factors.
405            scale_x = hypot(dmatrix[0], dmatrix[3]);
406            scale_y = hypot(dmatrix[1], dmatrix[4]);
407
408            // Select flips to make the main diagonal positive.
409            hflip = dmatrix[0] < 0.0;
410            vflip = dmatrix[4] < 0.0;
411            if (hflip)
412                scale_x = -scale_x;
413            if (vflip)
414                scale_y = -scale_y;
415
416            // Rescale.
417            for (i = 0; i < 9; i += 3) {
418                dmatrix[i]     /= scale_x;
419                dmatrix[i + 1] /= scale_y;
420            }
421
422            // Extract rotation.
423            angle = atan2(dmatrix[3], dmatrix[0]);
424
425            if (!(angle >= -M_PI && angle <= M_PI) ||
426                matrix[2] != 0.0 || matrix[5] != 0.0 ||
427                matrix[6] != 0.0 || matrix[7] != 0.0) {
428                av_log(bsf, AV_LOG_WARNING, "Input display matrix is not "
429                       "representable in H.264 parameters.\n");
430            } else {
431                disp->hor_flip = hflip;
432                disp->ver_flip = vflip;
433                disp->anticlockwise_rotation =
434                    (uint16_t)rint((angle >= 0.0 ? angle
435                                                 : angle + 2 * M_PI) *
436                                   32768.0 / M_PI);
437                write = 1;
438            }
439        }
440
441        if (seek_point) {
442            if (!isnan(ctx->rotate)) {
443                disp->anticlockwise_rotation =
444                    (uint16_t)rint((ctx->rotate >= 0.0 ? ctx->rotate
445                                                       : ctx->rotate + 360.0) *
446                                   65536.0 / 360.0);
447                write = 1;
448            }
449            if (ctx->flip) {
450                disp->hor_flip = !!(ctx->flip & FLIP_HORIZONTAL);
451                disp->ver_flip = !!(ctx->flip & FLIP_VERTICAL);
452                write = 1;
453            }
454        }
455
456        if (write) {
457            disp->display_orientation_repetition_period = 1;
458
459            err = ff_cbs_sei_add_message(ctx->common.output, au, 1,
460                                         SEI_TYPE_DISPLAY_ORIENTATION,
461                                         disp, NULL);
462            if (err < 0) {
463                av_log(bsf, AV_LOG_ERROR, "Failed to add display orientation "
464                       "SEI message to access unit.\n");
465                return err;
466            }
467        }
468    }
469
470    return 0;
471}
472
473static int h264_metadata_update_fragment(AVBSFContext *bsf, AVPacket *pkt,
474                                         CodedBitstreamFragment *au)
475{
476    H264MetadataContext *ctx = bsf->priv_data;
477    int err, i, has_sps, seek_point;
478
479    // If an AUD is present, it must be the first NAL unit.
480    if (au->nb_units && au->units[0].type == H264_NAL_AUD) {
481        if (ctx->aud == BSF_ELEMENT_REMOVE)
482            ff_cbs_delete_unit(au, 0);
483    } else {
484        if (pkt && ctx->aud == BSF_ELEMENT_INSERT) {
485            err = h264_metadata_insert_aud(bsf, au);
486            if (err < 0)
487                return err;
488        }
489    }
490
491    has_sps = 0;
492    for (i = 0; i < au->nb_units; i++) {
493        if (au->units[i].type == H264_NAL_SPS) {
494            err = h264_metadata_update_sps(bsf, au->units[i].content);
495            if (err < 0)
496                return err;
497            has_sps = 1;
498        }
499    }
500
501    if (pkt) {
502        // The current packet should be treated as a seek point for metadata
503        // insertion if any of:
504        // - It is the first packet in the stream.
505        // - It contains an SPS, indicating that a sequence might start here.
506        // - It is marked as containing a key frame.
507        seek_point = !ctx->done_first_au || has_sps ||
508            (pkt->flags & AV_PKT_FLAG_KEY);
509    } else {
510        seek_point = 0;
511    }
512
513    if (ctx->sei_user_data && seek_point) {
514        err = ff_cbs_sei_add_message(ctx->common.output, au, 1,
515                                     SEI_TYPE_USER_DATA_UNREGISTERED,
516                                     &ctx->sei_user_data_payload, NULL);
517        if (err < 0) {
518            av_log(bsf, AV_LOG_ERROR, "Failed to add user data SEI "
519                   "message to access unit.\n");
520            return err;
521        }
522    }
523
524    if (ctx->delete_filler) {
525        for (i = au->nb_units - 1; i >= 0; i--) {
526            if (au->units[i].type == H264_NAL_FILLER_DATA) {
527                ff_cbs_delete_unit(au, i);
528                continue;
529            }
530        }
531
532        ff_cbs_sei_delete_message_type(ctx->common.output, au,
533                                       SEI_TYPE_FILLER_PAYLOAD);
534    }
535
536    if (pkt && ctx->display_orientation != BSF_ELEMENT_PASS) {
537        err = h264_metadata_handle_display_orientation(bsf, pkt, au,
538                                                       seek_point);
539        if (err < 0)
540            return err;
541    }
542
543    if (pkt)
544        ctx->done_first_au = 1;
545
546    return 0;
547}
548
549static const CBSBSFType h264_metadata_type = {
550    .codec_id        = AV_CODEC_ID_H264,
551    .fragment_name   = "access unit",
552    .unit_name       = "NAL unit",
553    .update_fragment = &h264_metadata_update_fragment,
554};
555
556static int h264_metadata_init(AVBSFContext *bsf)
557{
558    H264MetadataContext *ctx = bsf->priv_data;
559
560    if (ctx->sei_user_data) {
561        SEIRawUserDataUnregistered *udu = &ctx->sei_user_data_payload;
562        int i, j;
563
564        // Parse UUID.  It must be a hex string of length 32, possibly
565        // containing '-'s between hex digits (which we ignore).
566        for (i = j = 0; j < 32 && i < 64 && ctx->sei_user_data[i]; i++) {
567            int c, v;
568            c = ctx->sei_user_data[i];
569            if (c == '-') {
570                continue;
571            } else if (av_isxdigit(c)) {
572                c = av_tolower(c);
573                v = (c <= '9' ? c - '0' : c - 'a' + 10);
574            } else {
575                break;
576            }
577            if (j & 1)
578                udu->uuid_iso_iec_11578[j / 2] |= v;
579            else
580                udu->uuid_iso_iec_11578[j / 2] = v << 4;
581            ++j;
582        }
583        if (j == 32 && ctx->sei_user_data[i] == '+') {
584            udu->data = (uint8_t*)ctx->sei_user_data + i + 1;
585            udu->data_length = strlen(udu->data) + 1;
586        } else {
587            av_log(bsf, AV_LOG_ERROR, "Invalid user data: "
588                   "must be \"UUID+string\".\n");
589            return AVERROR(EINVAL);
590        }
591    }
592
593    return ff_cbs_bsf_generic_init(bsf, &h264_metadata_type);
594}
595
596#define OFFSET(x) offsetof(H264MetadataContext, x)
597#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM)
598static const AVOption h264_metadata_options[] = {
599    BSF_ELEMENT_OPTIONS_PIR("aud", "Access Unit Delimiter NAL units",
600                            aud, FLAGS),
601
602    { "sample_aspect_ratio", "Set sample aspect ratio (table E-1)",
603        OFFSET(sample_aspect_ratio), AV_OPT_TYPE_RATIONAL,
604        { .dbl = 0.0 }, 0, 65535, FLAGS },
605
606    { "overscan_appropriate_flag", "Set VUI overscan appropriate flag",
607        OFFSET(overscan_appropriate_flag), AV_OPT_TYPE_INT,
608        { .i64 = -1 }, -1, 1, FLAGS },
609
610    { "video_format", "Set video format (table E-2)",
611        OFFSET(video_format), AV_OPT_TYPE_INT,
612        { .i64 = -1 }, -1, 7, FLAGS},
613    { "video_full_range_flag", "Set video full range flag",
614        OFFSET(video_full_range_flag), AV_OPT_TYPE_INT,
615        { .i64 = -1 }, -1, 1, FLAGS },
616    { "colour_primaries", "Set colour primaries (table E-3)",
617        OFFSET(colour_primaries), AV_OPT_TYPE_INT,
618        { .i64 = -1 }, -1, 255, FLAGS },
619    { "transfer_characteristics", "Set transfer characteristics (table E-4)",
620        OFFSET(transfer_characteristics), AV_OPT_TYPE_INT,
621        { .i64 = -1 }, -1, 255, FLAGS },
622    { "matrix_coefficients", "Set matrix coefficients (table E-5)",
623        OFFSET(matrix_coefficients), AV_OPT_TYPE_INT,
624        { .i64 = -1 }, -1, 255, FLAGS },
625
626    { "chroma_sample_loc_type", "Set chroma sample location type (figure E-1)",
627        OFFSET(chroma_sample_loc_type), AV_OPT_TYPE_INT,
628        { .i64 = -1 }, -1, 5, FLAGS },
629
630    { "tick_rate", "Set VUI tick rate (time_scale / num_units_in_tick)",
631        OFFSET(tick_rate), AV_OPT_TYPE_RATIONAL,
632        { .dbl = 0.0 }, 0, UINT_MAX, FLAGS },
633    { "fixed_frame_rate_flag", "Set VUI fixed frame rate flag",
634        OFFSET(fixed_frame_rate_flag), AV_OPT_TYPE_INT,
635        { .i64 = -1 }, -1, 1, FLAGS },
636    { "zero_new_constraint_set_flags", "Set constraint_set4_flag / constraint_set5_flag to zero",
637        OFFSET(zero_new_constraint_set_flags), AV_OPT_TYPE_BOOL,
638        { .i64 = 0 }, 0, 1, FLAGS },
639
640    { "crop_left", "Set left border crop offset",
641        OFFSET(crop_left), AV_OPT_TYPE_INT,
642        { .i64 = -1 }, -1, H264_MAX_WIDTH, FLAGS },
643    { "crop_right", "Set right border crop offset",
644        OFFSET(crop_right), AV_OPT_TYPE_INT,
645        { .i64 = -1 }, -1, H264_MAX_WIDTH, FLAGS },
646    { "crop_top", "Set top border crop offset",
647        OFFSET(crop_top), AV_OPT_TYPE_INT,
648        { .i64 = -1 }, -1, H264_MAX_HEIGHT, FLAGS },
649    { "crop_bottom", "Set bottom border crop offset",
650        OFFSET(crop_bottom), AV_OPT_TYPE_INT,
651        { .i64 = -1 }, -1, H264_MAX_HEIGHT, FLAGS },
652
653    { "sei_user_data", "Insert SEI user data (UUID+string)",
654        OFFSET(sei_user_data), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS },
655
656    { "delete_filler", "Delete all filler (both NAL and SEI)",
657        OFFSET(delete_filler), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS},
658
659    BSF_ELEMENT_OPTIONS_PIRE("display_orientation",
660                             "Display orientation SEI",
661                             display_orientation, FLAGS),
662
663    { "rotate", "Set rotation in display orientation SEI (anticlockwise angle in degrees)",
664        OFFSET(rotate), AV_OPT_TYPE_DOUBLE,
665        { .dbl = NAN }, -360.0, +360.0, FLAGS },
666    { "flip", "Set flip in display orientation SEI",
667        OFFSET(flip), AV_OPT_TYPE_FLAGS,
668        { .i64 = 0 }, 0, FLIP_HORIZONTAL | FLIP_VERTICAL, FLAGS, "flip" },
669    { "horizontal", "Set hor_flip",
670        0, AV_OPT_TYPE_CONST,
671        { .i64 = FLIP_HORIZONTAL }, .flags = FLAGS, .unit = "flip" },
672    { "vertical",   "Set ver_flip",
673        0, AV_OPT_TYPE_CONST,
674        { .i64 = FLIP_VERTICAL },   .flags = FLAGS, .unit = "flip" },
675
676    { "level", "Set level (table A-1)",
677        OFFSET(level), AV_OPT_TYPE_INT,
678        { .i64 = LEVEL_UNSET }, LEVEL_UNSET, 0xff, FLAGS, "level" },
679    { "auto", "Attempt to guess level from stream properties",
680        0, AV_OPT_TYPE_CONST,
681        { .i64 = LEVEL_AUTO }, .flags = FLAGS, .unit = "level" },
682#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \
683        { .i64 = value },      .flags = FLAGS, .unit = "level"
684    { LEVEL("1",   10) },
685    { LEVEL("1b",   9) },
686    { LEVEL("1.1", 11) },
687    { LEVEL("1.2", 12) },
688    { LEVEL("1.3", 13) },
689    { LEVEL("2",   20) },
690    { LEVEL("2.1", 21) },
691    { LEVEL("2.2", 22) },
692    { LEVEL("3",   30) },
693    { LEVEL("3.1", 31) },
694    { LEVEL("3.2", 32) },
695    { LEVEL("4",   40) },
696    { LEVEL("4.1", 41) },
697    { LEVEL("4.2", 42) },
698    { LEVEL("5",   50) },
699    { LEVEL("5.1", 51) },
700    { LEVEL("5.2", 52) },
701    { LEVEL("6",   60) },
702    { LEVEL("6.1", 61) },
703    { LEVEL("6.2", 62) },
704#undef LEVEL
705
706    { NULL }
707};
708
709static const AVClass h264_metadata_class = {
710    .class_name = "h264_metadata_bsf",
711    .item_name  = av_default_item_name,
712    .option     = h264_metadata_options,
713    .version    = LIBAVUTIL_VERSION_INT,
714};
715
716static const enum AVCodecID h264_metadata_codec_ids[] = {
717    AV_CODEC_ID_H264, AV_CODEC_ID_NONE,
718};
719
720const FFBitStreamFilter ff_h264_metadata_bsf = {
721    .p.name         = "h264_metadata",
722    .p.codec_ids    = h264_metadata_codec_ids,
723    .p.priv_class   = &h264_metadata_class,
724    .priv_data_size = sizeof(H264MetadataContext),
725    .init           = &h264_metadata_init,
726    .close          = &ff_cbs_bsf_generic_close,
727    .filter         = &ff_cbs_bsf_generic_filter,
728};
729