Mercurial > libavformat.hg
annotate rtp_h264.c @ 3754:8d267b43eaba libavformat
Move malloc() down until after all initializations, so that the resource is
only allocated if initialization worked. This means that on failure, we
don't have to deallocate it.
author | rbultje |
---|---|
date | Sat, 23 Aug 2008 18:46:30 +0000 |
parents | 7100924e2932 |
children | 44561554cb7e |
rev | line source |
---|---|
1460 | 1 /* |
2 * RTP H264 Protocol (RFC3984) | |
3 * Copyright (c) 2006 Ryan Martell. | |
4 * | |
5 * This file is part of FFmpeg. | |
6 * | |
7 * FFmpeg is free software; you can redistribute it and/or | |
8 * modify it under the terms of the GNU Lesser General Public | |
9 * License as published by the Free Software Foundation; either | |
10 * version 2.1 of the License, or (at your option) any later version. | |
11 * | |
12 * FFmpeg is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Lesser General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Lesser General Public | |
18 * License along with FFmpeg; if not, write to the Free Software | |
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
20 */ | |
21 | |
22 /** | |
23 * @file rtp_h264.c | |
24 * @brief H.264 / RTP Code (RFC3984) | |
25 * @author Ryan Martell <rdm4@martellventures.com> | |
26 * | |
27 * @note Notes: | |
28 * Notes: | |
29 * This currently supports packetization mode: | |
30 * Single Nal Unit Mode (0), or | |
31 * Non-Interleaved Mode (1). It currently does not support | |
32 * Interleaved Mode (2). (This requires implementing STAP-B, MTAP16, MTAP24, FU-B packet types) | |
33 * | |
34 * @note TODO: | |
35 * 1) RTCP sender reports for udp streams are required.. | |
36 * | |
37 */ | |
38 | |
3286 | 39 #include "libavutil/base64.h" |
40 #include "libavutil/avstring.h" | |
41 #include "libavcodec/bitstream.h" | |
1460 | 42 #include "avformat.h" |
43 #include "mpegts.h" | |
44 | |
45 #include <unistd.h> | |
1754 | 46 #include "network.h" |
1460 | 47 #include <assert.h> |
48 | |
49 #include "rtp_internal.h" | |
50 #include "rtp_h264.h" | |
51 | |
52 /** | |
53 RTP/H264 specific private data. | |
54 */ | |
55 typedef struct h264_rtp_extra_data { | |
56 unsigned long cookie; ///< sanity check, to make sure we get the pointer we're expecting. | |
57 | |
58 //sdp setup parameters | |
59 uint8_t profile_idc; ///< from the sdp setup parameters. | |
60 uint8_t profile_iop; ///< from the sdp setup parameters. | |
61 uint8_t level_idc; ///< from the sdp setup parameters. | |
62 int packetization_mode; ///< from the sdp setup parameters. | |
63 #ifdef DEBUG | |
64 int packet_types_received[32]; | |
65 #endif | |
66 } h264_rtp_extra_data; | |
67 | |
68 #define MAGIC_COOKIE (0xdeadbeef) ///< Cookie for the extradata; to verify we are what we think we are, and that we haven't been freed. | |
69 #define DEAD_COOKIE (0xdeaddead) ///< Cookie for the extradata; once it is freed. | |
70 | |
71 /* ---------------- private code */ | |
72 static void sdp_parse_fmtp_config_h264(AVStream * stream, | |
73 h264_rtp_extra_data * h264_data, | |
74 char *attr, char *value) | |
75 { | |
76 AVCodecContext *codec = stream->codec; | |
77 assert(codec->codec_id == CODEC_ID_H264); | |
78 assert(h264_data != NULL); | |
79 | |
80 if (!strcmp(attr, "packetization-mode")) { | |
2362 | 81 av_log(NULL, AV_LOG_DEBUG, "H.264/RTP Packetization Mode: %d\n", atoi(value)); |
82 h264_data->packetization_mode = atoi(value); | |
1460 | 83 /* |
84 Packetization Mode: | |
85 0 or not present: Single NAL mode (Only nals from 1-23 are allowed) | |
86 1: Non-interleaved Mode: 1-23, 24 (STAP-A), 28 (FU-A) are allowed. | |
87 2: Interleaved Mode: 25 (STAP-B), 26 (MTAP16), 27 (MTAP24), 28 (FU-A), and 29 (FU-B) are allowed. | |
88 */ | |
89 if (h264_data->packetization_mode > 1) | |
90 av_log(stream, AV_LOG_ERROR, | |
91 "H.264/RTP Interleaved RTP mode is not supported yet."); | |
92 } else if (!strcmp(attr, "profile-level-id")) { | |
93 if (strlen(value) == 6) { | |
94 char buffer[3]; | |
95 // 6 characters=3 bytes, in hex. | |
96 uint8_t profile_idc; | |
97 uint8_t profile_iop; | |
98 uint8_t level_idc; | |
99 | |
100 buffer[0] = value[0]; buffer[1] = value[1]; buffer[2] = '\0'; | |
101 profile_idc = strtol(buffer, NULL, 16); | |
102 buffer[0] = value[2]; buffer[1] = value[3]; | |
103 profile_iop = strtol(buffer, NULL, 16); | |
104 buffer[0] = value[4]; buffer[1] = value[5]; | |
105 level_idc = strtol(buffer, NULL, 16); | |
106 | |
107 // set the parameters... | |
108 av_log(NULL, AV_LOG_DEBUG, | |
109 "H.264/RTP Profile IDC: %x Profile IOP: %x Level: %x\n", | |
110 profile_idc, profile_iop, level_idc); | |
111 h264_data->profile_idc = profile_idc; | |
112 h264_data->profile_iop = profile_iop; | |
113 h264_data->level_idc = level_idc; | |
114 } | |
115 } else if (!strcmp(attr, "sprop-parameter-sets")) { | |
116 uint8_t start_sequence[]= { 0, 0, 1 }; | |
117 codec->extradata_size= 0; | |
118 codec->extradata= NULL; | |
119 | |
120 while (*value) { | |
121 char base64packet[1024]; | |
122 uint8_t decoded_packet[1024]; | |
123 uint32_t packet_size; | |
124 char *dst = base64packet; | |
125 | |
126 while (*value && *value != ',' | |
127 && (dst - base64packet) < sizeof(base64packet) - 1) { | |
128 *dst++ = *value++; | |
129 } | |
130 *dst++ = '\0'; | |
131 | |
132 if (*value == ',') | |
133 value++; | |
134 | |
135 packet_size= av_base64_decode(decoded_packet, base64packet, sizeof(decoded_packet)); | |
136 if (packet_size) { | |
137 uint8_t *dest= av_malloc(packet_size+sizeof(start_sequence)+codec->extradata_size); | |
138 if(dest) | |
139 { | |
140 if(codec->extradata_size) | |
141 { | |
142 // av_realloc? | |
143 memcpy(dest, codec->extradata, codec->extradata_size); | |
144 av_free(codec->extradata); | |
145 } | |
146 | |
147 memcpy(dest+codec->extradata_size, start_sequence, sizeof(start_sequence)); | |
148 memcpy(dest+codec->extradata_size+sizeof(start_sequence), decoded_packet, packet_size); | |
149 | |
150 codec->extradata= dest; | |
151 codec->extradata_size+= sizeof(start_sequence)+packet_size; | |
152 } else { | |
153 av_log(NULL, AV_LOG_ERROR, "H.264/RTP Unable to allocate memory for extradata!"); | |
154 } | |
155 } | |
156 } | |
157 av_log(NULL, AV_LOG_DEBUG, "H.264/RTP Extradata set to %p (size: %d)!", codec->extradata, codec->extradata_size); | |
158 } | |
159 } | |
160 | |
161 // return 0 on packet, no more left, 1 on packet, 1 on partial packet... | |
162 static int h264_handle_packet(RTPDemuxContext * s, | |
163 AVPacket * pkt, | |
164 uint32_t * timestamp, | |
165 const uint8_t * buf, | |
2941
6da0564c9d02
Add a flags field to the RTPDynamicPayloadPacketHandlerProc (PKT_FLAG_*).
rbultje
parents:
2702
diff
changeset
|
166 int len, int flags) |
1460 | 167 { |
2702
6a7b82888880
Enable debug variable only when debug code is enabled, fixes the warning:
diego
parents:
2362
diff
changeset
|
168 #ifdef DEBUG |
1888 | 169 h264_rtp_extra_data *data = s->dynamic_protocol_context; |
2702
6a7b82888880
Enable debug variable only when debug code is enabled, fixes the warning:
diego
parents:
2362
diff
changeset
|
170 #endif |
1460 | 171 uint8_t nal = buf[0]; |
172 uint8_t type = (nal & 0x1f); | |
173 int result= 0; | |
174 uint8_t start_sequence[]= {0, 0, 1}; | |
175 | |
3292 | 176 #ifdef DEBUG |
1460 | 177 assert(data); |
178 assert(data->cookie == MAGIC_COOKIE); | |
3292 | 179 #endif |
1460 | 180 assert(buf); |
181 | |
182 if (type >= 1 && type <= 23) | |
183 type = 1; // simplify the case. (these are all the nal types used internally by the h264 codec) | |
184 switch (type) { | |
185 case 0: // undefined; | |
186 result= -1; | |
187 break; | |
188 | |
189 case 1: | |
190 av_new_packet(pkt, len+sizeof(start_sequence)); | |
191 memcpy(pkt->data, start_sequence, sizeof(start_sequence)); | |
192 memcpy(pkt->data+sizeof(start_sequence), buf, len); | |
193 #ifdef DEBUG | |
194 data->packet_types_received[nal & 0x1f]++; | |
195 #endif | |
196 break; | |
197 | |
198 case 24: // STAP-A (one packet, multiple nals) | |
199 // consume the STAP-A NAL | |
200 buf++; | |
201 len--; | |
202 // first we are going to figure out the total size.... | |
203 { | |
204 int pass= 0; | |
205 int total_length= 0; | |
206 uint8_t *dst= NULL; | |
207 | |
208 for(pass= 0; pass<2; pass++) { | |
209 const uint8_t *src= buf; | |
210 int src_len= len; | |
211 | |
212 do { | |
1673 | 213 uint16_t nal_size = AV_RB16(src); // this going to be a problem if unaligned (can it be?) |
1460 | 214 |
215 // consume the length of the aggregate... | |
216 src += 2; | |
217 src_len -= 2; | |
218 | |
219 if (nal_size <= src_len) { | |
220 if(pass==0) { | |
221 // counting... | |
222 total_length+= sizeof(start_sequence)+nal_size; | |
223 } else { | |
224 // copying | |
225 assert(dst); | |
226 memcpy(dst, start_sequence, sizeof(start_sequence)); | |
227 dst+= sizeof(start_sequence); | |
228 memcpy(dst, src, nal_size); | |
229 #ifdef DEBUG | |
230 data->packet_types_received[*src & 0x1f]++; | |
231 #endif | |
232 dst+= nal_size; | |
233 } | |
234 } else { | |
235 av_log(NULL, AV_LOG_ERROR, | |
236 "nal size exceeds length: %d %d\n", nal_size, src_len); | |
237 } | |
238 | |
239 // eat what we handled... | |
240 src += nal_size; | |
241 src_len -= nal_size; | |
242 | |
243 if (src_len < 0) | |
244 av_log(NULL, AV_LOG_ERROR, | |
245 "Consumed more bytes than we got! (%d)\n", src_len); | |
246 } while (src_len > 2); // because there could be rtp padding.. | |
247 | |
248 if(pass==0) { | |
249 // now we know the total size of the packet (with the start sequences added) | |
250 av_new_packet(pkt, total_length); | |
251 dst= pkt->data; | |
252 } else { | |
253 assert(dst-pkt->data==total_length); | |
254 } | |
255 } | |
256 } | |
257 break; | |
258 | |
259 case 25: // STAP-B | |
260 case 26: // MTAP-16 | |
261 case 27: // MTAP-24 | |
262 case 29: // FU-B | |
263 av_log(NULL, AV_LOG_ERROR, | |
264 "Unhandled type (%d) (See RFC for implementation details\n", | |
265 type); | |
266 result= -1; | |
267 break; | |
268 | |
269 case 28: // FU-A (fragmented nal) | |
270 buf++; | |
271 len--; // skip the fu_indicator | |
272 { | |
273 // these are the same as above, we just redo them here for clarity... | |
274 uint8_t fu_indicator = nal; | |
275 uint8_t fu_header = *buf; // read the fu_header. | |
2154
b849507913da
Remove the unnecessary masking when extracting the start bit in the H.264 RTP
takis
parents:
1983
diff
changeset
|
276 uint8_t start_bit = fu_header >> 7; |
1460 | 277 // uint8_t end_bit = (fu_header & 0x40) >> 6; |
278 uint8_t nal_type = (fu_header & 0x1f); | |
279 uint8_t reconstructed_nal; | |
280 | |
281 // reconstruct this packet's true nal; only the data follows.. | |
282 reconstructed_nal = fu_indicator & (0xe0); // the original nal forbidden bit and NRI are stored in this packet's nal; | |
2155
a661d4e7cab2
Remove the unnecessary masking when reconstructing the NAL unit header in the
takis
parents:
2154
diff
changeset
|
283 reconstructed_nal |= nal_type; |
1460 | 284 |
285 // skip the fu_header... | |
286 buf++; | |
287 len--; | |
288 | |
289 #ifdef DEBUG | |
290 if (start_bit) | |
2156
cfd57cd5252b
Remove the unnecessary masking when counting received packet types in the H.264
takis
parents:
2155
diff
changeset
|
291 data->packet_types_received[nal_type]++; |
1460 | 292 #endif |
293 if(start_bit) { | |
294 // copy in the start sequence, and the reconstructed nal.... | |
295 av_new_packet(pkt, sizeof(start_sequence)+sizeof(nal)+len); | |
296 memcpy(pkt->data, start_sequence, sizeof(start_sequence)); | |
297 pkt->data[sizeof(start_sequence)]= reconstructed_nal; | |
298 memcpy(pkt->data+sizeof(start_sequence)+sizeof(nal), buf, len); | |
299 } else { | |
300 av_new_packet(pkt, len); | |
301 memcpy(pkt->data, buf, len); | |
302 } | |
303 } | |
304 break; | |
305 | |
306 case 30: // undefined | |
307 case 31: // undefined | |
308 default: | |
309 av_log(NULL, AV_LOG_ERROR, "Undefined type (%d)", type); | |
310 result= -1; | |
311 break; | |
312 } | |
313 | |
314 return result; | |
315 } | |
316 | |
317 /* ---------------- public code */ | |
1983
fbc66bf1f15d
changes some function declarations from () to (void) as per ansi c.
gpoirier
parents:
1888
diff
changeset
|
318 static void *h264_new_extradata(void) |
1460 | 319 { |
320 h264_rtp_extra_data *data = | |
321 av_mallocz(sizeof(h264_rtp_extra_data) + | |
322 FF_INPUT_BUFFER_PADDING_SIZE); | |
323 | |
324 if (data) { | |
325 data->cookie = MAGIC_COOKIE; | |
326 } | |
327 | |
328 return data; | |
329 } | |
330 | |
331 static void h264_free_extradata(void *d) | |
332 { | |
333 h264_rtp_extra_data *data = (h264_rtp_extra_data *) d; | |
334 #ifdef DEBUG | |
335 int ii; | |
336 | |
337 for (ii = 0; ii < 32; ii++) { | |
338 if (data->packet_types_received[ii]) | |
339 av_log(NULL, AV_LOG_DEBUG, "Received %d packets of type %d\n", | |
340 data->packet_types_received[ii], ii); | |
341 } | |
342 #endif | |
343 | |
344 assert(data); | |
345 assert(data->cookie == MAGIC_COOKIE); | |
346 | |
347 // avoid stale pointers (assert) | |
348 data->cookie = DEAD_COOKIE; | |
349 | |
350 // and clear out this... | |
351 av_free(data); | |
352 } | |
353 | |
354 static int parse_h264_sdp_line(AVStream * stream, void *data, | |
355 const char *line) | |
356 { | |
357 AVCodecContext *codec = stream->codec; | |
358 h264_rtp_extra_data *h264_data = (h264_rtp_extra_data *) data; | |
359 const char *p = line; | |
360 | |
361 assert(h264_data->cookie == MAGIC_COOKIE); | |
362 | |
2193
5ce5fad0dfac
replace the uses of old string functions that Reimar missed
mru
parents:
2156
diff
changeset
|
363 if (av_strstart(p, "framesize:", &p)) { |
1460 | 364 char buf1[50]; |
365 char *dst = buf1; | |
366 | |
367 // remove the protocol identifier.. | |
368 while (*p && *p == ' ') p++; // strip spaces. | |
369 while (*p && *p != ' ') p++; // eat protocol identifier | |
370 while (*p && *p == ' ') p++; // strip trailing spaces. | |
371 while (*p && *p != '-' && (buf1 - dst) < sizeof(buf1) - 1) { | |
372 *dst++ = *p++; | |
373 } | |
374 *dst = '\0'; | |
375 | |
376 // a='framesize:96 320-240' | |
377 // set our parameters.. | |
378 codec->width = atoi(buf1); | |
379 codec->height = atoi(p + 1); // skip the - | |
380 codec->pix_fmt = PIX_FMT_YUV420P; | |
2193
5ce5fad0dfac
replace the uses of old string functions that Reimar missed
mru
parents:
2156
diff
changeset
|
381 } else if (av_strstart(p, "fmtp:", &p)) { |
1460 | 382 char attr[256]; |
383 char value[4096]; | |
384 | |
385 // remove the protocol identifier.. | |
386 while (*p && *p == ' ') p++; // strip spaces. | |
387 while (*p && *p != ' ') p++; // eat protocol identifier | |
388 while (*p && *p == ' ') p++; // strip trailing spaces. | |
389 | |
390 /* loop on each attribute */ | |
391 while (rtsp_next_attr_and_value | |
392 (&p, attr, sizeof(attr), value, sizeof(value))) { | |
393 /* grab the codec extra_data from the config parameter of the fmtp line */ | |
394 sdp_parse_fmtp_config_h264(stream, h264_data, attr, value); | |
395 } | |
2193
5ce5fad0dfac
replace the uses of old string functions that Reimar missed
mru
parents:
2156
diff
changeset
|
396 } else if (av_strstart(p, "cliprect:", &p)) { |
1460 | 397 // could use this if we wanted. |
398 } | |
399 | |
400 av_set_pts_info(stream, 33, 1, 90000); // 33 should be right, because the pts is 64 bit? (done elsewhere; this is a one time thing) | |
401 | |
402 return 0; // keep processing it the normal way... | |
403 } | |
404 | |
405 /** | |
406 This is the structure for expanding on the dynamic rtp protocols (makes everything static. yay!) | |
407 */ | |
408 RTPDynamicProtocolHandler ff_h264_dynamic_handler = { | |
409 "H264", | |
410 CODEC_TYPE_VIDEO, | |
411 CODEC_ID_H264, | |
412 parse_h264_sdp_line, | |
413 h264_new_extradata, | |
414 h264_free_extradata, | |
415 h264_handle_packet | |
416 }; |