Coverage Report

Created: 2026-01-16 07:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavformat/rtpdec_mpeg4.c
Line
Count
Source
1
/*
2
 * Common code for the RTP depacketization of MPEG-4 formats.
3
 * Copyright (c) 2010 Fabrice Bellard
4
 *                    Romain Degez
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
 * @brief MPEG-4 / RTP Code
26
 * @author Fabrice Bellard
27
 * @author Romain Degez
28
 */
29
30
#include "rtpdec_formats.h"
31
#include "internal.h"
32
#include "libavutil/attributes.h"
33
#include "libavutil/avstring.h"
34
#include "libavutil/mem.h"
35
#include "libavcodec/get_bits.h"
36
37
0
#define MAX_AAC_HBR_FRAME_SIZE 8191
38
39
/** Structure listing useful vars to parse RTP packet payload */
40
struct PayloadContext {
41
    int bitrate;
42
    int sizelength;
43
    int indexlength;
44
    int indexdeltalength;
45
    int profile_level_id;
46
    int streamtype;
47
    int objecttype;
48
    char *mode;
49
50
    /** mpeg 4 AU headers */
51
    struct AUHeaders {
52
        int size;
53
        int index;
54
        int cts_flag;
55
        int cts;
56
        int dts_flag;
57
        int dts;
58
        int rap_flag;
59
        int streamstate;
60
    } *au_headers;
61
    int au_headers_allocated;
62
    int nb_au_headers;
63
    int au_headers_length_bytes;
64
    int cur_au_index;
65
66
    uint8_t buf[FFMAX(RTP_MAX_PACKET_LENGTH, MAX_AAC_HBR_FRAME_SIZE)];
67
    int buf_pos, buf_size;
68
    uint32_t timestamp;
69
};
70
71
typedef struct AttrNameMap {
72
    const char *str;
73
    uint16_t    type;
74
    uint32_t    offset;
75
76
    /** Range for integer values */
77
    struct Range {
78
        int min;
79
        int max;
80
    } range;
81
} AttrNameMap;
82
83
/* All known fmtp parameters and the corresponding RTPAttrTypeEnum */
84
0
#define ATTR_NAME_TYPE_INT 0
85
0
#define ATTR_NAME_TYPE_STR 1
86
static const AttrNameMap attr_names[] = {
87
    { "bitrate",       ATTR_NAME_TYPE_INT,
88
      offsetof(PayloadContext, bitrate),
89
      {0, INT32_MAX} },
90
    { "SizeLength",       ATTR_NAME_TYPE_INT,
91
      offsetof(PayloadContext, sizelength),
92
      {0, 32} }, // SizeLength number of bits used to encode AU-size integer value
93
    { "IndexLength",      ATTR_NAME_TYPE_INT,
94
      offsetof(PayloadContext, indexlength),
95
      {0, 32} }, // IndexLength number of bits used to encode AU-Index integer value
96
    { "IndexDeltaLength", ATTR_NAME_TYPE_INT,
97
      offsetof(PayloadContext, indexdeltalength),
98
      {0, 32} }, // IndexDeltaLength number of bits to encode AU-Index-delta integer value
99
    { "profile-level-id", ATTR_NAME_TYPE_INT,
100
      offsetof(PayloadContext, profile_level_id),
101
      {INT32_MIN, INT32_MAX} }, // It differs depending on StreamType
102
    { "StreamType",       ATTR_NAME_TYPE_INT,
103
      offsetof(PayloadContext, streamtype),
104
      {0x00, 0x3F} }, // Values from ISO/IEC 14496-1, 'StreamType Values' table
105
    { "mode",             ATTR_NAME_TYPE_STR,
106
      offsetof(PayloadContext, mode),
107
       {0} },
108
    { NULL, -1, -1, {0} },
109
};
110
111
static void close_context(PayloadContext *data)
112
0
{
113
0
    av_freep(&data->au_headers);
114
0
    av_freep(&data->mode);
115
0
}
116
117
static int parse_fmtp_config(AVCodecParameters *par, const char *value)
118
0
{
119
    /* decode the hexa encoded parameter */
120
0
    int len = ff_hex_to_data(NULL, value), ret;
121
122
0
    if ((ret = ff_alloc_extradata(par, len)) < 0)
123
0
        return ret;
124
0
    ff_hex_to_data(par->extradata, value);
125
0
    return 0;
126
0
}
127
128
static int rtp_parse_mp4_au(PayloadContext *data, const uint8_t *buf, int len)
129
0
{
130
0
    int au_headers_length, au_header_size, i;
131
0
    GetBitContext getbitcontext;
132
0
    int ret;
133
134
0
    if (len < 2)
135
0
        return AVERROR_INVALIDDATA;
136
137
    /* decode the first 2 bytes where the AUHeader sections are stored
138
       length in bits */
139
0
    au_headers_length = AV_RB16(buf);
140
141
0
    if (au_headers_length > RTP_MAX_PACKET_LENGTH)
142
0
      return -1;
143
144
0
    data->au_headers_length_bytes = (au_headers_length + 7) / 8;
145
146
    /* skip AU headers length section (2 bytes) */
147
0
    buf += 2;
148
0
    len -= 2;
149
150
0
    if (len < data->au_headers_length_bytes)
151
0
        return AVERROR_INVALIDDATA;
152
153
0
    ret = init_get_bits(&getbitcontext, buf, data->au_headers_length_bytes * 8);
154
0
    if (ret < 0)
155
0
        return ret;
156
157
    /* XXX: Wrong if optional additional sections are present (cts, dts etc...) */
158
0
    au_header_size = data->sizelength + data->indexlength;
159
0
    if (au_header_size <= 0 || (au_headers_length % au_header_size != 0))
160
0
        return -1;
161
162
0
    data->nb_au_headers = au_headers_length / au_header_size;
163
0
    if (!data->au_headers || data->au_headers_allocated < data->nb_au_headers) {
164
0
        av_free(data->au_headers);
165
0
        data->au_headers = av_malloc(sizeof(struct AUHeaders) * data->nb_au_headers);
166
0
        if (!data->au_headers)
167
0
            return AVERROR(ENOMEM);
168
0
        data->au_headers_allocated = data->nb_au_headers;
169
0
    }
170
171
0
    for (i = 0; i < data->nb_au_headers; ++i) {
172
0
        data->au_headers[i].size  = get_bits_long(&getbitcontext, data->sizelength);
173
0
        data->au_headers[i].index = get_bits_long(&getbitcontext, data->indexlength);
174
0
    }
175
176
0
    return 0;
177
0
}
178
179
180
/* Follows RFC 3640 */
181
static int aac_parse_packet(AVFormatContext *ctx, PayloadContext *data,
182
                            AVStream *st, AVPacket *pkt, uint32_t *timestamp,
183
                            const uint8_t *buf, int len, uint16_t seq,
184
                            int flags)
