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 | , |
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 | = 5, |
93 | = 6, |
94 | = 7, |
95 | } ; |
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 ; /**< Number of start code bytes left to write */ |
130 | uint8_t ; /**< 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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 = 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, ¶m) || !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 | */ |
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 | */ |
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 | */ |
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 * = (H264_PAYLOAD_T *)t_module->extra; |
560 | uint8_t ; |
561 | uint8_t ; |
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 | */ |
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 * = (H264_PAYLOAD_T *)t_module->extra; |
645 | uint32_t packet_flags = 0; |
646 | uint8_t ; |
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 ; |
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 ; |
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 | */ |
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 *; |
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 | |