rtpdec_h264.c
Go to the documentation of this file.
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
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,
33  * FU-B packet types)
34  */
35 
36 #include "libavutil/base64.h"
37 #include "libavutil/avstring.h"
38 #include "libavcodec/get_bits.h"
39 #include "avformat.h"
40 
41 #include "network.h"
42 #include <assert.h>
43 
44 #include "rtpdec.h"
45 #include "rtpdec_formats.h"
46 
47 struct PayloadContext {
48  // sdp setup parameters
53 #ifdef DEBUG
54  int packet_types_received[32];
55 #endif
56 };
57 
58 #ifdef DEBUG
59 #define COUNT_NAL_TYPE(data, nal) data->packet_types_received[(nal) & 0x1f]++
60 #else
61 #define COUNT_NAL_TYPE(data, nal) do { } while (0)
62 #endif
63 
64 static const uint8_t start_sequence[] = { 0, 0, 0, 1 };
65 
67  PayloadContext *h264_data,
68  char *attr, char *value)
69 {
70  AVCodecContext *codec = stream->codec;
71  assert(codec->codec_id == AV_CODEC_ID_H264);
72  assert(h264_data != NULL);
73 
74  if (!strcmp(attr, "packetization-mode")) {
75  av_log(codec, AV_LOG_DEBUG, "RTP Packetization Mode: %d\n", atoi(value));
76  h264_data->packetization_mode = atoi(value);
77  /*
78  * Packetization Mode:
79  * 0 or not present: Single NAL mode (Only nals from 1-23 are allowed)
80  * 1: Non-interleaved Mode: 1-23, 24 (STAP-A), 28 (FU-A) are allowed.
81  * 2: Interleaved Mode: 25 (STAP-B), 26 (MTAP16), 27 (MTAP24), 28 (FU-A),
82  * and 29 (FU-B) are allowed.
83  */
84  if (h264_data->packetization_mode > 1)
85  av_log(codec, AV_LOG_ERROR,
86  "Interleaved RTP mode is not supported yet.\n");
87  } else if (!strcmp(attr, "profile-level-id")) {
88  if (strlen(value) == 6) {
89  char buffer[3];
90  // 6 characters=3 bytes, in hex.
94 
95  buffer[0] = value[0];
96  buffer[1] = value[1];
97  buffer[2] = '\0';
98  profile_idc = strtol(buffer, NULL, 16);
99  buffer[0] = value[2];
100  buffer[1] = value[3];
101  profile_iop = strtol(buffer, NULL, 16);
102  buffer[0] = value[4];
103  buffer[1] = value[5];
104  level_idc = strtol(buffer, NULL, 16);
105 
106  av_log(codec, AV_LOG_DEBUG,
107  "RTP Profile IDC: %x Profile IOP: %x Level: %x\n",
108  profile_idc, profile_iop, level_idc);
109  h264_data->profile_idc = profile_idc;
110  h264_data->profile_iop = profile_iop;
111  h264_data->level_idc = level_idc;
112  }
113  } else if (!strcmp(attr, "sprop-parameter-sets")) {
114  codec->extradata_size = 0;
115  av_freep(&codec->extradata);
116 
117  while (*value) {
118  char base64packet[1024];
119  uint8_t decoded_packet[1024];
120  int packet_size;
121  char *dst = base64packet;
122 
123  while (*value && *value != ','
124  && (dst - base64packet) < sizeof(base64packet) - 1) {
125  *dst++ = *value++;
126  }
127  *dst++ = '\0';
128 
129  if (*value == ',')
130  value++;
131 
132  packet_size = av_base64_decode(decoded_packet, base64packet,
133  sizeof(decoded_packet));
134  if (packet_size > 0) {
135  uint8_t *dest = av_malloc(packet_size + sizeof(start_sequence) +
136  codec->extradata_size +
138  if (!dest) {
139  av_log(codec, AV_LOG_ERROR,
140  "Unable to allocate memory for extradata!\n");
141  return AVERROR(ENOMEM);
142  }
143  if (codec->extradata_size) {
144  memcpy(dest, codec->extradata, codec->extradata_size);
145  av_free(codec->extradata);
146  }
147 
148  memcpy(dest + codec->extradata_size, start_sequence,
149  sizeof(start_sequence));
150  memcpy(dest + codec->extradata_size + sizeof(start_sequence),
151  decoded_packet, packet_size);
152  memset(dest + codec->extradata_size + sizeof(start_sequence) +
153  packet_size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
154 
155  codec->extradata = dest;
156  codec->extradata_size += sizeof(start_sequence) + packet_size;
157  }
158  }
159  av_log(codec, AV_LOG_DEBUG, "Extradata set to %p (size: %d)!\n",
160  codec->extradata, codec->extradata_size);
161  }
162  return 0;
163 }
164 
165 // return 0 on packet, no more left, 1 on packet, 1 on partial packet
167  AVStream *st, AVPacket *pkt, uint32_t *timestamp,
168  const uint8_t *buf, int len, uint16_t seq,
169  int flags)
170 {
171  uint8_t nal;
172  uint8_t type;
173  int result = 0;
174 
175  if (!len) {
176  av_log(ctx, AV_LOG_ERROR, "Empty H264 RTP packet\n");
177  return AVERROR_INVALIDDATA;
178  }
179  nal = buf[0];
180  type = nal & 0x1f;
181 
182  assert(data);
183  assert(buf);
184 
185  /* Simplify the case (these are all the nal types used internally by
186  * the h264 codec). */
187  if (type >= 1 && type <= 23)
188  type = 1;
189  switch (type) {
190  case 0: // undefined, but pass them through
191  case 1:
192  av_new_packet(pkt, len + sizeof(start_sequence));
193  memcpy(pkt->data, start_sequence, sizeof(start_sequence));
194  memcpy(pkt->data + sizeof(start_sequence), buf, len);
195  COUNT_NAL_TYPE(data, nal);
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  while (src_len > 2) {
213  uint16_t nal_size = AV_RB16(src);
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  COUNT_NAL_TYPE(data, *src);
230  dst += nal_size;
231  }
232  } else {
233  av_log(ctx, AV_LOG_ERROR,
234  "nal size exceeds length: %d %d\n", nal_size, src_len);
235  }
236 
237  // eat what we handled
238  src += nal_size;
239  src_len -= nal_size;
240 
241  if (src_len < 0)
242  av_log(ctx, AV_LOG_ERROR,
243  "Consumed more bytes than we got! (%d)\n", src_len);
244  }
245 
246  if (pass == 0) {
247  /* now we know the total size of the packet (with the
248  * start sequences added) */
249  av_new_packet(pkt, total_length);
250  dst = pkt->data;
251  } else {
252  assert(dst - pkt->data == total_length);
253  }
254  }
255  }
256  break;
257 
258  case 25: // STAP-B
259  case 26: // MTAP-16
260  case 27: // MTAP-24
261  case 29: // FU-B
262  av_log(ctx, AV_LOG_ERROR,
263  "Unhandled type (%d) (See RFC for implementation details\n",
264  type);
265  result = AVERROR(ENOSYS);
266  break;
267 
268  case 28: // FU-A (fragmented nal)
269  buf++;
270  len--; // skip the fu_indicator
271  if (len > 1) {
272  // these are the same as above, we just redo them here for clarity
273  uint8_t fu_indicator = nal;
274  uint8_t fu_header = *buf;
275  uint8_t start_bit = fu_header >> 7;
276  uint8_t av_unused end_bit = (fu_header & 0x40) >> 6;
277  uint8_t nal_type = fu_header & 0x1f;
278  uint8_t reconstructed_nal;
279 
280  // Reconstruct this packet's true nal; only the data follows.
281  /* The original nal forbidden bit and NRI are stored in this
282  * packet's nal. */
283  reconstructed_nal = fu_indicator & 0xe0;
284  reconstructed_nal |= nal_type;
285 
286  // skip the fu_header
287  buf++;
288  len--;
289 
290  if (start_bit)
291  COUNT_NAL_TYPE(data, nal_type);
292  if (start_bit) {
293  /* copy in the start sequence, and the reconstructed nal */
294  av_new_packet(pkt, sizeof(start_sequence) + sizeof(nal) + len);
295  memcpy(pkt->data, start_sequence, sizeof(start_sequence));
296  pkt->data[sizeof(start_sequence)] = reconstructed_nal;
297  memcpy(pkt->data + sizeof(start_sequence) + sizeof(nal), buf, len);
298  } else {
299  av_new_packet(pkt, len);
300  memcpy(pkt->data, buf, len);
301  }
302  } else {
303  av_log(ctx, AV_LOG_ERROR, "Too short data for FU-A H264 RTP packet\n");
304  result = AVERROR_INVALIDDATA;
305  }
306  break;
307 
308  case 30: // undefined
309  case 31: // undefined
310  default:
311  av_log(ctx, AV_LOG_ERROR, "Undefined type (%d)\n", type);
312  result = AVERROR_INVALIDDATA;
313  break;
314  }
315 
316  pkt->stream_index = st->index;
317 
318  return result;
319 }
320 
322 {
324 }
325 
327 {
328 #ifdef DEBUG
329  int ii;
330 
331  for (ii = 0; ii < 32; ii++) {
332  if (data->packet_types_received[ii])
333  av_log(NULL, AV_LOG_DEBUG, "Received %d packets of type %d\n",
334  data->packet_types_received[ii], ii);
335  }
336 #endif
337 
338  av_free(data);
339 }
340 
341 static int h264_init(AVFormatContext *s, int st_index, PayloadContext *data)
342 {
343  if (st_index < 0)
344  return 0;
345  s->streams[st_index]->need_parsing = AVSTREAM_PARSE_FULL;
346  return 0;
347 }
348 
349 static int parse_h264_sdp_line(AVFormatContext *s, int st_index,
350  PayloadContext *h264_data, const char *line)
351 {
352  AVStream *stream;
353  AVCodecContext *codec;
354  const char *p = line;
355 
356  if (st_index < 0)
357  return 0;
358 
359  stream = s->streams[st_index];
360  codec = stream->codec;
361 
362  if (av_strstart(p, "framesize:", &p)) {
363  char buf1[50];
364  char *dst = buf1;
365 
366  // remove the protocol identifier
367  while (*p && *p == ' ')
368  p++; // strip spaces.
369  while (*p && *p != ' ')
370  p++; // eat protocol identifier
371  while (*p && *p == ' ')
372  p++; // strip trailing spaces.
373  while (*p && *p != '-' && (dst - buf1) < sizeof(buf1) - 1)
374  *dst++ = *p++;
375  *dst = '\0';
376 
377  // a='framesize:96 320-240'
378  // set our parameters
379  codec->width = atoi(buf1);
380  codec->height = atoi(p + 1); // skip the -
381  } else if (av_strstart(p, "fmtp:", &p)) {
382  return ff_parse_fmtp(stream, h264_data, p, sdp_parse_fmtp_config_h264);
383  } else if (av_strstart(p, "cliprect:", &p)) {
384  // could use this if we wanted.
385  }
386 
387  return 0;
388 }
389 
391  .enc_name = "H264",
392  .codec_type = AVMEDIA_TYPE_VIDEO,
393  .codec_id = AV_CODEC_ID_H264,
394  .init = h264_init,
395  .parse_sdp_a_line = parse_h264_sdp_line,
396  .alloc = h264_new_context,
397  .free = h264_free_context,
398  .parse_packet = h264_handle_packet
399 };
uint8_t profile_idc
Definition: rtpdec_h264.c:49
AVPacket pkt
Definition: rtpdec_qt.c:37
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:205
const char * s
Definition: avisynth_c.h:668
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
static int sdp_parse_fmtp_config_h264(AVStream *stream, PayloadContext *h264_data, char *attr, char *value)
Definition: rtpdec_h264.c:66
char buffer[RTP_MAX_PACKET_LENGTH+FF_INPUT_BUFFER_PADDING_SIZE]
Definition: rdt.c:89
RTP/JPEG specific private data.
Definition: rdt.c:83
int index
stream index in AVFormatContext
Definition: avformat.h:644
int packetization_mode
Definition: rtpdec_h264.c:52
#define pass
Definition: fft.c:335
RTPDynamicProtocolHandler ff_h264_dynamic_handler
Definition: rtpdec_h264.c:390
uint8_t * buf
the temporary storage buffer
Definition: rtpdec_asf.c:160
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
Format I/O context.
Definition: avformat.h:944
static void h264_free_context(PayloadContext *data)
Definition: rtpdec_h264.c:326
uint8_t
enum AVStreamParseType need_parsing
Definition: avformat.h:811
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
AVStream ** streams
Definition: avformat.h:992
uint8_t * data
bitstream reader API header.
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: avpacket.c:73
static PayloadContext * h264_new_context(void)
Definition: rtpdec_h264.c:321
uint32_t timestamp
current frame timestamp
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:183
#define AV_RB16
Definition: graph2dot.c:48
static int parse_h264_sdp_line(AVFormatContext *s, int st_index, PayloadContext *h264_data, const char *line)
Definition: rtpdec_h264.c:349
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
AVCodecContext * codec
Codec context associated with this stream.
Definition: avformat.h:662
#define FF_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding...
int width
picture width / height.
static int h264_init(AVFormatContext *s, int st_index, PayloadContext *data)
Definition: rtpdec_h264.c:341
uint8_t profile_iop
Definition: rtpdec_h264.c:50
#define COUNT_NAL_TYPE(data, nal)
Definition: rtpdec_h264.c:61
Stream structure.
Definition: avformat.h:643
NULL
Definition: eval.c:55
dest
Definition: start.py:60
AVS_Value src
Definition: avisynth_c.h:523
AVIOContext * data
Definition: rtpdec_vp8.c:35
enum AVCodecID codec_id
main external API structure.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
uint8_t level_idc
Definition: rtpdec_h264.c:51
double value
Definition: eval.c:82
void * av_malloc(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:73
const char enc_name[50]
Definition: rtpdec.h:120
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
#define type
static int flags
Definition: cpu.c:23
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
Definition: avstring.c:33
full parsing and repack
Definition: avformat.h:582
Main libavformat public API header.
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:162
static int h264_handle_packet(AVFormatContext *ctx, PayloadContext *data, AVStream *st, AVPacket *pkt, uint32_t *timestamp, const uint8_t *buf, int len, uint16_t seq, int flags)
Definition: rtpdec_h264.c:166
else dst[i][x+y *dst_stride[i]]
Definition: vf_mcdeint.c:160
About Git write you should know how to use GIT properly Luckily Git comes with excellent documentation git help man git shows you the available git< command > help man git< command > shows information about the subcommand< command > The most comprehensive manual is the website Git Reference visit they are quite exhaustive You do not need a special username or password All you need is to provide a ssh public key to the Git server admin What follows now is a basic introduction to Git and some FFmpeg specific guidelines Read it at least if you are granted commit privileges to the FFmpeg project you are expected to be familiar with these rules I if not You can get git from etc no matter how small Every one of them has been saved from looking like a fool by this many times It s very easy for stray debug output or cosmetic modifications to slip please avoid problems through this extra level of scrutiny For cosmetics only commits you should e g by running git config global user name My Name git config global user email my email which is either set in your personal configuration file through git config core editor or set by one of the following environment VISUAL or EDITOR Log messages should be concise but descriptive Explain why you made a what you did will be obvious from the changes themselves most of the time Saying just bug fix or is bad Remember that people of varying skill levels look at and educate themselves while reading through your code Don t include filenames in log Git provides that information Possibly make the commit message have a descriptive first line
Definition: git-howto.txt:153
static const uint8_t start_sequence[]
Definition: rtpdec_h264.c:64
int av_base64_decode(uint8_t *out, const char *in_str, int out_size)
Decode a base64-encoded string.
int ff_parse_fmtp(AVStream *stream, PayloadContext *data, const char *p, int(*parse_fmtp)(AVStream *stream, PayloadContext *data, char *attr, char *value))
Definition: rtpdec.c:829
This structure stores compressed data.
#define av_unused
Definition: attributes.h:114