| Line | Branch | Exec | Source |
|---|---|---|---|
| 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_bsf.h" | ||
| 26 | #include "cbs_av1.h" | ||
| 27 | |||
| 28 | typedef struct AV1MetadataContext { | ||
| 29 | CBSBSFContext common; | ||
| 30 | |||
| 31 | int td; | ||
| 32 | AV1RawOBU td_obu; | ||
| 33 | |||
| 34 | int color_primaries; | ||
| 35 | int transfer_characteristics; | ||
| 36 | int matrix_coefficients; | ||
| 37 | |||
| 38 | int color_range; | ||
| 39 | int chroma_sample_position; | ||
| 40 | |||
| 41 | AVRational tick_rate; | ||
| 42 | int num_ticks_per_picture; | ||
| 43 | |||
| 44 | int delete_padding; | ||
| 45 | } AV1MetadataContext; | ||
| 46 | |||
| 47 | |||
| 48 | 142 | static int av1_metadata_update_sequence_header(AVBSFContext *bsf, | |
| 49 | AV1RawSequenceHeader *seq) | ||
| 50 | { | ||
| 51 | 142 | AV1MetadataContext *ctx = bsf->priv_data; | |
| 52 | 142 | AV1RawColorConfig *clc = &seq->color_config; | |
| 53 | 142 | AV1RawTimingInfo *tim = &seq->timing_info; | |
| 54 | |||
| 55 |
1/2✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
|
142 | if (ctx->color_primaries >= 0 || |
| 56 |
1/2✓ Branch 0 taken 142 times.
✗ Branch 1 not taken.
|
142 | ctx->transfer_characteristics >= 0 || |
| 57 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 142 times.
|
142 | ctx->matrix_coefficients >= 0) { |
| 58 | ✗ | clc->color_description_present_flag = 1; | |
| 59 | |||
| 60 | ✗ | if (ctx->color_primaries >= 0) | |
| 61 | ✗ | clc->color_primaries = ctx->color_primaries; | |
| 62 | ✗ | if (ctx->transfer_characteristics >= 0) | |
| 63 | ✗ | clc->transfer_characteristics = ctx->transfer_characteristics; | |
| 64 | ✗ | if (ctx->matrix_coefficients >= 0) | |
| 65 | ✗ | clc->matrix_coefficients = ctx->matrix_coefficients; | |
| 66 | } | ||
| 67 | |||
| 68 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 142 times.
|
142 | if (ctx->color_range >= 0) { |
| 69 | ✗ | if (clc->color_primaries == AVCOL_PRI_BT709 && | |
| 70 | ✗ | clc->transfer_characteristics == AVCOL_TRC_IEC61966_2_1 && | |
| 71 | ✗ | clc->matrix_coefficients == AVCOL_SPC_RGB) { | |
| 72 | ✗ | av_log(bsf, AV_LOG_WARNING, "Warning: color_range cannot be set " | |
| 73 | "on RGB streams encoded in BT.709 sRGB.\n"); | ||
| 74 | } else { | ||
| 75 | ✗ | clc->color_range = ctx->color_range; | |
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 142 times.
|
142 | if (ctx->chroma_sample_position >= 0) { |
| 80 | ✗ | if (clc->mono_chrome || !clc->subsampling_x || !clc->subsampling_y) { | |
| 81 | ✗ | av_log(bsf, AV_LOG_WARNING, "Warning: chroma_sample_position " | |
| 82 | "can only be set for 4:2:0 streams.\n"); | ||
| 83 | } else { | ||
| 84 | ✗ | clc->chroma_sample_position = ctx->chroma_sample_position; | |
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 142 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
142 | if (ctx->tick_rate.num && ctx->tick_rate.den) { |
| 89 | int num, den; | ||
| 90 | |||
| 91 | ✗ | av_reduce(&num, &den, ctx->tick_rate.num, ctx->tick_rate.den, | |
| 92 | UINT32_MAX > INT_MAX ? UINT32_MAX : INT_MAX); | ||
| 93 | |||
| 94 | ✗ | tim->time_scale = num; | |
| 95 | ✗ | tim->num_units_in_display_tick = den; | |
| 96 | ✗ | seq->timing_info_present_flag = 1; | |
| 97 | |||
| 98 | ✗ | if (ctx->num_ticks_per_picture > 0) { | |
| 99 | ✗ | tim->equal_picture_interval = 1; | |
| 100 | ✗ | tim->num_ticks_per_picture_minus_1 = | |
| 101 | ✗ | ctx->num_ticks_per_picture - 1; | |
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | 142 | return 0; | |
| 106 | } | ||
| 107 | |||
| 108 | 343 | static int av1_metadata_update_fragment(AVBSFContext *bsf, AVPacket *pkt, | |
| 109 | CodedBitstreamFragment *frag) | ||
| 110 | { | ||
| 111 | 343 | AV1MetadataContext *ctx = bsf->priv_data; | |
| 112 | int err, i; | ||
| 113 | |||
| 114 |
2/2✓ Branch 0 taken 995 times.
✓ Branch 1 taken 343 times.
|
1338 | for (i = 0; i < frag->nb_units; i++) { |
| 115 |
2/2✓ Branch 0 taken 142 times.
✓ Branch 1 taken 853 times.
|
995 | if (frag->units[i].type == AV1_OBU_SEQUENCE_HEADER) { |
| 116 | 142 | AV1RawOBU *obu = frag->units[i].content; | |
| 117 | 142 | err = av1_metadata_update_sequence_header(bsf, &obu->obu.sequence_header); | |
| 118 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 142 times.
|
142 | if (err < 0) |
| 119 | ✗ | return err; | |
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | // If a Temporal Delimiter is present, it must be the first OBU. | ||
| 124 |
3/4✓ Branch 0 taken 343 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 327 times.
✓ Branch 3 taken 16 times.
|
343 | if (frag->nb_units && frag->units[0].type == AV1_OBU_TEMPORAL_DELIMITER) { |
| 125 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 327 times.
|
327 | if (ctx->td == BSF_ELEMENT_REMOVE) |
| 126 | ✗ | ff_cbs_delete_unit(frag, 0); | |
| 127 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
16 | } else if (pkt && ctx->td == BSF_ELEMENT_INSERT) { |
| 128 | ✗ | err = ff_cbs_insert_unit_content(frag, 0, AV1_OBU_TEMPORAL_DELIMITER, | |
| 129 | ✗ | &ctx->td_obu, NULL); | |
| 130 | ✗ | if (err < 0) { | |
| 131 | ✗ | av_log(bsf, AV_LOG_ERROR, "Failed to insert Temporal Delimiter.\n"); | |
| 132 | ✗ | return err; | |
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 343 times.
|
343 | if (ctx->delete_padding) { |
| 137 | ✗ | for (i = frag->nb_units - 1; i >= 0; i--) { | |
| 138 | ✗ | if (frag->units[i].type == AV1_OBU_PADDING) | |
| 139 | ✗ | ff_cbs_delete_unit(frag, i); | |
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | 343 | return 0; | |
| 144 | } | ||
| 145 | |||
| 146 | static const CBSBSFType av1_metadata_type = { | ||
| 147 | .codec_id = AV_CODEC_ID_AV1, | ||
| 148 | .fragment_name = "temporal unit", | ||
| 149 | .unit_name = "OBU", | ||
| 150 | .update_fragment = &av1_metadata_update_fragment, | ||
| 151 | }; | ||
| 152 | |||
| 153 | 16 | static int av1_metadata_init(AVBSFContext *bsf) | |
| 154 | { | ||
| 155 | 16 | AV1MetadataContext *ctx = bsf->priv_data; | |
| 156 | |||
| 157 | 16 | ctx->td_obu = (AV1RawOBU) { | |
| 158 | .header.obu_type = AV1_OBU_TEMPORAL_DELIMITER, | ||
| 159 | }; | ||
| 160 | |||
| 161 | 16 | return ff_cbs_bsf_generic_init(bsf, &av1_metadata_type); | |
| 162 | } | ||
| 163 | |||
| 164 | #define OFFSET(x) offsetof(AV1MetadataContext, x) | ||
| 165 | #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) | ||
| 166 | static const AVOption av1_metadata_options[] = { | ||
| 167 | BSF_ELEMENT_OPTIONS_PIR("td", "Temporal Delimiter OBU", | ||
| 168 | td, FLAGS), | ||
| 169 | |||
| 170 | { "color_primaries", "Set color primaries (section 6.4.2)", | ||
| 171 | OFFSET(color_primaries), AV_OPT_TYPE_INT, | ||
| 172 | { .i64 = -1 }, -1, 255, FLAGS }, | ||
| 173 | { "transfer_characteristics", "Set transfer characteristics (section 6.4.2)", | ||
| 174 | OFFSET(transfer_characteristics), AV_OPT_TYPE_INT, | ||
| 175 | { .i64 = -1 }, -1, 255, FLAGS }, | ||
| 176 | { "matrix_coefficients", "Set matrix coefficients (section 6.4.2)", | ||
| 177 | OFFSET(matrix_coefficients), AV_OPT_TYPE_INT, | ||
| 178 | { .i64 = -1 }, -1, 255, FLAGS }, | ||
| 179 | |||
| 180 | { "color_range", "Set color range flag (section 6.4.2)", | ||
| 181 | OFFSET(color_range), AV_OPT_TYPE_INT, | ||
| 182 | { .i64 = -1 }, -1, 1, FLAGS, .unit = "cr" }, | ||
| 183 | { "tv", "TV (limited) range", 0, AV_OPT_TYPE_CONST, | ||
| 184 | { .i64 = 0 }, .flags = FLAGS, .unit = "cr" }, | ||
| 185 | { "pc", "PC (full) range", 0, AV_OPT_TYPE_CONST, | ||
| 186 | { .i64 = 1 }, .flags = FLAGS, .unit = "cr" }, | ||
| 187 | |||
| 188 | { "chroma_sample_position", "Set chroma sample position (section 6.4.2)", | ||
| 189 | OFFSET(chroma_sample_position), AV_OPT_TYPE_INT, | ||
| 190 | { .i64 = -1 }, -1, 3, FLAGS, .unit = "csp" }, | ||
| 191 | { "unknown", "Unknown chroma sample position", 0, AV_OPT_TYPE_CONST, | ||
| 192 | { .i64 = AV1_CSP_UNKNOWN }, .flags = FLAGS, .unit = "csp" }, | ||
| 193 | { "vertical", "Left chroma sample position", 0, AV_OPT_TYPE_CONST, | ||
| 194 | { .i64 = AV1_CSP_VERTICAL }, .flags = FLAGS, .unit = "csp" }, | ||
| 195 | { "colocated", "Top-left chroma sample position", 0, AV_OPT_TYPE_CONST, | ||
| 196 | { .i64 = AV1_CSP_COLOCATED }, .flags = FLAGS, .unit = "csp" }, | ||
| 197 | |||
| 198 | { "tick_rate", "Set display tick rate (time_scale / num_units_in_display_tick)", | ||
| 199 | OFFSET(tick_rate), AV_OPT_TYPE_RATIONAL, | ||
| 200 | { .dbl = 0.0 }, 0, UINT_MAX, FLAGS }, | ||
| 201 | { "num_ticks_per_picture", "Set display ticks per picture for CFR streams", | ||
| 202 | OFFSET(num_ticks_per_picture), AV_OPT_TYPE_INT, | ||
| 203 | { .i64 = -1 }, -1, INT_MAX, FLAGS }, | ||
| 204 | |||
| 205 | { "delete_padding", "Delete all Padding OBUs", | ||
| 206 | OFFSET(delete_padding), AV_OPT_TYPE_BOOL, | ||
| 207 | { .i64 = 0 }, 0, 1, FLAGS}, | ||
| 208 | |||
| 209 | { NULL } | ||
| 210 | }; | ||
| 211 | |||
| 212 | static const AVClass av1_metadata_class = { | ||
| 213 | .class_name = "av1_metadata_bsf", | ||
| 214 | .item_name = av_default_item_name, | ||
| 215 | .option = av1_metadata_options, | ||
| 216 | .version = LIBAVUTIL_VERSION_INT, | ||
| 217 | }; | ||
| 218 | |||
| 219 | static const enum AVCodecID av1_metadata_codec_ids[] = { | ||
| 220 | AV_CODEC_ID_AV1, AV_CODEC_ID_NONE, | ||
| 221 | }; | ||
| 222 | |||
| 223 | const FFBitStreamFilter ff_av1_metadata_bsf = { | ||
| 224 | .p.name = "av1_metadata", | ||
| 225 | .p.codec_ids = av1_metadata_codec_ids, | ||
| 226 | .p.priv_class = &av1_metadata_class, | ||
| 227 | .priv_data_size = sizeof(AV1MetadataContext), | ||
| 228 | .init = &av1_metadata_init, | ||
| 229 | .close = &ff_cbs_bsf_generic_close, | ||
| 230 | .filter = &ff_cbs_bsf_generic_filter, | ||
| 231 | }; | ||
| 232 |