Statistics
| Branch: | Revision:

ffmpeg / libavformat / rtpdec_mpeg4.c @ 8b114d85

History | View | Annotate | Download (8.69 KB)

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 MPEG4 / RTP Code
26
 * @author Fabrice Bellard
27
 * @author Romain Degez
28
 */
29

    
30
#include "rtpdec_mpeg4.h"
31
#include "libavutil/avstring.h"
32
#include "libavcodec/get_bits.h"
33
#include <strings.h>
34

    
35
/** Structure listing useful vars to parse RTP packet payload*/
36
struct PayloadContext
37
{
38
    int sizelength;
39
    int indexlength;
40
    int indexdeltalength;
41
    int profile_level_id;
42
    int streamtype;
43
    int objecttype;
44
    char *mode;
45

    
46
    /** mpeg 4 AU headers */
47
    struct AUHeaders {
48
        int size;
49
        int index;
50
        int cts_flag;
51
        int cts;
52
        int dts_flag;
53
        int dts;
54
        int rap_flag;
55
        int streamstate;
56
    } *au_headers;
57
    int au_headers_allocated;
58
    int nb_au_headers;
59
    int au_headers_length_bytes;
60
    int cur_au_index;
61
};
62

    
63
/* return the length and optionally the data */
64
static int hex_to_data(uint8_t *data, const char *p)
65
{
66
    int c, len, v;
67

    
68
    len = 0;
69
    v = 1;
70
    for (;;) {
71
        p += strspn(p, SPACE_CHARS);
72
        if (*p == '\0')
73
            break;
74
        c = toupper((unsigned char) *p++);
75
        if (c >= '0' && c <= '9')
76
            c = c - '0';
77
        else if (c >= 'A' && c <= 'F')
78
            c = c - 'A' + 10;
79
        else
80
            break;
81
        v = (v << 4) | c;
82
        if (v & 0x100) {
83
            if (data)
84
                data[len] = v;
85
            len++;
86
            v = 1;
87
        }
88
    }
89
    return len;
90
}
91

    
92
typedef struct {
93
    const char *str;
94
    uint16_t    type;
95
    uint32_t    offset;
96
} AttrNameMap;
97

    
98
/* All known fmtp parameters and the corresponding RTPAttrTypeEnum */
99
#define ATTR_NAME_TYPE_INT 0
100
#define ATTR_NAME_TYPE_STR 1
101
static const AttrNameMap attr_names[]=
102
{
103
    { "SizeLength",       ATTR_NAME_TYPE_INT,
104
      offsetof(PayloadContext, sizelength) },
105
    { "IndexLength",      ATTR_NAME_TYPE_INT,
106
      offsetof(PayloadContext, indexlength) },
107
    { "IndexDeltaLength", ATTR_NAME_TYPE_INT,
108
      offsetof(PayloadContext, indexdeltalength) },
109
    { "profile-level-id", ATTR_NAME_TYPE_INT,
110
      offsetof(PayloadContext, profile_level_id) },
111
    { "StreamType",       ATTR_NAME_TYPE_INT,
112
      offsetof(PayloadContext, streamtype) },
113
    { "mode",             ATTR_NAME_TYPE_STR,
114
      offsetof(PayloadContext, mode) },
115
    { NULL, -1, -1 },
116
};
117

    
118
static PayloadContext *new_context(void)
119
{
120
    return av_mallocz(sizeof(PayloadContext));
121
}
122

    
123
static void free_context(PayloadContext * data)
124
{
125
    int i;
126
    for (i = 0; i < data->nb_au_headers; i++) {
127
         /* according to rtp_parse_mp4_au, we treat multiple
128
          * au headers as one, so nb_au_headers is always 1.
129
          * loop anyway in case this changes.
130
          * (note: changes done carelessly might lead to a double free)
131
          */
132
       av_free(&data->au_headers[i]);
133
    }
134
    av_free(data->mode);
135
    av_free(data);
136
}
137

    
138
static int parse_fmtp_config(AVCodecContext * codec, char *value)
139
{
140
    /* decode the hexa encoded parameter */
141
    int len = hex_to_data(NULL, value);
142
    if (codec->extradata)
143
        av_free(codec->extradata);
144
    codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
145
    if (!codec->extradata)
146
        return AVERROR(ENOMEM);
147
    codec->extradata_size = len;
148
    hex_to_data(codec->extradata, value);
149
    return 0;
150
}
151

    
152
static int rtp_parse_mp4_au(PayloadContext *data, const uint8_t *buf)
153
{
154
    int au_headers_length, au_header_size, i;
155
    GetBitContext getbitcontext;
156

    
157
    /* decode the first 2 bytes where the AUHeader sections are stored
158
       length in bits */
159
    au_headers_length = AV_RB16(buf);
160

    
161
    if (au_headers_length > RTP_MAX_PACKET_LENGTH)
162
      return -1;
163

    
164
    data->au_headers_length_bytes = (au_headers_length + 7) / 8;
165

    
166
    /* skip AU headers length section (2 bytes) */
167
    buf += 2;
168

    
169
    init_get_bits(&getbitcontext, buf, data->au_headers_length_bytes * 8);
170

    
171
    /* XXX: Wrong if optionnal additional sections are present (cts, dts etc...) */
172
    au_header_size = data->sizelength + data->indexlength;
173
    if (au_header_size <= 0 || (au_headers_length % au_header_size != 0))
174
        return -1;
175

    
176
    data->nb_au_headers = au_headers_length / au_header_size;
177
    if (!data->au_headers || data->au_headers_allocated < data->nb_au_headers) {
178
        av_free(data->au_headers);
179
        data->au_headers = av_malloc(sizeof(struct AUHeaders) * data->nb_au_headers);
180
        data->au_headers_allocated = data->nb_au_headers;
181
    }
182

    
183
    /* XXX: We handle multiple AU Section as only one (need to fix this for interleaving)
184
       In my test, the FAAD decoder does not behave correctly when sending each AU one by one
185
       but does when sending the whole as one big packet...  */
186
    data->au_headers[0].size = 0;
187
    data->au_headers[0].index = 0;
188
    for (i = 0; i < data->nb_au_headers; ++i) {
189
        data->au_headers[0].size += get_bits_long(&getbitcontext, data->sizelength);
190
        data->au_headers[0].index = get_bits_long(&getbitcontext, data->indexlength);
191
    }
192

    
193
    data->nb_au_headers = 1;
194

    
195
    return 0;
196
}
197

    
198

    
199
/* Follows RFC 3640 */
200
static int aac_parse_packet(AVFormatContext *ctx,
201
                            PayloadContext *data,
202
                            AVStream *st,
203
                            AVPacket *pkt,
204
                            uint32_t *timestamp,
205
                            const uint8_t *buf, int len, int flags)
