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