FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/vc1_parser.c
Date: 2026-09-24 08:25:19
Exec Total Coverage
Lines: 128 141 90.8%
Functions: 4 4 100.0%
Branches: 85 110 77.3%

Line Branch Exec Source
1 /*
2 * VC-1 and WMV3 parser
3 * Copyright (c) 2006-2007 Konstantin Shishkov
4 * Partly based on vc9.c (c) 2005 Anonymous, Alex Beregszaszi, Michael Niedermayer
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 /**
24 * @file
25 * VC-1 and WMV3 parser
26 */
27
28 #include "libavutil/attributes.h"
29 #include "libavutil/avassert.h"
30 #include "parser.h"
31 #include "parser_internal.h"
32 #include "vc1.h"
33 #include "get_bits.h"
34 #include "vc1dsp.h"
35
36 /** The maximum number of bytes of a sequence, entry point or
37 * frame header whose values we pay any attention to */
38 #define UNESCAPED_THRESHOLD 37
39
40 /** The maximum number of bytes of a sequence, entry point or
41 * frame header which must be valid memory (because they are
42 * used to update the bitstream cache in skip_bits() calls)
43 */
44 #define UNESCAPED_LIMIT 144
45
46 typedef enum {
47 NO_MATCH,
48 ONE_ZERO,
49 TWO_ZEROS,
50 ONE
51 } VC1ParseSearchState;
52
53 typedef struct VC1ParseContext {
54 ParseContext pc;
55 VC1Context v;
56 uint8_t prev_start_code;
57 uint8_t extradata_parsed;
58 size_t bytes_to_skip;
59 uint8_t unesc_buffer[UNESCAPED_LIMIT];
60 size_t unesc_index;
61 VC1ParseSearchState search_state;
62 } VC1ParseContext;
63
64 973 static void vc1_extract_header(AVCodecParserContext *s, AVCodecContext *avctx,
65 const uint8_t *buf, int buf_size)
66 {
67 /* Parse the header we just finished unescaping */
68 973 VC1ParseContext *vpc = s->priv_data;
69 GetBitContext gb;
70 int ret;
71 973 vpc->v.s.avctx = avctx;
72 973 ret = init_get_bits8(&gb, buf, buf_size);
73 av_assert1(ret >= 0); // buf_size is bounded by UNESCAPED_THRESHOLD
74
75
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 305 times.
✓ Branch 3 taken 645 times.
973 switch (vpc->prev_start_code) {
76 9 case VC1_CODE_SEQHDR & 0xFF:
77 9 ff_vc1_decode_sequence_header(avctx, &vpc->v, &gb);
78 9 break;
79 14 case VC1_CODE_ENTRYPOINT & 0xFF:
80 14 ff_vc1_decode_entry_point(avctx, &vpc->v, &gb);
81 14 break;
82 305 case VC1_CODE_FRAME & 0xFF:
83
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 305 times.
305 if(vpc->v.profile < PROFILE_ADVANCED)
84 ret = ff_vc1_parse_frame_header (&vpc->v, &gb);
85 else
86 305 ret = ff_vc1_parse_frame_header_adv(&vpc->v, &gb);
87
88
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 305 times.
305 if (ret < 0)
89 break;
90
91 /* keep AV_PICTURE_TYPE_BI internal to VC1 */
92
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 305 times.
305 if (vpc->v.s.pict_type == AV_PICTURE_TYPE_BI)
93 s->pict_type = AV_PICTURE_TYPE_B;
94 else
95 305 s->pict_type = vpc->v.s.pict_type;
96
97
1/2
✓ Branch 0 taken 305 times.
✗ Branch 1 not taken.
305 if (vpc->v.broadcast){
98 // process pulldown flags
99 305 s->repeat_pict = 1;
100 // Pulldown flags are only valid when 'broadcast' has been set.
101
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 305 times.
305 if (vpc->v.rff){
102 // repeat field
103 s->repeat_pict = 2;
104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 305 times.
305 }else if (vpc->v.rptfrm){
105 // repeat frames
106 s->repeat_pict = vpc->v.rptfrm * 2 + 1;
107 }
108 }else{
109 s->repeat_pict = 0;
110 }
111
112
4/6
✓ Branch 0 taken 305 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 261 times.
✓ Branch 4 taken 44 times.
✗ Branch 5 not taken.
305 if (vpc->v.broadcast && vpc->v.interlace && !vpc->v.psf)
113
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 s->field_order = vpc->v.tff ? AV_FIELD_TT : AV_FIELD_BB;
114 else
115 261 s->field_order = AV_FIELD_PROGRESSIVE;
116
117 305 break;
118 }
119 1946 s->format = vpc->v.chromaformat == 1 ? AV_PIX_FMT_YUV420P
120
2/2
✓ Branch 0 taken 967 times.
✓ Branch 1 taken 6 times.
973 : AV_PIX_FMT_NONE;
121
3/4
✓ Branch 0 taken 961 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 961 times.
✗ Branch 3 not taken.
973 if (avctx->width && avctx->height) {
122 961 s->width = avctx->width;
123 961 s->height = avctx->height;
124 961 s->coded_width = FFALIGN(avctx->coded_width, 16);
125 961 s->coded_height = FFALIGN(avctx->coded_height, 16);
126 }
127 973 }
128
129 /**
130 * Seed the parse context from extradata, the way the decoder does at init.
131 *
132 * libavformat closes and reopens the parser on every reposition
133 * (ff_read_frame_flush()), so each seek starts from a zeroed VC1Context: profile
134 * reads as simple, and max_coded_width/max_coded_height as zero, until an
135 * in-stream sequence header happens to pass. An entry point reaching a context in
136 * that state is read at the wrong bit offset, because whether hrd_full[] precedes
137 * coded_size_flag is a property of the sequence header, and the size it then
138 * falls back to is the zero pair.
139 *
140 * Unlike the decoder, a parser that learns nothing here still runs: it keeps
141 * reading headers out of the stream as it did before.
142 */
143 8 static void vc1_parse_extradata(AVCodecParserContext *s, AVCodecContext *avctx)
144 {
145 8 VC1ParseContext *vpc = s->priv_data;
146 int seq_initialized, ep_initialized;
147
148
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
8 if (!avctx->extradata || avctx->extradata_size < 16)
149 6 return;
150
151 2 vpc->v.s.avctx = avctx;
152 2 ff_vc1_decode_extradata(avctx, &vpc->v, &seq_initialized, &ep_initialized);
153 }
154
155 4745 static int vc1_parse(AVCodecParserContext *s,
156 AVCodecContext *avctx,
157 const uint8_t **poutbuf, int *poutbuf_size,
158 const uint8_t *buf, int buf_size)
159 {
160 /* Here we do the searching for frame boundaries and headers at
161 * the same time. Only a minimal amount at the start of each
162 * header is unescaped. */
163 4745 VC1ParseContext *vpc = s->priv_data;
164 4745 int pic_found = vpc->pc.frame_start_found;
165 4745 uint8_t *unesc_buffer = vpc->unesc_buffer;
166 4745 size_t unesc_index = vpc->unesc_index;
167 4745 VC1ParseSearchState search_state = vpc->search_state;
168 4745 int start_code_found = 0;
169 4745 int next = END_NOT_FOUND;
170 4745 int i = vpc->bytes_to_skip;
171
172
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4737 times.
4745 if (!vpc->extradata_parsed) {
173 8 vpc->extradata_parsed = 1;
174 8 vc1_parse_extradata(s, avctx);
175 }
176
177
4/4
✓ Branch 0 taken 4736 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 4720 times.
4745 if (pic_found && buf_size == 0) {
178 /* EOF considered as end of frame */
179 16 memset(unesc_buffer + unesc_index, 0, UNESCAPED_THRESHOLD - unesc_index);
180 16 vc1_extract_header(s, avctx, unesc_buffer, unesc_index);
181 16 next = 0;
182 }
183
2/2
✓ Branch 0 taken 5393 times.
✓ Branch 1 taken 4453 times.
9846 while (i < buf_size) {
184 uint8_t b;
185 5393 start_code_found = 0;
186
4/4
✓ Branch 0 taken 38265 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 32986 times.
✓ Branch 3 taken 5279 times.
38288 while (i < buf_size && unesc_index < UNESCAPED_THRESHOLD) {
187 32986 b = buf[i++];
188 32986 unesc_buffer[unesc_index++] = b;
189
2/2
✓ Branch 0 taken 32765 times.
✓ Branch 1 taken 221 times.
32986 if (search_state <= ONE_ZERO)
190
2/2
✓ Branch 0 taken 860 times.
✓ Branch 1 taken 31905 times.
32765 search_state = b ? NO_MATCH : search_state + 1;
191
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 91 times.
221 else if (search_state == TWO_ZEROS) {
192
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 39 times.
130 if (b == 1)
193 91 search_state = ONE;
194
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 else if (b > 1) {
195
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 17 times.
39 if (b == 3)
196 22 unesc_index--; // swallow emulation prevention byte
197 39 search_state = NO_MATCH;
198 }
199 }
200 else { // search_state == ONE
201 // Header unescaping terminates early due to detection of next start code
202 91 search_state = NO_MATCH;
203 91 start_code_found = 1;
204 91 break;
205 }
206 }
207
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 5393 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
5393 if ((s->flags & PARSER_FLAG_COMPLETE_FRAMES) &&
208 unesc_index >= UNESCAPED_THRESHOLD &&
209 vpc->prev_start_code == (VC1_CODE_FRAME & 0xFF))
210 {
211 // No need to keep scanning the rest of the buffer for
212 // start codes if we know it contains a complete frame and
213 // we've already unescaped all we need of the frame header
214 vc1_extract_header(s, avctx, unesc_buffer, unesc_index);
215 unesc_index = 0;
216 break;
217 }
218
3/4
✓ Branch 0 taken 5279 times.
✓ Branch 1 taken 114 times.
✓ Branch 2 taken 5279 times.
✗ Branch 3 not taken.
5393 if (unesc_index >= UNESCAPED_THRESHOLD && !start_code_found) {
219
2/2
✓ Branch 0 taken 52860 times.
✓ Branch 1 taken 4413 times.
57273 while (i < buf_size) {
220
2/2
✓ Branch 0 taken 27593 times.
✓ Branch 1 taken 25267 times.
52860 if (search_state == NO_MATCH) {
221 27593 i += vpc->v.vc1dsp.startcode_find_candidate(buf + i, buf_size - i);
222
2/2
✓ Branch 0 taken 23222 times.
✓ Branch 1 taken 4371 times.
27593 if (i < buf_size) {
223 23222 search_state = ONE_ZERO;
224 }
225 27593 i++;
226 } else {
227 25267 b = buf[i++];
228
2/2
✓ Branch 0 taken 23231 times.
✓ Branch 1 taken 2036 times.
25267 if (search_state == ONE_ZERO)
229
2/2
✓ Branch 0 taken 22061 times.
✓ Branch 1 taken 1170 times.
23231 search_state = b ? NO_MATCH : TWO_ZEROS;
230
2/2
✓ Branch 0 taken 1170 times.
✓ Branch 1 taken 866 times.
2036 else if (search_state == TWO_ZEROS) {
231
1/2
✓ Branch 0 taken 1170 times.
✗ Branch 1 not taken.
1170 if (b >= 1)
232
2/2
✓ Branch 0 taken 866 times.
✓ Branch 1 taken 304 times.
1170 search_state = b == 1 ? ONE : NO_MATCH;
233 }
234 else { // search_state == ONE
235 866 search_state = NO_MATCH;
236 866 start_code_found = 1;
237 866 break;
238 }
239 }
240 }
241 }
242
2/2
✓ Branch 0 taken 957 times.
✓ Branch 1 taken 4436 times.
5393 if (start_code_found) {
243 957 vc1_extract_header(s, avctx, unesc_buffer, unesc_index);
244
245 957 vpc->prev_start_code = b;
246 957 unesc_index = 0;
247
248
1/2
✓ Branch 0 taken 957 times.
✗ Branch 1 not taken.
957 if (!(s->flags & PARSER_FLAG_COMPLETE_FRAMES)) {
249
5/6
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 926 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 22 times.
957 if (!pic_found && (b == (VC1_CODE_FRAME & 0xFF) || b == (VC1_CODE_FIELD & 0xFF))) {
250 9 pic_found = 1;
251 }
252
6/6
✓ Branch 0 taken 926 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 890 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 293 times.
✓ Branch 5 taken 597 times.
948 else if (pic_found && b != (VC1_CODE_FIELD & 0xFF) && b != (VC1_CODE_SLICE & 0xFF)
253
2/2
✓ Branch 0 taken 292 times.
✓ Branch 1 taken 1 times.
293 && b != (VC1_CODE_ENDOFSEQ & 0xFF)) {
254 292 next = i - 4;
255 292 pic_found = b == (VC1_CODE_FRAME & 0xFF);
256 292 break;
257 }
258 }
259 }
260 }
261
262 4745 vpc->pc.frame_start_found = pic_found;
263 4745 vpc->unesc_index = unesc_index;
264 4745 vpc->search_state = search_state;
265
266
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4745 times.
4745 if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
267 next = buf_size;
268 } else {
269
2/2
✓ Branch 1 taken 4437 times.
✓ Branch 2 taken 308 times.
4745 if (ff_combine_frame(&vpc->pc, next, &buf, &buf_size) < 0) {
270 4437 vpc->bytes_to_skip = 0;
271 4437 *poutbuf = NULL;
272 4437 *poutbuf_size = 0;
273 4437 return buf_size;
274 }
275 }
276
277 /* If we return with a valid pointer to a combined frame buffer
278 * then on the next call then we'll have been unhelpfully rewound
279 * by up to 4 bytes (depending upon whether the start code
280 * overlapped the input buffer, and if so by how much). We don't
281 * want this: it will either cause spurious second detections of
282 * the start code we've already seen, or cause extra bytes to be
283 * inserted at the start of the unescaped buffer. */
284 308 vpc->bytes_to_skip = 4;
285
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 308 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
308 if (next < 0 && next != END_NOT_FOUND)
286 vpc->bytes_to_skip += next;
287
288 308 *poutbuf = buf;
289 308 *poutbuf_size = buf_size;
290 308 return next;
291 }
292
293 8 static av_cold int vc1_parse_init(AVCodecParserContext *s)
294 {
295 8 VC1ParseContext *vpc = s->priv_data;
296 /* Report no picture type until a frame header has actually been read.
297 * av_parser_init() leaves pict_type at AV_PICTURE_TYPE_I, and libavformat
298 * marks a packet a key frame from that default; a track whose frames carry
299 * no start codes yields no header to this parser at all. */
300 8 s->pict_type = AV_PICTURE_TYPE_NONE;
301 8 vpc->v.s.slice_context_count = 1;
302 8 vpc->v.first_pic_header_flag = 1;
303 8 vpc->v.parse_only = 1;
304 8 vpc->prev_start_code = 0;
305 8 vpc->extradata_parsed = 0;
306 8 vpc->bytes_to_skip = 0;
307 8 vpc->unesc_index = 0;
308 8 vpc->search_state = NO_MATCH;
309 8 ff_vc1dsp_init(&vpc->v.vc1dsp); /* startcode_find_candidate */
310 8 return 0;
311 }
312
313 const FFCodecParser ff_vc1_parser = {
314 PARSER_CODEC_LIST(AV_CODEC_ID_VC1),
315 .priv_data_size = sizeof(VC1ParseContext),
316 .init = vc1_parse_init,
317 .parse = vc1_parse,
318 .close = ff_parse_close,
319 };
320