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 |