1/**
2 * RTP Depacketization of MP4A-LATM, RFC 3016
3 * Copyright (c) 2010 Martin Storsjo
4 *
5 * This file is part of Libav.
6 *
7 * Libav is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * Libav is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include "rtpdec_formats.h"
23#include "internal.h"
24#include "libavutil/avstring.h"
25#include "libavcodec/get_bits.h"
26
27struct PayloadContext {
28    AVIOContext *dyn_buf;
29    uint8_t *buf;
30    int pos, len;
31    uint32_t timestamp;
32};
33
34static PayloadContext *latm_new_context(void)
35{
36    return av_mallocz(sizeof(PayloadContext));
37}
38
39static void latm_free_context(PayloadContext *data)
40{
41    if (!data)
42        return;
43    if (data->dyn_buf) {
44        uint8_t *p;
45        avio_close_dyn_buf(data->dyn_buf, &p);
46        av_free(p);
47    }
48    av_free(data->buf);
49    av_free(data);
50}
51
52static int latm_parse_packet(AVFormatContext *ctx, PayloadContext *data,
53                             AVStream *st, AVPacket *pkt, uint32_t *timestamp,
54                             const uint8_t *buf, int len, int flags)
55{
56    int ret, cur_len;
57
58    if (buf) {
59        if (!data->dyn_buf || data->timestamp != *timestamp) {
60            av_freep(&data->buf);
61            if (data->dyn_buf)
62                avio_close_dyn_buf(data->dyn_buf, &data->buf);
63            data->dyn_buf = NULL;
64            av_freep(&data->buf);
65
66            data->timestamp = *timestamp;
67            if ((ret = avio_open_dyn_buf(&data->dyn_buf)) < 0)
68                return ret;
69        }
70        avio_write(data->dyn_buf, buf, len);
71
72        if (!(flags & RTP_FLAG_MARKER))
73            return AVERROR(EAGAIN);
74        av_free(data->buf);
75        data->len = avio_close_dyn_buf(data->dyn_buf, &data->buf);
76        data->dyn_buf = NULL;
77        data->pos = 0;
78    }
79
80    if (!data->buf) {
81        av_log(ctx, AV_LOG_ERROR, "No data available yet\n");
82        return AVERROR(EIO);
83    }
84
85    cur_len = 0;
86    while (data->pos < data->len) {
87        uint8_t val = data->buf[data->pos++];
88        cur_len += val;
89        if (val != 0xff)
90            break;
91    }
92    if (data->pos + cur_len > data->len) {
93        av_log(ctx, AV_LOG_ERROR, "Malformed LATM packet\n");
94        return AVERROR(EIO);
95    }
96
97    if ((ret = av_new_packet(pkt, cur_len)) < 0)
98        return ret;
99    memcpy(pkt->data, data->buf + data->pos, cur_len);
100    data->pos += cur_len;
101    pkt->stream_index = st->index;
102    return data->pos < data->len;
103}
104
105static int parse_fmtp_config(AVStream *st, char *value)
106{
107    int len = ff_hex_to_data(NULL, value), i, ret = 0;
108    GetBitContext gb;
109    uint8_t *config;
110    int audio_mux_version, same_time_framing, num_programs, num_layers;
111
112    /* Pad this buffer, too, to avoid out of bounds reads with get_bits below */
113    config = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
114    if (!config)
115        return AVERROR(ENOMEM);
116    ff_hex_to_data(config, value);
117    init_get_bits(&gb, config, len*8);
118    audio_mux_version = get_bits(&gb, 1);
119    same_time_framing = get_bits(&gb, 1);
120    skip_bits(&gb, 6); /* num_sub_frames */
121    num_programs      = get_bits(&gb, 4);
122    num_layers        = get_bits(&gb, 3);
123    if (audio_mux_version != 0 || same_time_framing != 1 || num_programs != 0 ||
124        num_layers != 0) {
125        av_log(NULL, AV_LOG_WARNING, "Unsupported LATM config (%d,%d,%d,%d)\n",
126                                     audio_mux_version, same_time_framing,
127                                     num_programs, num_layers);
128        ret = AVERROR_PATCHWELCOME;
129        goto end;
130    }
131    av_freep(&st->codec->extradata);
132    st->codec->extradata_size = (get_bits_left(&gb) + 7)/8;
133    st->codec->extradata = av_mallocz(st->codec->extradata_size +
134                                      FF_INPUT_BUFFER_PADDING_SIZE);
135    if (!st->codec->extradata) {
136        ret = AVERROR(ENOMEM);
137        goto end;
138    }
139    for (i = 0; i < st->codec->extradata_size; i++)
140        st->codec->extradata[i] = get_bits(&gb, 8);
141
142end:
143    av_free(config);
144    return ret;
145}
146
147static int parse_fmtp(AVStream *stream, PayloadContext *data,
148                      char *attr, char *value)
149{
150    int res;
151
152    if (!strcmp(attr, "config")) {
153        res = parse_fmtp_config(stream, value);
154        if (res < 0)
155            return res;
156    } else if (!strcmp(attr, "cpresent")) {
157        int cpresent = atoi(value);
158        if (cpresent != 0)
159            av_log_missing_feature(NULL, "RTP MP4A-LATM with in-band "
160                                         "configuration", 1);
161    }
162
163    return 0;
164}
165
166static int latm_parse_sdp_line(AVFormatContext *s, int st_index,
167                               PayloadContext *data, const char *line)
168{
169    const char *p;
170
171    if (av_strstart(line, "fmtp:", &p))
172        return ff_parse_fmtp(s->streams[st_index], data, p, parse_fmtp);
173
174    return 0;
175}
176
177RTPDynamicProtocolHandler ff_mp4a_latm_dynamic_handler = {
178    .enc_name           = "MP4A-LATM",
179    .codec_type         = AVMEDIA_TYPE_AUDIO,
180    .codec_id           = CODEC_ID_AAC,
181    .parse_sdp_a_line   = latm_parse_sdp_line,
182    .alloc              = latm_new_context,
183    .free               = latm_free_context,
184    .parse_packet       = latm_parse_packet
185};
186