Coverage Report

Created: 2025-12-31 07:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/opus/parser.c
Line
Count
Source
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
#include "parser_internal.h"
35
36
typedef struct OpusParserContext {
37
    ParseContext pc;
38
    OpusParseContext ctx;
39
    OpusPacket pkt;
40
    int extradata_parsed;
41
    int ts_framing;
42
} OpusParserContext;
43
44
static const uint8_t *parse_opus_ts_header(const uint8_t *start, int *payload_len, int buf_len)
45
84.5k
{
46
84.5k
    const uint8_t *buf = start + 1;
47
84.5k
    int start_trim_flag, end_trim_flag, control_extension_flag, control_extension_length;
48
84.5k
    uint8_t flags;
49
84.5k
    uint64_t payload_len_tmp;
50
51
84.5k
    GetByteContext gb;
52
84.5k
    bytestream2_init(&gb, buf, buf_len);
53
54
84.5k
    flags = bytestream2_get_byte(&gb);
55
84.5k
    start_trim_flag        = (flags >> 4) & 1;
56
84.5k
    end_trim_flag          = (flags >> 3) & 1;
57
84.5k
    control_extension_flag = (flags >> 2) & 1;
58
59
84.5k
    payload_len_tmp = *payload_len = 0;
60
120k
    while (bytestream2_peek_byte(&gb) == 0xff)
61
35.9k
        payload_len_tmp += bytestream2_get_byte(&gb);
62
63
84.5k
    payload_len_tmp += bytestream2_get_byte(&gb);
64
65
84.5k
    if (start_trim_flag)
66
8.78k
        bytestream2_skip(&gb, 2);
67
84.5k
    if (end_trim_flag)
68
7.33k
        bytestream2_skip(&gb, 2);
69
84.5k
    if (control_extension_flag) {
70
7.35k
        control_extension_length = bytestream2_get_byte(&gb);
71
7.35k
        bytestream2_skip(&gb, control_extension_length);
72
7.35k
    }
73
74
84.5k
    if (bytestream2_tell(&gb) + payload_len_tmp > buf_len)
75
4.55k
        return NULL;
76
77
80.0k
    *payload_len = payload_len_tmp;
78
79
80.0k
    return buf + bytestream2_tell(&gb);
80
84.5k
}
81
82
static int set_frame_duration(AVCodecParserContext *ctx, AVCodecContext *avctx,
83
                              const uint8_t *buf, int buf_size)
84
605k
{
85
605k
    OpusParserContext *s = ctx->priv_data;
86
87
605k
    if (ff_opus_parse_packet(&s->pkt, buf, buf_size, s->ctx.nb_streams > 1) < 0) {
88
278k
        av_log(avctx, AV_LOG_ERROR, "Error parsing Opus packet header.\n");
89
278k
        return AVERROR_INVALIDDATA;
90
278k
    }
91
92
326k
    ctx->duration = s->pkt.frame_count * s->pkt.frame_duration;
93
94
326k
    return 0;
95
605k
}
96
97
/**
98
 * Find the end of the current frame in the bitstream.
99
 * @return the position of the first byte of the next frame, or -1
100
 */
101
static int opus_find_frame_end(AVCodecParserContext *ctx, AVCodecContext *avctx,
102
                               const uint8_t *buf, int buf_size, int *header_len)
