Coverage Report

Created: 2025-08-28 07:12

/src/ffmpeg/libavcodec/opus/parser.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2013-2014 Mozilla Corporation
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
/**
22
 * @file
23
 * Opus parser
24
 *
25
 * Determines the duration for each packet.
26
 */
27
28
#include "libavutil/mem.h"
29
#include "avcodec.h"
30
#include "bytestream.h"
31
#include "opus.h"
32
#include "parse.h"
33
#include "parser.h"
34
35
typedef struct OpusParserContext {
36
    ParseContext pc;
37
    OpusParseContext ctx;
38
    OpusPacket pkt;
39
    int extradata_parsed;
40
    int ts_framing;
41
} OpusParserContext;
42
43
static const uint8_t *parse_opus_ts_header(const uint8_t *start, int *payload_len, int buf_len)
44
97.7k
{
45
97.7k
    const uint8_t *buf = start + 1;
46
97.7k
    int start_trim_flag, end_trim_flag, control_extension_flag, control_extension_length;
47
97.7k
    uint8_t flags;
48
97.7k
    uint64_t payload_len_tmp;
49
50
97.7k
    GetByteContext gb;
51
97.7k
    bytestream2_init(&gb, buf, buf_len);
52
53
97.7k
    flags = bytestream2_get_byte(&gb);
54
97.7k
    start_trim_flag        = (flags >> 4) & 1;
55
97.7k
    end_trim_flag          = (flags >> 3) & 1;
56
97.7k
    control_extension_flag = (flags >> 2) & 1;
57
58
97.7k
    payload_len_tmp = *payload_len = 0;
59
156k
    while (bytestream2_peek_byte(&gb) == 0xff)
60
58.4k
        payload_len_tmp += bytestream2_get_byte(&gb);
61
62
97.7k
    payload_len_tmp += bytestream2_get_byte(&gb);
63
64
97.7k
    if (start_trim_flag)
65
9.86k
        bytestream2_skip(&gb, 2);
66
97.7k
    if (end_trim_flag)
67
8.23k
        bytestream2_skip(&gb, 2);
68
97.7k
    if (control_extension_flag) {
69
7.79k
        control_extension_length = bytestream2_get_byte(&gb);
70
7.79k
        bytestream2_skip(&gb, control_extension_length);
71
7.79k
    }
72
73
97.7k
    if (bytestream2_tell(&gb) + payload_len_tmp > buf_len)
74
4.63k
        return NULL;
75
76
93.1k
    *payload_len = payload_len_tmp;
77
78
93.1k
    return buf + bytestream2_tell(&gb);
79
97.7k
}
80
81
static int set_frame_duration(AVCodecParserContext *ctx, AVCodecContext *avctx,
82
                              const uint8_t *buf, int buf_size)
83
619k
{
84
619k
    OpusParserContext *s = ctx->priv_data;
85
86
619k
    if (ff_opus_parse_packet(&s->pkt, buf, buf_size, s->ctx.nb_streams > 1) < 0) {
87
272k
        av_log(avctx, AV_LOG_ERROR, "Error parsing Opus packet header.\n");
88
272k
        return AVERROR_INVALIDDATA;
89
272k
    }
90
91
347k
    ctx->duration = s->pkt.frame_count * s->pkt.frame_duration;
92
93
347k
    return 0;
94
619k
}
95
96
/**
97
 * Find the end of the current frame in the bitstream.
98
 * @return the position of the first byte of the next frame, or -1
99
 */
100
static int opus_find_frame_end(AVCodecParserContext *ctx, AVCodecContext *avctx,
101
                               const uint8_t *buf, int buf_size, int *header_len)
