FFmpeg
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rtpdec_mpeg4.c
Go to the documentation of this file.
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/avstring.h"
33 #include "libavcodec/get_bits.h"
34 
35 /** Structure listing useful vars to parse RTP packet payload */
36 struct PayloadContext {
43  char *mode;
44 
45  /** mpeg 4 AU headers */
46  struct AUHeaders {
47  int size;
48  int index;
49  int cts_flag;
50  int cts;
51  int dts_flag;
52  int dts;
53  int rap_flag;
55  } *au_headers;
60 };
61 
62 typedef struct {
63  const char *str;
64  uint16_t type;
65  uint32_t offset;
66 } AttrNameMap;
67 
68 /* All known fmtp parameters and the corresponding RTPAttrTypeEnum */
69 #define ATTR_NAME_TYPE_INT 0
70 #define ATTR_NAME_TYPE_STR 1
71 static const AttrNameMap attr_names[] = {
72  { "SizeLength", ATTR_NAME_TYPE_INT,
73  offsetof(PayloadContext, sizelength) },
74  { "IndexLength", ATTR_NAME_TYPE_INT,
75  offsetof(PayloadContext, indexlength) },
76  { "IndexDeltaLength", ATTR_NAME_TYPE_INT,
77  offsetof(PayloadContext, indexdeltalength) },
78  { "profile-level-id", ATTR_NAME_TYPE_INT,
79  offsetof(PayloadContext, profile_level_id) },
80  { "StreamType", ATTR_NAME_TYPE_INT,
81  offsetof(PayloadContext, streamtype) },
82  { "mode", ATTR_NAME_TYPE_STR,
83  offsetof(PayloadContext, mode) },
84  { NULL, -1, -1 },
85 };
86 
88 {
89  return av_mallocz(sizeof(PayloadContext));
90 }
91 
93 {
94  av_free(data->au_headers);
95  av_free(data->mode);
96  av_free(data);
97 }
98 
99 static int parse_fmtp_config(AVCodecContext *codec, char *value)
100 {
101  /* decode the hexa encoded parameter */
102  int len = ff_hex_to_data(NULL, value);
103  av_free(codec->extradata);
105  if (!codec->extradata)
106  return AVERROR(ENOMEM);
107  codec->extradata_size = len;
108  ff_hex_to_data(codec->extradata, value);
109  return 0;
110 }
111 
112 static int rtp_parse_mp4_au(PayloadContext *data, const uint8_t *buf)
113 {
114  int au_headers_length, au_header_size, i;
115  GetBitContext getbitcontext;
116 
117  /* decode the first 2 bytes where the AUHeader sections are stored
118  length in bits */
119  au_headers_length = AV_RB16(buf);
120 
121  if (au_headers_length > RTP_MAX_PACKET_LENGTH)
122  return -1;
123 
124  data->au_headers_length_bytes = (au_headers_length + 7) / 8;
125 
126  /* skip AU headers length section (2 bytes) */
127  buf += 2;
128 
129  init_get_bits(&getbitcontext, buf, data->au_headers_length_bytes * 8);
130 
131  /* XXX: Wrong if optional additional sections are present (cts, dts etc...) */
132  au_header_size = data->sizelength + data->indexlength;
133  if (au_header_size <= 0 || (au_headers_length % au_header_size != 0))
134  return -1;
135 
136  data->nb_au_headers = au_headers_length / au_header_size;
137  if (!data->au_headers || data->au_headers_allocated < data->nb_au_headers) {
138  av_free(data->au_headers);
139  data->au_headers = av_malloc(sizeof(struct AUHeaders) * data->nb_au_headers);
140  data->au_headers_allocated = data->nb_au_headers;
141  }
142 
143  /* XXX: We handle multiple AU Section as only one (need to fix this for interleaving)
144  In my test, the FAAD decoder does not behave correctly when sending each AU one by one
145  but does when sending the whole as one big packet... */
146  data->au_headers[0].size = 0;
147  data->au_headers[0].index = 0;
148  for (i = 0; i < data->nb_au_headers; ++i) {
149  data->au_headers[0].size += get_bits_long(&getbitcontext, data->sizelength);
150  data->au_headers[0].index = get_bits_long(&getbitcontext, data->indexlength);
151  }
152 
153  data->nb_au_headers = 1;
154 
155  return 0;
156 }
157 
158 
159 /* Follows RFC 3640 */
161  AVStream *st, AVPacket *pkt, uint32_t *timestamp,
162  const uint8_t *buf, int len, uint16_t seq,
163  int flags)
164 {
165  if (rtp_parse_mp4_au(data, buf))
166  return -1;
167 
168  buf += data->au_headers_length_bytes + 2;
169  len -= data->au_headers_length_bytes + 2;
170 
171  /* XXX: Fixme we only handle the case where rtp_parse_mp4_au define
172  one au_header */
173  av_new_packet(pkt, data->au_headers[0].size);
174  memcpy(pkt->data, buf, data->au_headers[0].size);
175 
176  pkt->stream_index = st->index;
177  return 0;
178 }
179 
180 static int parse_fmtp(AVStream *stream, PayloadContext *data,
181  char *attr, char *value)
182 {
183  AVCodecContext *codec = stream->codec;
184  int res, i;
185 
186  if (!strcmp(attr, "config")) {
187  res = parse_fmtp_config(codec, value);
188 
189  if (res < 0)
190  return res;
191  }
192 
193  if (codec->codec_id == AV_CODEC_ID_AAC) {
194  /* Looking for a known attribute */
195  for (i = 0; attr_names[i].str; ++i) {
196  if (!av_strcasecmp(attr, attr_names[i].str)) {
197  if (attr_names[i].type == ATTR_NAME_TYPE_INT) {
198  *(int *)((char *)data+
199  attr_names[i].offset) = atoi(value);
200  } else if (attr_names[i].type == ATTR_NAME_TYPE_STR)
201  *(char **)((char *)data+
202  attr_names[i].offset) = av_strdup(value);
203  }
204  }
205  }
206  return 0;
207 }
208 
209 static int parse_sdp_line(AVFormatContext *s, int st_index,
210  PayloadContext *data, const char *line)
211 {
212  const char *p;
213 
214  if (st_index < 0)
215  return 0;
216 
217  if (av_strstart(line, "fmtp:", &p))
218  return ff_parse_fmtp(s->streams[st_index], data, p, parse_fmtp);
219 
220  return 0;
221 }
222 
224  .enc_name = "MP4V-ES",
225  .codec_type = AVMEDIA_TYPE_VIDEO,
226  .codec_id = AV_CODEC_ID_MPEG4,
227  .parse_sdp_a_line = parse_sdp_line,
228 };
229 
231  .enc_name = "mpeg4-generic",
232  .codec_type = AVMEDIA_TYPE_AUDIO,
233  .codec_id = AV_CODEC_ID_AAC,
234  .parse_sdp_a_line = parse_sdp_line,
235  .alloc = new_context,
236  .free = free_context,
237  .parse_packet = aac_parse_packet
238 };