Coverage Report

Created: 2026-02-14 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/vc1_parser.c
Line
Count
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
36.2M
#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
    size_t bytes_to_skip;
58
    uint8_t unesc_buffer[UNESCAPED_LIMIT];
59
    size_t unesc_index;
60
    VC1ParseSearchState search_state;
61
} VC1ParseContext;
62
63
static void vc1_extract_header(AVCodecParserContext *s, AVCodecContext *avctx,
64
                               const uint8_t *buf, int buf_size)
65
1.26M
{
66
    /* Parse the header we just finished unescaping */
67
1.26M
    VC1ParseContext *vpc = s->priv_data;
68
1.26M
    GetBitContext gb;
69
1.26M
    int ret;
70
1.26M
    vpc->v.s.avctx = avctx;
71
1.26M
    ret = init_get_bits8(&gb, buf, buf_size);
72
1.26M
    av_assert1(ret >= 0); // buf_size is bounded by UNESCAPED_THRESHOLD
73
74
1.26M
    switch (vpc->prev_start_code) {
75
167k
    case VC1_CODE_SEQHDR & 0xFF:
76
167k
        ff_vc1_decode_sequence_header(avctx, &vpc->v, &gb);
77
167k
        break;
78
178k
    case VC1_CODE_ENTRYPOINT & 0xFF:
79
178k
        ff_vc1_decode_entry_point(avctx, &vpc->v, &gb);
80
178k
        break;
81
341k
    case VC1_CODE_FRAME & 0xFF:
82
341k
        if(vpc->v.profile < PROFILE_ADVANCED)
83
226k
            ret = ff_vc1_parse_frame_header    (&vpc->v, &gb);
84
114k
        else
85
114k
            ret = ff_vc1_parse_frame_header_adv(&vpc->v, &gb);
86
87
341k
        if (ret < 0)
88
29.2k
            break;
89
90
        /* keep AV_PICTURE_TYPE_BI internal to VC1 */
91
312k
        if (vpc->v.s.pict_type == AV_PICTURE_TYPE_BI)
92
9.66k
            s->pict_type = AV_PICTURE_TYPE_B;
93
302k
        else
94
302k
            s->pict_type = vpc->v.s.pict_type;
95
96
312k
        if (vpc->v.broadcast){
97
            // process pulldown flags
98
78.6k
            s->repeat_pict = 1;
99
            // Pulldown flags are only valid when 'broadcast' has been set.
100
78.6k
            if (vpc->v.rff){
101
                // repeat field
102
33.6k
                s->repeat_pict = 2;
103
45.0k
            }else if (vpc->v.rptfrm){
104
                // repeat frames
105
13.2k
                s->repeat_pict = vpc->v.rptfrm * 2 + 1;
106
13.2k
            }
107
233k
        }else{
108
233k
            s->repeat_pict = 0;
109
233k
        }
110
111
312k
        if (vpc->v.broadcast && vpc->v.interlace && !vpc->v.psf)
112
58.6k
            s->field_order = vpc->v.tff ? AV_FIELD_TT : AV_FIELD_BB;
113
253k
        else
114
253k
            s->field_order = AV_FIELD_PROGRESSIVE;
115
116
312k
        break;
117
1.26M
    }
118
1.26M
    s->format = vpc->v.chromaformat == 1 ? AV_PIX_FMT_YUV420P
119
1.26M
                                         : AV_PIX_FMT_NONE;
120
1.26M
    if (avctx->width && avctx->height) {
121
1.17M
        s->width        = avctx->width;
122
1.17M
        s->height       = avctx->height;
123
1.17M
        s->coded_width  = FFALIGN(avctx->coded_width,  16);
124
1.17M
        s->coded_height = FFALIGN(avctx->coded_height, 16);
125
1.17M
    }
126
1.26M
}
127
128
static int vc1_parse(AVCodecParserContext *s,
129
                           AVCodecContext *avctx,
130
                           const uint8_t **poutbuf, int *poutbuf_size,
131
                           const uint8_t *buf, int buf_size)
