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_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 /******************************************************************************
44 Defines and constants.
45 ******************************************************************************/
46 
47 /******************************************************************************
48 Type definitions
49 ******************************************************************************/
50 
51 /** MPEG-4 stream types, ISO/IEC 14496-1:2010 Table 6 */
52 typedef 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 */
68 typedef 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 */
110 typedef 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 
119 typedef 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 */
127 static 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 
135 static int mp4_mode_comparator(const MP4_MODE_ENTRY_T *a, const MP4_MODE_ENTRY_T *b);
136 
137 VC_CONTAINERS_STATIC_LIST(mp4_mode_lookup, mp4_mode_array, mp4_mode_comparator);
138 
139 typedef 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 
147 typedef 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 /******************************************************************************
166 Function prototypes
167 ******************************************************************************/
168 VC_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 /******************************************************************************
172 Local 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  */
hex_to_nybble(char hex)182 static 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  */
hex_to_byte_buffer(const char * hex,uint8_t * buffer,uint32_t bytes_to_convert)203 static 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  */
mp4_get_stream_type(VC_CONTAINER_T * p_ctx,VC_CONTAINER_TRACK_T * track,const VC_CONTAINERS_LIST_T * params)225 static 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  */
mp4_decode_audio_config(VC_CONTAINER_T * p_ctx,VC_CONTAINER_TRACK_T * track,VC_CONTAINER_BITS_T * bit_stream)262 static 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  */
mp4_get_config(VC_CONTAINER_T * p_ctx,VC_CONTAINER_TRACK_T * track,const VC_CONTAINERS_LIST_T * params)338 static 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  */
mp4_mode_comparator(const MP4_MODE_ENTRY_T * a,const MP4_MODE_ENTRY_T * b)400 static 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  */
mp4_get_mode(VC_CONTAINER_T * p_ctx,VC_CONTAINER_TRACK_T * track,const VC_CONTAINERS_LIST_T * params)413 static 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  */
mp4_check_unsupported_features(VC_CONTAINER_T * p_ctx,VC_CONTAINER_TRACK_T * track,const VC_CONTAINERS_LIST_T * params)452 static 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  */
mp4_check_parameters(VC_CONTAINER_T * p_ctx,VC_CONTAINER_TRACK_T * track)493 static 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  */
mp4_new_rtp_packet(VC_CONTAINER_T * p_ctx,VC_CONTAINER_TRACK_MODULE_T * t_module)550 static 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  */
mp4_flagged_delta(VC_CONTAINER_T * p_ctx,VC_CONTAINER_BITS_T * au_headers,uint32_t delta_length)597 static 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  */
mp4_next_au_header(VC_CONTAINER_T * p_ctx,MP4_PAYLOAD_T * extra,bool is_first_au)624 static 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  */
mp4_payload_handler(VC_CONTAINER_T * p_ctx,VC_CONTAINER_TRACK_T * track,VC_CONTAINER_PACKET_T * p_packet,uint32_t flags)661 static 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 /*****************************************************************************
725 Functions 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  */
mp4_parameter_handler(VC_CONTAINER_T * p_ctx,VC_CONTAINER_TRACK_T * track,const VC_CONTAINERS_LIST_T * params)737 VC_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