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