]> git.sesse.net Git - vlc/blob - modules/demux/mpeg4_iod.c
b8276562db2ee4a97399e1f29f1c20727b6992b2
[vlc] / modules / demux / mpeg4_iod.c
1 /*****************************************************************************
2  * mpeg4_iod.c: ISO 14496-1 IOD and parsers
3  *****************************************************************************
4  * Copyright (C) 2004-2015 VLC authors and VideoLAN
5  *
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.
10  *
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.
15  *
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  *****************************************************************************/
20
21 /*****************************************************************************
22  * Preamble
23  *****************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <vlc_common.h>
30
31 #include "mpeg4_iod.h"
32
33 //#define IOD_DEBUG 1
34 static void iod_debug( vlc_object_t *p_object, const char *format, ... )
35 {
36 #ifdef IOD_DEBUG
37     va_list ap;
38     va_start(ap, format);
39     msg_GenericVa( p_object, VLC_MSG_DBG, format, ap );
40     va_end(ap);
41 #else
42     VLC_UNUSED(format);
43     VLC_UNUSED(p_object);
44 #endif
45 }
46
47 /*****************************************************************************
48  * MP4 specific functions (IOD parser)
49  *****************************************************************************/
50 static unsigned IODDescriptorLength( unsigned *pi_data, const uint8_t **pp_data )
51 {
52     unsigned int i_b;
53     unsigned int i_len = 0;
54
55     if(*pi_data == 0)
56         return 0;
57
58     do
59     {
60         i_b = **pp_data;
61         (*pp_data)++;
62         (*pi_data)--;
63         i_len = ( i_len << 7 ) + ( i_b&0x7f );
64
65     } while( i_b&0x80 && *pi_data > 0 );
66
67     if (i_len > *pi_data)
68         i_len = *pi_data;
69
70     return i_len;
71 }
72
73 static unsigned IODGetBytes( unsigned *pi_data, const uint8_t **pp_data, size_t bytes )
74 {
75     unsigned res = 0;
76     while( *pi_data > 0 && bytes-- )
77     {
78         res <<= 8;
79         res |= **pp_data;
80         (*pp_data)++;
81         (*pi_data)--;
82     }
83
84     return res;
85 }
86
87 static char* IODGetURL( unsigned *pi_data, const uint8_t **pp_data )
88 {
89     unsigned len = IODGetBytes( pi_data, pp_data, 1 );
90     if (len > *pi_data)
91         len = *pi_data;
92     char *url = strndup( (char*)*pp_data, len );
93     *pp_data += len;
94     *pi_data -= len;
95     return url;
96 }
97
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
104
105 /* Unified pointer for read helper */
106 typedef union
107 {
108     iod_descriptor_t *p_iod;
109     es_mpeg4_descriptor_t *es_descr;
110     decoder_config_descriptor_t *p_dec_config;
111 } iod_read_params_t;
112
113 static uint8_t IOD_Desc_Read( vlc_object_t *, unsigned *, const uint8_t **, uint8_t, uint8_t, iod_read_params_t params );
114
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 )
117 {
118     VLC_UNUSED(p_object);
119     VLC_UNUSED(i_data);
120     VLC_UNUSED(p_data);
121     VLC_UNUSED(params);
122     return true;
123 }
124
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 )
127 {
128     VLC_UNUSED(p_object);
129     decoder_config_descriptor_t *p_dec_config = params.p_dec_config;
130
131     p_dec_config->p_extra = malloc( i_data );
132     if( p_dec_config->p_extra )
133     {
134         p_dec_config->i_extra = i_data;
135         memcpy( p_dec_config->p_extra, p_data, p_dec_config->i_extra );
136     }
137
138     return !!p_dec_config->i_extra;
139 }
140
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 )
143 {
144     decoder_config_descriptor_t *p_dec_config = params.p_dec_config;
145
146     if( i_data < 13 )
147         return false;
148
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;
152
153     IODGetBytes( &i_data, &p_data, 3 ); /* bufferSizeDB */
154     IODGetBytes( &i_data, &p_data, 4 ); /* maxBitrate */
155     IODGetBytes( &i_data, &p_data, 4 ); /* avgBitrate */
156
157     /* DecoderSpecificDescr */
158     IOD_Desc_Read( p_object, &i_data, &p_data,
159                    IODTag_DecSpecificDescr, 1, params );
160
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] */
164     return true;
165 }
166
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 )
169 {
170     es_mpeg4_descriptor_t *es_descr = params.es_descr;
171
172     if ( i_data < 3 )
173         return false;
174     es_descr->i_es_id = IODGetBytes( &i_data, &p_data, 2 );
175     uint8_t i_flags = IODGetBytes( &i_data, &p_data, 1 );
176
177     if( ( i_flags >> 7 )&0x01 )
178     {
179         if ( i_data < 2 )
180             return false;
181         IODGetBytes( &i_data, &p_data, 2 ); /* dependOn_es_id */
182     }
183
184     if( (i_flags >> 6) & 0x01 )
185         es_descr->psz_url = IODGetURL( &i_data, &p_data );
186
187     if( ( i_flags >> 5 )&0x01 )
188     {
189         if ( i_data < 2 )
190             return false;
191         IODGetBytes( &i_data, &p_data, 2 ); /* OCR_es_id */
192     }
193
194     iod_debug( p_object, "   * read ES Descriptor for es id %"PRIx16, es_descr->i_es_id );
195
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 ) )
200         return false;
201
202     /* SLDescr */
203     IOD_Desc_Read( p_object, &i_data, &p_data, IODTag_SLDescr, 1, params );
204
205     /* IPI / IP / IPMP ... */
206
207     es_descr->b_ok = true;
208
209     return true;
210 }
211
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 )
214 {
215     iod_descriptor_t *p_iod = params.p_iod;
216     if( i_data < 3 + 5 + 2 )
217         return false;
218
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;
222
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 )
226     {
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 */
230     }
231
232     if( i_data < 5 + 2 ) /* at least one ES desc */
233         return false;
234
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 */
241
242     /* Now read */
243     /* 1..255 ESdescr */
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 )
247     {
248         iod_debug( p_object, "   * missing ES Descriptor" );
249         return false;
250     }
251
252     /* 0..255 OCIdescr */
253     /* 0..255 IPMPdescpointer */
254     /* 0..255 IPMPdesc */
255     /* 0..1   IPMPtoollistdesc */
256     /* 0..255 Extensiondescr */
257
258     return true;
259 }
260
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 )
263 {
264     uint8_t i_read_count = 0;
265
266     for (unsigned i = 0; *pi_data > 2 && i < i_max_desc; i++)
267     {
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 )
271             break;
272
273         unsigned i_descriptor_data = i_length;
274         const uint8_t *p_descriptor_data = *pp_data;
275
276         iod_debug( p_object, "  Reading descriptor 0x%"PRIx8": found tag 0x%"PRIx8" left %d",
277                    i_target_tag, i_tag, *pi_data );
278         switch( i_tag )
279         {
280             case IODTag_InitialObjectDescr:
281             {
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 ) )
285                 {};
286                 break;
287             }
288
289             case IODTag_ESDescr: /**/
290             {
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 ) )
295                 {};
296                 break;
297             }
298
299             case IODTag_DecConfigDescr:
300             {
301                 if ( !IOD_DecConfigDesc_Read( p_object, i_descriptor_data,
302                                               p_descriptor_data, params ) )
303                 {};
304                 break;
305             }
306
307             case IODTag_DecSpecificDescr:
308             {
309                 if ( !IOD_DecSpecificDesc_Read( p_object, i_descriptor_data,
310                                                 p_descriptor_data, params ) )
311                 {};
312                 break;
313             }
314
315             case IODTag_SLDescr:
316             {
317                 if ( !IOD_SLDesc_Read( p_object, i_descriptor_data,
318                                        p_descriptor_data, params ) )
319                 {};
320                 break;
321             }
322
323             default:
324                 iod_debug( p_object, "trying to read unsupported descriptor" );
325                 break;
326         }
327
328         *pp_data += i_length;
329         *pi_data -= i_length;
330
331         i_read_count++;
332     }
333
334     return i_read_count;
335 }
336
337 iod_descriptor_t *IODNew( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data )
338 {
339     if( i_data < 4 )
340         return NULL;
341
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 */
345     {
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 */
349     }
350
351     iod_debug( p_object, "  * iod label:0x%"PRIx8" scope:0x%"PRIx8,
352                i_iod_label, i_iod_scope );
353
354     if( i_iod_scope != 0x10 && i_iod_scope != 0x11 ) /* Uniqueness in program or transport */
355     {
356         iod_debug( p_object, "  * can't handle reserved scope 0x%"PRIx8, i_iod_scope );
357         return NULL;
358     }
359
360     /* Initial Object Descriptor must follow */
361     iod_descriptor_t *p_iod = calloc( 1, sizeof( iod_descriptor_t ) );
362     if( !p_iod )
363         return NULL;
364
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 ) )
370     {
371         iod_debug( p_object, "   cannot read InitialObjectDescr" );
372         free( p_iod );
373         return NULL;
374     }
375
376     return p_iod;
377 }
378
379 void IODFree( iod_descriptor_t *p_iod )
380 {
381     if( p_iod->psz_url )
382     {
383         free( p_iod->psz_url );
384         free( p_iod );
385         return;
386     }
387
388     for( int i = 0; i < 255; i++ )
389     {
390 #define es_descr p_iod->es_descr[i]
391         if( es_descr.b_ok )
392         {
393             if( es_descr.psz_url )
394                 free( es_descr.psz_url );
395             else
396                 free( es_descr.dec_descr.p_extra );
397         }
398 #undef  es_descr
399     }
400     free( p_iod );
401 }