2 * RTP Depacketization of MP4A-LATM, RFC 3016
3 * Copyright (c) 2010 Martin Storsjo
5 * This file is part of Libav.
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.
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.
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
22 #include "rtpdec_formats.h"
24 #include "libavutil/avstring.h"
25 #include "libavcodec/get_bits.h"
27 struct PayloadContext
{
34 static PayloadContext
*latm_new_context(void)
36 return av_mallocz(sizeof(PayloadContext
));
39 static void latm_free_context(PayloadContext
*data
)
45 avio_close_dyn_buf(data
->dyn_buf
, &p
);
52 static int latm_parse_packet(AVFormatContext
*ctx
, PayloadContext
*data
,
53 AVStream
*st
, AVPacket
*pkt
, uint32_t *timestamp
,
54 const uint8_t *buf
, int len
, uint16_t seq
,
60 if (!data
->dyn_buf
|| data
->timestamp
!= *timestamp
) {
63 avio_close_dyn_buf(data
->dyn_buf
, &data
->buf
);
67 data
->timestamp
= *timestamp
;
68 if ((ret
= avio_open_dyn_buf(&data
->dyn_buf
)) < 0)
71 avio_write(data
->dyn_buf
, buf
, len
);
73 if (!(flags
& RTP_FLAG_MARKER
))
74 return AVERROR(EAGAIN
);
76 data
->len
= avio_close_dyn_buf(data
->dyn_buf
, &data
->buf
);
82 av_log(ctx
, AV_LOG_ERROR
, "No data available yet\n");
87 while (data
->pos
< data
->len
) {
88 uint8_t val
= data
->buf
[data
->pos
++];
93 if (data
->pos
+ cur_len
> data
->len
) {
94 av_log(ctx
, AV_LOG_ERROR
, "Malformed LATM packet\n");
98 if ((ret
= av_new_packet(pkt
, cur_len
)) < 0)
100 memcpy(pkt
->data
, data
->buf
+ data
->pos
, cur_len
);
101 data
->pos
+= cur_len
;
102 pkt
->stream_index
= st
->index
;
103 return data
->pos
< data
->len
;
106 static int parse_fmtp_config(AVStream
*st
, char *value
)
108 int len
= ff_hex_to_data(NULL
, value
), i
, ret
= 0;
111 int audio_mux_version
, same_time_framing
, num_programs
, num_layers
;
113 /* Pad this buffer, too, to avoid out of bounds reads with get_bits below */
114 config
= av_mallocz(len
+ FF_INPUT_BUFFER_PADDING_SIZE
);
116 return AVERROR(ENOMEM
);
117 ff_hex_to_data(config
, value
);
118 init_get_bits(&gb
, config
, len
*8);
119 audio_mux_version
= get_bits(&gb
, 1);
120 same_time_framing
= get_bits(&gb
, 1);
121 skip_bits(&gb
, 6); /* num_sub_frames */
122 num_programs
= get_bits(&gb
, 4);
123 num_layers
= get_bits(&gb
, 3);
124 if (audio_mux_version
!= 0 || same_time_framing
!= 1 || num_programs
!= 0 ||
126 av_log(NULL
, AV_LOG_WARNING
, "Unsupported LATM config (%d,%d,%d,%d)\n",
127 audio_mux_version
, same_time_framing
,
128 num_programs
, num_layers
);
129 ret
= AVERROR_PATCHWELCOME
;
132 av_freep(&st
->codec
->extradata
);
133 st
->codec
->extradata_size
= (get_bits_left(&gb
) + 7)/8;
134 st
->codec
->extradata
= av_mallocz(st
->codec
->extradata_size
+
135 FF_INPUT_BUFFER_PADDING_SIZE
);
136 if (!st
->codec
->extradata
) {
137 ret
= AVERROR(ENOMEM
);
140 for (i
= 0; i
< st
->codec
->extradata_size
; i
++)
141 st
->codec
->extradata
[i
] = get_bits(&gb
, 8);
148 static int parse_fmtp(AVStream
*stream
, PayloadContext
*data
,
149 char *attr
, char *value
)
153 if (!strcmp(attr
, "config")) {
154 res
= parse_fmtp_config(stream
, value
);
157 } else if (!strcmp(attr
, "cpresent")) {
158 int cpresent
= atoi(value
);
160 av_log_missing_feature(NULL
, "RTP MP4A-LATM with in-band "
167 static int latm_parse_sdp_line(AVFormatContext
*s
, int st_index
,
168 PayloadContext
*data
, const char *line
)
175 if (av_strstart(line
, "fmtp:", &p
))
176 return ff_parse_fmtp(s
->streams
[st_index
], data
, p
, parse_fmtp
);
181 RTPDynamicProtocolHandler ff_mp4a_latm_dynamic_handler
= {
182 .enc_name
= "MP4A-LATM",
183 .codec_type
= AVMEDIA_TYPE_AUDIO
,
184 .codec_id
= AV_CODEC_ID_AAC
,
185 .parse_sdp_a_line
= latm_parse_sdp_line
,
186 .alloc
= latm_new_context
,
187 .free
= latm_free_context
,
188 .parse_packet
= latm_parse_packet