1 /*****************************************************************************
2 * mpeg4_iod.c: ISO 14496-1 IOD and parsers
3 *****************************************************************************
4 * Copyright (C) 2004-2015 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 /*****************************************************************************
23 *****************************************************************************/
29 #include <vlc_common.h>
31 #include "mpeg4_iod.h"
34 static void iod_debug( vlc_object_t *p_object, const char *format, ... )
39 msg_GenericVa( p_object, VLC_MSG_DBG, format, ap );
47 /*****************************************************************************
48 * MP4 specific functions (IOD parser)
49 *****************************************************************************/
50 static unsigned IODDescriptorLength( unsigned *pi_data, const uint8_t **pp_data )
53 unsigned int i_len = 0;
63 i_len = ( i_len << 7 ) + ( i_b&0x7f );
65 } while( i_b&0x80 && *pi_data > 0 );
73 static unsigned IODGetBytes( unsigned *pi_data, const uint8_t **pp_data, size_t bytes )
76 while( *pi_data > 0 && bytes-- )
87 static char* IODGetURL( unsigned *pi_data, const uint8_t **pp_data )
89 unsigned len = IODGetBytes( pi_data, pp_data, 1 );
92 char *url = strndup( (char*)*pp_data, len );
98 #define IODTag_ObjectDescr 0x01
99 #define IODTag_InitialObjectDescr 0x02
100 #define IODTag_ESDescr 0x03
101 #define IODTag_DecConfigDescr 0x04
102 #define IODTag_DecSpecificDescr 0x05
103 #define IODTag_SLDescr 0x06
105 /* Unified pointer for read helper */
108 iod_descriptor_t *p_iod;
109 es_mpeg4_descriptor_t *es_descr;
110 decoder_config_descriptor_t *p_dec_config;
113 static uint8_t IOD_Desc_Read( vlc_object_t *, unsigned *, const uint8_t **, uint8_t, uint8_t, iod_read_params_t params );
115 static bool IOD_SLDesc_Read( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data,
116 iod_read_params_t params )
118 VLC_UNUSED(p_object);
125 static bool IOD_DecSpecificDesc_Read( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data,
126 iod_read_params_t params )
128 VLC_UNUSED(p_object);
129 decoder_config_descriptor_t *p_dec_config = params.p_dec_config;
131 p_dec_config->p_extra = malloc( i_data );
132 if( p_dec_config->p_extra )
134 p_dec_config->i_extra = i_data;
135 memcpy( p_dec_config->p_extra, p_data, p_dec_config->i_extra );
138 return !!p_dec_config->i_extra;
141 static bool IOD_DecConfigDesc_Read( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data,
142 iod_read_params_t params )
144 decoder_config_descriptor_t *p_dec_config = params.p_dec_config;
149 p_dec_config->i_objectTypeIndication = IODGetBytes( &i_data, &p_data, 1 );
150 uint8_t i_flags = IODGetBytes( &i_data, &p_data, 1 );
151 p_dec_config->i_streamType = i_flags >> 2;
153 IODGetBytes( &i_data, &p_data, 3 ); /* bufferSizeDB */
154 IODGetBytes( &i_data, &p_data, 4 ); /* maxBitrate */
155 IODGetBytes( &i_data, &p_data, 4 ); /* avgBitrate */
157 /* DecoderSpecificDescr */
158 IOD_Desc_Read( p_object, &i_data, &p_data,
159 IODTag_DecSpecificDescr, 1, params );
161 iod_debug( p_object, " * read decoder objecttype: %x streamtype:%x extra: %u",
162 p_dec_config->i_objectTypeIndication, p_dec_config->i_streamType, p_dec_config->i_extra );
163 /* ProfileLevelIndicator [0..255] */
167 static bool IOD_ESDesc_Read( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data,
168 iod_read_params_t params )
170 es_mpeg4_descriptor_t *es_descr = params.es_descr;
174 es_descr->i_es_id = IODGetBytes( &i_data, &p_data, 2 );
175 uint8_t i_flags = IODGetBytes( &i_data, &p_data, 1 );
177 if( ( i_flags >> 7 )&0x01 )
181 IODGetBytes( &i_data, &p_data, 2 ); /* dependOn_es_id */
184 if( (i_flags >> 6) & 0x01 )
185 es_descr->psz_url = IODGetURL( &i_data, &p_data );
187 if( ( i_flags >> 5 )&0x01 )
191 IODGetBytes( &i_data, &p_data, 2 ); /* OCR_es_id */
194 iod_debug( p_object, " * read ES Descriptor for es id %"PRIx16, es_descr->i_es_id );
196 /* DecoderConfigDescr */
197 params.p_dec_config = &es_descr->dec_descr;
198 if ( 1 != IOD_Desc_Read( p_object, &i_data, &p_data,
199 IODTag_DecConfigDescr, 1, params ) )
203 IOD_Desc_Read( p_object, &i_data, &p_data, IODTag_SLDescr, 1, params );
205 /* IPI / IP / IPMP ... */
207 es_descr->b_ok = true;
212 static bool IOD_InitialObjectDesc_Read( vlc_object_t *p_object, unsigned i_data,
213 const uint8_t *p_data, iod_read_params_t params )
215 iod_descriptor_t *p_iod = params.p_iod;
216 if( i_data < 3 + 5 + 2 )
219 uint16_t i_object_descriptor_id = ( IODGetBytes( &i_data, &p_data, 1 ) << 2 );
220 uint8_t i_flags = IODGetBytes( &i_data, &p_data, 1 );
221 i_object_descriptor_id |= i_flags >> 6;
223 iod_debug( p_object, " * ObjectDescriptorID: %"PRIu16, i_object_descriptor_id );
224 iod_debug( p_object, " * includeInlineProfileLevel flag: 0x%"PRIx8, ( i_flags >> 4 )&0x01 );
225 if ( (i_flags >> 5) & 0x01 )
227 p_iod->psz_url = IODGetURL( &i_data, &p_data );
228 iod_debug( p_object, " * URL: %s", p_iod->psz_url );
229 return true; /* leaves out unparsed remaining extdescr */
232 if( i_data < 5 + 2 ) /* at least one ES desc */
235 /* Profile Level Indication */
236 IODGetBytes( &i_data, &p_data, 1 ); /* OD */
237 IODGetBytes( &i_data, &p_data, 1 ); /* scene */
238 IODGetBytes( &i_data, &p_data, 1 ); /* audio */
239 IODGetBytes( &i_data, &p_data, 1 ); /* visual */
240 IODGetBytes( &i_data, &p_data, 1 ); /* graphics */
244 uint8_t i_desc_count = IOD_Desc_Read( p_object, &i_data, &p_data,
245 IODTag_ESDescr, ES_DESCRIPTOR_COUNT, params );
246 if( i_desc_count == 0 )
248 iod_debug( p_object, " * missing ES Descriptor" );
252 /* 0..255 OCIdescr */
253 /* 0..255 IPMPdescpointer */
254 /* 0..255 IPMPdesc */
255 /* 0..1 IPMPtoollistdesc */
256 /* 0..255 Extensiondescr */
261 static uint8_t IOD_Desc_Read( vlc_object_t *p_object, unsigned *pi_data, const uint8_t **pp_data,
262 uint8_t i_target_tag, uint8_t i_max_desc, iod_read_params_t params )
264 uint8_t i_read_count = 0;
266 for (unsigned i = 0; *pi_data > 2 && i < i_max_desc; i++)
268 const uint8_t i_tag = IODGetBytes( pi_data, pp_data, 1 );
269 const unsigned i_length = IODDescriptorLength( pi_data, pp_data );
270 if( i_target_tag != i_tag || i_length > *pi_data )
273 unsigned i_descriptor_data = i_length;
274 const uint8_t *p_descriptor_data = *pp_data;
276 iod_debug( p_object, " Reading descriptor 0x%"PRIx8": found tag 0x%"PRIx8" left %d",
277 i_target_tag, i_tag, *pi_data );
280 case IODTag_InitialObjectDescr:
282 /* iod_descriptor_t *p_iod = (iod_descriptor_t *) param; */
283 if ( !IOD_InitialObjectDesc_Read( p_object, i_descriptor_data,
284 p_descriptor_data, params ) )
289 case IODTag_ESDescr: /**/
291 iod_descriptor_t *p_iod = params.p_iod;
292 params.es_descr = &p_iod->es_descr[i_read_count];
293 if ( !IOD_ESDesc_Read( p_object, i_descriptor_data,
294 p_descriptor_data, params ) )
299 case IODTag_DecConfigDescr:
301 if ( !IOD_DecConfigDesc_Read( p_object, i_descriptor_data,
302 p_descriptor_data, params ) )
307 case IODTag_DecSpecificDescr:
309 if ( !IOD_DecSpecificDesc_Read( p_object, i_descriptor_data,
310 p_descriptor_data, params ) )
317 if ( !IOD_SLDesc_Read( p_object, i_descriptor_data,
318 p_descriptor_data, params ) )
324 iod_debug( p_object, "trying to read unsupported descriptor" );
328 *pp_data += i_length;
329 *pi_data -= i_length;
337 iod_descriptor_t *IODNew( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data )
342 uint8_t i_iod_scope = IODGetBytes( &i_data, &p_data, 1 ); /* scope */
343 uint8_t i_iod_label = IODGetBytes( &i_data, &p_data, 1 );
344 if( i_iod_label == 0x02 ) /* old vlc's buggy implementation of the IOD_descriptor */
346 i_iod_label = i_iod_scope;
347 i_iod_scope = 0x10; /* Add the missing front iod scope byte */
348 i_data++; p_data--; /* next byte must be tag */
351 iod_debug( p_object, " * iod label:0x%"PRIx8" scope:0x%"PRIx8,
352 i_iod_label, i_iod_scope );
354 if( i_iod_scope != 0x10 && i_iod_scope != 0x11 ) /* Uniqueness in program or transport */
356 iod_debug( p_object, " * can't handle reserved scope 0x%"PRIx8, i_iod_scope );
360 /* Initial Object Descriptor must follow */
361 iod_descriptor_t *p_iod = calloc( 1, sizeof( iod_descriptor_t ) );
365 /* IOD_InitialObjectDescrTag Parsing */
366 iod_read_params_t params;
367 params.p_iod = p_iod;
368 if ( 1 != IOD_Desc_Read( p_object, &i_data, &p_data,
369 IODTag_InitialObjectDescr, 1, params ) )
371 iod_debug( p_object, " cannot read InitialObjectDescr" );
379 void IODFree( iod_descriptor_t *p_iod )
383 free( p_iod->psz_url );
388 for( int i = 0; i < 255; i++ )
390 #define es_descr p_iod->es_descr[i]
393 if( es_descr.psz_url )
394 free( es_descr.psz_url );
396 free( es_descr.dec_descr.p_extra );