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 ; |
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 | */ |
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 | */ |
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 | */ |
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 * = (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 | */ |
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 | */ |
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 * = (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, ¶m) || !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 | */ |
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 | */ |
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 * = (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, ¶m) || !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 | */ |
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 | */ |
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 * = (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 | */ |
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 * = (MP4_PAYLOAD_T *)t_module->extra; |
555 | VC_CONTAINER_BITS_T * = &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 ; |
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 | */ |
597 | static int32_t mp4_flagged_delta(VC_CONTAINER_T *p_ctx, |
598 | VC_CONTAINER_BITS_T *, |
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 | */ |
624 | static VC_CONTAINER_STATUS_T (VC_CONTAINER_T *p_ctx, |
625 | MP4_PAYLOAD_T *, |
626 | bool is_first_au) |
627 | { |
628 | VC_CONTAINER_BITS_T * = &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 | */ |
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 * = (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 | */ |
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 *; |
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 | |