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 url_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 url_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 = url_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 = url_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_sub_frames,
00112 num_programs, num_layers;
00113
00114
00115 config = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
00116 if (!config)
00117 return AVERROR(ENOMEM);
00118 ff_hex_to_data(config, value);
00119 init_get_bits(&gb, config, len*8);
00120 audio_mux_version = get_bits(&gb, 1);
00121 same_time_framing = get_bits(&gb, 1);
00122 num_sub_frames = get_bits(&gb, 6);
00123 num_programs = get_bits(&gb, 4);
00124 num_layers = get_bits(&gb, 3);
00125 if (audio_mux_version != 0 || same_time_framing != 1 || num_programs != 0 ||
00126 num_layers != 0) {
00127 av_log(NULL, AV_LOG_WARNING, "Unsupported LATM config (%d,%d,%d,%d)\n",
00128 audio_mux_version, same_time_framing,
00129 num_programs, num_layers);
00130 ret = AVERROR_PATCHWELCOME;
00131 goto end;
00132 }
00133 av_freep(&st->codec->extradata);
00134 st->codec->extradata_size = (get_bits_left(&gb) + 7)/8;
00135 st->codec->extradata = av_mallocz(st->codec->extradata_size +
00136 FF_INPUT_BUFFER_PADDING_SIZE);
00137 if (!st->codec->extradata) {
00138 ret = AVERROR(ENOMEM);
00139 goto end;
00140 }
00141 for (i = 0; i < st->codec->extradata_size; i++)
00142 st->codec->extradata[i] = get_bits(&gb, 8);
00143
00144 end:
00145 av_free(config);
00146 return ret;
00147 }
00148
00149 static int parse_fmtp(AVStream *stream, PayloadContext *data,
00150 char *attr, char *value)
00151 {
00152 int res;
00153
00154 if (!strcmp(attr, "config")) {
00155 res = parse_fmtp_config(stream, value);
00156 if (res < 0)
00157 return res;
00158 } else if (!strcmp(attr, "cpresent")) {
00159 int cpresent = atoi(value);
00160 if (cpresent != 0)
00161 av_log_missing_feature(NULL, "RTP MP4A-LATM with in-band "
00162 "configuration", 1);
00163 }
00164
00165 return 0;
00166 }
00167
00168 static int latm_parse_sdp_line(AVFormatContext *s, int st_index,
00169 PayloadContext *data, const char *line)
00170 {
00171 const char *p;
00172
00173 if (av_strstart(line, "fmtp:", &p))
00174 return ff_parse_fmtp(s->streams[st_index], data, p, parse_fmtp);
00175
00176 return 0;
00177 }
00178
00179 RTPDynamicProtocolHandler ff_mp4a_latm_dynamic_handler = {
00180 .enc_name = "MP4A-LATM",
00181 .codec_type = AVMEDIA_TYPE_AUDIO,
00182 .codec_id = CODEC_ID_AAC,
00183 .parse_sdp_a_line = latm_parse_sdp_line,
00184 .open = latm_new_context,
00185 .close = latm_free_context,
00186 .parse_packet = latm_parse_packet
00187 };