132
542k
{
133
    /* Here we do the searching for frame boundaries and headers at
134
     * the same time. Only a minimal amount at the start of each
135
     * header is unescaped. */
136
542k
    VC1ParseContext *vpc = s->priv_data;
137
542k
    int pic_found = vpc->pc.frame_start_found;
138
542k
    uint8_t *unesc_buffer = vpc->unesc_buffer;
139
542k
    size_t unesc_index = vpc->unesc_index;
140
542k
    VC1ParseSearchState search_state = vpc->search_state;
141
542k
    int start_code_found = 0;
142
542k
    int next = END_NOT_FOUND;
143
542k
    int i = vpc->bytes_to_skip;
144
145
542k
    if (pic_found && buf_size == 0) {
146
        /* EOF considered as end of frame */
147
526
        memset(unesc_buffer + unesc_index, 0, UNESCAPED_THRESHOLD - unesc_index);
148
526
        vc1_extract_header(s, avctx, unesc_buffer, unesc_index);
149
526
        next = 0;
150
526
    }
151
1.48M
    while (i < buf_size) {
152
1.37M
        uint8_t b;
153
1.37M
        start_code_found = 0;
154
32.1M
        while (i < buf_size && unesc_index < UNESCAPED_THRESHOLD) {
155
31.6M
            b = buf[i++];
156
31.6M
            unesc_buffer[unesc_index++] = b;
157
31.6M
            if (search_state <= ONE_ZERO)
158
26.5M
                search_state = b ? NO_MATCH : search_state + 1;
159
5.10M
            else if (search_state == TWO_ZEROS) {
160
4.29M
                if (b == 1)
161
819k
                    search_state = ONE;
162
3.47M
                else if (b > 1) {
163
1.29M
                    if (b == 3)
164
62.9k
                        unesc_index--; // swallow emulation prevention byte
165
1.29M
                    search_state = NO_MATCH;
166
1.29M
                }
167
4.29M
            }
168
809k
            else { // search_state == ONE
169
                // Header unescaping terminates early due to detection of next start code
170
809k
                search_state = NO_MATCH;
171
809k
                start_code_found = 1;
172
809k
                break;
173
809k
            }
174
31.6M
        }
175
1.37M
        if ((s->flags & PARSER_FLAG_COMPLETE_FRAMES) &&
176
4.51k
                unesc_index >= UNESCAPED_THRESHOLD &&
177
1.81k
                vpc->prev_start_code == (VC1_CODE_FRAME & 0xFF))
178
2
        {
179
            // No need to keep scanning the rest of the buffer for
180
            // start codes if we know it contains a complete frame and
181
            // we've already unescaped all we need of the frame header
182
2
            vc1_extract_header(s, avctx, unesc_buffer, unesc_index);
183
2
            unesc_index = 0;
184
2
            break;
185
2
        }
186
1.37M
        if (unesc_index >= UNESCAPED_THRESHOLD && !start_code_found) {
187
11.2M
            while (i < buf_size) {
188
11.2M
                if (search_state == NO_MATCH) {
189
2.57M
                    i += vpc->v.vc1dsp.startcode_find_candidate(buf + i, buf_size - i);
190
2.57M
                    if (i < buf_size) {
191
2.53M
                        search_state = ONE_ZERO;
192
2.53M
                    }
193
2.57M
                    i++;
194
8.62M
                } else {
195
8.62M
                    b = buf[i++];
196
8.62M
                    if (search_state == ONE_ZERO)
197
2.58M
                        search_state = b ? NO_MATCH : TWO_ZEROS;
198
6.04M
                    else if (search_state == TWO_ZEROS) {
199
5.58M
                        if (b >= 1)
200
1.60M
                            search_state = b == 1 ? ONE : NO_MATCH;
201
5.58M
                    }
202
455k
                    else { // search_state == ONE
203
455k
                        search_state = NO_MATCH;
204
455k
                        start_code_found = 1;
205
455k
                        break;
206
455k
                    }
207
8.62M
                }
208
11.2M
            }
209
512k
        }
210
1.37M
        if (start_code_found) {
211
1.26M
            vc1_extract_header(s, avctx, unesc_buffer, unesc_index);
212
213
1.26M
            vpc->prev_start_code = b;
214
1.26M
            unesc_index = 0;
215
216
1.26M
            if (!(s->flags & PARSER_FLAG_COMPLETE_FRAMES)) {
217
1.26M
                if (!pic_found && (b == (VC1_CODE_FRAME & 0xFF) || b == (VC1_CODE_FIELD & 0xFF))) {
218
170k
                    pic_found = 1;
219
170k
                }
220
1.09M
                else if (pic_found && b != (VC1_CODE_FIELD & 0xFF) && b != (VC1_CODE_SLICE & 0xFF)
221
430k
                                   && b != (VC1_CODE_ENDOFSEQ & 0xFF)) {
222
430k
                    next = i - 4;
223
430k
                    pic_found = b == (VC1_CODE_FRAME & 0xFF);
224
430k
                    break;
225
430k
                }
226
1.26M
            }
227
1.26M
        }
228
1.37M
    }
229
230
542k
    vpc->pc.frame_start_found = pic_found;
231
542k
    vpc->unesc_index = unesc_index;
232
542k
    vpc->search_state = search_state;
233
234
542k
    if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
235
144
        next = buf_size;
236
542k
    } else {
237
542k
        if (ff_combine_frame(&vpc->pc, next, &buf, &buf_size) < 0) {
238
110k
            vpc->bytes_to_skip = 0;
239
110k
            *poutbuf = NULL;
240
110k
            *poutbuf_size = 0;
241
110k
            return buf_size;
242
110k
        }
243
542k
    }
