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