185
0
{
186
0
    int ret;
187
188
189
0
    if (!buf) {
190
0
        if (data->cur_au_index > data->nb_au_headers) {
191
0
            av_log(ctx, AV_LOG_ERROR, "Invalid parser state\n");
192
0
            return AVERROR_INVALIDDATA;
193
0
        }
194
0
        if (data->buf_size - data->buf_pos < data->au_headers[data->cur_au_index].size) {
195
0
            av_log(ctx, AV_LOG_ERROR, "Invalid AU size\n");
196
0
            return AVERROR_INVALIDDATA;
197
0
        }
198
0
        if ((ret = av_new_packet(pkt, data->au_headers[data->cur_au_index].size)) < 0) {
199
0
            av_log(ctx, AV_LOG_ERROR, "Out of memory\n");
200
0
            return ret;
201
0
        }
202
0
        memcpy(pkt->data, &data->buf[data->buf_pos], data->au_headers[data->cur_au_index].size);
203
0
        data->buf_pos += data->au_headers[data->cur_au_index].size;
204
0
        pkt->stream_index = st->index;
205
0
        data->cur_au_index++;
206
207
0
        if (data->cur_au_index == data->nb_au_headers) {
208
0
            data->buf_pos = 0;
209
0
            return 0;
210
0
        }
211
212
0
        return 1;
213
0
    }
214
215
0
    if (rtp_parse_mp4_au(data, buf, len)) {
216
0
        av_log(ctx, AV_LOG_ERROR, "Error parsing AU headers\n");
217
0
        return -1;
218
0
    }
219
220
0
    buf += data->au_headers_length_bytes + 2;
221
0
    len -= data->au_headers_length_bytes + 2;
222
0
    if (data->nb_au_headers == 1 && len < data->au_headers[0].size) {
223
        /* Packet is fragmented */
224
225
0
        if (!data->buf_pos) {
226
0
            if (data->au_headers[0].size > MAX_AAC_HBR_FRAME_SIZE) {
227
0
                av_log(ctx, AV_LOG_ERROR, "Invalid AU size\n");
228
0
                return AVERROR_INVALIDDATA;
229
0
            }
230
231
0
            data->buf_size = data->au_headers[0].size;
232
0
            data->timestamp = *timestamp;
233
0
        }
234
235
0
        if (data->timestamp != *timestamp ||
236
0
            data->au_headers[0].size != data->buf_size ||
237
0
            data->buf_pos + len > MAX_AAC_HBR_FRAME_SIZE) {
238
0
            data->buf_pos = 0;
239
0
            data->buf_size = 0;
240
0
            av_log(ctx, AV_LOG_ERROR, "Invalid packet received\n");
241
0
            return AVERROR_INVALIDDATA;
242
0
        }
243
244
0
        memcpy(&data->buf[data->buf_pos], buf, len);
245
0
        data->buf_pos += len;
246
247
0
        if (!(flags & RTP_FLAG_MARKER))
248
0
            return AVERROR(EAGAIN);
249
250
0
        if (data->buf_pos != data->buf_size) {
251
0
            data->buf_pos = 0;
252
0
            av_log(ctx, AV_LOG_ERROR, "Missed some packets, discarding frame\n");
253
0
            return AVERROR_INVALIDDATA;
254
0
        }
255
256
0
        data->buf_pos = 0;
257
0
        ret = av_new_packet(pkt, data->buf_size);
258
0
        if (ret < 0) {
259
0
            av_log(ctx, AV_LOG_ERROR, "Out of memory\n");
260
0
            return ret;
261
0
        }
262
0
        pkt->stream_index = st->index;
263
264
0
        memcpy(pkt->data, data->buf, data->buf_size);
265
266
0
        return 0;
267
0
    }
268
269
0
    if (len < data->au_headers[0].size) {
270
0
        av_log(ctx, AV_LOG_ERROR, "First AU larger than packet size\n");
271
0
        return AVERROR_INVALIDDATA;
272
0
    }
273
0
    if ((ret = av_new_packet(pkt, data->au_headers[0].size)) < 0) {
274
0
        av_log(ctx, AV_LOG_ERROR, "Out of memory\n");
275
0
        return ret;
276
0
    }
277
0
    memcpy(pkt->data, buf, data->au_headers[0].size);
278
0
    len -= data->au_headers[0].size;
279
0
    buf += data->au_headers[0].size;
280
0
    pkt->stream_index = st->index;
281
282
0
    if (len > 0 && data->nb_au_headers > 1) {
283
0
        data->buf_size = FFMIN(len, sizeof(data->buf));
284
0
        memcpy(data->buf, buf, data->buf_size);
285
0
        data->cur_au_index = 1;
286
0
        data->buf_pos = 0;
287
0
        return 1;
288
0
    }
289
290
0
    return 0;
291
0
}
292
293
static int parse_fmtp(AVFormatContext *s,
294
                      AVStream *stream, PayloadContext *data,
295
                      const char *attr, const char *value)