102
462k
{
103
462k
    OpusParserContext *s = ctx->priv_data;
104
462k
    ParseContext *pc    = &s->pc;
105
462k
    int ret, start_found, i = 0, payload_len = 0;
106
462k
    const uint8_t *payload;
107
462k
    uint32_t state;
108
462k
    uint16_t hdr;
109
462k
    *header_len = 0;
110
111
462k
    if (!buf_size)
112
114
        return 0;
113
114
462k
    start_found = pc->frame_start_found;
115
462k
    state = pc->state;
116
462k
    payload = buf;
117
118
    /* Check if we're using Opus in MPEG-TS framing */
119
462k
    if (!s->ts_framing && buf_size > 2) {
120
126k
        hdr = AV_RB16(buf);
121
126k
        if ((hdr & OPUS_TS_MASK) == OPUS_TS_HEADER)
122
838
            s->ts_framing = 1;
123
126k
    }
124
125
462k
    if (s->ts_framing && !start_found) {
126
714M
        for (i = 0; i < buf_size-2; i++) {
127
714M
            state = (state << 8) | payload[i];
128
714M
            if ((state & OPUS_TS_MASK) == OPUS_TS_HEADER) {
129
97.7k
                payload = parse_opus_ts_header(payload, &payload_len, buf_size - i);
130
97.7k
                if (!payload) {
131
4.63k
                    av_log(avctx, AV_LOG_ERROR, "Error parsing Ogg TS header.\n");
132
4.63k
                    return AVERROR_INVALIDDATA;
133
4.63k
                }
134
93.1k
                *header_len = payload - buf;
135
93.1k
                start_found = 1;
136
93.1k
                break;
137
97.7k
            }
138
714M
        }
139
203k
    }
140
141
457k
    if (!s->ts_framing)
142
258k
        payload_len = buf_size;
143
144
457k
    if (payload_len <= buf_size && (!s->ts_framing || start_found)) {
145
351k
        ret = set_frame_duration(ctx, avctx, payload, payload_len);
146
351k
        if (ret < 0) {
147
116k
            pc->frame_start_found = 0;
148
116k
            return AVERROR_INVALIDDATA;
149
116k
        }
150
351k
    }
151
152
341k
    if (s->ts_framing) {
153
195k
        if (start_found) {
154
90.1k
            if (payload_len + *header_len <= buf_size) {
155
90.1k
                pc->frame_start_found = 0;
156
90.1k
                pc->state             = -1;
157
90.1k
                return payload_len + *header_len;
158
90.1k
            }
159
90.1k
        }
160
161
105k
        pc->frame_start_found = start_found;
162
105k
        pc->state = state;
163
105k
        return END_NOT_FOUND;
164
195k
    }
165
166
145k
    return buf_size;
167
341k
}
168
169
static int opus_parse(AVCodecParserContext *ctx, AVCodecContext *avctx,
170
                       const uint8_t **poutbuf, int *poutbuf_size,
171
                       const uint8_t *buf, int buf_size)
172
743k
{
173
743k
    OpusParserContext *s = ctx->priv_data;
174
743k
    ParseContext *pc    = &s->pc;
175
743k
    int next, header_len = 0;
176
177
743k
    avctx->sample_rate = 48000;
178
179
743k
    if (avctx->extradata && !s->extradata_parsed) {
180
14.3k
        if (ff_opus_parse_extradata(avctx, &s->ctx) < 0) {
181
13.3k
            av_log(avctx, AV_LOG_ERROR, "Error parsing Ogg extradata.\n");
182
13.3k
            goto fail;
183
13.3k
        }
184
1.00k
        av_freep(&s->ctx.channel_maps);
185
1.00k
        s->extradata_parsed = 1;
186
1.00k
    }
187
188
729k
    if (ctx->flags & PARSER_FLAG_COMPLETE_FRAMES) {
189
267k
        next = buf_size;
190
191
267k
        if (set_frame_duration(ctx, avctx, buf, buf_size) < 0)
192
156k
            goto fail;
193
462k
    } else {
194
462k
        next = opus_find_frame_end(ctx, avctx, buf, buf_size, &header_len);
195
196
462k
        if (s->ts_framing && next != AVERROR_INVALIDDATA &&
197
462k
            ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
198
105k
            goto fail;
199
105k
        }
200
201
356k
        if (next == AVERROR_INVALIDDATA){
202
120k
            goto fail;
203
120k
        }
204
356k
    }
205
206
347k
    *poutbuf      = buf + header_len;
207
347k
    *poutbuf_size = buf_size - header_len;
208
347k
    return next;
209
210
395k
fail:
211
395k
    *poutbuf      = NULL;
212
395k
    *poutbuf_size = 0;
213
395k
    return buf_size;
214
729k
}
215
216
const AVCodecParser ff_opus_parser = {
217
    .codec_ids      = { AV_CODEC_ID_OPUS },
218
    .priv_data_size = sizeof(OpusParserContext),
219
    .parser_parse   = opus_parse,
220
    .parser_close   = ff_parse_close
221
};