00001
00022 #include "rtpdec_formats.h"
00023 #include "internal.h"
00024 #include "libavutil/avstring.h"
00025 #include "libavcodec/get_bits.h"
00026 #include <strings.h>
00027
00028 struct PayloadContext {
00029 AVIOContext *dyn_buf;
00030 uint8_t *buf;
00031 int pos, len;
00032 uint32_t timestamp;
00033 };
00034
00035 static PayloadContext *latm_new_context(void)
00036 {
00037 return av_mallocz(sizeof(PayloadContext));
00038 }
00039
00040 static void latm_free_context(PayloadContext *data)
00041 {
00042 if (!data)
00043 return;
00044 if (data->dyn_buf) {
00045 uint8_t *p;
00046 avio_close_dyn_buf(data->dyn_buf, &p);
00047 av_free(p);
00048 }
00049 av_free(data->buf);
00050 av_free(data);
00051 }
00052
00053 static int latm_parse_packet(AVFormatContext *ctx, PayloadContext *data,
00054 AVStream *st, AVPacket *pkt, uint32_t *timestamp,
00055 const uint8_t *buf, int len, int flags)
00056 {
00057 int ret, cur_len;
00058
00059 if (buf) {
00060 if (!data->dyn_buf || data->timestamp != *timestamp) {
00061 av_freep(&data->buf);
00062 if (data->dyn_buf)
00063 avio_close_dyn_buf(data->dyn_buf, &data->buf);
00064 data->dyn_buf = NULL;
00065 av_freep(&data->buf);
00066
00067 data->timestamp = *timestamp;
00068 if ((ret = avio_open_dyn_buf(&data->dyn_buf)) < 0)
00069 return ret;
00070 }
00071 avio_write(data->dyn_buf, buf, len);
00072
00073 if (!(flags & RTP_FLAG_MARKER))
00074 return AVERROR(EAGAIN);
00075 av_free(data->buf);
00076 data->len = avio_close_dyn_buf(data->dyn_buf, &data->buf);
00077 data->dyn_buf = NULL;
00078 data->pos = 0;
00079 }
00080
00081 if (!data->buf) {
00082 av_log(ctx, AV_LOG_ERROR, "No data available yet\n");
00083 return AVERROR(EIO);
00084 }
00085
00086 cur_len = 0;
00087 while (data->pos < data->len) {
00088 uint8_t val = data->buf[data->pos++];
00089 cur_len += val;
00090 if (val != 0xff)
00091 break;
00092 }
00093 if (data->pos + cur_len > data->len) {
00094 av_log(ctx, AV_LOG_ERROR, "Malformed LATM packet\n");
00095 return AVERROR(EIO);
00096 }
00097
00098 if ((ret = av_new_packet(pkt, cur_len)) < 0)
00099 return ret;
00100 memcpy(pkt->data, data->buf + data->pos, cur_len);
00101 data->pos += cur_len;
00102 pkt->stream_index = st->index;
00103 return data->pos < data->len;
00104 }
00105
00106 static int parse_fmtp_config(AVStream *st, char *value)
00107 {
00108 int len = ff_hex_to_data(NULL, value), i, ret = 0;
00109 GetBitContext gb;
00110 uint8_t *config;
00111 int audio_mux_version, same_time_framing, num_programs, num_layers;
00112
00113
00114 config = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
00115 if (!config)
00116 return AVERROR(ENOMEM);
00117 ff_hex_to_data(config, value);
00118 init_get_bits(&gb, config, len*8);
00119 audio_mux_version = get_bits(&gb, 1);
00120 same_time_framing = get_bits(&gb, 1);
00121 skip_bits(&gb, 6);
00122 num_programs = get_bits(&gb, 4);
00123 num_layers = get_bits(&gb, 3);
00124 if (audio_mux_version != 0 || same_time_framing != 1 || num_programs != 0 ||
00125 num_layers != 0) {
00126 av_log(NULL, AV_LOG_WARNING, "Unsupported LATM config (%d,%d,%d,%d)\n",
00127 audio_mux_version, same_time_framing,
00128 num_programs, num_layers);
00129 ret = AVERROR_PATCHWELCOME;
00130 goto end;
00131 }
00132 av_freep(&st->codec->extradata);
00133 st->codec->extradata_size = (get_bits_left(&gb) + 7)/8;
00134 st->codec->extradata = av_mallocz(st->codec->extradata_size +
00135 FF_INPUT_BUFFER_PADDING_SIZE);
00136 if (!st->codec->extradata) {
00137 ret = AVERROR(ENOMEM);
00138 goto end;
00139 }
00140 for (i = 0; i < st->codec->extradata_size; i++)
00141 st->codec->extradata[i] = get_bits(&gb, 8);
00142
00143 end:
00144 av_free(config);
00145 return ret;
00146 }
00147
00148 static int parse_fmtp(AVStream *stream, PayloadContext *data,
00149 char *attr, char *value)
00150 {
00151 int res;
00152
00153 if (!strcmp(attr, "config")) {
00154 res = parse_fmtp_config(stream, value);
00155 if (res < 0)
00156 return res;
00157 } else if (!strcmp(attr, "cpresent")) {
00158 int cpresent = atoi(value);
00159 if (cpresent != 0)
00160 av_log_missing_feature(NULL, "RTP MP4A-LATM with in-band "
00161 "configuration", 1);
00162 }
00163
00164 return 0;
00165 }
00166
00167 static int latm_parse_sdp_line(AVFormatContext *s, int st_index,
00168 PayloadContext *data, const char *line)
00169 {
00170 const char *p;
00171
00172 if (av_strstart(line, "fmtp:", &p))
00173 return ff_parse_fmtp(s->streams[st_index], data, p, parse_fmtp);
00174
00175 return 0;
00176 }
00177
00178 RTPDynamicProtocolHandler ff_mp4a_latm_dynamic_handler = {
00179 .enc_name = "MP4A-LATM",
00180 .codec_type = AVMEDIA_TYPE_AUDIO,
00181 .codec_id = CODEC_ID_AAC,
00182 .parse_sdp_a_line = latm_parse_sdp_line,
00183 .alloc = latm_new_context,
00184 .free = latm_free_context,
00185 .parse_packet = latm_parse_packet
00186 };