annotate ffmpeg/libavformat/rtpdec_mpeg4.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
yading@11 1 /*
yading@11 2 * Common code for the RTP depacketization of MPEG-4 formats.
yading@11 3 * Copyright (c) 2010 Fabrice Bellard
yading@11 4 * Romain Degez
yading@11 5 *
yading@11 6 * This file is part of FFmpeg.
yading@11 7 *
yading@11 8 * FFmpeg is free software; you can redistribute it and/or
yading@11 9 * modify it under the terms of the GNU Lesser General Public
yading@11 10 * License as published by the Free Software Foundation; either
yading@11 11 * version 2.1 of the License, or (at your option) any later version.
yading@11 12 *
yading@11 13 * FFmpeg is distributed in the hope that it will be useful,
yading@11 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@11 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@11 16 * Lesser General Public License for more details.
yading@11 17 *
yading@11 18 * You should have received a copy of the GNU Lesser General Public
yading@11 19 * License along with FFmpeg; if not, write to the Free Software
yading@11 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@11 21 */
yading@11 22
yading@11 23 /**
yading@11 24 * @file
yading@11 25 * @brief MPEG4 / RTP Code
yading@11 26 * @author Fabrice Bellard
yading@11 27 * @author Romain Degez
yading@11 28 */
yading@11 29
yading@11 30 #include "rtpdec_formats.h"
yading@11 31 #include "internal.h"
yading@11 32 #include "libavutil/avstring.h"
yading@11 33 #include "libavcodec/get_bits.h"
yading@11 34
yading@11 35 /** Structure listing useful vars to parse RTP packet payload */
yading@11 36 struct PayloadContext {
yading@11 37 int sizelength;
yading@11 38 int indexlength;
yading@11 39 int indexdeltalength;
yading@11 40 int profile_level_id;
yading@11 41 int streamtype;
yading@11 42 int objecttype;
yading@11 43 char *mode;
yading@11 44
yading@11 45 /** mpeg 4 AU headers */
yading@11 46 struct AUHeaders {
yading@11 47 int size;
yading@11 48 int index;
yading@11 49 int cts_flag;
yading@11 50 int cts;
yading@11 51 int dts_flag;
yading@11 52 int dts;
yading@11 53 int rap_flag;
yading@11 54 int streamstate;
yading@11 55 } *au_headers;
yading@11 56 int au_headers_allocated;
yading@11 57 int nb_au_headers;
yading@11 58 int au_headers_length_bytes;
yading@11 59 int cur_au_index;
yading@11 60
yading@11 61 uint8_t buf[RTP_MAX_PACKET_LENGTH];
yading@11 62 int buf_pos, buf_size;
yading@11 63 };
yading@11 64
yading@11 65 typedef struct {
yading@11 66 const char *str;
yading@11 67 uint16_t type;
yading@11 68 uint32_t offset;
yading@11 69 } AttrNameMap;
yading@11 70
yading@11 71 /* All known fmtp parameters and the corresponding RTPAttrTypeEnum */
yading@11 72 #define ATTR_NAME_TYPE_INT 0
yading@11 73 #define ATTR_NAME_TYPE_STR 1
yading@11 74 static const AttrNameMap attr_names[] = {
yading@11 75 { "SizeLength", ATTR_NAME_TYPE_INT,
yading@11 76 offsetof(PayloadContext, sizelength) },
yading@11 77 { "IndexLength", ATTR_NAME_TYPE_INT,
yading@11 78 offsetof(PayloadContext, indexlength) },
yading@11 79 { "IndexDeltaLength", ATTR_NAME_TYPE_INT,
yading@11 80 offsetof(PayloadContext, indexdeltalength) },
yading@11 81 { "profile-level-id", ATTR_NAME_TYPE_INT,
yading@11 82 offsetof(PayloadContext, profile_level_id) },
yading@11 83 { "StreamType", ATTR_NAME_TYPE_INT,
yading@11 84 offsetof(PayloadContext, streamtype) },
yading@11 85 { "mode", ATTR_NAME_TYPE_STR,
yading@11 86 offsetof(PayloadContext, mode) },
yading@11 87 { NULL, -1, -1 },
yading@11 88 };
yading@11 89
yading@11 90 static PayloadContext *new_context(void)
yading@11 91 {
yading@11 92 return av_mallocz(sizeof(PayloadContext));
yading@11 93 }
yading@11 94
yading@11 95 static void free_context(PayloadContext *data)
yading@11 96 {
yading@11 97 av_free(data->au_headers);
yading@11 98 av_free(data->mode);
yading@11 99 av_free(data);
yading@11 100 }
yading@11 101
yading@11 102 static int parse_fmtp_config(AVCodecContext *codec, char *value)
yading@11 103 {
yading@11 104 /* decode the hexa encoded parameter */
yading@11 105 int len = ff_hex_to_data(NULL, value);
yading@11 106 av_free(codec->extradata);
yading@11 107 codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE);
yading@11 108 if (!codec->extradata)
yading@11 109 return AVERROR(ENOMEM);
yading@11 110 codec->extradata_size = len;
yading@11 111 ff_hex_to_data(codec->extradata, value);
yading@11 112 return 0;
yading@11 113 }
yading@11 114
yading@11 115 static int rtp_parse_mp4_au(PayloadContext *data, const uint8_t *buf, int len)
yading@11 116 {
yading@11 117 int au_headers_length, au_header_size, i;
yading@11 118 GetBitContext getbitcontext;
yading@11 119
yading@11 120 if (len < 2)
yading@11 121 return AVERROR_INVALIDDATA;
yading@11 122
yading@11 123 /* decode the first 2 bytes where the AUHeader sections are stored
yading@11 124 length in bits */
yading@11 125 au_headers_length = AV_RB16(buf);
yading@11 126
yading@11 127 if (au_headers_length > RTP_MAX_PACKET_LENGTH)
yading@11 128 return -1;
yading@11 129
yading@11 130 data->au_headers_length_bytes = (au_headers_length + 7) / 8;
yading@11 131
yading@11 132 /* skip AU headers length section (2 bytes) */
yading@11 133 buf += 2;
yading@11 134 len -= 2;
yading@11 135
yading@11 136 if (len < data->au_headers_length_bytes)
yading@11 137 return AVERROR_INVALIDDATA;
yading@11 138
yading@11 139 init_get_bits(&getbitcontext, buf, data->au_headers_length_bytes * 8);
yading@11 140
yading@11 141 /* XXX: Wrong if optional additional sections are present (cts, dts etc...) */
yading@11 142 au_header_size = data->sizelength + data->indexlength;
yading@11 143 if (au_header_size <= 0 || (au_headers_length % au_header_size != 0))
yading@11 144 return -1;
yading@11 145
yading@11 146 data->nb_au_headers = au_headers_length / au_header_size;
yading@11 147 if (!data->au_headers || data->au_headers_allocated < data->nb_au_headers) {
yading@11 148 av_free(data->au_headers);
yading@11 149 data->au_headers = av_malloc(sizeof(struct AUHeaders) * data->nb_au_headers);
yading@11 150 if (!data->au_headers)
yading@11 151 return AVERROR(ENOMEM);
yading@11 152 data->au_headers_allocated = data->nb_au_headers;
yading@11 153 }
yading@11 154
yading@11 155 for (i = 0; i < data->nb_au_headers; ++i) {
yading@11 156 data->au_headers[i].size = get_bits_long(&getbitcontext, data->sizelength);
yading@11 157 data->au_headers[i].index = get_bits_long(&getbitcontext, data->indexlength);
yading@11 158 }
yading@11 159
yading@11 160 return 0;
yading@11 161 }
yading@11 162
yading@11 163
yading@11 164 /* Follows RFC 3640 */
yading@11 165 static int aac_parse_packet(AVFormatContext *ctx, PayloadContext *data,
yading@11 166 AVStream *st, AVPacket *pkt, uint32_t *timestamp,
yading@11 167 const uint8_t *buf, int len, uint16_t seq,
yading@11 168 int flags)
yading@11 169 {
yading@11 170 int ret;
yading@11 171
yading@11 172 if (!buf) {
yading@11 173 if (data->cur_au_index > data->nb_au_headers)
yading@11 174 return AVERROR_INVALIDDATA;
yading@11 175 if (data->buf_size - data->buf_pos < data->au_headers[data->cur_au_index].size)
yading@11 176 return AVERROR_INVALIDDATA;
yading@11 177 if ((ret = av_new_packet(pkt, data->au_headers[data->cur_au_index].size)) < 0)
yading@11 178 return ret;
yading@11 179 memcpy(pkt->data, &data->buf[data->buf_pos], data->au_headers[data->cur_au_index].size);
yading@11 180 data->buf_pos += data->au_headers[data->cur_au_index].size;
yading@11 181 pkt->stream_index = st->index;
yading@11 182 data->cur_au_index++;
yading@11 183 return data->cur_au_index < data->nb_au_headers;
yading@11 184 }
yading@11 185
yading@11 186 if (rtp_parse_mp4_au(data, buf, len))
yading@11 187 return -1;
yading@11 188
yading@11 189 buf += data->au_headers_length_bytes + 2;
yading@11 190 len -= data->au_headers_length_bytes + 2;
yading@11 191
yading@11 192 if (len < data->au_headers[0].size)
yading@11 193 return AVERROR_INVALIDDATA;
yading@11 194 if ((ret = av_new_packet(pkt, data->au_headers[0].size)) < 0)
yading@11 195 return ret;
yading@11 196 memcpy(pkt->data, buf, data->au_headers[0].size);
yading@11 197 len -= data->au_headers[0].size;
yading@11 198 buf += data->au_headers[0].size;
yading@11 199 pkt->stream_index = st->index;
yading@11 200
yading@11 201 if (len > 0 && data->nb_au_headers > 1) {
yading@11 202 data->buf_size = FFMIN(len, sizeof(data->buf));
yading@11 203 memcpy(data->buf, buf, data->buf_size);
yading@11 204 data->cur_au_index = 1;
yading@11 205 data->buf_pos = 0;
yading@11 206 return 1;
yading@11 207 }
yading@11 208
yading@11 209 return 0;
yading@11 210 }
yading@11 211
yading@11 212 static int parse_fmtp(AVStream *stream, PayloadContext *data,
yading@11 213 char *attr, char *value)
yading@11 214 {
yading@11 215 AVCodecContext *codec = stream->codec;
yading@11 216 int res, i;
yading@11 217
yading@11 218 if (!strcmp(attr, "config")) {
yading@11 219 res = parse_fmtp_config(codec, value);
yading@11 220
yading@11 221 if (res < 0)
yading@11 222 return res;
yading@11 223 }
yading@11 224
yading@11 225 if (codec->codec_id == AV_CODEC_ID_AAC) {
yading@11 226 /* Looking for a known attribute */
yading@11 227 for (i = 0; attr_names[i].str; ++i) {
yading@11 228 if (!av_strcasecmp(attr, attr_names[i].str)) {
yading@11 229 if (attr_names[i].type == ATTR_NAME_TYPE_INT) {
yading@11 230 *(int *)((char *)data+
yading@11 231 attr_names[i].offset) = atoi(value);
yading@11 232 } else if (attr_names[i].type == ATTR_NAME_TYPE_STR)
yading@11 233 *(char **)((char *)data+
yading@11 234 attr_names[i].offset) = av_strdup(value);
yading@11 235 }
yading@11 236 }
yading@11 237 }
yading@11 238 return 0;
yading@11 239 }
yading@11 240
yading@11 241 static int parse_sdp_line(AVFormatContext *s, int st_index,
yading@11 242 PayloadContext *data, const char *line)
yading@11 243 {
yading@11 244 const char *p;
yading@11 245
yading@11 246 if (st_index < 0)
yading@11 247 return 0;
yading@11 248
yading@11 249 if (av_strstart(line, "fmtp:", &p))
yading@11 250 return ff_parse_fmtp(s->streams[st_index], data, p, parse_fmtp);
yading@11 251
yading@11 252 return 0;
yading@11 253 }
yading@11 254
yading@11 255 static int init_video(AVFormatContext *s, int st_index, PayloadContext *data)
yading@11 256 {
yading@11 257 if (st_index < 0)
yading@11 258 return 0;
yading@11 259 s->streams[st_index]->need_parsing = AVSTREAM_PARSE_FULL;
yading@11 260 return 0;
yading@11 261 }
yading@11 262
yading@11 263 RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler = {
yading@11 264 .enc_name = "MP4V-ES",
yading@11 265 .codec_type = AVMEDIA_TYPE_VIDEO,
yading@11 266 .codec_id = AV_CODEC_ID_MPEG4,
yading@11 267 .init = init_video,
yading@11 268 .parse_sdp_a_line = parse_sdp_line,
yading@11 269 };
yading@11 270
yading@11 271 RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler = {
yading@11 272 .enc_name = "mpeg4-generic",
yading@11 273 .codec_type = AVMEDIA_TYPE_AUDIO,
yading@11 274 .codec_id = AV_CODEC_ID_AAC,
yading@11 275 .parse_sdp_a_line = parse_sdp_line,
yading@11 276 .alloc = new_context,
yading@11 277 .free = free_context,
yading@11 278 .parse_packet = aac_parse_packet
yading@11 279 };