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