/src/vlc/modules/demux/mpeg/mpeg4_iod.c
Line | Count | Source |
1 | | /***************************************************************************** |
2 | | * mpeg4_iod.c: ISO 14496-1 IOD and OD 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 | | #include <vlc_bits.h> |
31 | | |
32 | | #include "mpeg4_iod.h" |
33 | | |
34 | | #include <stdlib.h> |
35 | | |
36 | | //#define OD_DEBUG 1 |
37 | | static void od_debug( vlc_object_t *p_object, const char *format, ... ) |
38 | 354k | { |
39 | | #ifdef OD_DEBUG |
40 | | va_list ap; |
41 | | va_start(ap, format); |
42 | | msg_GenericVa( p_object, VLC_MSG_DBG, format, ap ); |
43 | | va_end(ap); |
44 | | #else |
45 | 354k | VLC_UNUSED(format); |
46 | 354k | VLC_UNUSED(p_object); |
47 | 354k | #endif |
48 | 354k | } |
49 | | |
50 | | /***************************************************************************** |
51 | | * MP4 specific functions (OD parser) |
52 | | *****************************************************************************/ |
53 | | static unsigned ODDescriptorLength( unsigned *pi_data, const uint8_t **pp_data ) |
54 | 209k | { |
55 | 209k | unsigned int i_b; |
56 | 209k | unsigned int i_len = 0; |
57 | | |
58 | 209k | if(*pi_data == 0) |
59 | 48 | return 0; |
60 | | |
61 | 209k | do |
62 | 266k | { |
63 | 266k | i_b = **pp_data; |
64 | 266k | (*pp_data)++; |
65 | 266k | (*pi_data)--; |
66 | 266k | i_len = ( i_len << 7 ) + ( i_b&0x7f ); |
67 | | |
68 | 266k | } while( i_b&0x80 && *pi_data > 0 ); |
69 | | |
70 | 209k | if (i_len > *pi_data) |
71 | 15.7k | i_len = *pi_data; |
72 | | |
73 | 209k | return i_len; |
74 | 209k | } |
75 | | |
76 | | static unsigned ODGetBytes( unsigned *pi_data, const uint8_t **pp_data, size_t bytes ) |
77 | 929k | { |
78 | 929k | unsigned res = 0; |
79 | 2.48M | while( *pi_data > 0 && bytes-- ) |
80 | 1.55M | { |
81 | 1.55M | res <<= 8; |
82 | 1.55M | res |= **pp_data; |
83 | 1.55M | (*pp_data)++; |
84 | 1.55M | (*pi_data)--; |
85 | 1.55M | } |
86 | | |
87 | 929k | return res; |
88 | 929k | } |
89 | | |
90 | | static char* ODGetURL( unsigned *pi_data, const uint8_t **pp_data ) |
91 | 74 | { |
92 | 74 | unsigned len = ODGetBytes( pi_data, pp_data, 1 ); |
93 | 74 | if (len > *pi_data) |
94 | 38 | len = *pi_data; |
95 | 74 | char *url = strndup( (char*)*pp_data, len ); |
96 | 74 | *pp_data += len; |
97 | 74 | *pi_data -= len; |
98 | 74 | return url; |
99 | 74 | } |
100 | | |
101 | 46.2k | #define ODTag_ObjectDescr 0x01 |
102 | 9.89k | #define ODTag_InitialObjectDescr 0x02 |
103 | 72.4k | #define ODTag_ESDescr 0x03 |
104 | 76.2k | #define ODTag_DecConfigDescr 0x04 |
105 | 63.1k | #define ODTag_DecSpecificDescr 0x05 |
106 | 72.8k | #define ODTag_SLDescr 0x06 |
107 | | |
108 | | /* Unified pointer for read helper */ |
109 | | typedef union |
110 | | { |
111 | | od_descriptor_t *p_od; |
112 | | od_descriptor_t **pp_ods; |
113 | | es_mpeg4_descriptor_t *es_descr; |
114 | | decoder_config_descriptor_t *p_dec_config; |
115 | | sl_config_descriptor_t *sl_descr; |
116 | | } od_read_params_t; |
117 | | |
118 | | static uint8_t OD_Desc_Read( vlc_object_t *, unsigned *, const uint8_t **, uint8_t, uint8_t, od_read_params_t params ); |
119 | | |
120 | 34.7k | #define SL_Predefined_Custom 0x00 |
121 | 1 | #define SL_Predefined_NULL 0x01 |
122 | 1 | #define SL_Predefined_MP4 0x02 |
123 | | static bool OD_SLDesc_Read( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data, |
124 | | od_read_params_t params ) |
125 | 34.7k | { |
126 | 34.7k | sl_config_descriptor_t *sl_descr = params.sl_descr; |
127 | | |
128 | 34.7k | uint8_t i_predefined = ODGetBytes( &i_data, &p_data, 1 ); |
129 | 34.7k | switch( i_predefined ) |
130 | 34.7k | { |
131 | 34.7k | case SL_Predefined_Custom: |
132 | 34.7k | if( i_data < 15 ) |
133 | 2 | return false; |
134 | 34.6k | sl_descr->i_flags = ODGetBytes( &i_data, &p_data, 1 ); |
135 | 34.6k | sl_descr->i_timestamp_resolution = ODGetBytes( &i_data, &p_data, 4 ); |
136 | 34.6k | sl_descr->i_OCR_resolution = ODGetBytes( &i_data, &p_data, 4 ); |
137 | 34.6k | sl_descr->i_timestamp_length = ODGetBytes( &i_data, &p_data, 1 ); |
138 | 34.6k | sl_descr->i_OCR_length = ODGetBytes( &i_data, &p_data, 1 ); |
139 | 34.6k | sl_descr->i_AU_length = ODGetBytes( &i_data, &p_data, 1 ); |
140 | 34.6k | sl_descr->i_instant_bitrate_length = ODGetBytes( &i_data, &p_data, 1 ); |
141 | 34.6k | uint16_t i16 = ODGetBytes( &i_data, &p_data, 2 ); |
142 | 34.6k | sl_descr->i_degradation_priority_length = i16 >> 12; |
143 | 34.6k | sl_descr->i_AU_seqnum_length = (i16 >> 7) & 0x1f; |
144 | 34.6k | sl_descr->i_packet_seqnum_length = (i16 >> 2) & 0x1f; |
145 | 34.6k | break; |
146 | 1 | case SL_Predefined_NULL: |
147 | 1 | memset( sl_descr, 0, sizeof(*sl_descr) ); |
148 | 1 | sl_descr->i_timestamp_resolution = 1000; |
149 | 1 | sl_descr->i_timestamp_length = 32; |
150 | 1 | break; |
151 | 1 | case SL_Predefined_MP4: |
152 | 1 | memset( sl_descr, 0, sizeof(*sl_descr) ); |
153 | 1 | sl_descr->i_flags = USE_TIMESTAMPS_FLAG; |
154 | 1 | break; |
155 | 70 | default: |
156 | | /* reserved */ |
157 | 70 | return false; |
158 | 34.7k | } |
159 | | |
160 | 34.7k | if( sl_descr->i_flags & USE_DURATION_FLAG ) |
161 | 138 | { |
162 | 138 | if( i_data < 8 ) |
163 | 138 | return false; |
164 | 0 | sl_descr->i_timescale = ODGetBytes( &i_data, &p_data, 4 ); |
165 | 0 | sl_descr->i_accessunit_duration = ODGetBytes( &i_data, &p_data, 2 ); |
166 | 0 | sl_descr->i_compositionunit_duration = ODGetBytes( &i_data, &p_data, 2 ); |
167 | 0 | } |
168 | | |
169 | 34.5k | if( (sl_descr->i_flags & USE_TIMESTAMPS_FLAG) == 0 ) |
170 | 55 | { |
171 | 55 | bs_t s; |
172 | 55 | bs_init( &s, p_data, i_data ); |
173 | 55 | sl_descr->i_startdecoding_timestamp = bs_read( &s, sl_descr->i_timestamp_length ); |
174 | 55 | sl_descr->i_startcomposition_timestamp = bs_read( &s, sl_descr->i_timestamp_length ); |
175 | 55 | } |
176 | | |
177 | 34.5k | od_debug( p_object, " * read sl desc predefined: 0x%x", i_predefined ); |
178 | 34.5k | return true; |
179 | 34.7k | } |
180 | | |
181 | | static bool OD_DecSpecificDesc_Read( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data, |
182 | | od_read_params_t params ) |
183 | 25.1k | { |
184 | 25.1k | VLC_UNUSED(p_object); |
185 | 25.1k | decoder_config_descriptor_t *p_dec_config = params.p_dec_config; |
186 | | |
187 | 25.1k | p_dec_config->p_extra = malloc( i_data ); |
188 | 25.1k | if( p_dec_config->p_extra ) |
189 | 25.1k | { |
190 | 25.1k | p_dec_config->i_extra = i_data; |
191 | 25.1k | memcpy( p_dec_config->p_extra, p_data, p_dec_config->i_extra ); |
192 | 25.1k | } |
193 | | |
194 | 25.1k | return !!p_dec_config->i_extra; |
195 | 25.1k | } |
196 | | |
197 | | static bool OD_DecConfigDesc_Read( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data, |
198 | | od_read_params_t params ) |
199 | 38.0k | { |
200 | 38.0k | decoder_config_descriptor_t *p_dec_config = params.p_dec_config; |
201 | | |
202 | 38.0k | if( i_data < 13 ) |
203 | 87 | return false; |
204 | | |
205 | 37.9k | p_dec_config->i_objectTypeIndication = ODGetBytes( &i_data, &p_data, 1 ); |
206 | 37.9k | uint8_t i_flags = ODGetBytes( &i_data, &p_data, 1 ); |
207 | 37.9k | p_dec_config->i_streamType = i_flags >> 2; |
208 | | |
209 | 37.9k | ODGetBytes( &i_data, &p_data, 3 ); /* bufferSizeDB */ |
210 | 37.9k | ODGetBytes( &i_data, &p_data, 4 ); /* maxBitrate */ |
211 | 37.9k | ODGetBytes( &i_data, &p_data, 4 ); /* avgBitrate */ |
212 | | |
213 | | /* DecoderSpecificDescr */ |
214 | 37.9k | OD_Desc_Read( p_object, &i_data, &p_data, |
215 | 37.9k | ODTag_DecSpecificDescr, 1, params ); |
216 | | |
217 | 37.9k | od_debug( p_object, " * read decoder objecttype: %x streamtype:%x extra: %u", |
218 | 37.9k | p_dec_config->i_objectTypeIndication, p_dec_config->i_streamType, p_dec_config->i_extra ); |
219 | | /* ProfileLevelIndicator [0..255] */ |
220 | 37.9k | return true; |
221 | 38.0k | } |
222 | | |
223 | | static bool OD_ESDesc_Read( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data, |
224 | | od_read_params_t params ) |
225 | 38.6k | { |
226 | 38.6k | es_mpeg4_descriptor_t *es_descr = params.es_descr; |
227 | | |
228 | 38.6k | if ( i_data < 3 ) |
229 | 1 | return false; |
230 | 38.6k | es_descr->i_es_id = ODGetBytes( &i_data, &p_data, 2 ); |
231 | 38.6k | uint8_t i_flags = ODGetBytes( &i_data, &p_data, 1 ); |
232 | | |
233 | 38.6k | if( ( i_flags >> 7 )&0x01 ) |
234 | 81 | { |
235 | 81 | if ( i_data < 2 ) |
236 | 64 | return false; |
237 | 17 | ODGetBytes( &i_data, &p_data, 2 ); /* dependOn_es_id */ |
238 | 17 | } |
239 | | |
240 | 38.5k | if( (i_flags >> 6) & 0x01 ) |
241 | 27 | es_descr->psz_url = ODGetURL( &i_data, &p_data ); |
242 | | |
243 | 38.5k | if( ( i_flags >> 5 )&0x01 ) |
244 | 38.4k | { |
245 | 38.4k | if ( i_data < 2 ) |
246 | 394 | return false; |
247 | 38.0k | ODGetBytes( &i_data, &p_data, 2 ); /* OCR_es_id */ |
248 | 38.0k | } |
249 | | |
250 | 38.1k | od_debug( p_object, " * read ES Descriptor for es id %"PRIx16, es_descr->i_es_id ); |
251 | | |
252 | | /* DecoderConfigDescr */ |
253 | 38.1k | params.p_dec_config = &es_descr->dec_descr; |
254 | 38.1k | if ( 1 != OD_Desc_Read( p_object, &i_data, &p_data, |
255 | 38.1k | ODTag_DecConfigDescr, 1, params ) ) |
256 | 145 | return false; |
257 | | |
258 | | /* SLDescr */ |
259 | 38.0k | params.sl_descr = &es_descr->sl_descr; |
260 | 38.0k | OD_Desc_Read( p_object, &i_data, &p_data, ODTag_SLDescr, 1, params ); |
261 | | |
262 | | /* IPI / IP / IPMP ... */ |
263 | | |
264 | 38.0k | es_descr->b_ok = true; |
265 | | |
266 | 38.0k | return true; |
267 | 38.1k | } |
268 | | |
269 | | static bool OD_InitialObjectDesc_Read( vlc_object_t *p_object, unsigned i_data, |
270 | | const uint8_t *p_data, od_read_params_t params ) |
271 | 4.94k | { |
272 | 4.94k | od_descriptor_t *p_iod = params.p_od; |
273 | 4.94k | if( i_data < 3 + 5 + 2 ) |
274 | 0 | return false; |
275 | | |
276 | 4.94k | p_iod->i_ID = ( ODGetBytes( &i_data, &p_data, 1 ) << 2 ); |
277 | 4.94k | uint8_t i_flags = ODGetBytes( &i_data, &p_data, 1 ); |
278 | 4.94k | p_iod->i_ID |= i_flags >> 6; |
279 | | |
280 | 4.94k | od_debug( p_object, " * ObjectDescriptorID: %"PRIu16, p_iod->i_ID ); |
281 | 4.94k | od_debug( p_object, " * includeInlineProfileLevel flag: 0x%"PRIx8, ( i_flags >> 4 )&0x01 ); |
282 | 4.94k | if ( (i_flags >> 5) & 0x01 ) |
283 | 0 | { |
284 | 0 | p_iod->psz_url = ODGetURL( &i_data, &p_data ); |
285 | 0 | od_debug( p_object, " * URL: %s", p_iod->psz_url ); |
286 | 0 | return true; /* leaves out unparsed remaining extdescr */ |
287 | 0 | } |
288 | | |
289 | 4.94k | if( i_data < 5 + 2 ) /* at least one ES desc */ |
290 | 0 | return false; |
291 | | |
292 | | /* Profile Level Indication */ |
293 | 4.94k | ODGetBytes( &i_data, &p_data, 1 ); /* OD */ |
294 | 4.94k | ODGetBytes( &i_data, &p_data, 1 ); /* scene */ |
295 | 4.94k | ODGetBytes( &i_data, &p_data, 1 ); /* audio */ |
296 | 4.94k | ODGetBytes( &i_data, &p_data, 1 ); /* visual */ |
297 | 4.94k | ODGetBytes( &i_data, &p_data, 1 ); /* graphics */ |
298 | | |
299 | | /* Now read */ |
300 | | /* 1..255 ESdescr */ |
301 | 4.94k | uint8_t i_desc_count = OD_Desc_Read( p_object, &i_data, &p_data, |
302 | 4.94k | ODTag_ESDescr, ES_DESCRIPTOR_COUNT, params ); |
303 | 4.94k | if( i_desc_count == 0 ) |
304 | 0 | { |
305 | 0 | od_debug( p_object, " * missing ES Descriptor" ); |
306 | 0 | return false; |
307 | 0 | } |
308 | | |
309 | | /* 0..255 OCIdescr */ |
310 | | /* 0..255 IPMPdescpointer */ |
311 | | /* 0..255 IPMPdesc */ |
312 | | /* 0..1 IPMPtoollistdesc */ |
313 | | /* 0..255 Extensiondescr */ |
314 | | |
315 | 4.94k | return true; |
316 | 4.94k | } |
317 | | |
318 | | static bool ODObjectDescriptorRead( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data, |
319 | | od_read_params_t params ) |
320 | 28.9k | { |
321 | 28.9k | od_descriptor_t *p_iod = params.p_od; |
322 | 28.9k | if( i_data < 3 + 2 ) |
323 | 73 | return false; |
324 | | |
325 | 28.8k | p_iod->i_ID = ( ODGetBytes( &i_data, &p_data, 1 ) << 2 ); |
326 | 28.8k | uint8_t i_flags = ODGetBytes( &i_data, &p_data, 1 ); |
327 | 28.8k | p_iod->i_ID |= i_flags >> 6; |
328 | | |
329 | 28.8k | od_debug( p_object, " * ObjectDescriptorID: %"PRIu16, p_iod->i_ID ); |
330 | 28.8k | if ( (i_flags >> 5) & 0x01 ) |
331 | 47 | { |
332 | 47 | p_iod->psz_url = ODGetURL( &i_data, &p_data ); |
333 | 47 | od_debug( p_object, " * URL: %s", p_iod->psz_url ); |
334 | 47 | return true; |
335 | 47 | } |
336 | | |
337 | 28.8k | if( i_data < 2 ) /* at least one ES desc */ |
338 | 0 | return false; |
339 | | |
340 | | /* 1..255 ESdescr */ |
341 | 28.8k | uint8_t i_desc_count = OD_Desc_Read( p_object, &i_data, &p_data, |
342 | 28.8k | ODTag_ESDescr, ES_DESCRIPTOR_COUNT, params ); |
343 | 28.8k | if( i_desc_count == 0 ) |
344 | 96 | { |
345 | 96 | od_debug( p_object, " * missing ES Descriptor" ); |
346 | 96 | return false; |
347 | 96 | } |
348 | | |
349 | | /* 0..255 OCIdescr */ |
350 | | /* 0..255 IPMPdescpointer */ |
351 | | /* 0..255 IPMPdesc */ |
352 | | /* 0..1 IPMPtoollistdesc */ |
353 | | /* 0..255 Extensiondescr */ |
354 | | |
355 | 28.7k | return true; |
356 | 28.8k | } |
357 | | |
358 | | static uint8_t OD_Desc_Read( vlc_object_t *p_object, unsigned *pi_data, const uint8_t **pp_data, |
359 | | uint8_t i_target_tag, uint8_t i_max_desc, od_read_params_t params ) |
360 | 170k | { |
361 | 170k | uint8_t i_read_count = 0; |
362 | | |
363 | 340k | for (unsigned i = 0; *pi_data > 2 && i < i_max_desc; i++) |
364 | 180k | { |
365 | 180k | const uint8_t i_tag = ODGetBytes( pi_data, pp_data, 1 ); |
366 | 180k | const unsigned i_length = ODDescriptorLength( pi_data, pp_data ); |
367 | 180k | if( i_target_tag != i_tag || i_length > *pi_data ) |
368 | 9.83k | break; |
369 | | |
370 | 170k | unsigned i_descriptor_data = i_length; |
371 | 170k | const uint8_t *p_descriptor_data = *pp_data; |
372 | | |
373 | 170k | od_debug( p_object, " Reading descriptor 0x%"PRIx8": found tag 0x%"PRIx8" left %d", |
374 | 170k | i_target_tag, i_tag, *pi_data ); |
375 | 170k | switch( i_tag ) |
376 | 170k | { |
377 | 28.9k | case ODTag_ObjectDescr: |
378 | 28.9k | { |
379 | 28.9k | od_descriptor_t *p_od = calloc( 1, sizeof( od_descriptor_t ) ); |
380 | 28.9k | if( !p_od ) |
381 | 0 | break; |
382 | 28.9k | od_read_params_t childparams; |
383 | 28.9k | childparams.p_od = params.pp_ods[i_read_count] = p_od; |
384 | | /* od_descriptor_t *p_iod = (od_descriptor_t *) param; */ |
385 | 28.9k | if ( !ODObjectDescriptorRead( p_object, i_descriptor_data, |
386 | 28.9k | p_descriptor_data, childparams ) ) |
387 | 169 | {}; |
388 | 28.9k | break; |
389 | 28.9k | } |
390 | | |
391 | 4.94k | case ODTag_InitialObjectDescr: |
392 | 4.94k | { |
393 | 4.94k | od_descriptor_t *p_iod = calloc( 1, sizeof( od_descriptor_t ) ); |
394 | 4.94k | if( !p_iod ) |
395 | 0 | break; |
396 | 4.94k | od_read_params_t childparams; |
397 | 4.94k | childparams.p_od = params.pp_ods[i_read_count] = p_iod; |
398 | | /* od_descriptor_t *p_iod = (od_descriptor_t *) param; */ |
399 | 4.94k | if ( !OD_InitialObjectDesc_Read( p_object, i_descriptor_data, |
400 | 4.94k | p_descriptor_data, childparams ) ) |
401 | 0 | {}; |
402 | 4.94k | break; |
403 | 4.94k | } |
404 | | |
405 | 38.6k | case ODTag_ESDescr: /**/ |
406 | 38.6k | { |
407 | 38.6k | od_descriptor_t *p_iod = params.p_od; |
408 | 38.6k | od_read_params_t childparams; |
409 | 38.6k | childparams.es_descr = &p_iod->es_descr[i_read_count]; |
410 | 38.6k | if ( !OD_ESDesc_Read( p_object, i_descriptor_data, |
411 | 38.6k | p_descriptor_data, childparams ) ) |
412 | 604 | {}; |
413 | 38.6k | break; |
414 | 4.94k | } |
415 | | |
416 | 38.0k | case ODTag_DecConfigDescr: |
417 | 38.0k | { |
418 | 38.0k | if ( !OD_DecConfigDesc_Read( p_object, i_descriptor_data, |
419 | 38.0k | p_descriptor_data, params ) ) |
420 | 87 | {}; |
421 | 38.0k | break; |
422 | 4.94k | } |
423 | | |
424 | 25.1k | case ODTag_DecSpecificDescr: |
425 | 25.1k | { |
426 | 25.1k | if ( !OD_DecSpecificDesc_Read( p_object, i_descriptor_data, |
427 | 25.1k | p_descriptor_data, params ) ) |
428 | 0 | {}; |
429 | 25.1k | break; |
430 | 4.94k | } |
431 | | |
432 | 34.7k | case ODTag_SLDescr: |
433 | 34.7k | { |
434 | 34.7k | if ( !OD_SLDesc_Read( p_object, i_descriptor_data, |
435 | 34.7k | p_descriptor_data, params ) ) |
436 | 210 | {}; |
437 | 34.7k | break; |
438 | 4.94k | } |
439 | | |
440 | 0 | default: |
441 | 0 | od_debug( p_object, "trying to read unsupported descriptor" ); |
442 | 0 | break; |
443 | 170k | } |
444 | | |
445 | 170k | *pp_data += i_length; |
446 | 170k | *pi_data -= i_length; |
447 | | |
448 | 170k | i_read_count++; |
449 | 170k | } |
450 | | |
451 | 170k | return i_read_count; |
452 | 170k | } |
453 | | |
454 | | static uint8_t ODInit( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data, |
455 | | uint8_t i_start_tag, uint8_t i_min, uint8_t i_max, od_descriptor_t **pp_ods ) |
456 | 22.2k | { |
457 | 22.2k | od_read_params_t params; |
458 | 22.2k | params.pp_ods = pp_ods; |
459 | 22.2k | uint8_t i_read = OD_Desc_Read( p_object, &i_data, &p_data, i_start_tag, i_max, params ); |
460 | 22.2k | if ( i_read < i_min ) |
461 | 1.06k | { |
462 | 1.06k | od_debug( p_object, " cannot read first tag 0x%"PRIx8, i_start_tag ); |
463 | 1.06k | return 0; |
464 | 1.06k | } |
465 | | |
466 | 21.2k | return i_read; |
467 | 22.2k | } |
468 | | |
469 | | od_descriptor_t *IODNew( vlc_object_t *p_object, unsigned i_data, const uint8_t *p_data ) |
470 | 4.94k | { |
471 | 4.94k | if( i_data < 4 ) |
472 | 0 | return NULL; |
473 | | |
474 | 4.94k | uint8_t i_iod_scope = ODGetBytes( &i_data, &p_data, 1 ); /* scope */ |
475 | 4.94k | uint8_t i_iod_label = ODGetBytes( &i_data, &p_data, 1 ); |
476 | 4.94k | if( i_iod_label == 0x02 ) /* old vlc's buggy implementation of the OD_descriptor */ |
477 | 0 | { |
478 | 0 | i_iod_label = i_iod_scope; |
479 | 0 | i_iod_scope = 0x10; /* Add the missing front iod scope byte */ |
480 | 0 | i_data++; p_data--; /* next byte must be tag */ |
481 | 0 | } |
482 | | |
483 | 4.94k | od_debug( p_object, " * iod label:0x%"PRIx8" scope:0x%"PRIx8, |
484 | 4.94k | i_iod_label, i_iod_scope ); |
485 | | |
486 | 4.94k | if( i_iod_scope != 0x10 && i_iod_scope != 0x11 ) /* Uniqueness in program or transport */ |
487 | 0 | { |
488 | 0 | od_debug( p_object, " * can't handle reserved scope 0x%"PRIx8, i_iod_scope ); |
489 | 0 | return NULL; |
490 | 0 | } |
491 | | |
492 | 4.94k | od_descriptor_t * ods[1]; |
493 | 4.94k | uint8_t i_count = ODInit( p_object, i_data, p_data, ODTag_InitialObjectDescr, 1, 1, ods ); |
494 | 4.94k | if( !i_count ) |
495 | 0 | { |
496 | 0 | ODFree( ods[0] ); |
497 | 0 | return NULL; |
498 | 0 | } |
499 | 4.94k | return ods[0]; |
500 | 4.94k | } |
501 | | |
502 | | void ODFree( od_descriptor_t *p_iod ) |
503 | 33.8k | { |
504 | 33.8k | if( p_iod->psz_url ) |
505 | 47 | { |
506 | 47 | free( p_iod->psz_url ); |
507 | 47 | free( p_iod ); |
508 | 47 | return; |
509 | 47 | } |
510 | | |
511 | 8.65M | for( int i = 0; i < 255; i++ ) |
512 | 8.61M | { |
513 | 8.69M | #define es_descr p_iod->es_descr[i] |
514 | 8.61M | if( es_descr.b_ok ) |
515 | 38.0k | { |
516 | 38.0k | if( es_descr.psz_url ) |
517 | 4 | free( es_descr.psz_url ); |
518 | 38.0k | else |
519 | 38.0k | free( es_descr.dec_descr.p_extra ); |
520 | 38.0k | } |
521 | 8.61M | #undef es_descr |
522 | 8.61M | } |
523 | 33.8k | free( p_iod ); |
524 | 33.8k | } |
525 | | |
526 | | /***************************************************************************** |
527 | | * SL Packet Parser |
528 | | *****************************************************************************/ |
529 | | sl_header_data DecodeSLHeader( unsigned i_data, const uint8_t *p_data, |
530 | | const sl_config_descriptor_t *sl ) |
531 | 458k | { |
532 | 458k | sl_header_data ret = { 0 }; |
533 | | |
534 | 458k | bs_t s; |
535 | 458k | bs_init( &s, p_data, i_data ); |
536 | | |
537 | 458k | bool b_has_ocr = false; |
538 | 458k | bool b_is_idle = false; |
539 | 458k | bool b_has_padding = false; |
540 | 458k | uint8_t i_padding = 0; |
541 | | |
542 | 458k | if( sl->i_flags & USE_ACCESS_UNIT_START_FLAG ) |
543 | 396k | ret.b_au_start = bs_read1( &s ); |
544 | 458k | if( sl->i_flags & USE_ACCESS_UNIT_END_FLAG ) |
545 | 395k | ret.b_au_end = bs_read1( &s ); |
546 | 458k | if( sl->i_OCR_length > 0 ) |
547 | 202k | b_has_ocr = bs_read1( &s ); |
548 | 458k | if( sl->i_flags & USE_IDLE_FLAG ) |
549 | 397k | b_is_idle = bs_read1( &s ); |
550 | 458k | if( sl->i_flags & USE_PADDING_FLAG ) |
551 | 4.18k | b_has_padding = bs_read1( &s ); |
552 | | |
553 | 458k | if( ret.b_au_end == ret.b_au_start && ret.b_au_start == false ) |
554 | 127k | ret.b_au_end = ret.b_au_start = true; |
555 | | |
556 | 458k | if( b_has_padding ) |
557 | 2.08k | i_padding = bs_read( &s, 3 ); |
558 | | |
559 | | /* Optional fields */ |
560 | 458k | if( !b_is_idle && ( !b_has_padding || !i_padding ) ) /* When not idle and not only padding */ |
561 | 428k | { |
562 | 428k | bool b_has_dts = false; |
563 | 428k | bool b_has_cts = false; |
564 | 428k | bool b_has_instant_bitrate = false; |
565 | 428k | struct |
566 | 428k | { |
567 | 428k | bool *p_b; |
568 | 428k | vlc_tick_t *p_t; |
569 | 428k | } const timestamps[2] = { { &b_has_dts, &ret.i_dts }, { &b_has_cts, &ret.i_pts } }; |
570 | | |
571 | 428k | bs_read( &s, sl->i_packet_seqnum_length ); |
572 | | |
573 | 428k | if( sl->i_degradation_priority_length && bs_read1( &s ) ) |
574 | 2.95k | bs_read( &s, sl->i_degradation_priority_length ); |
575 | | |
576 | 428k | if( b_has_ocr ) |
577 | 19.7k | bs_read( &s, sl->i_OCR_length ); |
578 | | |
579 | 428k | if ( ret.b_au_start ) |
580 | 425k | { |
581 | 425k | if( sl->i_flags & USE_RANDOM_ACCESS_POINT_FLAG ) |
582 | 3.50k | bs_read1( &s ); |
583 | | |
584 | 425k | bs_read( &s, sl->i_AU_seqnum_length ); |
585 | | |
586 | 425k | if ( sl->i_flags & USE_TIMESTAMPS_FLAG ) |
587 | 362k | { |
588 | 362k | b_has_dts = bs_read1( &s ); |
589 | 362k | b_has_cts = bs_read1( &s ); |
590 | 362k | } |
591 | | |
592 | 425k | if( sl->i_instant_bitrate_length ) |
593 | 6.49k | b_has_instant_bitrate = bs_read1( &s ); |
594 | | |
595 | 1.27M | for( int i=0; i<2; i++ ) |
596 | 850k | { |
597 | 850k | if( !*(timestamps[i].p_b) ) |
598 | 519k | continue; |
599 | 331k | uint64_t i_read = bs_read( &s, __MIN( 32, sl->i_timestamp_length ) ); |
600 | 331k | if( sl->i_timestamp_length > 32 ) |
601 | 318k | { |
602 | 318k | uint8_t i_bits = __MAX( 1, sl->i_timestamp_length - 32 ); |
603 | 318k | i_read = i_read << i_bits; |
604 | 318k | i_read |= bs_read( &s, i_bits ); |
605 | 318k | } |
606 | 331k | if( sl->i_timestamp_resolution ) |
607 | 317k | *(timestamps[i].p_t) = VLC_TICK_0 + |
608 | 317k | vlc_tick_from_samples(i_read, sl->i_timestamp_resolution); |
609 | 331k | } |
610 | | |
611 | 425k | bs_read( &s, sl->i_AU_length ); |
612 | | |
613 | 425k | if( b_has_instant_bitrate ) |
614 | 1.89k | bs_read( &s, sl->i_instant_bitrate_length ); |
615 | 425k | } |
616 | | |
617 | | /* more to read if ExtSLConfigDescrTag */ |
618 | 428k | } |
619 | | |
620 | 458k | if ( b_has_padding && !i_padding ) /* all padding */ |
621 | 1.74k | ret.i_size = i_data; |
622 | 457k | else |
623 | 457k | ret.i_size = (bs_pos( &s ) + 7) / 8; |
624 | | |
625 | 458k | return ret; |
626 | 458k | } |
627 | | |
628 | | /***************************************************************************** |
629 | | * OD Commands Parser |
630 | | *****************************************************************************/ |
631 | 17.3k | #define ODTag_ObjectDescrUpdate 0x01 |
632 | 455 | #define ODTag_ObjectDescrRemove 0x02 |
633 | | |
634 | | struct bsearch_key |
635 | | { |
636 | | uint16_t id; |
637 | | const od_descriptor_t ***ppp_lowerbest; |
638 | | }; |
639 | | |
640 | | static int bsearch_cmp( const void *key_, const void *el_ ) |
641 | 38.0k | { |
642 | 38.0k | const struct bsearch_key *key = key_; |
643 | 38.0k | const od_descriptor_t *el = *((const od_descriptor_t **) el_); |
644 | 38.0k | if( key->id < el->i_ID ) |
645 | 11.1k | return -1; |
646 | 26.8k | if( key->ppp_lowerbest ) |
647 | 24.6k | *key->ppp_lowerbest = (const od_descriptor_t **) el_; |
648 | 26.8k | if( key->id > el->i_ID ) |
649 | 5.78k | return 1; |
650 | 21.1k | return 0; |
651 | 26.8k | } |
652 | | |
653 | | static void ObjectDescrUpdateCommandRead( vlc_object_t *p_object, od_descriptors_t *p_ods, |
654 | | unsigned i_data, const uint8_t *p_data ) |
655 | 17.3k | { |
656 | 17.3k | od_descriptor_t *p_odsread[255]; |
657 | 17.3k | uint8_t i_count = ODInit( p_object, i_data, p_data, ODTag_ObjectDescr, 1, 255, p_odsread ); |
658 | 46.2k | for( int i=0; i<i_count; i++ ) |
659 | 28.9k | { |
660 | 28.9k | od_descriptor_t *p_od = p_odsread[i]; |
661 | 28.9k | const od_descriptor_t **pp_lowerbest = NULL; |
662 | 28.9k | struct bsearch_key key = { .id = p_od->i_ID, .ppp_lowerbest = &pp_lowerbest }; |
663 | 28.9k | od_descriptor_t **pp_cur = bsearch( &key, p_ods->objects.p_elems, |
664 | 28.9k | p_ods->objects.i_size, sizeof(*pp_cur), |
665 | 28.9k | bsearch_cmp ); |
666 | 28.9k | if ( pp_cur ) |
667 | 21.0k | { |
668 | 21.0k | int i_pos = pp_cur - p_ods->objects.p_elems; |
669 | 21.0k | ODFree( *pp_cur ); |
670 | 21.0k | p_ods->objects.p_elems[i_pos] = p_od; |
671 | 21.0k | } |
672 | 7.85k | else |
673 | 7.85k | { |
674 | 7.85k | int i_pos = pp_lowerbest ? pp_lowerbest - (const od_descriptor_t **) p_ods->objects.p_elems + 1 : 0; |
675 | 7.85k | ARRAY_INSERT( p_ods->objects, p_od, i_pos ); |
676 | 7.85k | } |
677 | 28.9k | } |
678 | 17.3k | } |
679 | | |
680 | | static void ObjectDescrRemoveCommandRead( vlc_object_t *p_object, od_descriptors_t *p_ods, |
681 | | unsigned i_data, const uint8_t *p_data ) |
682 | 455 | { |
683 | 455 | VLC_UNUSED(p_object); |
684 | 455 | bs_t s; |
685 | 455 | bs_init( &s, p_data, i_data ); |
686 | 6.50k | for( unsigned i=0; i< (i_data * 8 / 10); i++ ) |
687 | 6.04k | { |
688 | 6.04k | struct bsearch_key key = { 0 }; |
689 | 6.04k | key.id = bs_read( &s, 10 ); |
690 | 6.04k | od_descriptor_t **pp_cur = bsearch( &key, p_ods->objects.p_elems, |
691 | 6.04k | p_ods->objects.i_size, sizeof(*pp_cur), |
692 | 6.04k | bsearch_cmp ); |
693 | 6.04k | if( pp_cur ) |
694 | 27 | ARRAY_REMOVE( p_ods->objects, pp_cur - p_ods->objects.p_elems ); |
695 | 6.04k | } |
696 | 455 | } |
697 | | |
698 | | void DecodeODCommand( vlc_object_t *p_object, od_descriptors_t *p_ods, |
699 | | unsigned i_data, const uint8_t *p_data ) |
700 | 18.1k | { |
701 | 46.9k | while( i_data ) |
702 | 28.9k | { |
703 | 28.9k | const uint8_t i_tag = ODGetBytes( &i_data, &p_data, 1 ); |
704 | 28.9k | const unsigned i_length = ODDescriptorLength( &i_data, &p_data ); |
705 | 28.9k | if( !i_length || i_length > i_data ) |
706 | 162 | break; |
707 | 28.8k | od_debug( p_object, "Decode tag 0x%x length %d", i_tag, i_length ); |
708 | 28.8k | switch( i_tag ) |
709 | 28.8k | { |
710 | 17.3k | case ODTag_ObjectDescrUpdate: |
711 | 17.3k | ObjectDescrUpdateCommandRead( p_object, p_ods, i_length, p_data ); |
712 | 17.3k | break; |
713 | 455 | case ODTag_ObjectDescrRemove: |
714 | 455 | ObjectDescrRemoveCommandRead( p_object, p_ods, i_length, p_data ); |
715 | 455 | break; |
716 | 11.0k | default: |
717 | 11.0k | break; |
718 | 28.8k | } |
719 | 28.8k | p_data += i_length; |
720 | 28.8k | i_data -= i_length; |
721 | 28.8k | } |
722 | 18.1k | } |