ffmpeg / libavformat / rtpdec_h264.c @ 72415b2a
History | View | Annotate | Download (14.6 KB)
1 | 1d1be919 | Ryan Martell | /*
|
---|---|---|---|
2 | * RTP H264 Protocol (RFC3984)
|
||
3 | 406792e7 | Diego Biurrun | * Copyright (c) 2006 Ryan Martell
|
4 | 1d1be919 | Ryan Martell | *
|
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 | f65919af | Martin Storsjö | * @file libavformat/rtpdec_h264.c
|
24 | 1d1be919 | Ryan Martell | * @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 | |||
39 | 245976da | Diego Biurrun | #include "libavutil/base64.h" |
40 | #include "libavutil/avstring.h" |
||
41 | 9106a698 | Stefano Sabatini | #include "libavcodec/get_bits.h" |
42 | 1d1be919 | Ryan Martell | #include "avformat.h" |
43 | #include "mpegts.h" |
||
44 | |||
45 | #include <unistd.h> |
||
46 | 42572ef5 | Ramiro Polla | #include "network.h" |
47 | 1d1be919 | Ryan Martell | #include <assert.h> |
48 | |||
49 | 302879cb | Luca Abeni | #include "rtpdec.h" |
50 | f65919af | Martin Storsjö | #include "rtpdec_h264.h" |
51 | 1d1be919 | Ryan Martell | |
52 | /**
|
||
53 | RTP/H264 specific private data.
|
||
54 | */
|
||
55 | ed0aacc7 | Ronald S. Bultje | struct PayloadContext {
|
56 | 1d1be919 | Ryan Martell | 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 | ed0aacc7 | Ronald S. Bultje | }; |
67 | 1d1be919 | Ryan Martell | |
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 | ed0aacc7 | Ronald S. Bultje | PayloadContext * h264_data, |
74 | 1d1be919 | Ryan Martell | 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")) { |
||
81 | 2fddbb68 | Benoit Fouet | av_log(codec, AV_LOG_DEBUG, "RTP Packetization Mode: %d\n", atoi(value));
|
82 | 272872e4 | Luca Barbato | h264_data->packetization_mode = atoi(value); |
83 | 1d1be919 | Ryan Martell | /*
|
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 | 2fddbb68 | Benoit Fouet | av_log(codec, AV_LOG_ERROR, |
91 | "Interleaved RTP mode is not supported yet.");
|
||
92 | 1d1be919 | Ryan Martell | } 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 | 2fddbb68 | Benoit Fouet | av_log(codec, AV_LOG_DEBUG, |
109 | "RTP Profile IDC: %x Profile IOP: %x Level: %x\n",
|
||
110 | 1d1be919 | Ryan Martell | 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 | b9b8ed2a | Martin Storsjö | uint8_t *dest = av_malloc(packet_size + sizeof(start_sequence) +
|
138 | codec->extradata_size + |
||
139 | FF_INPUT_BUFFER_PADDING_SIZE); |
||
140 | 1d1be919 | Ryan Martell | if(dest)
|
141 | { |
||
142 | if(codec->extradata_size)
|
||
143 | { |
||
144 | // av_realloc?
|
||
145 | memcpy(dest, codec->extradata, codec->extradata_size); |
||
146 | av_free(codec->extradata); |
||
147 | } |
||
148 | |||
149 | memcpy(dest+codec->extradata_size, start_sequence, sizeof(start_sequence));
|
||
150 | memcpy(dest+codec->extradata_size+sizeof(start_sequence), decoded_packet, packet_size);
|
||
151 | b9b8ed2a | Martin Storsjö | memset(dest+codec->extradata_size+sizeof(start_sequence)+
|
152 | packet_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
|
||
153 | 1d1be919 | Ryan Martell | |
154 | codec->extradata= dest; |
||
155 | codec->extradata_size+= sizeof(start_sequence)+packet_size;
|
||
156 | } else {
|
||
157 | 2fddbb68 | Benoit Fouet | av_log(codec, AV_LOG_ERROR, "Unable to allocate memory for extradata!");
|
158 | 1d1be919 | Ryan Martell | } |
159 | } |
||
160 | } |
||
161 | 2fddbb68 | Benoit Fouet | av_log(codec, AV_LOG_DEBUG, "Extradata set to %p (size: %d)!", codec->extradata, codec->extradata_size);
|
162 | 1d1be919 | Ryan Martell | } |
163 | } |
||
164 | |||
165 | // return 0 on packet, no more left, 1 on packet, 1 on partial packet...
|
||
166 | 1a45a9f4 | Ronald S. Bultje | static int h264_handle_packet(AVFormatContext *ctx, |
167 | PayloadContext *data, |
||
168 | 9b932b8a | Ronald S. Bultje | AVStream *st, |
169 | 1d1be919 | Ryan Martell | AVPacket * pkt, |
170 | uint32_t * timestamp, |
||
171 | const uint8_t * buf,
|
||
172 | f841a0fc | Ronald S. Bultje | int len, int flags) |
173 | 1d1be919 | Ryan Martell | { |
174 | uint8_t nal = buf[0];
|
||
175 | uint8_t type = (nal & 0x1f);
|
||
176 | int result= 0; |
||
177 | uint8_t start_sequence[]= {0, 0, 1}; |
||
178 | |||
179 | 7cf6af27 | François Revol | #ifdef DEBUG
|
180 | 1d1be919 | Ryan Martell | assert(data); |
181 | assert(data->cookie == MAGIC_COOKIE); |
||
182 | 7cf6af27 | François Revol | #endif
|
183 | 1d1be919 | Ryan Martell | assert(buf); |
184 | |||
185 | if (type >= 1 && type <= 23) |
||
186 | type = 1; // simplify the case. (these are all the nal types used internally by the h264 codec) |
||
187 | switch (type) {
|
||
188 | case 0: // undefined; |
||
189 | result= -1;
|
||
190 | break;
|
||
191 | |||
192 | case 1: |
||
193 | av_new_packet(pkt, len+sizeof(start_sequence));
|
||
194 | memcpy(pkt->data, start_sequence, sizeof(start_sequence));
|
||
195 | memcpy(pkt->data+sizeof(start_sequence), buf, len);
|
||
196 | #ifdef DEBUG
|
||
197 | data->packet_types_received[nal & 0x1f]++;
|
||
198 | #endif
|
||
199 | break;
|
||
200 | |||
201 | case 24: // STAP-A (one packet, multiple nals) |
||
202 | // consume the STAP-A NAL
|
||
203 | buf++; |
||
204 | len--; |
||
205 | // first we are going to figure out the total size....
|
||
206 | { |
||
207 | int pass= 0; |
||
208 | int total_length= 0; |
||
209 | uint8_t *dst= NULL;
|
||
210 | |||
211 | for(pass= 0; pass<2; pass++) { |
||
212 | const uint8_t *src= buf;
|
||
213 | int src_len= len;
|
||
214 | |||
215 | do {
|
||
216 | fead30d4 | Alex Beregszaszi | uint16_t nal_size = AV_RB16(src); // this going to be a problem if unaligned (can it be?)
|
217 | 1d1be919 | Ryan Martell | |
218 | // consume the length of the aggregate...
|
||
219 | src += 2;
|
||
220 | src_len -= 2;
|
||
221 | |||
222 | if (nal_size <= src_len) {
|
||
223 | if(pass==0) { |
||
224 | // counting...
|
||
225 | total_length+= sizeof(start_sequence)+nal_size;
|
||
226 | } else {
|
||
227 | // copying
|
||
228 | assert(dst); |
||
229 | memcpy(dst, start_sequence, sizeof(start_sequence));
|
||
230 | dst+= sizeof(start_sequence);
|
||
231 | memcpy(dst, src, nal_size); |
||
232 | #ifdef DEBUG
|
||
233 | data->packet_types_received[*src & 0x1f]++;
|
||
234 | #endif
|
||
235 | dst+= nal_size; |
||
236 | } |
||
237 | } else {
|
||
238 | 2fddbb68 | Benoit Fouet | av_log(ctx, AV_LOG_ERROR, |
239 | 1d1be919 | Ryan Martell | "nal size exceeds length: %d %d\n", nal_size, src_len);
|
240 | } |
||
241 | |||
242 | // eat what we handled...
|
||
243 | src += nal_size; |
||
244 | src_len -= nal_size; |
||
245 | |||
246 | if (src_len < 0) |
||
247 | 2fddbb68 | Benoit Fouet | av_log(ctx, AV_LOG_ERROR, |
248 | 1d1be919 | Ryan Martell | "Consumed more bytes than we got! (%d)\n", src_len);
|
249 | } while (src_len > 2); // because there could be rtp padding.. |
||
250 | |||
251 | if(pass==0) { |
||
252 | // now we know the total size of the packet (with the start sequences added)
|
||
253 | av_new_packet(pkt, total_length); |
||
254 | dst= pkt->data; |
||
255 | } else {
|
||
256 | assert(dst-pkt->data==total_length); |
||
257 | } |
||
258 | } |
||
259 | } |
||
260 | break;
|
||
261 | |||
262 | case 25: // STAP-B |
||
263 | case 26: // MTAP-16 |
||
264 | case 27: // MTAP-24 |
||
265 | case 29: // FU-B |
||
266 | 2fddbb68 | Benoit Fouet | av_log(ctx, AV_LOG_ERROR, |
267 | 1d1be919 | Ryan Martell | "Unhandled type (%d) (See RFC for implementation details\n",
|
268 | type); |
||
269 | result= -1;
|
||
270 | break;
|
||
271 | |||
272 | case 28: // FU-A (fragmented nal) |
||
273 | buf++; |
||
274 | len--; // skip the fu_indicator
|
||
275 | { |
||
276 | // these are the same as above, we just redo them here for clarity...
|
||
277 | uint8_t fu_indicator = nal; |
||
278 | uint8_t fu_header = *buf; // read the fu_header.
|
||
279 | 6ab6525e | Panagiotis Issaris | uint8_t start_bit = fu_header >> 7;
|
280 | 1d1be919 | Ryan Martell | // uint8_t end_bit = (fu_header & 0x40) >> 6;
|
281 | uint8_t nal_type = (fu_header & 0x1f);
|
||
282 | uint8_t reconstructed_nal; |
||
283 | |||
284 | // reconstruct this packet's true nal; only the data follows..
|
||
285 | reconstructed_nal = fu_indicator & (0xe0); // the original nal forbidden bit and NRI are stored in this packet's nal; |
||
286 | 7699645e | Panagiotis Issaris | reconstructed_nal |= nal_type; |
287 | 1d1be919 | Ryan Martell | |
288 | // skip the fu_header...
|
||
289 | buf++; |
||
290 | len--; |
||
291 | |||
292 | #ifdef DEBUG
|
||
293 | if (start_bit)
|
||
294 | 716f6b47 | Panagiotis Issaris | data->packet_types_received[nal_type]++; |
295 | 1d1be919 | Ryan Martell | #endif
|
296 | if(start_bit) {
|
||
297 | // copy in the start sequence, and the reconstructed nal....
|
||
298 | av_new_packet(pkt, sizeof(start_sequence)+sizeof(nal)+len); |
||
299 | memcpy(pkt->data, start_sequence, sizeof(start_sequence));
|
||
300 | pkt->data[sizeof(start_sequence)]= reconstructed_nal;
|
||
301 | memcpy(pkt->data+sizeof(start_sequence)+sizeof(nal), buf, len); |
||
302 | } else {
|
||
303 | av_new_packet(pkt, len); |
||
304 | memcpy(pkt->data, buf, len); |
||
305 | } |
||
306 | } |
||
307 | break;
|
||
308 | |||
309 | case 30: // undefined |
||
310 | case 31: // undefined |
||
311 | default:
|
||
312 | 2fddbb68 | Benoit Fouet | av_log(ctx, AV_LOG_ERROR, "Undefined type (%d)", type);
|
313 | 1d1be919 | Ryan Martell | result= -1;
|
314 | break;
|
||
315 | } |
||
316 | |||
317 | eafb17d1 | Ronald S. Bultje | pkt->stream_index = st->index; |
318 | |||
319 | 1d1be919 | Ryan Martell | return result;
|
320 | } |
||
321 | |||
322 | /* ---------------- public code */
|
||
323 | 202a6697 | Colin McQuillan | static PayloadContext *h264_new_context(void) |
324 | 1d1be919 | Ryan Martell | { |
325 | ed0aacc7 | Ronald S. Bultje | PayloadContext *data = |
326 | av_mallocz(sizeof(PayloadContext) +
|
||
327 | 1d1be919 | Ryan Martell | FF_INPUT_BUFFER_PADDING_SIZE); |
328 | |||
329 | if (data) {
|
||
330 | data->cookie = MAGIC_COOKIE; |
||
331 | } |
||
332 | |||
333 | return data;
|
||
334 | } |
||
335 | |||
336 | 202a6697 | Colin McQuillan | static void h264_free_context(PayloadContext *data) |
337 | 1d1be919 | Ryan Martell | { |
338 | #ifdef DEBUG
|
||
339 | int ii;
|
||
340 | |||
341 | for (ii = 0; ii < 32; ii++) { |
||
342 | if (data->packet_types_received[ii])
|
||
343 | av_log(NULL, AV_LOG_DEBUG, "Received %d packets of type %d\n", |
||
344 | data->packet_types_received[ii], ii); |
||
345 | } |
||
346 | #endif
|
||
347 | |||
348 | assert(data); |
||
349 | assert(data->cookie == MAGIC_COOKIE); |
||
350 | |||
351 | // avoid stale pointers (assert)
|
||
352 | data->cookie = DEAD_COOKIE; |
||
353 | |||
354 | // and clear out this...
|
||
355 | av_free(data); |
||
356 | } |
||
357 | |||
358 | 7b2a0708 | Ronald S. Bultje | static int parse_h264_sdp_line(AVFormatContext *s, int st_index, |
359 | PayloadContext *h264_data, const char *line) |
||
360 | 1d1be919 | Ryan Martell | { |
361 | 7b2a0708 | Ronald S. Bultje | AVStream *stream = s->streams[st_index]; |
362 | 1d1be919 | Ryan Martell | AVCodecContext *codec = stream->codec; |
363 | const char *p = line; |
||
364 | |||
365 | assert(h264_data->cookie == MAGIC_COOKIE); |
||
366 | |||
367 | f7d78f36 | Måns Rullgård | if (av_strstart(p, "framesize:", &p)) { |
368 | 1d1be919 | Ryan Martell | char buf1[50]; |
369 | char *dst = buf1;
|
||
370 | |||
371 | // remove the protocol identifier..
|
||
372 | while (*p && *p == ' ') p++; // strip spaces. |
||
373 | while (*p && *p != ' ') p++; // eat protocol identifier |
||
374 | while (*p && *p == ' ') p++; // strip trailing spaces. |
||
375 | 9cad7e21 | Gordon Irlam | while (*p && *p != '-' && (dst - buf1) < sizeof(buf1) - 1) { |
376 | 1d1be919 | Ryan Martell | *dst++ = *p++; |
377 | } |
||
378 | *dst = '\0';
|
||
379 | |||
380 | // a='framesize:96 320-240'
|
||
381 | // set our parameters..
|
||
382 | codec->width = atoi(buf1); |
||
383 | codec->height = atoi(p + 1); // skip the - |
||
384 | codec->pix_fmt = PIX_FMT_YUV420P; |
||
385 | f7d78f36 | Måns Rullgård | } else if (av_strstart(p, "fmtp:", &p)) { |
386 | 1d1be919 | Ryan Martell | char attr[256]; |
387 | char value[4096]; |
||
388 | |||
389 | // remove the protocol identifier..
|
||
390 | while (*p && *p == ' ') p++; // strip spaces. |
||
391 | while (*p && *p != ' ') p++; // eat protocol identifier |
||
392 | while (*p && *p == ' ') p++; // strip trailing spaces. |
||
393 | |||
394 | /* loop on each attribute */
|
||
395 | 3307e6ea | Ronald S. Bultje | while (ff_rtsp_next_attr_and_value
|
396 | 1d1be919 | Ryan Martell | (&p, attr, sizeof(attr), value, sizeof(value))) { |
397 | /* grab the codec extra_data from the config parameter of the fmtp line */
|
||
398 | sdp_parse_fmtp_config_h264(stream, h264_data, attr, value); |
||
399 | } |
||
400 | f7d78f36 | Måns Rullgård | } else if (av_strstart(p, "cliprect:", &p)) { |
401 | 1d1be919 | Ryan Martell | // could use this if we wanted.
|
402 | } |
||
403 | |||
404 | 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) |
||
405 | |||
406 | return 0; // keep processing it the normal way... |
||
407 | } |
||
408 | |||
409 | /**
|
||
410 | This is the structure for expanding on the dynamic rtp protocols (makes everything static. yay!)
|
||
411 | */
|
||
412 | RTPDynamicProtocolHandler ff_h264_dynamic_handler = { |
||
413 | 202a6697 | Colin McQuillan | .enc_name = "H264",
|
414 | 72415b2a | Stefano Sabatini | .codec_type = AVMEDIA_TYPE_VIDEO, |
415 | 202a6697 | Colin McQuillan | .codec_id = CODEC_ID_H264, |
416 | .parse_sdp_a_line = parse_h264_sdp_line, |
||
417 | .open = h264_new_context, |
||
418 | .close = h264_free_context, |
||
419 | .parse_packet = h264_handle_packet |
||
420 | 1d1be919 | Ryan Martell | }; |