296
0
{
297
0
    AVCodecParameters *par = stream->codecpar;
298
0
    int res, i;
299
300
0
    if (!strcmp(attr, "config")) {
301
0
        res = parse_fmtp_config(par, value);
302
303
0
        if (res < 0)
304
0
            return res;
305
0
    }
306
307
0
    if (par->codec_id == AV_CODEC_ID_AAC) {
308
        /* Looking for a known attribute */
309
0
        for (i = 0; attr_names[i].str; ++i) {
310
0
            if (!av_strcasecmp(attr, attr_names[i].str)) {
311
0
                if (attr_names[i].type == ATTR_NAME_TYPE_INT) {
312
0
                    char *end_ptr = NULL;
313
0
                    long long int val = strtoll(value, &end_ptr, 10);
314
0
                    if (end_ptr == value || end_ptr[0] != '\0') {
315
0
                        av_log(s, AV_LOG_ERROR,
316
0
                               "The %s field value is not a valid number: %s\n",
317
0
                               attr, value);
318
0
                        return AVERROR_INVALIDDATA;
319
0
                    }
320
0
                    if (val < attr_names[i].range.min ||
321
0
                        val > attr_names[i].range.max) {
322
0
                        av_log(s, AV_LOG_ERROR,
323
0
                            "fmtp field %s should be in range [%d,%d] (provided value: %lld)",
324
0
                            attr, attr_names[i].range.min, attr_names[i].range.max, val);
325
0
                        return  AVERROR_INVALIDDATA;
326
0
                    }
327
328
0
                    *(int *)((char *)data+
329
0
                        attr_names[i].offset) = (int) val;
330
0
                } else if (attr_names[i].type == ATTR_NAME_TYPE_STR) {
331
0
                    char *val = av_strdup(value);
332
0
                    if (!val)
333
0
                        return AVERROR(ENOMEM);
334
0
                    *(char **)((char *)data+
335
0
                        attr_names[i].offset) = val;
336
0
                }
337
0
            }
338
0
        }
339
0
        if (!strcmp(attr, "bitrate")) {
340
0
            par->bit_rate = data->bitrate;
341
0
        }
342
0
    }
343
0
    return 0;
344
0
}
345
346
static int parse_sdp_line(AVFormatContext *s, int st_index,
347
                          PayloadContext *data, const char *line)
