1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27#include <stdlib.h>
28#include <stdio.h>
29#include <string.h>
30
31#include "containers/containers.h"
32
33#include "containers/core/containers_logging.h"
34#include "containers/core/containers_list.h"
35#include "containers/core/containers_bits.h"
36#include "rtp_priv.h"
37#include "rtp_base64.h"
38#include "rtp_h264.h"
39
40/******************************************************************************
41Defines and constants.
42******************************************************************************/
43
44/** H.264 payload flag bits */
45typedef enum
46{
47 H264F_NEXT_PACKET_IS_START = 0,
48 H264F_INSIDE_FRAGMENT,
49 H264F_OUTPUT_NAL_HEADER,
50} h264_flag_bit_t;
51
52/** Bit mask to extract F zero bit from NAL unit header */
53#define NAL_UNIT_FZERO_MASK 0x80
54/** Bit mask to extract NAL unit type from NAL unit header */
55#define NAL_UNIT_TYPE_MASK 0x1F
56
57/** NAL unit type codes */
58enum
59{
60 /* 0 unspecified */
61 NAL_UNIT_NON_IDR = 1,
62 NAL_UNIT_PARTITION_A = 2,
63 NAL_UNIT_PARTITION_B = 3,
64 NAL_UNIT_PARTITION_C = 4,
65 NAL_UNIT_IDR = 5,
66 NAL_UNIT_SEI = 6,
67 NAL_UNIT_SEQUENCE_PARAMETER_SET = 7,
68 NAL_UNIT_PICTURE_PARAMETER_SET = 8,
69 NAL_UNIT_ACCESS_UNIT_DELIMITER = 9,
70 NAL_UNIT_END_OF_SEQUENCE = 10,
71 NAL_UNIT_END_OF_STREAM = 11,
72 NAL_UNIT_FILLER = 12,
73 NAL_UNIT_EXT_SEQUENCE_PARAMETER_SET = 13,
74 NAL_UNIT_PREFIX = 14,
75 NAL_UNIT_SUBSET_SEQUENCE_PARAMETER_SET = 15,
76 /* 16 to 18 reserved */
77 NAL_UNIT_AUXILIARY = 19,
78 NAL_UNIT_EXTENSION = 20,
79 /* 21 to 23 reserved */
80 NAL_UNIT_STAP_A = 24,
81 NAL_UNIT_STAP_B = 25,
82 NAL_UNIT_MTAP16 = 26,
83 NAL_UNIT_MTAP24 = 27,
84 NAL_UNIT_FU_A = 28,
85 NAL_UNIT_FU_B = 29,
86 /* 30 to 31 unspecified */
87};
88
89/** Fragment unit header indicator bits */
90typedef enum
91{
92 FRAGMENT_UNIT_HEADER_RESERVED = 5,
93 FRAGMENT_UNIT_HEADER_END = 6,
94 FRAGMENT_UNIT_HEADER_START = 7,
95} fragment_unit_header_bit_t;
96
97#define MACROBLOCK_WIDTH 16
98#define MACROBLOCK_HEIGHT 16
99
100/** H.264 RTP timestamp clock rate */
101#define H264_TIMESTAMP_CLOCK 90000
102
103typedef enum
104{
105 CHROMA_FORMAT_MONO = 0,
106 CHROMA_FORMAT_YUV_420 = 1,
107 CHROMA_FORMAT_YUV_422 = 2,
108 CHROMA_FORMAT_YUV_444 = 3,
109 CHROMA_FORMAT_YUV_444_PLANAR = 4,
110 CHROMA_FORMAT_RGB = 5,
111} CHROMA_FORMAT_T;
112
113uint32_t chroma_sub_width[] = {
114 1, 2, 2, 1, 1, 1
115};
116
117uint32_t chroma_sub_height[] = {
118 1, 2, 1, 1, 1, 1
119};
120
121/******************************************************************************
122Type definitions
123******************************************************************************/
124
125typedef struct h264_payload_tag
126{
127 uint32_t nal_unit_size; /**< Number of NAL unit bytes left to write */
128 uint8_t flags; /**< H.264 payload flags */
129 uint8_t header_bytes_to_write; /**< Number of start code bytes left to write */
130 uint8_t nal_header; /**< Header for next NAL unit */
131} H264_PAYLOAD_T;
132
133/******************************************************************************
134Function prototypes
135******************************************************************************/
136VC_CONTAINER_STATUS_T h264_parameter_handler(VC_CONTAINER_T *p_ctx,
137 VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params);
138
139/******************************************************************************
140Local Functions
141******************************************************************************/
142
143/**************************************************************************//**
144 * Remove emulation prevention bytes from a buffer.
145 * These are 0x03 bytes inserted to prevent misinterprentation of a byte
146 * sequence in a buffer as a start code.
147 *
148 * @param sprop The buffer from which bytes are to be removed.
149 * @param sprop_size The number of bytes in the buffer.
150 * @return The new number of bytes in the buffer.
151 */
152static uint32_t h264_remove_emulation_prevention_bytes(uint8_t *sprop,
153 uint32_t sprop_size)
154{
155 uint32_t offset = 0;
156 uint8_t nal_unit_type = sprop[offset++];
157 uint32_t new_sprop_size = sprop_size;
158 uint8_t first_byte, second_byte;
159
160 nal_unit_type &= 0x1F; /* Just keep NAL unit type bits */
161
162 /* Certain NAL unit types need a byte triplet passed first */
163 if (nal_unit_type == NAL_UNIT_PREFIX || nal_unit_type == NAL_UNIT_EXTENSION)
164 offset += 3;
165
166 /* Make sure there is enough data for there to be a 0x00 0x00 0x03 sequence */
167 if (offset + 2 >= new_sprop_size)
168 return new_sprop_size;
169
170 /* Keep a rolling set of the last couple of bytes */
171 first_byte = sprop[offset++];
172 second_byte = sprop[offset++];
173
174 while (offset < new_sprop_size)
175 {
176 uint8_t next_byte = sprop[offset];
177
178 if (!first_byte && !second_byte && next_byte == 0x03)
179 {
180 /* Remove the emulation prevention byte (0x03) */
181 new_sprop_size--;
182 if (offset == new_sprop_size) /* No more data to check */
183 break;
184 memmove(&sprop[offset], &sprop[offset + 1], new_sprop_size - offset);
185 next_byte = sprop[offset];
186 } else
187 offset++;
188
189 first_byte = second_byte;
190 second_byte = next_byte;
191 }
192
193 return new_sprop_size;
194}
195
196/**************************************************************************//**
197 * Skip a scaling list in a bit stream.
198 *
199 * @param p_ctx The container context.
200 * @param sprop The bit stream containing the scaling list.
201 * @param size_of_scaling_list The size of the scaling list.
202 */
203static void h264_skip_scaling_list(VC_CONTAINER_T *p_ctx,
204 VC_CONTAINER_BITS_T *sprop,
205 uint32_t size_of_scaling_list)
206{
207 uint32_t last_scale = 8;
208 uint32_t next_scale = 8;
209 int32_t delta_scale;
210 uint32_t jj;
211
212 /* Algorithm taken from H.264 section 7.3.2.1.1.1 */
213 for (jj = 0; jj < size_of_scaling_list; jj++)
214 {
215 if (next_scale)
216 {
217 delta_scale = BITS_READ_S32_EXP(p_ctx, sprop, "delta_scale");
218 next_scale = (last_scale + delta_scale + 256) & 0xFF;
219
220 if (next_scale)
221 last_scale = next_scale;
222 }
223 }
224}
225
226/**************************************************************************//**
227 * Get the chroma format from the bit stream.
228 *
229 * @param p_ctx The container context.
230 * @param sprop The bit stream containing the scaling list.
231 * @return The chroma format index.
232 */
233static uint32_t h264_get_chroma_format(VC_CONTAINER_T *p_ctx,
234 VC_CONTAINER_BITS_T *sprop)
235{
236 uint32_t chroma_format_idc;
237
238 chroma_format_idc = BITS_READ_U32_EXP(p_ctx, sprop, "chroma_format_idc");
239 if (chroma_format_idc == 3 && BITS_READ_U32(p_ctx, sprop, 1, "separate_colour_plane_flag"))
240 chroma_format_idc = CHROMA_FORMAT_YUV_444_PLANAR;
241
242 BITS_SKIP_EXP(p_ctx, sprop, "bit_depth_luma_minus8");
243 BITS_SKIP_EXP(p_ctx, sprop, "bit_depth_chroma_minus8");
244 BITS_SKIP(p_ctx, sprop, 1, "qpprime_y_zero_transform_bypass_flag");
245
246 if (BITS_READ_U32(p_ctx, sprop, 1, "seq_scaling_matrix_present_flag"))
247 {
248 uint32_t scaling_lists = (chroma_format_idc == 3) ? 12 : 8;
249 uint32_t ii;
250
251 for (ii = 0; ii < scaling_lists; ii++)
252 {
253 if (BITS_READ_U32(p_ctx, sprop, 1, "seq_scaling_list_present_flag"))
254 h264_skip_scaling_list(p_ctx, sprop, (ii < 6) ? 16 : 64);
255 }
256 }
257
258 return chroma_format_idc;
259}
260
261/**************************************************************************//**
262 * Decode an H.264 sequence parameter set and update track information.
263 *
264 * @param p_ctx The RTP container context.
265 * @param track The track to be updated.
266 * @param sprop The bit stream containing the sequence parameter set.
267 * @return The resulting status of the function.
268 */
269static VC_CONTAINER_STATUS_T h264_decode_sequence_parameter_set(VC_CONTAINER_T *p_ctx,
270 VC_CONTAINER_TRACK_T *track,
271 VC_CONTAINER_BITS_T *sprop)
272{
273 VC_CONTAINER_VIDEO_FORMAT_T *video = &track->format->type->video;
274 uint32_t pic_order_cnt_type, chroma_format_idc;
275 uint32_t pic_width_in_mbs_minus1, pic_height_in_map_units_minus1, frame_mbs_only_flag;
276 uint32_t frame_crop_left_offset, frame_crop_right_offset, frame_crop_top_offset, frame_crop_bottom_offset;
277 uint8_t profile_idc;
278
279 /* This structure is defined by H.264 section 7.3.2.1.1 */
280 profile_idc = BITS_READ_U8(p_ctx, sprop, 8, "profile_idc");
281 BITS_SKIP(p_ctx, sprop, 16, "Rest of profile_level_id");
282
283 BITS_READ_U32_EXP(p_ctx, sprop, "seq_parameter_set_id");
284
285 chroma_format_idc = CHROMA_FORMAT_RGB;
286 if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 ||
287 profile_idc == 244 || profile_idc == 44 || profile_idc == 83 ||
288 profile_idc == 86 || profile_idc == 118 || profile_idc == 128)
289 {
290 chroma_format_idc = h264_get_chroma_format(p_ctx, sprop);
291 if (chroma_format_idc > CHROMA_FORMAT_YUV_444_PLANAR)
292 goto error;
293 }
294
295 BITS_SKIP_EXP(p_ctx, sprop, "log2_max_frame_num_minus4");
296 pic_order_cnt_type = BITS_READ_U32_EXP(p_ctx, sprop, "pic_order_cnt_type");
297 if (pic_order_cnt_type == 0)
298 {
299 BITS_SKIP_EXP(p_ctx, sprop, "log2_max_pic_order_cnt_lsb_minus4");
300 }
301 else if (pic_order_cnt_type == 1)
302 {
303 uint32_t num_ref_frames_in_pic_order_cnt_cycle;
304 uint32_t ii;
305
306 BITS_SKIP(p_ctx, sprop, 1, "delta_pic_order_always_zero_flag");
307 BITS_SKIP_EXP(p_ctx, sprop, "offset_for_non_ref_pic");
308 BITS_SKIP_EXP(p_ctx, sprop, "offset_for_top_to_bottom_field");
309 num_ref_frames_in_pic_order_cnt_cycle = BITS_READ_U32_EXP(p_ctx, sprop, "num_ref_frames_in_pic_order_cnt_cycle");
310
311 for (ii = 0; ii < num_ref_frames_in_pic_order_cnt_cycle; ii++)
312 BITS_SKIP_EXP(p_ctx, sprop, "offset_for_ref_frame");
313 }
314
315 BITS_SKIP_EXP(p_ctx, sprop, "max_num_ref_frames");
316 BITS_SKIP(p_ctx, sprop, 1, "gaps_in_frame_num_value_allowed_flag");
317
318 pic_width_in_mbs_minus1 = BITS_READ_U32_EXP(p_ctx, sprop, "pic_width_in_mbs_minus1");
319 pic_height_in_map_units_minus1 = BITS_READ_U32_EXP(p_ctx, sprop, "pic_height_in_map_units_minus1");
320 frame_mbs_only_flag = BITS_READ_U32(p_ctx, sprop, 1, "frame_mbs_only_flag");
321
322 /* Can now set the overall width and height in pixels */
323 video->width = (pic_width_in_mbs_minus1 + 1) * MACROBLOCK_WIDTH;
324 video->height = (2 - frame_mbs_only_flag) * (pic_height_in_map_units_minus1 + 1) * MACROBLOCK_HEIGHT;
325
326 if (!frame_mbs_only_flag)
327 BITS_SKIP(p_ctx, sprop, 1, "mb_adaptive_frame_field_flag");
328 BITS_SKIP(p_ctx, sprop, 1, "direct_8x8_inference_flag");
329
330 if (BITS_READ_U32(p_ctx, sprop, 1, "frame_cropping_flag"))
331 {
332 /* Visible area is restricted */
333 frame_crop_left_offset = BITS_READ_U32_EXP(p_ctx, sprop, "frame_crop_left_offset");
334 frame_crop_right_offset = BITS_READ_U32_EXP(p_ctx, sprop, "frame_crop_right_offset");
335 frame_crop_top_offset = BITS_READ_U32_EXP(p_ctx, sprop, "frame_crop_top_offset");
336 frame_crop_bottom_offset = BITS_READ_U32_EXP(p_ctx, sprop, "frame_crop_bottom_offset");
337
338 /* Need to adjust offsets for 4:2:0 and 4:2:2 chroma formats and field/frame flag */
339 frame_crop_left_offset *= chroma_sub_width[chroma_format_idc];
340 frame_crop_right_offset *= chroma_sub_width[chroma_format_idc];
341 frame_crop_top_offset *= chroma_sub_height[chroma_format_idc] * (2 - frame_mbs_only_flag);
342 frame_crop_bottom_offset *= chroma_sub_height[chroma_format_idc] * (2 - frame_mbs_only_flag);
343
344 if ((frame_crop_left_offset + frame_crop_right_offset) >= video->width ||
345 (frame_crop_top_offset + frame_crop_bottom_offset) >= video->height)
346 {
347 LOG_ERROR(p_ctx, "H.264: frame crop offsets (%u, %u, %u, %u) larger than frame (%u, %u)",
348 frame_crop_left_offset, frame_crop_right_offset, frame_crop_top_offset,
349 frame_crop_bottom_offset, video->width, video->height);
350 goto error;
351 }
352
353 video->x_offset = frame_crop_left_offset;
354 video->y_offset = frame_crop_top_offset;
355 video->visible_width = video->width - frame_crop_left_offset - frame_crop_right_offset;
356 video->visible_height = video->height - frame_crop_top_offset - frame_crop_bottom_offset;
357 } else {
358 video->visible_width = video->width;
359 video->visible_height = video->height;
360 }
361
362 /* vui_parameters may follow, but these will not be decoded */
363
364 if (!BITS_VALID(p_ctx, sprop))
365 goto error;
366
367 return VC_CONTAINER_SUCCESS;
368
369error:
370 LOG_ERROR(p_ctx, "H.264: sequence_parameter_set failed to decode");
371 return VC_CONTAINER_ERROR_FORMAT_INVALID;
372}
373
374/**************************************************************************//**
375 * Decode an H.264 sprop and update track information.
376 *
377 * @param p_ctx The RTP container context.
378 * @param track The track to be updated.
379 * @param sprop The bit stream containing the sprop.
380 * @return The resulting status of the function.
381 */
382static VC_CONTAINER_STATUS_T h264_decode_sprop(VC_CONTAINER_T *p_ctx,
383 VC_CONTAINER_TRACK_T *track,
384 VC_CONTAINER_BITS_T *sprop)
385{
386 switch (BITS_READ_U32(p_ctx, sprop, 8, "nal_unit_header") & NAL_UNIT_TYPE_MASK)
387 {
388 case NAL_UNIT_SEQUENCE_PARAMETER_SET:
389 return h264_decode_sequence_parameter_set(p_ctx, track, sprop);
390 case NAL_UNIT_PICTURE_PARAMETER_SET:
391 /* Not handled, but valid */
392 return VC_CONTAINER_SUCCESS;
393 default:
394 return VC_CONTAINER_ERROR_FORMAT_INVALID;
395 }
396}
397
398/**************************************************************************//**
399 * Decode the sprop parameter sets URI parameter and update track information.
400 *
401 * @param p_ctx The RTP container context.
402 * @param track The track to be updated.
403 * @param params The URI parameter list.
404 * @return The resulting status of the function.
405 */
406static VC_CONTAINER_STATUS_T h264_get_sprop_parameter_sets(VC_CONTAINER_T *p_ctx,
407 VC_CONTAINER_TRACK_T *track,
408 const VC_CONTAINERS_LIST_T *params)
409{
410 VC_CONTAINER_STATUS_T status;
411 PARAMETER_T param;
412 size_t str_len;
413 uint32_t extradata_size = 0;
414 uint8_t *sprop;
415 const char *set;
416 const char *comma;
417
418 /* Get the value of sprop-parameter-sets, base64 decode the (comma separated)
419 * sets, store all of them in track->priv->extradata and also decode to
420 * validate and fill in video format info. */
421
422 param.name = "sprop-parameter-sets";
423 if (!vc_containers_list_find_entry(params, &param) || !param.value)
424 {
425 LOG_ERROR(p_ctx, "H.264: sprop-parameter-sets is required, but not found");
426 return VC_CONTAINER_ERROR_FORMAT_INVALID;
427 }
428
429 /* First pass, calculate total size of buffer needed */
430 set = param.value;
431 do {
432 comma = strchr(set, ',');
433 str_len = comma ? (size_t)(comma - set) : strlen(set);
434 /* Allow space for the NAL unit and a start code */
435 extradata_size += rtp_base64_byte_length(set, str_len) + 4;
436 set = comma + 1;
437 } while (comma);
438
439 if (!extradata_size)
440 {
441 LOG_ERROR(p_ctx, "H.264: sprop-parameter-sets doesn't contain useful data");
442 return VC_CONTAINER_ERROR_FORMAT_INVALID;
443 }
444
445 status = vc_container_track_allocate_extradata(p_ctx, track, extradata_size);
446 if(status != VC_CONTAINER_SUCCESS) return status;
447
448 track->format->extradata_size = extradata_size;
449 sprop = track->priv->extradata;
450
451 /* Now decode the data into the buffer, and validate / use it to fill in format */
452 set = param.value;
453 do {
454 uint8_t *next_sprop;
455 uint32_t sprop_size;
456 VC_CONTAINER_BITS_T sprop_stream;
457
458 comma = strchr(set, ',');
459 str_len = comma ? (size_t)(comma - set) : strlen(set);
460
461 /* Insert a start code (0x00000001 in network order) */
462 *sprop++ = 0x00; *sprop++ = 0x00; *sprop++ = 0x00; *sprop++ = 0x01;
463 extradata_size -= 4;
464
465 next_sprop = rtp_base64_decode(set, str_len, sprop, extradata_size);
466 if (!next_sprop)
467 {
468 LOG_ERROR(p_ctx, "H.264: sprop-parameter-sets failed to decode");
469 return VC_CONTAINER_ERROR_FORMAT_INVALID;
470 }
471
472 sprop_size = next_sprop - sprop;
473 if (sprop_size)
474 {
475 uint32_t new_sprop_size;
476
477 /* Need to remove emulation prevention bytes before decoding */
478 new_sprop_size = h264_remove_emulation_prevention_bytes(sprop, sprop_size);
479
480 BITS_INIT(p_ctx, &sprop_stream, sprop, new_sprop_size);
481 status = h264_decode_sprop(p_ctx, track, &sprop_stream);
482 if(status != VC_CONTAINER_SUCCESS) return status;
483
484 /* If necessary, decode sprop again, to put back the emulation prevention bytes */
485 if (new_sprop_size != sprop_size)
486 rtp_base64_decode(set, str_len, sprop, sprop_size);
487
488 extradata_size -= sprop_size;
489 sprop = next_sprop;
490 }
491
492 set = comma + 1;
493 } while (comma);
494
495 return VC_CONTAINER_SUCCESS;
496}
497
498/**************************************************************************//**
499 * Check URI parameter list for unsupported features.
500 *
501 * @param p_ctx The RTP container context.
502 * @param params The URI parameter list.
503 * @return The resulting status of the function.
504 */
505static VC_CONTAINER_STATUS_T h264_check_unsupported_features(VC_CONTAINER_T *p_ctx,
506 const VC_CONTAINERS_LIST_T *params)
507{
508 uint32_t u32_unused;
509
510 /* Limitation: interleaving not yet supported */
511 if (rtp_get_parameter_u32(params, "sprop-interleaving-depth", &u32_unused) ||
512 rtp_get_parameter_u32(params, "sprop-deint-buf-req", &u32_unused) ||
513 rtp_get_parameter_u32(params, "sprop-init-buf-time", &u32_unused) ||
514 rtp_get_parameter_u32(params, "sprop-max-don-diff", &u32_unused))
515 {
516 LOG_ERROR(p_ctx, "H.264: Interleaved packetization is not supported");
517 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
518 }
519
520 return VC_CONTAINER_SUCCESS;
521}
522
523/**************************************************************************//**
524 * Get and check the packetization mode URI parameter.
525 *
526 * @param p_ctx The RTP container context.
527 * @param params The URI parameter list.
528 * @return The resulting status of the function.
529 */
530static VC_CONTAINER_STATUS_T h264_get_packetization_mode(VC_CONTAINER_T *p_ctx,
531 const VC_CONTAINERS_LIST_T *params)
532{
533 uint32_t packetization_mode;
534
535 if (rtp_get_parameter_u32(params, "packetization-mode", &packetization_mode))
536 {
537 /* Only modes 0 and 1 are supported, no interleaving */
538 if (packetization_mode > 1)
539 {
540 LOG_ERROR(p_ctx, "H.264: Unsupported packetization mode: %u", packetization_mode);
541 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
542 }
543 }
544
545 return VC_CONTAINER_SUCCESS;
546}
547
548/**************************************************************************//**
549 * Initialise payload bit stream for a new RTP packet.
550 *
551 * @param p_ctx The RTP container context.
552 * @param t_module The track module with the new RTP packet.
553 * @return The resulting status of the function.
554 */
555static VC_CONTAINER_STATUS_T h264_new_rtp_packet(VC_CONTAINER_T *p_ctx,
556 VC_CONTAINER_TRACK_MODULE_T *t_module)
557{
558 VC_CONTAINER_BITS_T *payload = &t_module->payload;
559 H264_PAYLOAD_T *extra = (H264_PAYLOAD_T *)t_module->extra;
560 uint8_t unit_header;
561 uint8_t fragment_header;
562
563 /* Read the NAL unit type and process as necessary */
564 unit_header = BITS_READ_U8(p_ctx, payload, 8, "nal_unit_header");
565
566 /* When the top bit is set, the NAL unit is invalid */
567 if (unit_header & NAL_UNIT_FZERO_MASK)
568 {
569 LOG_DEBUG(p_ctx, "H.264: Invalid NAL unit (top bit of header set)");
570 return VC_CONTAINER_ERROR_FORMAT_INVALID;
571 }
572
573 /* In most cases, a new packet means a new NAL unit, which will need a start code and the header */
574 extra->header_bytes_to_write = 5;
575 extra->nal_header = unit_header;
576 extra->nal_unit_size = BITS_BYTES_AVAILABLE(p_ctx, payload);
577
578 switch (unit_header & NAL_UNIT_TYPE_MASK)
579 {
580 case NAL_UNIT_STAP_A:
581 /* Single Time Aggregation Packet A */
582 CLEAR_BIT(extra->flags, H264F_INSIDE_FRAGMENT);
583 /* Trigger reading NAL unit length and header */
584 extra->nal_unit_size = 0;
585 break;
586
587 case NAL_UNIT_FU_A:
588 /* Fragementation Unit A */
589 fragment_header = BITS_READ_U8(p_ctx, payload, 8, "fragment_header");
590 extra->nal_unit_size--;
591
592 if (BIT_IS_CLEAR(fragment_header, FRAGMENT_UNIT_HEADER_START) ||
593 BIT_IS_SET(extra->flags, H264F_INSIDE_FRAGMENT))
594 {
595 /* This is a continuation packet, prevent start code and header from being output */
596 extra->header_bytes_to_write = 0;
597
598 /* If this is the end of a fragment, the next FU will be a new one */
599 if (BIT_IS_SET(fragment_header, FRAGMENT_UNIT_HEADER_END))
600 CLEAR_BIT(extra->flags, H264F_INSIDE_FRAGMENT);
601 } else {
602 /* Start of a new fragment. */
603 SET_BIT(extra->flags, H264F_INSIDE_FRAGMENT);
604
605 /* Merge type from fragment header and the rest from NAL unit header to form real NAL unit header */
606 fragment_header &= NAL_UNIT_TYPE_MASK;
607 fragment_header |= (unit_header & ~NAL_UNIT_TYPE_MASK);
608 extra->nal_header = fragment_header;
609 }
610 break;
611
612 case NAL_UNIT_STAP_B:
613 case NAL_UNIT_MTAP16:
614 case NAL_UNIT_MTAP24:
615 case NAL_UNIT_FU_B:
616 LOG_ERROR(p_ctx, "H.264: Unsupported RTP NAL unit type: %u", unit_header & NAL_UNIT_TYPE_MASK);
617 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
618
619 default:
620 /* Single NAL unit case */
621 CLEAR_BIT(extra->flags, H264F_INSIDE_FRAGMENT);
622 }
623
624 return VC_CONTAINER_SUCCESS;
625}
626
627/**************************************************************************//**
628 * H.264 payload handler.
629 * Extracts/skips data from the payload according to the NAL unit headers.
630 *
631 * @param p_ctx The RTP container context.
632 * @param track The track being read.
633 * @param p_packet The container packet information, or NULL.
634 * @param flags The container read flags.
635 * @return The resulting status of the function.
636 */
637static VC_CONTAINER_STATUS_T h264_payload_handler(VC_CONTAINER_T *p_ctx,
638 VC_CONTAINER_TRACK_T *track,
639 VC_CONTAINER_PACKET_T *p_packet,
640 uint32_t flags)
641{
642 VC_CONTAINER_TRACK_MODULE_T *t_module = track->priv->module;
643 VC_CONTAINER_BITS_T *payload = &t_module->payload;
644 H264_PAYLOAD_T *extra = (H264_PAYLOAD_T *)t_module->extra;
645 uint32_t packet_flags = 0;
646 uint8_t header_bytes_to_write;
647 uint32_t size, offset;
648 uint8_t *data_ptr;
649 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
650 bool last_nal_unit_in_packet = false;
651
652 if (BIT_IS_SET(t_module->flags, TRACK_NEW_PACKET))
653 {
654 status = h264_new_rtp_packet(p_ctx, t_module);
655 if (status != VC_CONTAINER_SUCCESS)
656 return status;
657 }
658
659 if (BIT_IS_SET(extra->flags, H264F_NEXT_PACKET_IS_START))
660 {
661 packet_flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
662
663 if (!(flags & VC_CONTAINER_READ_FLAG_INFO))
664 CLEAR_BIT(extra->flags, H264F_NEXT_PACKET_IS_START);
665 }
666
667 if (!extra->nal_unit_size && BITS_BYTES_AVAILABLE(p_ctx, payload))
668 {
669 uint32_t stap_unit_header;
670
671 /* STAP-A packet: read NAL unit size and header from payload */
672 stap_unit_header = BITS_READ_U32(p_ctx, payload, 24, "STAP unit header");
673 extra->nal_unit_size = stap_unit_header >> 8;
674 if (extra->nal_unit_size > BITS_BYTES_AVAILABLE(p_ctx, payload))
675 {
676 LOG_ERROR(p_ctx, "H.264: STAP-A NAL unit size bigger than payload");
677 return VC_CONTAINER_ERROR_FORMAT_INVALID;
678 }
679 extra->header_bytes_to_write = 5;
680 extra->nal_header = (uint8_t)stap_unit_header;
681 }
682
683 header_bytes_to_write = extra->header_bytes_to_write;
684 size = extra->nal_unit_size + header_bytes_to_write;
685
686 if (p_packet && !(flags & VC_CONTAINER_READ_FLAG_SKIP))
687 {
688 if (flags & VC_CONTAINER_READ_FLAG_INFO)
689 {
690 /* In order to set the frame end flag correctly, need to work out if this
691 * is the only NAL unit or last in an aggregated packet */
692 last_nal_unit_in_packet = (extra->nal_unit_size == BITS_BYTES_AVAILABLE(p_ctx, payload));
693 } else {
694 offset = 0;
695 data_ptr = p_packet->data;
696
697 if (size > p_packet->buffer_size)
698 {
699 /* Buffer not big enough */
700 size = p_packet->buffer_size;
701 }
702
703 /* Insert start code and header into the data stream */
704 while (offset < size && header_bytes_to_write)
705 {
706 uint8_t header_byte;
707
708 switch (header_bytes_to_write)
709 {
710 case 2: header_byte = 0x01; break;
711 case 1: header_byte = extra->nal_header; break;
712 default: header_byte = 0x00;
713 }
714 data_ptr[offset++] = header_byte;
715 header_bytes_to_write--;
716 }
717 extra->header_bytes_to_write = header_bytes_to_write;
718
719 if (offset < size)
720 {
721 BITS_COPY_BYTES(p_ctx, payload, size - offset, data_ptr + offset, "Packet data");
722 extra->nal_unit_size -= (size - offset);
723 }
724
725 /* If we've read the final bytes of the packet, this must be the last (or only)
726 * NAL unit in it */
727 last_nal_unit_in_packet = !BITS_BYTES_AVAILABLE(p_ctx, payload);
728 }
729 p_packet->size = size;
730 } else {
731 extra->header_bytes_to_write = 0;
732 BITS_SKIP_BYTES(p_ctx, payload, extra->nal_unit_size, "Packet data");
733 last_nal_unit_in_packet = !BITS_BYTES_AVAILABLE(p_ctx, payload);
734 extra->nal_unit_size = 0;
735 }
736
737 /* The marker bit on an RTP packet indicates the frame ends at the end of packet */
738 if (last_nal_unit_in_packet && BIT_IS_SET(t_module->flags, TRACK_HAS_MARKER))
739 {
740 packet_flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
741
742 /* If this was the last packet of a frame, the next one must be the start */
743 if (!(flags & VC_CONTAINER_READ_FLAG_INFO))
744 SET_BIT(extra->flags, H264F_NEXT_PACKET_IS_START);
745 }
746
747 if (p_packet)
748 p_packet->flags = packet_flags;
749
750 return status;
751}
752
753/*****************************************************************************
754Functions exported as part of the RTP parameter handler API
755 *****************************************************************************/
756
757/**************************************************************************//**
758 * H.264 parameter handler.
759 * Parses the URI parameters to set up the track for an H.264 stream.
760 *
761 * @param p_ctx The reader context.
762 * @param track The track to be updated.
763 * @param params The URI parameter list.
764 * @return The resulting status of the function.
765 */
766VC_CONTAINER_STATUS_T h264_parameter_handler(VC_CONTAINER_T *p_ctx,
767 VC_CONTAINER_TRACK_T *track,
768 const VC_CONTAINERS_LIST_T *params)
769{
770 H264_PAYLOAD_T *extra;
771 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
772
773 VC_CONTAINER_PARAM_UNUSED(p_ctx);
774 VC_CONTAINER_PARAM_UNUSED(params);
775
776 /* See RFC3984, section 8.1, for parameter names and details. */
777 extra = (H264_PAYLOAD_T *)malloc(sizeof(H264_PAYLOAD_T));
778 if (!extra)
779 return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
780 track->priv->module->extra = extra;
781 memset(extra, 0, sizeof(H264_PAYLOAD_T));
782
783 /* Mandatory parameters */
784 status = h264_get_sprop_parameter_sets(p_ctx, track, params);
785 if (status != VC_CONTAINER_SUCCESS) return status;
786
787 /* Unsupported parameters */
788 status = h264_check_unsupported_features(p_ctx, params);
789 if (status != VC_CONTAINER_SUCCESS) return status;
790
791 /* Optional parameters */
792 status = h264_get_packetization_mode(p_ctx, params);
793 if (status != VC_CONTAINER_SUCCESS) return status;
794
795 track->priv->module->payload_handler = h264_payload_handler;
796 SET_BIT(extra->flags, H264F_NEXT_PACKET_IS_START);
797
798 track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
799 track->priv->module->timestamp_clock = H264_TIMESTAMP_CLOCK;
800
801 return status;
802}
803
804