103
420k
{
104
420k
    OpusParserContext *s = ctx->priv_data;
105
420k
    ParseContext *pc    = &s->pc;
106
420k
    int ret, start_found, i = 0, payload_len = 0;
107
420k
    const uint8_t *payload;
108
420k
    uint32_t state;
109
420k
    uint16_t hdr;
110
420k
    *header_len = 0;
111
112
420k
    if (!buf_size)
113
95
        return 0;
114
115
420k
    start_found = pc->frame_start_found;
116
420k
    state = pc->state;
117
420k
    payload = buf;
118
119
    /* Check if we're using Opus in MPEG-TS framing */
120
420k
    if (!s->ts_framing && buf_size > 2) {
121
157k
        hdr = AV_RB16(buf);
122
157k
        if ((hdr & OPUS_TS_MASK) == OPUS_TS_HEADER)
123
691
            s->ts_framing = 1;
124
157k
    }
125
126
420k
    if (s->ts_framing && !start_found) {
127
593M
        for (i = 0; i < buf_size-2; i++) {
128
593M
            state = (state << 8) | payload[i];
129
593M
            if ((state & OPUS_TS_MASK) == OPUS_TS_HEADER) {
130
84.5k
                payload = parse_opus_ts_header(payload, &payload_len, buf_size - i);
131
84.5k
                if (!payload) {
132
4.55k
                    av_log(avctx, AV_LOG_ERROR, "Error parsing Ogg TS header.\n");
133
4.55k
                    return AVERROR_INVALIDDATA;
134
4.55k
                }
135
80.0k
                *header_len = payload - buf;
136
80.0k
                start_found = 1;
137
80.0k
                break;
138
84.5k
            }
139
593M
        }
140
166k
    }
141
142
415k
    if (!s->ts_framing)
143
253k
        payload_len = buf_size;
144
145
415k
    if (payload_len <= buf_size && (!s->ts_framing || start_found)) {
146
333k
        ret = set_frame_duration(ctx, avctx, payload, payload_len);
147
333k
        if (ret < 0) {
148
110k
            pc->frame_start_found = 0;
149
110k
            return AVERROR_INVALIDDATA;
150
110k
        }
151
333k
    }
152
153
305k
    if (s->ts_framing) {
154
160k
        if (start_found) {
155
78.4k
            if (payload_len + *header_len <= buf_size) {
156
78.4k
                pc->frame_start_found = 0;
157
78.4k
                pc->state             = -1;
158
78.4k
                return payload_len + *header_len;
159
78.4k
            }
160
78.4k
        }
161
162
82.4k
        pc->frame_start_found = start_found;
163
82.4k
        pc->state = state;
164
82.4k
        return END_NOT_FOUND;
165
160k
    }
166
167
144k
    return buf_size;
168
305k
}
169
170
static int opus_parse(AVCodecParserContext *ctx, AVCodecContext *avctx,
171
                       const uint8_t **poutbuf, int *poutbuf_size,
172
                       const uint8_t *buf, int buf_size)
173
717k
{
174
717k
    OpusParserContext *s = ctx->priv_data;
175
717k
    ParseContext *pc    = &s->pc;
176
717k
    int next, header_len = 0;
177
178
717k
    avctx->sample_rate = 48000;
179
180
717k
    if (avctx->extradata && !s->extradata_parsed) {
181
25.1k
        if (ff_opus_parse_extradata(avctx, &s->ctx) < 0) {
182
24.1k
            av_log(avctx, AV_LOG_ERROR, "Error parsing Ogg extradata.\n");
183
24.1k
            goto fail;
184
24.1k
        }
185
1.00k
        av_freep(&s->ctx.channel_maps);
186
1.00k
        s->extradata_parsed = 1;
187
1.00k
    }
188
189
692k
    if (ctx->flags & PARSER_FLAG_COMPLETE_FRAMES) {
190
272k
        next = buf_size;
191
192
272k
        if (buf_size && set_frame_duration(ctx, avctx, buf, buf_size) < 0)
193
168k
            goto fail;
194
420k
    } else {
195
420k
        next = opus_find_frame_end(ctx, avctx, buf, buf_size, &header_len);
196
197
420k
        if (s->ts_framing && next != AVERROR_INVALIDDATA &&
198
160k
            ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
199
82.4k
            goto fail;
200
82.4k
        }
201
202
337k
        if (next == AVERROR_INVALIDDATA){
203
114k
            goto fail;
204
114k
        }
205
337k
    }
206
207
327k
    *poutbuf      = buf + header_len;
208
327k
    *poutbuf_size = buf_size - header_len;
209
327k
    return next;
210
211
389k
fail:
212
    *poutbuf      = NULL;
213
389k
    *poutbuf_size = 0;
214
389k
    return buf_size;
215
692k
}
216
217
const FFCodecParser ff_opus_parser = {
218
    PARSER_CODEC_LIST(AV_CODEC_ID_OPUS),
219
    .priv_data_size = sizeof(OpusParserContext),
220
    .parse          = opus_parse,
221
    .close          = ff_parse_close
222
};