348
0
{
349
0
    const char *p;
350
351
0
    if (st_index < 0)
352
0
        return 0;
353
354
0
    if (av_strstart(line, "fmtp:", &p))
355
0
        return ff_parse_fmtp(s, s->streams[st_index], data, p, parse_fmtp);
356
357
0
    return 0;
358
0
}
359
360
const RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler = {
361
    .enc_name           = "MP4V-ES",
362
    .codec_type         = AVMEDIA_TYPE_VIDEO,
363
    .codec_id           = AV_CODEC_ID_MPEG4,
364
    .need_parsing       = AVSTREAM_PARSE_FULL,
365
    .priv_data_size     = sizeof(PayloadContext),
366
    .parse_sdp_a_line   = parse_sdp_line,
367
};
368
369
const RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler = {
370
    .enc_name           = "mpeg4-generic",
371
    .codec_type         = AVMEDIA_TYPE_AUDIO,
372
    .codec_id           = AV_CODEC_ID_AAC,
373
    .need_parsing       = AVSTREAM_PARSE_HEADERS,
374
    .priv_data_size     = sizeof(PayloadContext),
375
    .parse_sdp_a_line   = parse_sdp_line,
376
    .close              = close_context,
377
    .parse_packet       = aac_parse_packet,
378
};