206
{
207
    if (rtp_parse_mp4_au(data, buf))
208
        return -1;
209

    
210
    buf += data->au_headers_length_bytes + 2;
211
    len -= data->au_headers_length_bytes + 2;
212

    
213
    /* XXX: Fixme we only handle the case where rtp_parse_mp4_au define
214
                    one au_header */
215
    av_new_packet(pkt, data->au_headers[0].size);
216
    memcpy(pkt->data, buf, data->au_headers[0].size);
217

    
218
    pkt->stream_index = st->index;
219
    return 0;
220
}
221

    
222
static int parse_sdp_line(AVFormatContext *s, int st_index,
223
                          PayloadContext *data, const char *line)
224
{
225
    const char *p;
226
    char value[4096], attr[25];
227
    int res = 0, i;
228
    AVStream *st = s->streams[st_index];
229
    AVCodecContext* codec = st->codec;
230

    
231
    if (av_strstart(line, "fmtp:", &p)) {
232
        // remove protocol identifier
233
        while (*p && *p == ' ') p++; // strip spaces
234
        while (*p && *p != ' ') p++; // eat protocol identifier
235
        while (*p && *p == ' ') p++; // strip trailing spaces
236

    
237
        while (ff_rtsp_next_attr_and_value(&p,
238
                                           attr, sizeof(attr),
239
                                           value, sizeof(value))) {
240
            if (!strcmp(attr, "config")) {
241
                res = parse_fmtp_config(codec, value);
242

    
243
                if (res < 0)
244
                    return res;
245
            }
246

    
247
            if (codec->codec_id == CODEC_ID_AAC) {
248
                /* Looking for a known attribute */
249
                for (i = 0; attr_names[i].str; ++i) {
250
                    if (!strcasecmp(attr, attr_names[i].str)) {
251
                        if (attr_names[i].type == ATTR_NAME_TYPE_INT) {
252
                            *(int *)((char *)data+
253
                                attr_names[i].offset) = atoi(value);
254
                        } else if (attr_names[i].type == ATTR_NAME_TYPE_STR)
255
                            *(char **)((char *)data+
256
                                attr_names[i].offset) = av_strdup(value);
257
                    }
258
                }
259
            }
260
        }
261
    }
262

    
263
    return 0;
264

    
265
}
266

    
267
RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler = {
268
    .enc_name           = "MP4V-ES",
269
    .codec_type         = AVMEDIA_TYPE_VIDEO,
270
    .codec_id           = CODEC_ID_MPEG4,
271
    .parse_sdp_a_line   = parse_sdp_line,
272
    .open               = NULL,
273
    .close              = NULL,
274
    .parse_packet       = NULL
275
};
276

    
277
RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler = {
278
    .enc_name           = "mpeg4-generic",
279
    .codec_type         = AVMEDIA_TYPE_AUDIO,
280
    .codec_id           = CODEC_ID_AAC,
281
    .parse_sdp_a_line   = parse_sdp_line,
282
    .open               = new_context,
283
    .close              = free_context,
284
    .parse_packet       = aac_parse_packet
285
};