1 /*
2 Copyright (c) 2012, Broadcom Europe Ltd
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, 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 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON 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
25 SOFTWARE, 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 /******************************************************************************
41 Defines and constants.
42 ******************************************************************************/
43 
44 /** H.264 payload flag bits */
45 typedef 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 */
58 enum
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 */
90 typedef 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 
103 typedef 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 
113 uint32_t chroma_sub_width[] = {
114    1, 2, 2, 1, 1, 1
115 };
116 
117 uint32_t chroma_sub_height[] = {
118    1, 2, 1, 1, 1, 1
119 };
120 
121 /******************************************************************************
122 Type definitions
123 ******************************************************************************/
124 
125 typedef 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 /******************************************************************************
134 Function prototypes
135 ******************************************************************************/
136 VC_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 /******************************************************************************
140 Local 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  */
h264_remove_emulation_prevention_bytes(uint8_t * sprop,uint32_t sprop_size)152 static 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  */
h264_skip_scaling_list(VC_CONTAINER_T * p_ctx,VC_CONTAINER_BITS_T * sprop,uint32_t size_of_scaling_list)203 static 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  */
h264_get_chroma_format(VC_CONTAINER_T * p_ctx,VC_CONTAINER_BITS_T * sprop)233 static 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  */
h264_decode_sequence_parameter_set(VC_CONTAINER_T * p_ctx,VC_CONTAINER_TRACK_T * track,VC_CONTAINER_BITS_T * sprop)269 static 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 
369 error:
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  */
h264_decode_sprop(VC_CONTAINER_T * p_ctx,VC_CONTAINER_TRACK_T * track,VC_CONTAINER_BITS_T * sprop)382 static 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  */
h264_get_sprop_parameter_sets(VC_CONTAINER_T * p_ctx,VC_CONTAINER_TRACK_T * track,const VC_CONTAINERS_LIST_T * params)406 static 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  */
h264_check_unsupported_features(VC_CONTAINER_T * p_ctx,const VC_CONTAINERS_LIST_T * params)505 static 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  */
h264_get_packetization_mode(VC_CONTAINER_T * p_ctx,const VC_CONTAINERS_LIST_T * params)530 static 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  */
h264_new_rtp_packet(VC_CONTAINER_T * p_ctx,VC_CONTAINER_TRACK_MODULE_T * t_module)555 static 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  */
h264_payload_handler(VC_CONTAINER_T * p_ctx,VC_CONTAINER_TRACK_T * track,VC_CONTAINER_PACKET_T * p_packet,uint32_t flags)637 static 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 /*****************************************************************************
754 Functions 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  */
h264_parameter_handler(VC_CONTAINER_T * p_ctx,VC_CONTAINER_TRACK_T * track,const VC_CONTAINERS_LIST_T * params)766 VC_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