244
245
    /* If we return with a valid pointer to a combined frame buffer
246
     * then on the next call then we'll have been unhelpfully rewound
247
     * by up to 4 bytes (depending upon whether the start code
248
     * overlapped the input buffer, and if so by how much). We don't
249
     * want this: it will either cause spurious second detections of
250
     * the start code we've already seen, or cause extra bytes to be
251
     * inserted at the start of the unescaped buffer. */
252
432k
    vpc->bytes_to_skip = 4;
253
432k
    if (next < 0 && next != END_NOT_FOUND)
254
1.51k
        vpc->bytes_to_skip += next;
255
256
432k
    *poutbuf = buf;
257
432k
    *poutbuf_size = buf_size;
258
432k
    return next;
259
542k
}
260
261
static av_cold int vc1_parse_init(AVCodecParserContext *s)
262
7.17k
{
263
7.17k
    VC1ParseContext *vpc = s->priv_data;
264
7.17k
    vpc->v.s.slice_context_count = 1;
265
7.17k
    vpc->v.first_pic_header_flag = 1;
266
7.17k
    vpc->v.parse_only = 1;
267
7.17k
    vpc->prev_start_code = 0;
268
7.17k
    vpc->bytes_to_skip = 0;
269
7.17k
    vpc->unesc_index = 0;
270
7.17k
    vpc->search_state = NO_MATCH;
271
7.17k
    ff_vc1dsp_init(&vpc->v.vc1dsp); /* startcode_find_candidate */
272
7.17k
    return 0;
273
7.17k
}
274
275
const FFCodecParser ff_vc1_parser = {
276
    PARSER_CODEC_LIST(AV_CODEC_ID_VC1),
277
    .priv_data_size = sizeof(VC1ParseContext),
278
    .init           = vc1_parse_init,
279
    .parse          = vc1_parse,
280
    .close          = ff_parse_close,
281
};