FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/nal.c
Date: 2026-10-29 07:45:57
Exec Total Coverage
Lines: 84 98 85.7%
Functions: 8 9 88.9%
Branches: 75 90 83.3%

Line Branch Exec Source
1 /*
2 * NAL 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 <stdint.h>
22 #include <string.h>
23
24 #include "libavutil/mem.h"
25 #include "libavutil/error.h"
26 #include "libavcodec/defs.h"
27 #include "avio.h"
28 #include "avio_internal.h"
29 #include "nal.h"
30
31 3637 static const uint8_t *nal_find_startcode_internal(const uint8_t *p, const uint8_t *end)
32 {
33 3637 const uint8_t *a = p + 4 - ((intptr_t)p & 3);
34
35
4/4
✓ Branch 0 taken 9999 times.
✓ Branch 1 taken 2503 times.
✓ Branch 2 taken 9998 times.
✓ Branch 3 taken 1 times.
12502 for (end -= 3; p < a && p < end; p++) {
36
6/6
✓ Branch 0 taken 2551 times.
✓ Branch 1 taken 7447 times.
✓ Branch 2 taken 2130 times.
✓ Branch 3 taken 421 times.
✓ Branch 4 taken 1133 times.
✓ Branch 5 taken 997 times.
9998 if (p[0] == 0 && p[1] == 0 && p[2] == 1)
37 1133 return p;
38 }
39
40
2/2
✓ Branch 0 taken 836701 times.
✓ Branch 1 taken 1063 times.
837764 for (end -= 3; p < end; p += 4) {
41 836701 uint32_t x = *(const uint32_t*)p;
42 // if ((x - 0x01000100) & (~x) & 0x80008000) // little endian
43 // if ((x - 0x00010001) & (~x) & 0x00800080) // big endian
44
2/2
✓ Branch 0 taken 13599 times.
✓ Branch 1 taken 823102 times.
836701 if ((x - 0x01010101) & (~x) & 0x80808080) { // generic
45
2/2
✓ Branch 0 taken 4039 times.
✓ Branch 1 taken 9560 times.
13599 if (p[1] == 0) {
46
4/4
✓ Branch 0 taken 554 times.
✓ Branch 1 taken 3485 times.
✓ Branch 2 taken 310 times.
✓ Branch 3 taken 244 times.
4039 if (p[0] == 0 && p[2] == 1)
47 310 return p;
48
4/4
✓ Branch 0 taken 848 times.
✓ Branch 1 taken 2881 times.
✓ Branch 2 taken 528 times.
✓ Branch 3 taken 320 times.
3729 if (p[2] == 0 && p[3] == 1)
49 528 return p+1;
50 }
51
2/2
✓ Branch 0 taken 3922 times.
✓ Branch 1 taken 8839 times.
12761 if (p[3] == 0) {
52
4/4
✓ Branch 0 taken 527 times.
✓ Branch 1 taken 3395 times.
✓ Branch 2 taken 294 times.
✓ Branch 3 taken 233 times.
3922 if (p[2] == 0 && p[4] == 1)
53 294 return p+2;
54
4/4
✓ Branch 0 taken 573 times.
✓ Branch 1 taken 3055 times.
✓ Branch 2 taken 309 times.
✓ Branch 3 taken 264 times.
3628 if (p[4] == 0 && p[5] == 1)
55 309 return p+3;
56 }
57 }
58 }
59
60
2/2
✓ Branch 0 taken 1616 times.
✓ Branch 1 taken 1063 times.
2679 for (end += 3; p < end; p++) {
61
3/6
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 1558 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 58 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1616 if (p[0] == 0 && p[1] == 0 && p[2] == 1)
62 ✗ return p;
63 }
64
65 1063 return end + 3;
66 }
67
68 3637 const uint8_t *ff_nal_find_startcode(const uint8_t *p, const uint8_t *end){
69 3637 const uint8_t *out = nal_find_startcode_internal(p, end);
70
6/6
✓ Branch 0 taken 3527 times.
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 2464 times.
✓ Branch 3 taken 1063 times.
✓ Branch 4 taken 1200 times.
✓ Branch 5 taken 1264 times.
3637 if(p<out && out<end && !out[-1]) out--;
71 3637 return out;
72 }
73
74 1045 static int nal_parse_units(AVIOContext *pb, NALUList *list,
75 const uint8_t *buf_in, int size)
76 {
77 1045 const uint8_t *p = buf_in;
78 1045 const uint8_t *end = p + size;
79 const uint8_t *nal_start, *nal_end;
80
81 1045 size = 0;
82 1045 nal_start = ff_nal_find_startcode(p, end);
83 2534 for (;;) {
84 3579 const size_t nalu_limit = SIZE_MAX / sizeof(*list->nalus);
85
4/4
✓ Branch 0 taken 8764 times.
✓ Branch 1 taken 1045 times.
✓ Branch 2 taken 6230 times.
✓ Branch 3 taken 2534 times.
9809 while (nal_start < end && !*(nal_start++));
86
2/2
✓ Branch 0 taken 1045 times.
✓ Branch 1 taken 2534 times.
3579 if (nal_start == end)
87 1045 break;
88
89 2534 nal_end = ff_nal_find_startcode(nal_start, end);
90 2534 size_t nalu_size = nal_end - nal_start;
91
3/4
✓ Branch 0 taken 2564 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 2534 times.
2564 while (nalu_size > 0 && nal_start[nalu_size - 1] == 0)
92 30 --nalu_size;
93
2/2
✓ Branch 0 taken 2206 times.
✓ Branch 1 taken 328 times.
2534 if (pb) {
94 2206 avio_wb32(pb, nalu_size);
95 2206 avio_write(pb, nal_start, nalu_size);
96
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 328 times.
328 } else if (list->nb_nalus >= nalu_limit) {
97 ✗ return AVERROR(ERANGE);
98 } else {
99 328 NALU *tmp = av_fast_realloc(list->nalus, &list->nalus_array_size,
100 328 (list->nb_nalus + 1) * sizeof(*list->nalus));
101
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 328 times.
328 if (!tmp)
102 ✗ return AVERROR(ENOMEM);
103 328 list->nalus = tmp;
104 328 tmp[list->nb_nalus++] = (NALU){ .offset = nal_start - p,
105 .size = nalu_size };
106 }
107 2534 size += 4 + nalu_size;
108 2534 nal_start = nal_end;
109 }
110 1045 return size;
111 }
112
113 956 int ff_nal_parse_units(AVIOContext *pb, const uint8_t *buf_in, int size)
114 {
115 956 return nal_parse_units(pb, NULL, buf_in, size);
116 }
117
118 89 int ff_nal_units_create_list(NALUList *list, const uint8_t *buf, int size)
119 {
120 89 list->nb_nalus = 0;
121 89 return nal_parse_units(NULL, list, buf, size);
122 }
123
124 89 void ff_nal_units_write_list(const NALUList *list, AVIOContext *pb,
125 const uint8_t *buf)
126 {
127
2/2
✓ Branch 0 taken 328 times.
✓ Branch 1 taken 89 times.
417 for (unsigned i = 0; i < list->nb_nalus; i++) {
128 328 avio_wb32(pb, list->nalus[i].size);
129 328 avio_write(pb, buf + list->nalus[i].offset, list->nalus[i].size);
130 }
131 89 }
132
133 16 int ff_nal_parse_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size)
134 {
135 AVIOContext *pb;
136 16 int ret = avio_open_dyn_buf(&pb);
137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 if(ret < 0)
138 ✗ return ret;
139
140 16 ff_nal_parse_units(pb, buf_in, *size);
141
142 16 *size = avio_close_dyn_buf(pb, buf);
143 16 return 0;
144 }
145
146 ✗ const uint8_t *ff_nal_mp4_find_startcode(const uint8_t *start,
147 const uint8_t *end,
148 int nal_length_size)
149 {
150 ✗ unsigned int res = 0;
151
152 ✗ if (end - start < nal_length_size)
153 ✗ return NULL;
154 ✗ while (nal_length_size--)
155 ✗ res = (res << 8) | *start++;
156
157 ✗ if (res > end - start)
158 ✗ return NULL;
159
160 ✗ return start + res;
161 }
162
163 111 uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len,
164 uint32_t *dst_len, int header_len)
165 {
166 uint8_t *dst;
167 uint32_t i, len;
168
169 111 dst = av_malloc(src_len + AV_INPUT_BUFFER_PADDING_SIZE);
170
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 111 times.
111 if (!dst)
171 ✗ return NULL;
172
173 /* NAL unit header */
174 111 i = len = 0;
175
3/4
✓ Branch 0 taken 196 times.
✓ Branch 1 taken 111 times.
✓ Branch 2 taken 196 times.
✗ Branch 3 not taken.
307 while (i < header_len && i < src_len)
176 196 dst[len++] = src[i++];
177
178
2/2
✓ Branch 0 taken 6712 times.
✓ Branch 1 taken 111 times.
6823 while (i + 2 < src_len)
179
6/6
✓ Branch 0 taken 539 times.
✓ Branch 1 taken 6173 times.
✓ Branch 2 taken 304 times.
✓ Branch 3 taken 235 times.
✓ Branch 4 taken 225 times.
✓ Branch 5 taken 79 times.
6712 if (!src[i] && !src[i + 1] && src[i + 2] == 3) {
180 225 dst[len++] = src[i++];
181 225 dst[len++] = src[i++];
182 225 i++; // remove emulation_prevention_three_byte
183 } else
184 6487 dst[len++] = src[i++];
185
186
2/2
✓ Branch 0 taken 222 times.
✓ Branch 1 taken 111 times.
333 while (i < src_len)
187 222 dst[len++] = src[i++];
188
189 111 memset(dst + len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
190
191 111 *dst_len = len;
192 111 return dst;
193 }
194