FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/lcevc.c
Date: 2026-05-02 17:52:23
Exec Total Coverage
Lines: 83 202 41.1%
Functions: 2 3 66.7%
Branches: 30 100 30.0%

Line Branch Exec Source
1 /*
2 * LCEVC helper functions for muxers
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "libavutil/error.h"
22 #include "libavutil/intreadwrite.h"
23 #include "libavutil/mem.h"
24 #include "libavcodec/bytestream.h"
25 #include "libavcodec/h2645_parse.h"
26 #include "libavcodec/lcevc.h"
27 #include "libavcodec/lcevctab.h"
28 #include "libavcodec/lcevc_parse.h"
29 #include "avio.h"
30 #include "avio_internal.h"
31 #include "lcevc.h"
32
33 /**
34 * Rewrite the NALu stripping the unneeded blocks.
35 * Given that length fields coded inside the NALu are not aware of any emulation_3bytes
36 * present in the bitstream, we need to keep track of the raw buffer as we navigate
37 * the stripped buffer in order to write proper NALu sizes.
38 */
39 9 static int write_nalu(LCEVCDecoderConfigurationRecord *lvcc, AVIOContext *pb,
40 const H2645NAL *nal)
41 {
42 GetByteContext gbc, raw_gbc;
43 9 int64_t start = avio_tell(pb), end;
44 9 int sc = 0, gc = 0;
45 9 int skipped_byte_pos = 0, nalu_length = 3;
46
47 9 bytestream2_init(&gbc, nal->data, nal->size);
48 9 bytestream2_init(&raw_gbc, nal->raw_data, nal->raw_size);
49 9 avio_wb16(pb, 0); // size placeholder
50 9 avio_wb16(pb, bytestream2_get_be16(&gbc)); // nal_unit_header
51 9 bytestream2_skip(&raw_gbc, 2);
52
53
5/6
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 9 times.
36 while (bytestream2_get_bytes_left(&gbc) > 1 && (!sc || !gc)) {
54 GetBitContext gb;
55 uint64_t payload_size;
56 int payload_size_type, payload_type;
57 int block_size, raw_block_size, block_end;
58
59 27 init_get_bits8(&gb, gbc.buffer, bytestream2_get_bytes_left(&gbc));
60
61 27 payload_size_type = get_bits(&gb, 3);
62 27 payload_type = get_bits(&gb, 5);
63 27 payload_size = payload_size_type;
64
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
27 if (payload_size_type == 6)
65 return AVERROR_PATCHWELCOME;
66
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 18 times.
27 if (payload_size_type == 7)
67 9 payload_size = get_mb(&gb);
68
69
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 if (payload_size > INT_MAX - (get_bits_count(&gb) >> 3))
70 return AVERROR_INVALIDDATA;
71
72 27 block_size = raw_block_size = payload_size + (get_bits_count(&gb) >> 3);
73
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 if (block_size >= bytestream2_get_bytes_left(&gbc))
74 return AVERROR_INVALIDDATA;
75
76 27 block_end = bytestream2_tell(&gbc) + block_size;
77 // Take into account removed emulation 3bytes, as payload_size in
78 // the bitstream is not aware of them.
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
27 for (; skipped_byte_pos < nal->skipped_bytes; skipped_byte_pos++) {
80 if (nal->skipped_bytes_pos[skipped_byte_pos] >= block_end)
81 break;
82 raw_block_size++;
83 }
84
85
3/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
27 switch (payload_type) {
86 9 case 0:
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (sc)
88 break;
89
90 9 lvcc->profile_idc = get_bits(&gb, 4);
91 9 lvcc->level_idc = get_bits(&gb, 4);
92
93 9 avio_write(pb, raw_gbc.buffer, raw_block_size);
94 9 nalu_length += raw_block_size;
95 9 sc = 1;
96 9 break;
97 9 case 1: {
98 int resolution_type, bit_depth;
99 int processed_planes_type_flag;
100
101
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (gc)
102 break;
103
104 9 processed_planes_type_flag = get_bits1(&gb);
105 9 resolution_type = get_bits(&gb, 6);
106
107 9 skip_bits1(&gb);
108 9 lvcc->chroma_format_idc = get_bits(&gb, 2);
109
110 9 skip_bits(&gb, 2);
111 9 bit_depth = get_bits(&gb, 2) * 2; // enhancement_depth_type
112 9 lvcc->bit_depth_luma_minus8 = bit_depth;
113 9 lvcc->bit_depth_chroma_minus8 = bit_depth;
114
115
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (resolution_type < 63) {
116 9 lvcc->pic_width_in_luma_samples = ff_lcevc_resolution_type[resolution_type].width;
117 9 lvcc->pic_height_in_luma_samples = ff_lcevc_resolution_type[resolution_type].height;
118 } else {
119 int upsample_type, tile_dimensions_type;
120 int temporal_step_width_modifier_signalled_flag, level1_filtering_signalled_flag;
121 // Skip syntax elements until we get to the custom dimension ones
122 temporal_step_width_modifier_signalled_flag = get_bits1(&gb);
123 skip_bits(&gb, 3);
124 upsample_type = get_bits(&gb, 3);
125 level1_filtering_signalled_flag = get_bits1(&gb);
126 skip_bits(&gb, 4);
127 tile_dimensions_type = get_bits(&gb, 2);
128 skip_bits(&gb, 4);
129 if (processed_planes_type_flag)
130 skip_bits(&gb, 4);
131 if (temporal_step_width_modifier_signalled_flag)
132 skip_bits(&gb, 8);
133 if (upsample_type)
134 skip_bits_long(&gb, 64);
135 if (level1_filtering_signalled_flag)
136 skip_bits(&gb, 8);
137 if (tile_dimensions_type) {
138 if (tile_dimensions_type == 3)
139 skip_bits_long(&gb, 32);
140 skip_bits(&gb, 8);
141 }
142
143 lvcc->pic_width_in_luma_samples = get_bits(&gb, 16);
144 lvcc->pic_height_in_luma_samples = get_bits(&gb, 16);
145 }
146
147
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 if (!lvcc->pic_width_in_luma_samples || !lvcc->pic_height_in_luma_samples)
148 break;
149
150 9 avio_write(pb, raw_gbc.buffer, raw_block_size);
151 9 nalu_length += raw_block_size;
152 9 gc = 1;
153 9 break;
154 }
155 9 case 5:
156 9 avio_write(pb, raw_gbc.buffer, raw_block_size);
157 9 nalu_length += raw_block_size;
158 9 break;
159 default:
160 break;
161 }
162
163 27 bytestream2_skip(&gbc, block_size);
164 27 bytestream2_skip(&raw_gbc, raw_block_size);
165 }
166
167
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 if (!sc || !gc)
168 return AVERROR_INVALIDDATA;
169
170 9 avio_w8(pb, 0x80); // rbsp_alignment bits
171
172 9 end = avio_tell(pb);
173 9 avio_seek(pb, start, SEEK_SET);
174 9 avio_wb16(pb, nalu_length);
175 9 avio_seek(pb, end, SEEK_SET);
176
177 9 return 0;
178 }
179
180 9 int ff_lcvec_parse_config_record(LCEVCDecoderConfigurationRecord *lvcc,
181 const uint8_t *buf, int size)
182 {
183 9 H2645Packet h2645_pkt = { 0 };
184 AVIOContext *pb;
185 int ret;
186 int found;
187
188
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (size <= 0)
189 return AVERROR_INVALIDDATA;
190
191
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (buf[0] == 1) {
192 GetBitContext gb;
193
194 if (size < 13)
195 return AVERROR_INVALIDDATA;
196
197 ret = init_get_bits8(&gb, buf, 13);
198 if (ret < 0)
199 return ret;
200
201 memset(lvcc, 0, sizeof(*lvcc));
202
203 skip_bits(&gb, 8);
204 lvcc->profile_idc = get_bits(&gb, 8);
205 lvcc->level_idc = get_bits(&gb, 8);
206 lvcc->chroma_format_idc = get_bits(&gb, 2);
207 lvcc->bit_depth_luma_minus8 = get_bits(&gb, 3);
208 lvcc->bit_depth_chroma_minus8 = get_bits(&gb, 3);
209 skip_bits(&gb, 8);
210 lvcc->pic_width_in_luma_samples = get_bits_long(&gb, 32);
211 lvcc->pic_height_in_luma_samples = get_bits_long(&gb, 32);
212
213 return 0;
214 }
215
216 9 ret = ffio_open_null_buf(&pb);
217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (ret < 0)
218 return ret;
219
220 9 ret = ff_h2645_packet_split(&h2645_pkt, buf, size, NULL, 0, AV_CODEC_ID_LCEVC, 0);
221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (ret < 0)
222 goto fail;
223
224 /* look for IDR or NON_IDR */
225 9 found = 0;
226
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 for (int i = 0; i < h2645_pkt.nb_nals; i++) {
227 9 const H2645NAL *nal = &h2645_pkt.nals[i];
228
229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (nal->type == LCEVC_IDR_NUT ||
230 nal->type == LCEVC_NON_IDR_NUT) {
231 9 ret = write_nalu(lvcc, pb, nal);
232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (ret < 0)
233 goto fail;
234 9 found = 1;
235 }
236 }
237
238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!found) {
239 ret = AVERROR_INVALIDDATA;
240 goto fail;
241 }
242
243 9 ret = 0;
244 9 fail:
245 9 ffio_close_null_buf(pb);
246 9 ff_h2645_packet_uninit(&h2645_pkt);
247
248 9 return ret;
249 }
250
251 int ff_isom_write_lvcc(AVIOContext *pb, const uint8_t *data, int len)
252 {
253 LCEVCDecoderConfigurationRecord lvcc = { 0 };
254 AVIOContext *idr_pb = NULL, *nidr_pb = NULL;
255 H2645Packet h2645_pkt = { 0 };
256 uint8_t *idr, *nidr;
257 uint32_t idr_size = 0, nidr_size = 0;
258 int ret, nb_idr = 0, nb_nidr = 0;
259
260 if (len <= 6)
261 return AVERROR_INVALIDDATA;
262
263 /* check for start code */
264 if (AV_RB32(data) != 0x00000001 &&
265 AV_RB24(data) != 0x000001) {
266 avio_write(pb, data, len);
267 return 0;
268 }
269
270 ret = ff_h2645_packet_split(&h2645_pkt, data, len, NULL, 0, AV_CODEC_ID_LCEVC, 0);
271 if (ret < 0)
272 return ret;
273
274 ret = avio_open_dyn_buf(&idr_pb);
275 if (ret < 0)
276 goto fail;
277 ret = avio_open_dyn_buf(&nidr_pb);
278 if (ret < 0)
279 goto fail;
280
281 /* look for IDR or NON_IDR */
282 for (int i = 0; i < h2645_pkt.nb_nals; i++) {
283 const H2645NAL *nal = &h2645_pkt.nals[i];
284
285 if (nal->type == LCEVC_IDR_NUT) {
286 nb_idr++;
287
288 ret = write_nalu(&lvcc, idr_pb, nal);
289 if (ret < 0)
290 goto fail;
291 } else if (nal->type == LCEVC_NON_IDR_NUT) {
292 nb_nidr++;
293
294 ret = write_nalu(&lvcc, nidr_pb, nal);
295 if (ret < 0)
296 goto fail;
297 }
298 }
299 idr_size = avio_get_dyn_buf(idr_pb, &idr);
300 nidr_size = avio_get_dyn_buf(nidr_pb, &nidr);
301
302 if (!idr_size && !nidr_size) {
303 ret = AVERROR_INVALIDDATA;
304 goto fail;
305 }
306
307 avio_w8(pb, 1); /* version */
308 avio_w8(pb, lvcc.profile_idc);
309 avio_w8(pb, lvcc.level_idc);
310 avio_w8(pb, (lvcc.chroma_format_idc << 6) |
311 (lvcc.bit_depth_luma_minus8 << 3) |
312 lvcc.bit_depth_chroma_minus8);
313 avio_w8(pb, 0xff); /* 2 bits nal size length - 1 (11) + 6 bits reserved (111111)*/
314 avio_wb32(pb, lvcc.pic_width_in_luma_samples);
315 avio_wb32(pb, lvcc.pic_height_in_luma_samples);
316 avio_w8(pb, 0xff);
317
318 int nb_arrays = !!nb_idr + !!nb_nidr;
319 avio_w8(pb, nb_arrays);
320
321 if (nb_idr) {
322 avio_w8(pb, LCEVC_IDR_NUT);
323 avio_wb16(pb, nb_idr);
324 avio_write(pb, idr, idr_size);
325 }
326 if (nb_nidr) {
327 avio_w8(pb, LCEVC_NON_IDR_NUT);
328 avio_wb16(pb, nb_nidr);
329 avio_write(pb, nidr, nidr_size);
330 }
331
332 ret = 0;
333 fail:
334 ffio_free_dyn_buf(&idr_pb);
335 ffio_free_dyn_buf(&nidr_pb);
336 ff_h2645_packet_uninit(&h2645_pkt);
337
338 return ret;
339 }
340