FFmpeg
rtpdec_h264.c
Go to the documentation of this file.
1 /*
2  * RTP H.264 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/attributes.h"
37 #include "libavutil/base64.h"
38 #include "libavutil/intreadwrite.h"
39 #include "libavutil/avstring.h"
40 #include "libavutil/mem.h"
41 #include "avformat.h"
42 
43 #include "rtpdec.h"
44 #include "rtpdec_formats.h"
45 
46 struct PayloadContext {
47  // sdp setup parameters
48  uint8_t profile_idc;
49  uint8_t profile_iop;
50  uint8_t level_idc;
52 #ifdef DEBUG
53  int packet_types_received[32];
54 #endif
55 };
56 
57 #ifdef DEBUG
58 #define COUNT_NAL_TYPE(data, nal) data->packet_types_received[(nal) & 0x1f]++
59 #define NAL_COUNTERS data->packet_types_received
60 #else
61 #define COUNT_NAL_TYPE(data, nal) do { } while (0)
62 #define NAL_COUNTERS NULL
63 #endif
64 #define NAL_MASK 0x1f
65 
66 static const uint8_t start_sequence[] = { 0, 0, 0, 1 };
67 
69  PayloadContext *h264_data,
70  const char *value)
71 {
72  char buffer[3];
73  // 6 characters=3 bytes, in hex.
74  uint8_t profile_idc;
75  uint8_t profile_iop;
76  uint8_t level_idc;
77 
78  buffer[0] = value[0];
79  buffer[1] = value[1];
80  buffer[2] = '\0';
81  profile_idc = strtol(buffer, NULL, 16);
82  buffer[0] = value[2];
83  buffer[1] = value[3];
84  profile_iop = strtol(buffer, NULL, 16);
85  buffer[0] = value[4];
86  buffer[1] = value[5];
87  level_idc = strtol(buffer, NULL, 16);
88 
90  "RTP Profile IDC: %x Profile IOP: %x Level: %x\n",
91  profile_idc, profile_iop, level_idc);
92  h264_data->profile_idc = profile_idc;
93  h264_data->profile_iop = profile_iop;
94  h264_data->level_idc = level_idc;
95 }
96 
98  uint8_t **data_ptr, int *size_ptr,
99  const char *value)
100 {
101  char base64packet[1024];
102  uint8_t decoded_packet[1024];
103  int packet_size;
104 
105  while (*value) {
106  char *dst = base64packet;
107 
108  while (*value && *value != ','
109  && (dst - base64packet) < sizeof(base64packet) - 1) {
110  *dst++ = *value++;
111  }
112  *dst++ = '\0';
113 
114  if (*value == ',')
115  value++;
116 
117  packet_size = av_base64_decode(decoded_packet, base64packet,
118  sizeof(decoded_packet));
119  if (packet_size > 0) {
120  uint8_t *dest = av_realloc(*data_ptr,
121  packet_size + sizeof(start_sequence) +
122  *size_ptr +
124  if (!dest) {
126  "Unable to allocate memory for extradata!\n");
127  return AVERROR(ENOMEM);
128  }
129  *data_ptr = dest;
130 
131  memcpy(dest + *size_ptr, start_sequence,
132  sizeof(start_sequence));
133  memcpy(dest + *size_ptr + sizeof(start_sequence),
134  decoded_packet, packet_size);
135  memset(dest + *size_ptr + sizeof(start_sequence) +
136  packet_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
137 
138  *size_ptr += sizeof(start_sequence) + packet_size;
139  }
140  }
141 
142  return 0;
143 }
144 
146  AVStream *stream,
147  PayloadContext *h264_data,
148  const char *attr, const char *value)
149 {
150  AVCodecParameters *par = stream->codecpar;
151 
152  if (!strcmp(attr, "packetization-mode")) {
153  av_log(s, AV_LOG_DEBUG, "RTP Packetization Mode: %d\n", atoi(value));
154  h264_data->packetization_mode = atoi(value);
155  /*
156  * Packetization Mode:
157  * 0 or not present: Single NAL mode (Only nals from 1-23 are allowed)
158  * 1: Non-interleaved Mode: 1-23, 24 (STAP-A), 28 (FU-A) are allowed.
159  * 2: Interleaved Mode: 25 (STAP-B), 26 (MTAP16), 27 (MTAP24), 28 (FU-A),
160  * and 29 (FU-B) are allowed.
161  */
162  if (h264_data->packetization_mode > 1)
164  "Interleaved RTP mode is not supported yet.\n");
165  } else if (!strcmp(attr, "profile-level-id")) {
166  if (strlen(value) == 6)
167  parse_profile_level_id(s, h264_data, value);
168  } else if (!strcmp(attr, "sprop-parameter-sets")) {
169  int ret;
170  if (*value == 0 || value[strlen(value) - 1] == ',') {
171  av_log(s, AV_LOG_WARNING, "Missing PPS in sprop-parameter-sets, ignoring\n");
172  return 0;
173  }
174  par->extradata_size = 0;
175  av_freep(&par->extradata);
177  &par->extradata_size, value);
178  av_log(s, AV_LOG_DEBUG, "Extradata set to %p (size: %d)\n",
179  par->extradata, par->extradata_size);
180  return ret;
181  }
182  return 0;
183 }
184 
186 {
187  char buf1[50];
188  char *dst = buf1;
189 
190  // remove the protocol identifier
191  while (*p && *p == ' ')
192  p++; // strip spaces.
193  while (*p && *p != ' ')
194  p++; // eat protocol identifier
195  while (*p && *p == ' ')
196  p++; // strip trailing spaces.
197  while (*p && *p != '-' && (dst - buf1) < sizeof(buf1) - 1)
198  *dst++ = *p++;
199  *dst = '\0';
200 
201  // a='framesize:96 320-240'
202  // set our parameters
203  par->width = atoi(buf1);
204  par->height = atoi(p + 1); // skip the -
205 }
206 
208  const uint8_t *buf, int len,
209  int skip_between, int *nal_counters,
210  int nal_mask)
211 {
212  int pass = 0;
213  int total_length = 0;
214  uint8_t *dst = NULL;
215  int ret;
216 
217  // first we are going to figure out the total size
218  for (pass = 0; pass < 2; pass++) {
219  const uint8_t *src = buf;
220  int src_len = len;
221 
222  while (src_len > 2) {
223  uint16_t nal_size = AV_RB16(src);
224 
225  // consume the length of the aggregate
226  src += 2;
227  src_len -= 2;
228 
229  if (nal_size <= src_len) {
230  if (pass == 0) {
231  // counting
232  total_length += sizeof(start_sequence) + nal_size;
233  } else {
234  // copying
235  memcpy(dst, start_sequence, sizeof(start_sequence));
236  dst += sizeof(start_sequence);
237  memcpy(dst, src, nal_size);
238  if (nal_counters)
239  nal_counters[(*src) & nal_mask]++;
240  dst += nal_size;
241  }
242  } else {
244  "nal size exceeds length: %d %d\n", nal_size, src_len);
245  return AVERROR_INVALIDDATA;
246  }
247 
248  // eat what we handled
249  src += nal_size + skip_between;
250  src_len -= nal_size + skip_between;
251  }
252 
253  if (pass == 0) {
254  /* now we know the total size of the packet (with the
255  * start sequences added) */
256  if ((ret = av_new_packet(pkt, total_length)) < 0)
257  return ret;
258  dst = pkt->data;
259  }
260  }
261 
262  return 0;
263 }
264 
265 int ff_h264_handle_frag_packet(AVPacket *pkt, const uint8_t *buf, int len,
266  int start_bit, const uint8_t *nal_header,
267  int nal_header_len)
268 {
269  int ret;
270  int tot_len = len;
271  int pos = 0;
272  if (start_bit)
273  tot_len += sizeof(start_sequence) + nal_header_len;
274  if ((ret = av_new_packet(pkt, tot_len)) < 0)
275  return ret;
276  if (start_bit) {
277  memcpy(pkt->data + pos, start_sequence, sizeof(start_sequence));
278  pos += sizeof(start_sequence);
279  memcpy(pkt->data + pos, nal_header, nal_header_len);
280  pos += nal_header_len;
281  }
282  memcpy(pkt->data + pos, buf, len);
283  return 0;
284 }
285 
287  const uint8_t *buf, int len,
288  int *nal_counters, int nal_mask)
289 {
290  uint8_t fu_indicator, fu_header, start_bit, nal_type, nal;
291 
292  if (len < 3) {
293  av_log(ctx, AV_LOG_ERROR, "Too short data for FU-A H.264 RTP packet\n");
294  return AVERROR_INVALIDDATA;
295  }
296 
297  fu_indicator = buf[0];
298  fu_header = buf[1];
299  start_bit = fu_header >> 7;
300  nal_type = fu_header & 0x1f;
301  nal = fu_indicator & 0xe0 | nal_type;
302 
303  // skip the fu_indicator and fu_header
304  buf += 2;
305  len -= 2;
306 
307  if (start_bit && nal_counters)
308  nal_counters[nal_type & nal_mask]++;
309  return ff_h264_handle_frag_packet(pkt, buf, len, start_bit, &nal, 1);
310 }
311 
312 // return 0 on packet, no more left, 1 on packet, 1 on partial packet
314  AVStream *st, AVPacket *pkt, uint32_t *timestamp,
315  const uint8_t *buf, int len, uint16_t seq,
316  int flags)
317 {
318  uint8_t nal;
319  uint8_t type;
320  int result = 0;
321 
322  if (!len) {
323  av_log(ctx, AV_LOG_ERROR, "Empty H.264 RTP packet\n");
324  return AVERROR_INVALIDDATA;
325  }
326  nal = buf[0];
327  type = nal & 0x1f;
328 
329  /* Simplify the case (these are all the NAL types used internally by
330  * the H.264 codec). */
331  if (type >= 1 && type <= 23)
332  type = 1;
333  switch (type) {
334  case 0: // undefined, but pass them through
335  case 1:
336  if ((result = av_new_packet(pkt, len + sizeof(start_sequence))) < 0)
337  return result;
338  memcpy(pkt->data, start_sequence, sizeof(start_sequence));
339  memcpy(pkt->data + sizeof(start_sequence), buf, len);
340  COUNT_NAL_TYPE(data, nal);
341  break;
342 
343  case 24: // STAP-A (one packet, multiple nals)
344  // consume the STAP-A NAL
345  buf++;
346  len--;
349  break;
350 
351  case 25: // STAP-B
352  case 26: // MTAP-16
353  case 27: // MTAP-24
354  case 29: // FU-B
355  avpriv_report_missing_feature(ctx, "RTP H.264 NAL unit type %d", type);
357  break;
358 
359  case 28: // FU-A (fragmented nal)
362  break;
363 
364  case 30: // undefined
365  case 31: // undefined
366  default:
367  av_log(ctx, AV_LOG_ERROR, "Undefined type (%d)\n", type);
369  break;
370  }
371 
372  pkt->stream_index = st->index;
373 
374  return result;
375 }
376 
378 {
379 #ifdef DEBUG
380  int ii;
381 
382  for (ii = 0; ii < 32; ii++) {
383  if (data->packet_types_received[ii])
384  av_log(NULL, AV_LOG_DEBUG, "Received %d packets of type %d\n",
385  data->packet_types_received[ii], ii);
386  }
387 #endif
388 }
389 
390 static int parse_h264_sdp_line(AVFormatContext *s, int st_index,
391  PayloadContext *h264_data, const char *line)
392 {
393  AVStream *stream;
394  const char *p = line;
395 
396  if (st_index < 0)
397  return 0;
398 
399  stream = s->streams[st_index];
400 
401  if (av_strstart(p, "framesize:", &p)) {
402  ff_h264_parse_framesize(stream->codecpar, p);
403  } else if (av_strstart(p, "fmtp:", &p)) {
404  return ff_parse_fmtp(s, stream, h264_data, p, sdp_parse_fmtp_config_h264);
405  } else if (av_strstart(p, "cliprect:", &p)) {
406  // could use this if we wanted.
407  }
408 
409  return 0;
410 }
411 
413  .enc_name = "H264",
414  .codec_type = AVMEDIA_TYPE_VIDEO,
415  .codec_id = AV_CODEC_ID_H264,
416  .need_parsing = AVSTREAM_PARSE_FULL,
417  .priv_data_size = sizeof(PayloadContext),
418  .parse_sdp_a_line = parse_h264_sdp_line,
419  .close = h264_close_context,
421 };
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:215
AVCodecParameters::extradata
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: codec_par.h:69
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame 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. Frame references ownership and permissions
AVCodecParameters
This struct describes the properties of an encoded stream.
Definition: codec_par.h:47
rtpdec_formats.h
ff_parse_fmtp
int ff_parse_fmtp(AVFormatContext *s, AVStream *stream, PayloadContext *data, const char *p, int(*parse_fmtp)(AVFormatContext *s, AVStream *stream, PayloadContext *data, const char *attr, const char *value))
Definition: rtpdec.c:965
AVPacket::data
uint8_t * data
Definition: packet.h:539
level_idc
int level_idc
Definition: h264_levels.c:29
data
const char data[16]
Definition: mxf.c:149
ff_h264_parse_framesize
void ff_h264_parse_framesize(AVCodecParameters *par, const char *p)
Definition: rtpdec_h264.c:185
ff_h264_dynamic_handler
const RTPDynamicProtocolHandler ff_h264_dynamic_handler
Definition: rtpdec_h264.c:412
PayloadContext::level_idc
uint8_t level_idc
Definition: rtpdec_h264.c:50
PayloadContext::packetization_mode
int packetization_mode
Definition: rtpdec_h264.c:51
parse_profile_level_id
static void parse_profile_level_id(AVFormatContext *s, PayloadContext *h264_data, const char *value)
Definition: rtpdec_h264.c:68
RTPDynamicProtocolHandler::enc_name
const char * enc_name
Definition: rtpdec.h:117
NAL_MASK
#define NAL_MASK
Definition: rtpdec_h264.c:64
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
pkt
AVPacket * pkt
Definition: movenc.c:60
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:209
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:198
av_new_packet
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: packet.c:98
AVCodecParameters::width
int width
Video only.
Definition: codec_par.h:134
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:230
ctx
AVFormatContext * ctx
Definition: movenc.c:49
AV_CODEC_ID_H264
@ AV_CODEC_ID_H264
Definition: codec_id.h:79
COUNT_NAL_TYPE
#define COUNT_NAL_TYPE(data, nal)
Definition: rtpdec_h264.c:61
AVFormatContext
Format I/O context.
Definition: avformat.h:1300
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:771
result
and forward the result(frame or status change) to the corresponding input. If nothing is possible
NULL
#define NULL
Definition: coverity.c:32
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:64
PayloadContext::profile_iop
uint8_t profile_iop
Definition: rtpdec_h264.c:49
h264_handle_packet
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:313
profile_idc
int profile_idc
Definition: h264_levels.c:53
ff_h264_parse_sprop_parameter_sets
int ff_h264_parse_sprop_parameter_sets(AVFormatContext *s, uint8_t **data_ptr, int *size_ptr, const char *value)
Definition: rtpdec_h264.c:97
av_base64_decode
int av_base64_decode(uint8_t *out, const char *in_str, int out_size)
Decode a base64-encoded string.
Definition: base64.c:81
base64.h
rtpdec.h
AVCodecParameters::extradata_size
int extradata_size
Size of the extradata content in bytes.
Definition: codec_par.h:73
NAL_COUNTERS
#define NAL_COUNTERS
Definition: rtpdec_h264.c:62
sdp_parse_fmtp_config_h264
static int sdp_parse_fmtp_config_h264(AVFormatContext *s, AVStream *stream, PayloadContext *h264_data, const char *attr, const char *value)
Definition: rtpdec_h264.c:145
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:83
ff_h264_handle_frag_packet
int ff_h264_handle_frag_packet(AVPacket *pkt, const uint8_t *buf, int len, int start_bit, const uint8_t *nal_header, int nal_header_len)
Definition: rtpdec_h264.c:265
avpriv_report_missing_feature
void avpriv_report_missing_feature(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
ff_h264_handle_aggregated_packet
int ff_h264_handle_aggregated_packet(AVFormatContext *ctx, PayloadContext *data, AVPacket *pkt, const uint8_t *buf, int len, int skip_between, int *nal_counters, int nal_mask)
Definition: rtpdec_h264.c:207
line
Definition: graph2dot.c:48
attributes.h
av_strstart
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:36
AVCodecParameters::height
int height
Definition: codec_par.h:135
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
len
int len
Definition: vorbis_enc_data.h:426
start_sequence
static const uint8_t start_sequence[]
Definition: rtpdec_h264.c:66
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:748
pos
unsigned int pos
Definition: spdifenc.c:414
avformat.h
AV_INPUT_BUFFER_PADDING_SIZE
#define AV_INPUT_BUFFER_PADDING_SIZE
Definition: defs.h:40
AVStream::index
int index
stream index in AVFormatContext
Definition: avformat.h:754
buffer
the frame and frame reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFrame structures Several references can point to the same frame buffer
Definition: filter_design.txt:49
h264_close_context
static void h264_close_context(PayloadContext *data)
Definition: rtpdec_h264.c:377
AVPacket::stream_index
int stream_index
Definition: packet.h:541
parse_packet
static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index, int flush)
Parse a packet, add all split parts to parse_queue.
Definition: demux.c:1162
h264_handle_packet_fu_a
static int h264_handle_packet_fu_a(AVFormatContext *ctx, PayloadContext *data, AVPacket *pkt, const uint8_t *buf, int len, int *nal_counters, int nal_mask)
Definition: rtpdec_h264.c:286
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
mem.h
AVPacket
This structure stores compressed data.
Definition: packet.h:516
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
PayloadContext::profile_idc
uint8_t profile_idc
Definition: rtpdec_h264.c:48
AVSTREAM_PARSE_FULL
@ AVSTREAM_PARSE_FULL
full parsing and repack
Definition: avformat.h:593
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:482
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
avstring.h
PayloadContext
RTP/JPEG specific private data.
Definition: rdt.c:85
parse_h264_sdp_line
static int parse_h264_sdp_line(AVFormatContext *s, int st_index, PayloadContext *h264_data, const char *line)
Definition: rtpdec_h264.c:390
src
#define src
Definition: vp8dsp.c:248
line
The official guide to swscale for confused that consecutive non overlapping rectangles of slice_bottom special converter These generally are unscaled converters of common like for each output line the vertical scaler pulls lines from a ring buffer When the ring buffer does not contain the wanted line
Definition: swscale.txt:40
RTPDynamicProtocolHandler
Definition: rtpdec.h:116
AV_RB16
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_WB24 unsigned int_TMPL AV_RB16
Definition: bytestream.h:98
av_realloc
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:155