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_bits.h"
35#include "containers/core/containers_list.h"
36#include "rtp_priv.h"
37#include "rtp_mpeg4.h"
38
39#ifdef _DEBUG
40#define RTP_DEBUG 1
41#endif
42
43/******************************************************************************
44Defines and constants.
45******************************************************************************/
46
47/******************************************************************************
48Type definitions
49******************************************************************************/
50
51/** MPEG-4 stream types, ISO/IEC 14496-1:2010 Table 6 */
52typedef enum
53{
54 MPEG4_OBJECT_DESCRIPTOR_STREAM = 1,
55 MPEG4_CLOCK_REFERENCE_STREAM = 2,
56 MPEG4_SCENE_DESCRIPTION_STREAM = 3,
57 MPEG4_VISUAL_STREAM = 4,
58 MPEG4_AUDIO_STREAM = 5,
59 MPEG4_MPEG7_STREAM = 6,
60 MPEG4_IPMP_STREAM = 7,
61 MPEG4_OBJECT_CONTENT_INFO_STREAM = 8,
62 MPEG4_MPEGJ_STREAM = 9,
63 MPEG4_INTERACTION_STREAM = 10,
64 MPEG4_IPMP_TOOL_STREAM = 11,
65} mp4_stream_type_t;
66
67/** MPEG-4 audio object types, ISO/IEC 14496-3:2009 Table 1.17 */
68typedef enum
69{
70 MPEG4A_AAC_MAIN = 1,
71 MPEG4A_AAC_LC = 2,
72 MPEG4A_AAC_SSR = 3,
73 MPEG4A_AAC_LTP = 4,
74 MPEG4A_SBR = 5,
75 MPEG4A_AAC_SCALABLE = 6,
76 MPEG4A_TWIN_VQ = 7,
77 MPEG4A_CELP = 8,
78 MPEG4A_HVXC = 9,
79 MPEG4A_TTSI = 12,
80 MPEG4A_MAIN_SYNTHETIC = 13,
81 MPEG4A_WAVETABLE_SYNTHESIS = 14,
82 MPEG4A_GENERAL_MIDI = 15,
83 MPEG4A_ALGORITHMIC_SYNTHESIS = 16,
84 MPEG4A_ER_AAC_LC = 17,
85 MPEG4A_ER_AAC_LTP = 19,
86 MPEG4A_ER_AAC_SCALABLE = 20,
87 MPEG4A_ER_TWIN_VQ = 21,
88 MPEG4A_ER_BSAC = 22,
89 MPEG4A_ER_AAC_LD = 23,
90 MPEG4A_ER_CELP = 24,
91 MPEG4A_ER_HVXC = 25,
92 MPEG4A_ER_HILN = 26,
93 MPEG4A_ER_PARAMETERIC = 27,
94 MPEG4A_SSC = 28,
95 MPEG4A_PS = 29,
96 MPEG4A_MPEG_SURROUND = 30,
97 MPEG4A_LAYER_1 = 32,
98 MPEG4A_LAYER_2 = 33,
99 MPEG4A_LAYER_3 = 34,
100 MPEG4A_DST = 35,
101 MPEG4A_ALS = 36,
102 MPEG4A_SLS = 37,
103 MPEG4A_SLS_NON_CORE = 38,
104 MPEG4A_ER_AAC_ELD = 39,
105 MPEG4A_SMR_SIMPLE = 40,
106 MPEG4A_SMR_MAIN = 41,
107} mp4_audio_object_type_t;
108
109/** RTP MPEG-4 modes */
110typedef enum
111{
112 MP4_GENERIC_MODE = 0,
113 MP4_CELP_CBR_MODE,
114 MP4_CELP_VBR_MODE,
115 MP4_AAC_LBR_MODE,
116 MP4_AAC_HBR_MODE
117} mp4_mode_t;
118
119typedef struct mp4_mode_detail_tag
120{
121 const char *name;
122 mp4_mode_t mode;
123} MP4_MODE_ENTRY_T;
124
125/* RTP MPEG-4 mode look-up table.
126 * Note: case-insensitive sort by name */
127static MP4_MODE_ENTRY_T mp4_mode_array[] = {
128 { "aac-hbr", MP4_AAC_HBR_MODE },
129 { "aac-lbr", MP4_AAC_LBR_MODE },
130 { "celp-cbr", MP4_CELP_CBR_MODE },
131 { "celp-vbr", MP4_CELP_VBR_MODE },
132 { "generic", MP4_GENERIC_MODE },
133};
134
135static int mp4_mode_comparator(const MP4_MODE_ENTRY_T *a, const MP4_MODE_ENTRY_T *b);
136
137VC_CONTAINERS_STATIC_LIST(mp4_mode_lookup, mp4_mode_array, mp4_mode_comparator);
138
139typedef struct au_info_tag
140{
141 uint32_t available;
142 uint32_t index;
143 int32_t cts_delta;
144 int32_t dts_delta;
145} AU_INFO_T;
146
147typedef struct mp4_payload_tag
148{
149 mp4_stream_type_t stream_type;
150 uint32_t profile_level_id;
151 mp4_mode_t mode;
152 uint32_t size_length;
153 uint32_t index_length;
154 uint32_t index_delta_length;
155 uint32_t cts_delta_length;
156 uint32_t dts_delta_length;
157 uint32_t object_type;
158 uint32_t constant_size;
159 uint32_t constant_duration;
160 uint32_t auxiliary_length;
161 VC_CONTAINER_BITS_T au_headers;
162 AU_INFO_T au_info;
163} MP4_PAYLOAD_T;
164
165/******************************************************************************
166Function prototypes
167******************************************************************************/
168VC_CONTAINER_STATUS_T mp4_parameter_handler(VC_CONTAINER_T *p_ctx,
169 VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params);
170
171/******************************************************************************
172Local Functions
173******************************************************************************/
174
175/**************************************************************************//**
176 * Convert a hexadecimal character to a value between 0 and 15.
177 * Upper and lower case characters are supported. An invalid chacter return zero.
178 *
179 * @param hex The character to convert.
180 * @return The value of the character.
181 */
182static uint8_t hex_to_nybble(char hex)
183{
184 if (hex >= '0' && hex <= '9')
185 return hex - '0';
186 if (hex >= 'A' && hex <= 'F')
187 return hex - 'A' + 10;
188 if (hex >= 'a' && hex <= 'f')
189 return hex - 'a' + 10;
190 return 0; /* Illegal character (not hex) */
191}
192
193/**************************************************************************//**
194 * Convert a sequence of hexadecimal characters to consecutive entries in a
195 * byte array.
196 * The string must contain at least twice as many characters as the number of
197 * bytes to convert.
198 *
199 * @param hex The hexadecimal string.
200 * @param buffer The buffer into which bytes are to be stored.
201 * @param bytes_to_convert The number of bytes in the array to be filled.
202 */
203static void hex_to_byte_buffer(const char *hex,
204 uint8_t *buffer,
205 uint32_t bytes_to_convert)
206{
207 uint8_t value;
208
209 while (bytes_to_convert--)
210 {
211 value = hex_to_nybble(*hex++) << 4;
212 value |= hex_to_nybble(*hex++);
213 *buffer++ = value;
214 }
215}
216
217/**************************************************************************//**
218 * Retrieves and checks the stream type in the URI parameters.
219 *
220 * @param p_ctx The RTP container context.
221 * @param track The track being constructed.
222 * @param params The URI parameter list.
223 * @return The resulting status of the function.
224 */
225static VC_CONTAINER_STATUS_T mp4_get_stream_type(VC_CONTAINER_T *p_ctx,
226 VC_CONTAINER_TRACK_T *track,
227 const VC_CONTAINERS_LIST_T *params)
228{
229 MP4_PAYLOAD_T *extra = (MP4_PAYLOAD_T *)track->priv->module->extra;
230 uint32_t stream_type;
231 VC_CONTAINER_ES_TYPE_T expected_es_type;
232
233 if (!rtp_get_parameter_u32(params, "streamType", &stream_type))
234 return VC_CONTAINER_ERROR_FORMAT_INVALID;
235
236 switch (stream_type)
237 {
238 case MPEG4_AUDIO_STREAM:
239 extra->stream_type = MPEG4_AUDIO_STREAM;
240 expected_es_type = VC_CONTAINER_ES_TYPE_AUDIO;
241 break;
242 default:
243 LOG_ERROR(p_ctx, "Unsupported MPEG-4 stream type: %u", stream_type);
244 return VC_CONTAINER_ERROR_FORMAT_INVALID;
245 }
246
247 if (track->format->es_type != expected_es_type)
248 return VC_CONTAINER_ERROR_FORMAT_INVALID;
249
250 return VC_CONTAINER_SUCCESS;
251}
252
253/**************************************************************************//**
254 * Decode and store audio configuration information from an MP4 audio
255 * configuration bit stream.
256 *
257 * @param p_ctx The RTP container context.
258 * @param track The track being constructed.
259 * @param bit_stream The bit stream containing the audio configuration.
260 * @return True if the configuration was decoded successfully, false otherwise.
261 */
262static bool mp4_decode_audio_config(VC_CONTAINER_T *p_ctx,
263 VC_CONTAINER_TRACK_T *track,
264 VC_CONTAINER_BITS_T *bit_stream)
265{
266 static uint32_t mp4_audio_sample_rate[] =
267 { 96000, 88200, 64000, 48000, 44100, 32000, 24000,
268 22050, 16000, 12000, 11025, 8000, 7350, 0, 0 };
269
270 VC_CONTAINER_AUDIO_FORMAT_T *audio = &track->format->type->audio;
271 uint32_t audio_object_type;
272 uint32_t sampling_frequency_index;
273 uint32_t channel_configuration;
274
275 audio_object_type = BITS_READ_U32(p_ctx, bit_stream, 5, "audioObjectType");
276 if (audio_object_type == 31)
277 audio_object_type = BITS_READ_U32(p_ctx, bit_stream, 6, "audioObjectTypeExt") + 32;
278
279 sampling_frequency_index = BITS_READ_U32(p_ctx, bit_stream, 4, "samplingFrequencyIndex");
280 if (sampling_frequency_index == 0xF)
281 audio->sample_rate = BITS_READ_U32(p_ctx, bit_stream, 24, "samplingFrequency");
282 else
283 audio->sample_rate = mp4_audio_sample_rate[sampling_frequency_index];
284 if (!audio->sample_rate) return false;
285
286 track->priv->module->timestamp_clock = audio->sample_rate;
287
288 channel_configuration = BITS_READ_U32(p_ctx, bit_stream, 4, "channelConfiguration");
289 switch (channel_configuration)
290 {
291 case 1: /* 1 channel, centre front */
292 case 2: /* 2 channel, stereo front */
293 case 3: /* 3 channel, centre and stereo front */
294 case 4: /* 4 channel, centre and stereo front, mono surround */
295 case 5: /* 5 channel, centre and stereo front, stereo surround */
296 case 6: /* 5.1 channel, centre and stereo front, stereo surround, low freq */
297 audio->channels = channel_configuration;
298 break;
299 case 7: /* 7.1 channel, centre, stereo and stereo outside front, stereo surround, low freq */
300 audio->channels = channel_configuration + 1;
301 break;
302 default:
303 LOG_DEBUG(p_ctx, "MPEG-4: Unsupported channel configuration (%u)", channel_configuration);
304 return false;
305 }
306
307 switch (audio_object_type)
308 {
309 case MPEG4A_AAC_LC:
310 {
311 uint32_t ga_specific_config = BITS_READ_U32(p_ctx, bit_stream, 3, "GASpecificConfig");
312
313 /* Make sure there are no unexpected (and unsupported) additional configuration elements */
314 if (ga_specific_config != 0)
315 {
316 LOG_DEBUG(p_ctx, "MPEG-4: Unexpected additional configuration data (%u)", ga_specific_config);
317 return false;
318 }
319 }
320 break;
321 /* Add any further supported codecs here */
322 default:
323 LOG_DEBUG(p_ctx, "MPEG-4: Unsupported Audio Object Type (%u)", audio_object_type);
324 return false;
325 }
326
327 return true;
328}
329
330/**************************************************************************//**
331 * Get, store and decode the configuration information from the URI parameters.
332 *
333 * @param p_ctx The RTP container context.
334 * @param track The track being constructed.
335 * @param params The URI parameter list.
336 * @return The resulting status of the function.
337 */
338static VC_CONTAINER_STATUS_T mp4_get_config(VC_CONTAINER_T *p_ctx,
339 VC_CONTAINER_TRACK_T *track,
340 const VC_CONTAINERS_LIST_T *params)
341{
342 MP4_PAYLOAD_T *extra = (MP4_PAYLOAD_T *)track->priv->module->extra;
343 PARAMETER_T param;
344 uint32_t config_len;
345 VC_CONTAINER_STATUS_T status;
346 uint8_t *config;
347 VC_CONTAINER_BITS_T bit_stream;
348
349 param.name = "config";
350 if (!vc_containers_list_find_entry(params, &param) || !param.value)
351 {
352 LOG_ERROR(p_ctx, "MPEG-4: config parameter missing");
353 return VC_CONTAINER_ERROR_FORMAT_INVALID;
354 }
355
356 config_len = strlen(param.value);
357 if (config_len & 1)
358 {
359 LOG_ERROR(p_ctx, "MPEG-4: config parameter invalid");
360 return VC_CONTAINER_ERROR_FORMAT_INVALID;
361 }
362 config_len /= 2;
363
364 /* Copy AudioSpecificConfig into track extradata, to be decoded by client */
365 status = vc_container_track_allocate_extradata(p_ctx, track, config_len);
366 if(status != VC_CONTAINER_SUCCESS) return status;
367
368 config = track->priv->extradata;
369 track->format->extradata_size = config_len;
370 hex_to_byte_buffer(param.value, config, config_len);
371
372 /* Decode config locally, to determine sample rate, etc. */
373 BITS_INIT(p_ctx, &bit_stream, config, config_len);
374
375 switch (extra->stream_type)
376 {
377 case MPEG4_AUDIO_STREAM:
378 if (!mp4_decode_audio_config(p_ctx, track, &bit_stream))
379 return VC_CONTAINER_ERROR_FORMAT_INVALID;
380 break;
381 default:
382 /* Other stream types not yet supported */
383 LOG_ERROR(p_ctx, "MPEG-4: stream type %d not supported", extra->stream_type);
384 return VC_CONTAINER_ERROR_FORMAT_INVALID;
385 }
386
387 return VC_CONTAINER_SUCCESS;
388}
389
390/**************************************************************************//**
391 * MP4 mode comparison function.
392 * Compare two MP4 mode structures and return whether the first is less than,
393 * equal to or greater than the second.
394 *
395 * @param first The first structure to be compared.
396 * @param second The second structure to be compared.
397 * @return Negative if first is less than second, positive if first is greater
398 * and zero if they are equal.
399 */
400static int mp4_mode_comparator(const MP4_MODE_ENTRY_T *a, const MP4_MODE_ENTRY_T *b)
401{
402 return strcasecmp(a->name, b->name);
403}
404
405/**************************************************************************//**
406 * Get and store the MP4 mode, if recognised, from the URI parameters.
407 *
408 * @param p_ctx The RTP container context.
409 * @param track The track being constructed.
410 * @param params The URI parameter list.
411 * @return The resulting status of the function.
412 */
413static VC_CONTAINER_STATUS_T mp4_get_mode(VC_CONTAINER_T *p_ctx,
414 VC_CONTAINER_TRACK_T *track,
415 const VC_CONTAINERS_LIST_T *params)
416{
417 MP4_PAYLOAD_T *extra = (MP4_PAYLOAD_T *)track->priv->module->extra;
418 PARAMETER_T param;
419 MP4_MODE_ENTRY_T mode_entry;
420
421 param.name = "mode";
422 if (!vc_containers_list_find_entry(params, &param) || !param.value)
423 {
424 LOG_ERROR(p_ctx, "MPEG-4: mode parameter missing");
425 return VC_CONTAINER_ERROR_FORMAT_INVALID;
426 }
427
428#ifdef RTP_DEBUG
429 vc_containers_list_validate(&mp4_mode_lookup);
430#endif
431
432 mode_entry.name = param.value;
433 if (!vc_containers_list_find_entry(&mp4_mode_lookup, &mode_entry))
434 {
435 LOG_ERROR(p_ctx, "MPEG-4: Unrecognised mode parameter \"%s\"", mode_entry.name);
436 return VC_CONTAINER_ERROR_FORMAT_INVALID;
437 }
438
439 extra->mode = mode_entry.mode;
440
441 return VC_CONTAINER_SUCCESS;
442}
443
444/**************************************************************************//**
445 * Check URI parameters for unsupported features.
446 *
447 * @param p_ctx The RTP container context.
448 * @param track The track being constructed.
449 * @param params The URI parameter list.
450 * @return The resulting status of the function.
451 */
452static VC_CONTAINER_STATUS_T mp4_check_unsupported_features(VC_CONTAINER_T *p_ctx,
453 VC_CONTAINER_TRACK_T *track,
454 const VC_CONTAINERS_LIST_T *params)
455{
456 uint32_t u32_unused;
457
458 VC_CONTAINER_PARAM_UNUSED(p_ctx);
459 VC_CONTAINER_PARAM_UNUSED(track);
460
461 /* Limitation: RAP flag not yet supported */
462 if (rtp_get_parameter_u32(params, "randomAccessIndication", &u32_unused))
463 {
464 LOG_ERROR(p_ctx, "MPEG-4: random access not supported");
465 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
466 }
467
468 /* Limitation: interleaving not yet supported */
469 if (rtp_get_parameter_u32(params, "maxDisplacement", &u32_unused) ||
470 rtp_get_parameter_u32(params, "de-interleaveBufferSize", &u32_unused))
471 {
472 LOG_ERROR(p_ctx, "MPEG-4: interleaved packetization not supported");
473 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
474 }
475
476 /* Limitation: system streams not supported */
477 if (rtp_get_parameter_u32(params, "streamStateIndication", &u32_unused))
478 {
479 LOG_ERROR(p_ctx, "MPEG-4: system streams not supported");
480 return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
481 }
482
483 return VC_CONTAINER_SUCCESS;
484}
485
486/**************************************************************************//**
487 * Validate parameters that have been read form the URI parameter list.
488 *
489 * @param p_ctx The RTP container context.
490 * @param track The track being constructed.
491 * @return The resulting status of the function.
492 */
493static VC_CONTAINER_STATUS_T mp4_check_parameters(VC_CONTAINER_T *p_ctx,
494 VC_CONTAINER_TRACK_T *track)
495{
496 MP4_PAYLOAD_T *extra = (MP4_PAYLOAD_T *)track->priv->module->extra;
497
498 switch (extra->mode)
499 {
500 case MP4_CELP_CBR_MODE:
501 if (!extra->constant_size)
502 {
503 LOG_ERROR(p_ctx, "MPEG-4: CELP-cbr requires constantSize parameter.");
504 return VC_CONTAINER_ERROR_FORMAT_INVALID;
505 }
506 break;
507 case MP4_CELP_VBR_MODE:
508 case MP4_AAC_LBR_MODE:
509 if (extra->size_length != 6 || extra->index_length != 2 || extra->index_delta_length != 2)
510 {
511 LOG_ERROR(p_ctx, "MPEG-4: CELP-vbr/AAC-lbr invalid lengths (%u/%u/%u)",
512 extra->size_length, extra->index_length, extra->index_delta_length);
513 return VC_CONTAINER_ERROR_FORMAT_INVALID;
514 }
515 break;
516 case MP4_AAC_HBR_MODE:
517 if (extra->size_length != 13 || extra->index_length != 3 || extra->index_delta_length != 3)
518 {
519 LOG_ERROR(p_ctx, "MPEG-4: AAC-hbr invalid lengths (%u/%u/%u)",
520 extra->size_length, extra->index_length, extra->index_delta_length);
521 return VC_CONTAINER_ERROR_FORMAT_INVALID;
522 }
523 break;
524 default: /* MP4_GENERIC_MODE */
525 if (extra->size_length > 32 || extra->index_length > 32 || extra->index_delta_length > 32)
526 {
527 LOG_ERROR(p_ctx, "MPEG-4: generic invalid lengths (%u/%u/%u)",
528 extra->size_length, extra->index_length, extra->index_delta_length);
529 return VC_CONTAINER_ERROR_FORMAT_INVALID;
530 }
531 }
532
533 if (extra->cts_delta_length > 32 || extra->dts_delta_length > 32)
534 {
535 LOG_ERROR(p_ctx, "MPEG-4: CTS/DTS invalid lengths (%u/%u)",
536 extra->cts_delta_length, extra->dts_delta_length);
537 return VC_CONTAINER_ERROR_FORMAT_INVALID;
538 }
539
540 return VC_CONTAINER_SUCCESS;
541}
542
543/**************************************************************************//**
544 * Initialise payload bit stream for a new RTP packet.
545 *
546 * @param p_ctx The RTP container context.
547 * @param t_module The track module with the new RTP packet.
548 * @return The resulting status of the function.
549 */
550static VC_CONTAINER_STATUS_T mp4_new_rtp_packet(VC_CONTAINER_T *p_ctx,
551 VC_CONTAINER_TRACK_MODULE_T *t_module)
552{
553 VC_CONTAINER_BITS_T *payload = &t_module->payload;
554 MP4_PAYLOAD_T *extra = (MP4_PAYLOAD_T *)t_module->extra;
555 VC_CONTAINER_BITS_T *au_headers = &extra->au_headers;
556
557 /* There will be an AU header section if any of its fields are non-zero. */
558 if (extra->size_length || extra->index_length || extra->cts_delta_length || extra->dts_delta_length)
559 {
560 uint32_t au_headers_length;
561
562 /* Calculate how far to advance the payload, to get past the AU headers */
563 au_headers_length = BITS_READ_U32(p_ctx, payload, 16, "AU headers length");
564 au_headers_length = BITS_TO_BYTES(au_headers_length); /* Round up to bytes */
565
566 /* Record where the AU headers are in the payload */
567 BITS_INIT(p_ctx, au_headers, BITS_CURRENT_POINTER(p_ctx, payload), au_headers_length);
568 BITS_SKIP_BYTES(p_ctx, &t_module->payload, au_headers_length, "Move payload past AU headers");
569 }
570
571 /* Skip the auxiliary section, if present */
572 if (extra->auxiliary_length)
573 {
574 uint32_t auxiliary_data_size;
575
576 auxiliary_data_size = BITS_READ_U32(p_ctx, payload, extra->auxiliary_length, "Auxiliary length");
577 auxiliary_data_size = BITS_TO_BYTES(auxiliary_data_size); /* Round up to bytes */
578 BITS_SKIP_BYTES(p_ctx, payload, auxiliary_data_size, "Auxiliary data");
579 }
580
581 return BITS_VALID(p_ctx, payload) ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FORMAT_INVALID;
582}
583
584/**************************************************************************//**
585 * Read a flagged delta from an AU header bit stream.
586 * A flagged delta is an optional value in the stream that is preceded by a
587 * flag bit that indicates whether the value is present in the stream. If the
588 * length of the value is zero bits, the flag is never present.
589 *
590 * @pre The delta_length must be 32 or less.
591 *
592 * @param p_ctx The container context.
593 * @param au_headers The AU header bit stream.
594 * @param delta_length The number of bits in the delta value.
595 * @return The delta value, or zero if not present.
596 */
597static int32_t mp4_flagged_delta(VC_CONTAINER_T *p_ctx,
598 VC_CONTAINER_BITS_T *au_headers,
599 uint32_t delta_length)
600{
601 uint32_t value = 0;
602
603 /* Flag is only present if the delta length is non-zero */
604 if (delta_length && BITS_READ_U32(p_ctx, au_headers, 1, "CTS/DTS delta present"))
605 {
606 value = BITS_READ_U32(p_ctx, au_headers, delta_length, "CTS/DTS delta");
607
608 /* Sign extend value based on bit length */
609 if (value & (1 << (delta_length - 1)))
610 value |= ~((1 << delta_length) - 1);
611 }
612
613 return (int32_t)value;
614}
615
616/**************************************************************************//**
617 * Read next AU header from the bit stream.
618 *
619 * @param p_ctx The RTP container context.
620 * @param extra The MP4-specific track module information.
621 * @param is_first_au True if the first AU header in the packet is being read.
622 * @return The resulting status of the function.
623 */
624static VC_CONTAINER_STATUS_T mp4_next_au_header(VC_CONTAINER_T *p_ctx,
625 MP4_PAYLOAD_T *extra,
626 bool is_first_au)
627{
628 VC_CONTAINER_BITS_T *au_headers = &extra->au_headers;
629 AU_INFO_T *au_info = &extra->au_info;
630
631 /* See RFC3550 section 3.2.1.1 */
632
633 if (extra->constant_size)
634 au_info->available = extra->constant_size;
635 else
636 au_info->available = BITS_READ_U32(p_ctx, au_headers, extra->size_length, "AU size");
637
638 if (is_first_au)
639 au_info->index = BITS_READ_U32(p_ctx, au_headers, extra->index_length, "AU index");
640 else
641 au_info->index += BITS_READ_U32(p_ctx, au_headers, extra->index_delta_length, "AU index delta") + 1;
642
643 au_info->cts_delta = mp4_flagged_delta(p_ctx, au_headers, extra->cts_delta_length);
644 au_info->dts_delta = mp4_flagged_delta(p_ctx, au_headers, extra->dts_delta_length);
645
646 /* RAP and stream state not supported yet */
647
648 return BITS_VALID(p_ctx, au_headers) ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FORMAT_INVALID;
649}
650
651/**************************************************************************//**
652 * MP4 payload handler.
653 * Extracts/skips data from the payload according to the AU headers.
654 *
655 * @param p_ctx The RTP container context.
656 * @param track The track being read.
657 * @param p_packet The container packet information, or NULL.
658 * @param flags The container read flags.
659 * @return The resulting status of the function.
660 */
661static VC_CONTAINER_STATUS_T mp4_payload_handler(VC_CONTAINER_T *p_ctx,
662 VC_CONTAINER_TRACK_T *track,
663 VC_CONTAINER_PACKET_T *p_packet,
664 uint32_t flags)
665{
666 VC_CONTAINER_TRACK_MODULE_T *t_module = track->priv->module;
667 VC_CONTAINER_BITS_T *payload = &t_module->payload;
668 MP4_PAYLOAD_T *extra = (MP4_PAYLOAD_T *)t_module->extra;
669 AU_INFO_T *au_info = &extra->au_info;
670 bool is_new_packet = BIT_IS_SET(t_module->flags, TRACK_NEW_PACKET);
671 uint32_t bytes_left_in_payload;
672 uint32_t size;
673 VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
674
675 if (is_new_packet)
676 {
677 status = mp4_new_rtp_packet(p_ctx, t_module);
678 if (status != VC_CONTAINER_SUCCESS)
679 return status;
680 }
681
682 if (!au_info->available)
683 {
684 status = mp4_next_au_header(p_ctx, extra, is_new_packet);
685 if (status != VC_CONTAINER_SUCCESS)
686 return status;
687 }
688
689 if (p_packet)
690 {
691 /* Adjust the packet time stamps using deltas */
692 p_packet->pts += au_info->cts_delta;
693 p_packet->dts += au_info->dts_delta;
694 }
695
696 size = au_info->available;
697 bytes_left_in_payload = BITS_BYTES_AVAILABLE(p_ctx, payload);
698 if (size > bytes_left_in_payload)
699 {
700 /* AU is fragmented across RTP packets */
701 size = bytes_left_in_payload;
702 }
703
704 if (p_packet && !(flags & VC_CONTAINER_READ_FLAG_SKIP))
705 {
706 if (!(flags & VC_CONTAINER_READ_FLAG_INFO))
707 {
708 if (size > p_packet->buffer_size)
709 size = p_packet->buffer_size;
710
711 BITS_COPY_BYTES(p_ctx, payload, size, p_packet->data, "Packet data");
712 }
713 p_packet->size = size;
714 } else {
715 BITS_SKIP_BYTES(p_ctx, payload, size, "Packet data");
716 }
717
718 if (!(flags & VC_CONTAINER_READ_FLAG_INFO))
719 au_info->available -= size;
720
721 return BITS_VALID(p_ctx, payload) ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FORMAT_INVALID;
722}
723
724/*****************************************************************************
725Functions exported as part of the RTP parameter handler API
726 *****************************************************************************/
727
728/**************************************************************************//**
729 * MP4 parameter handler.
730 * Parses the URI parameters to set up the track for an MP4 stream.
731 *
732 * @param p_ctx The reader context.
733 * @param track The track to be updated.
734 * @param params The URI parameter list.
735 * @return The resulting status of the function.
736 */
737VC_CONTAINER_STATUS_T mp4_parameter_handler(VC_CONTAINER_T *p_ctx,
738 VC_CONTAINER_TRACK_T *track,
739 const VC_CONTAINERS_LIST_T *params)
740{
741 MP4_PAYLOAD_T *extra;
742 VC_CONTAINER_STATUS_T status;
743
744 /* See RFC3640, section 4.1, for parameter names and details. */
745 extra = (MP4_PAYLOAD_T *)malloc(sizeof(MP4_PAYLOAD_T));
746 if (!extra)
747 return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
748 track->priv->module->extra = extra;
749 memset(extra, 0, sizeof(MP4_PAYLOAD_T));
750
751 /* Mandatory parameters */
752 status = mp4_get_stream_type(p_ctx, track, params);
753 if (status != VC_CONTAINER_SUCCESS) return status;
754
755 status = mp4_get_config(p_ctx, track, params);
756 if (status != VC_CONTAINER_SUCCESS) return status;
757
758 status = mp4_get_mode(p_ctx, track, params);
759 if (status != VC_CONTAINER_SUCCESS) return status;
760
761 /* Unsupported parameters */
762 status = mp4_check_unsupported_features(p_ctx, track, params);
763 if (status != VC_CONTAINER_SUCCESS) return status;
764
765 /* Optional parameters */
766 rtp_get_parameter_u32(params, "sizeLength", &extra->size_length);
767 rtp_get_parameter_u32(params, "indexLength", &extra->index_length);
768 rtp_get_parameter_u32(params, "indexDeltaLength", &extra->index_delta_length);
769 rtp_get_parameter_u32(params, "CTSDeltaLength", &extra->cts_delta_length);
770 rtp_get_parameter_u32(params, "DTSDeltaLength", &extra->dts_delta_length);
771 rtp_get_parameter_u32(params, "objectType", &extra->object_type);
772 rtp_get_parameter_u32(params, "constantSize", &extra->constant_size);
773 rtp_get_parameter_u32(params, "constantDuration", &extra->constant_duration);
774 rtp_get_parameter_u32(params, "auxiliaryDataSizeLength", &extra->auxiliary_length);
775
776 if (extra->constant_size && extra->size_length)
777 {
778 LOG_ERROR(p_ctx, "MPEG4: constantSize and sizeLength cannot both be set.");
779 return VC_CONTAINER_ERROR_FORMAT_INVALID;
780 }
781
782 status = mp4_check_parameters(p_ctx, track);
783 if (status != VC_CONTAINER_SUCCESS) return status;
784
785 track->priv->module->payload_handler = mp4_payload_handler;
786
787 return VC_CONTAINER_SUCCESS;
788}
789