/src/vlc/modules/demux/asf/asfpacket.c
Line | Count | Source (jump to first uncovered line) |
1 | | /***************************************************************************** |
2 | | * asfpacket.c : |
3 | | ***************************************************************************** |
4 | | * Copyright © 2001-2004, 2011, 2014 VLC authors and VideoLAN |
5 | | * |
6 | | * Authors: Laurent Aimar <fenrir@via.ecp.fr> |
7 | | * |
8 | | * This program is free software; you can redistribute it and/or modify it |
9 | | * under the terms of the GNU Lesser General Public License as published by |
10 | | * the Free Software Foundation; either version 2.1 of the License, or |
11 | | * (at your option) any later version. |
12 | | * |
13 | | * This program is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU Lesser General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public License |
19 | | * along with this program; if not, write to the Free Software Foundation, |
20 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
21 | | *****************************************************************************/ |
22 | | #ifdef HAVE_CONFIG_H |
23 | | # include "config.h" |
24 | | #endif |
25 | | |
26 | | #include "asfpacket.h" |
27 | | #include <limits.h> |
28 | | |
29 | | #ifndef NDEBUG |
30 | | # define ASF_DEBUG 1 |
31 | | #endif |
32 | | |
33 | | typedef struct asf_packet_t |
34 | | { |
35 | | uint32_t property; |
36 | | uint32_t length; |
37 | | uint32_t padding_length; |
38 | | vlc_tick_t send_time; |
39 | | bool multiple; |
40 | | int length_type; |
41 | | |
42 | | /* buffer handling for this ASF packet */ |
43 | | uint32_t i_skip; |
44 | | const uint8_t *p_peek; |
45 | | uint32_t left; |
46 | | } asf_packet_t; |
47 | | |
48 | | static inline int GetValue2b(uint32_t *var, const uint8_t *p, unsigned int *skip, int left, int bits) |
49 | 208k | { |
50 | 208k | switch(bits&0x03) |
51 | 208k | { |
52 | 81.0k | case 1: |
53 | 81.0k | if (left < 1) |
54 | 4 | return -1; |
55 | 81.0k | *var = p[*skip]; *skip += 1; |
56 | 81.0k | return 0; |
57 | 34.4k | case 2: |
58 | 34.4k | if (left < 2) |
59 | 4 | return -1; |
60 | 34.4k | *var = GetWLE(&p[*skip]); *skip += 2; |
61 | 34.4k | return 0; |
62 | 37.6k | case 3: |
63 | 37.6k | if (left < 4) |
64 | 5 | return -1; |
65 | 37.6k | *var = GetDWLE(&p[*skip]); *skip += 4; |
66 | 37.6k | return 0; |
67 | 54.9k | case 0: |
68 | 54.9k | default: |
69 | 54.9k | return 0; |
70 | 208k | } |
71 | 208k | } |
72 | | |
73 | | static int DemuxSubPayload( asf_packet_sys_t *p_packetsys, |
74 | | uint8_t i_stream_number, asf_track_info_t *p_tkinfo, |
75 | | uint32_t i_sub_payload_data_length, vlc_tick_t i_pts, vlc_tick_t i_dts, |
76 | | uint32_t i_media_object_number, uint32_t i_media_object_offset, |
77 | | bool b_keyframe, bool b_ignore_pts ) |
78 | 25.8k | { |
79 | 25.8k | block_t **pp_frame = &p_tkinfo->p_frame; |
80 | | |
81 | 25.8k | if( p_packetsys->b_deduplicate ) |
82 | 0 | { |
83 | 0 | for(size_t i=0; i<p_tkinfo->i_pktcount; i++) |
84 | 0 | { |
85 | 0 | if(p_tkinfo->prev[i].media_number == i_media_object_number && |
86 | 0 | p_tkinfo->prev[i].media_offset == i_media_object_offset) |
87 | 0 | { |
88 | 0 | vlc_debug(p_packetsys->logger, "dropping duplicate num %"PRIu32" off %"PRIu32, |
89 | 0 | i_media_object_number , i_media_object_offset); |
90 | 0 | return vlc_stream_Read( p_packetsys->s, NULL, i_sub_payload_data_length ) != i_sub_payload_data_length ? -1 : 0; |
91 | 0 | } |
92 | 0 | } |
93 | | |
94 | 0 | unsigned dedupindex; |
95 | 0 | if( p_tkinfo->i_pktcount < ASFPACKET_DEDUPLICATE ) |
96 | 0 | dedupindex = p_tkinfo->i_pkt = p_tkinfo->i_pktcount++; |
97 | 0 | else |
98 | 0 | dedupindex = (++p_tkinfo->i_pkt) % ASFPACKET_DEDUPLICATE; |
99 | |
|
100 | 0 | p_tkinfo->prev[dedupindex].media_number = i_media_object_number; |
101 | 0 | p_tkinfo->prev[dedupindex].media_offset = i_media_object_offset; |
102 | 0 | } |
103 | | |
104 | | /* FIXME I don't use i_media_object_number, sould I ? */ |
105 | 25.8k | if( *pp_frame && i_media_object_offset == 0 ) |
106 | 15.5k | { |
107 | 15.5k | p_packetsys->pf_send( p_packetsys, i_stream_number, pp_frame ); |
108 | 15.5k | } |
109 | | |
110 | 25.8k | block_t *p_frag = vlc_stream_Block( p_packetsys->s, i_sub_payload_data_length ); |
111 | 25.8k | if( p_frag == NULL ) { |
112 | 0 | vlc_warning( p_packetsys->logger, "cannot read data" ); |
113 | 0 | return -1; |
114 | 0 | } |
115 | | |
116 | 25.8k | p_frag->i_pts = (b_ignore_pts) ? VLC_TICK_INVALID : VLC_TICK_0 + i_pts; |
117 | 25.8k | p_frag->i_dts = VLC_TICK_0 + i_dts; |
118 | 25.8k | if ( b_keyframe ) |
119 | 3.85k | p_frag->i_flags |= BLOCK_FLAG_TYPE_I; |
120 | | |
121 | 25.8k | block_ChainAppend( pp_frame, p_frag ); |
122 | | |
123 | 25.8k | return 0; |
124 | 25.8k | } |
125 | | |
126 | | static void ParsePayloadExtensions( asf_packet_sys_t *p_packetsys, |
127 | | const asf_track_info_t *p_tkinfo, |
128 | | const uint8_t *p_data, size_t i_data, |
129 | | bool *b_keyframe ) |
130 | 25.5k | { |
131 | 25.5k | if ( !p_tkinfo || !p_tkinfo->p_esp || !p_tkinfo->p_esp->p_ext ) |
132 | 3.23k | return; |
133 | | |
134 | 22.3k | uint16_t i_payload_extensions_size; |
135 | 22.3k | asf_payload_extension_system_t *p_ext = NULL; |
136 | | |
137 | | /* Extensions always come in the declared order */ |
138 | 41.9k | for ( int i=0; i< p_tkinfo->p_esp->i_payload_extension_system_count; i++ ) |
139 | 19.7k | { |
140 | 19.7k | p_ext = &p_tkinfo->p_esp->p_ext[i]; |
141 | 19.7k | if ( p_ext->i_data_size == 0xFFFF ) /* Variable length extension data */ |
142 | 0 | { |
143 | 0 | if ( i_data < 2 ) return; |
144 | 0 | i_payload_extensions_size = GetWLE( p_data ); |
145 | 0 | p_data += 2; |
146 | 0 | i_data -= 2; |
147 | 0 | i_payload_extensions_size = 0; |
148 | 0 | } |
149 | 19.7k | else |
150 | 19.7k | { |
151 | 19.7k | i_payload_extensions_size = p_ext->i_data_size; |
152 | 19.7k | } |
153 | | |
154 | 19.7k | if ( i_data < i_payload_extensions_size ) return; |
155 | | |
156 | 19.6k | if ( guidcmp( &p_ext->i_extension_id, &mfasf_sampleextension_outputcleanpoint_guid ) ) |
157 | 0 | { |
158 | 0 | if ( i_payload_extensions_size != 1 ) goto sizeerror; |
159 | 0 | *b_keyframe |= *p_data; |
160 | 0 | } |
161 | 19.6k | else if ( guidcmp( &p_ext->i_extension_id, &asf_dvr_sampleextension_videoframe_guid ) ) |
162 | 0 | { |
163 | 0 | if ( i_payload_extensions_size != 4U ) goto sizeerror; |
164 | | |
165 | 0 | uint32_t i_val = GetDWLE( p_data ); |
166 | | /* Valid keyframe must be a split frame start fragment */ |
167 | 0 | *b_keyframe = i_val & ASF_EXTENSION_VIDEOFRAME_NEWFRAME; |
168 | 0 | if ( *b_keyframe ) |
169 | 0 | { |
170 | | /* And flagged as IFRAME */ |
171 | 0 | *b_keyframe |= ( ( i_val & ASF_EXTENSION_VIDEOFRAME_TYPE_MASK ) |
172 | 0 | == ASF_EXTENSION_VIDEOFRAME_IFRAME ); |
173 | 0 | } |
174 | 0 | } |
175 | 19.6k | else if ( guidcmp( &p_ext->i_extension_id, &mfasf_sampleextension_pixelaspectratio_guid ) && |
176 | 19.6k | p_packetsys->pf_setaspectratio ) |
177 | 0 | { |
178 | 0 | if ( i_payload_extensions_size != 2U ) goto sizeerror; |
179 | | |
180 | 0 | p_packetsys->pf_setaspectratio( p_packetsys, p_tkinfo->p_sp->i_stream_number, |
181 | 0 | p_data[0], p_data[1] ); |
182 | 0 | } |
183 | 19.6k | else if ( guidcmp( &p_ext->i_extension_id, &asf_dvr_sampleextension_timing_rep_data_guid ) ) |
184 | 0 | { |
185 | 0 | if ( i_payload_extensions_size != 48 ) goto sizeerror; |
186 | | /* const int64_t i_pts = GetQWLE(&p_data[8]); */ |
187 | 0 | } |
188 | | #if 0 |
189 | | else |
190 | | { |
191 | | msg_Dbg( p_demux, "Unknown extension " GUID_FMT, GUID_PRINT( p_ext->i_extension_id ) ); |
192 | | } |
193 | | #endif |
194 | 19.6k | i_data -= i_payload_extensions_size; |
195 | 19.6k | p_data += i_payload_extensions_size; |
196 | 19.6k | } |
197 | | |
198 | 22.2k | return; |
199 | | |
200 | 22.2k | sizeerror: |
201 | 0 | vlc_warning( p_packetsys->logger, "Unknown extension " GUID_FMT " data size of %u", |
202 | 0 | GUID_PRINT( p_ext->i_extension_id ), i_payload_extensions_size ); |
203 | 0 | } |
204 | | |
205 | | static int DemuxPayload(asf_packet_sys_t *p_packetsys, asf_packet_t *pkt, int i_payload) |
206 | 43.9k | { |
207 | | #ifndef ASF_DEBUG |
208 | | VLC_UNUSED( i_payload ); |
209 | | #endif |
210 | 43.9k | if( ! pkt->left || pkt->i_skip >= pkt->left ) |
211 | 48 | return -1; |
212 | | |
213 | 43.8k | bool b_packet_keyframe = pkt->p_peek[pkt->i_skip] >> 7; |
214 | 43.8k | uint8_t i_stream_number = pkt->p_peek[pkt->i_skip++] & 0x7f; |
215 | | |
216 | 43.8k | uint32_t i_media_object_number = 0; |
217 | 43.8k | if (GetValue2b(&i_media_object_number, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property >> 4) < 0) |
218 | 7 | return -1; |
219 | 43.8k | uint32_t i_media_object_offset = 0; |
220 | 43.8k | if (GetValue2b(&i_media_object_offset, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property >> 2) < 0) |
221 | 3 | return -1; |
222 | 43.8k | uint32_t i_replicated_data_length = 0; |
223 | 43.8k | if (GetValue2b(&i_replicated_data_length, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property) < 0) |
224 | 3 | return -1; |
225 | | |
226 | 43.8k | vlc_tick_t i_pkt_time; |
227 | 43.8k | vlc_tick_t i_pkt_time_delta = 0; |
228 | 43.8k | uint32_t i_payload_data_length = 0; |
229 | 43.8k | uint32_t i_temp_payload_length = 0; |
230 | | |
231 | | /* First packet, in case we do not have index to guess preroll start time */ |
232 | 43.8k | if ( *p_packetsys->pi_preroll_start == ASFPACKET_PREROLL_FROM_CURRENT ) |
233 | 0 | *p_packetsys->pi_preroll_start = pkt->send_time; |
234 | | |
235 | 43.8k | asf_track_info_t *p_tkinfo = p_packetsys->pf_gettrackinfo( p_packetsys, i_stream_number ); |
236 | 43.8k | if ( !p_tkinfo ) |
237 | 17.9k | goto skip; |
238 | | |
239 | 25.9k | bool b_ignore_pts = (p_tkinfo->i_cat == VIDEO_ES); /* ignore PTS delta with video when not set by mux */ |
240 | | |
241 | 25.9k | if( pkt->left - pkt->i_skip < i_replicated_data_length ) |
242 | 46 | return -1; |
243 | | |
244 | | /* Non compressed */ |
245 | 25.8k | if( i_replicated_data_length > 7 ) // should be at least 8 bytes |
246 | 25.5k | { |
247 | | /* Followed by 2 optional DWORDS, offset in media and *media* presentation time */ |
248 | 25.5k | i_pkt_time = VLC_TICK_FROM_MS(GetDWLE( pkt->p_peek + pkt->i_skip + 4 )); |
249 | | |
250 | | /* Parsing extensions, See 7.3.1 */ |
251 | 25.5k | ParsePayloadExtensions( p_packetsys, p_tkinfo, |
252 | 25.5k | &pkt->p_peek[pkt->i_skip + 8], |
253 | 25.5k | i_replicated_data_length - 8, |
254 | 25.5k | &b_packet_keyframe ); |
255 | 25.5k | i_pkt_time -= *p_packetsys->pi_preroll; |
256 | 25.5k | pkt->i_skip += i_replicated_data_length; |
257 | 25.5k | } |
258 | 325 | else if ( i_replicated_data_length == 0 ) |
259 | 270 | { |
260 | | /* optional DWORDS missing */ |
261 | 270 | i_pkt_time = pkt->send_time; |
262 | 270 | } |
263 | | /* Compressed payload */ |
264 | 55 | else if( i_replicated_data_length == 1 ) |
265 | 22 | { |
266 | | /* i_media_object_offset is *media* presentation time */ |
267 | | /* Next byte is *media* Presentation Time Delta */ |
268 | 22 | i_pkt_time_delta = VLC_TICK_FROM_MS(pkt->p_peek[pkt->i_skip]); |
269 | 22 | b_ignore_pts = false; |
270 | 22 | i_pkt_time = VLC_TICK_FROM_MS(i_media_object_offset); |
271 | 22 | i_pkt_time -= *p_packetsys->pi_preroll; |
272 | 22 | pkt->i_skip++; |
273 | 22 | i_media_object_offset = 0; |
274 | 22 | } |
275 | 33 | else |
276 | 33 | { |
277 | | /* >1 && <8 Invalid replicated length ! */ |
278 | 33 | vlc_warning( p_packetsys->logger, "Invalid replicated data length detected." ); |
279 | 33 | if( pkt->length - pkt->i_skip < pkt->padding_length ) |
280 | 2 | return -1; |
281 | | |
282 | 31 | i_payload_data_length = pkt->length - pkt->padding_length - pkt->i_skip; |
283 | 31 | goto skip; |
284 | 33 | } |
285 | | |
286 | 25.8k | if( ! pkt->left || pkt->i_skip >= pkt->left ) |
287 | 0 | return -1; |
288 | | |
289 | 25.8k | bool b_preroll_done = ( pkt->send_time > (*p_packetsys->pi_preroll_start + *p_packetsys->pi_preroll) ); |
290 | | |
291 | 25.8k | if (i_pkt_time < 0) i_pkt_time = 0; // FIXME? |
292 | | |
293 | 25.8k | if( pkt->multiple ) { |
294 | 21.7k | if (GetValue2b(&i_temp_payload_length, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->length_type) < 0) |
295 | 0 | return -1; |
296 | 21.7k | } |
297 | 4.11k | else |
298 | 4.11k | { |
299 | 4.11k | if( pkt->length - pkt->i_skip < pkt->padding_length ) |
300 | 3 | return -1; |
301 | 4.11k | i_temp_payload_length = pkt->length - pkt->padding_length - pkt->i_skip; |
302 | 4.11k | } |
303 | | |
304 | 25.8k | i_payload_data_length = i_temp_payload_length; |
305 | | |
306 | 25.8k | #ifdef ASF_DEBUG |
307 | 25.8k | vlc_debug( p_packetsys->logger, |
308 | 25.8k | "payload(%d) stream_number:%"PRIu8" media_object_number:%d media_object_offset:%"PRIu32 |
309 | 25.8k | " replicated_data_length:%"PRIu32" payload_data_length %"PRIu32, |
310 | 25.8k | i_payload + 1, i_stream_number, i_media_object_number, |
311 | 25.8k | i_media_object_offset, i_replicated_data_length, i_payload_data_length ); |
312 | 25.8k | vlc_debug( p_packetsys->logger, |
313 | 25.8k | " pkttime=%"PRId64" st=%"PRId64, |
314 | 25.8k | i_pkt_time, MS_FROM_VLC_TICK(pkt->send_time) ); |
315 | 25.8k | #endif |
316 | | |
317 | 25.8k | if( ! i_payload_data_length || i_payload_data_length > pkt->left ) |
318 | 116 | { |
319 | 116 | vlc_debug( p_packetsys->logger, " payload length problem %d %"PRIu32 |
320 | 116 | " %"PRIu32, pkt->multiple, i_payload_data_length, pkt->left ); |
321 | 116 | return -1; |
322 | 116 | } |
323 | | |
324 | 25.7k | if ( p_packetsys->pf_doskip && |
325 | 25.7k | p_packetsys->pf_doskip( p_packetsys, i_stream_number, b_packet_keyframe ) ) |
326 | 355 | goto skip; |
327 | | |
328 | 25.3k | if ( b_preroll_done ) |
329 | 13.2k | { |
330 | 13.2k | vlc_tick_t i_track_time = i_pkt_time; |
331 | | |
332 | 13.2k | if ( p_packetsys->pf_updatetime ) |
333 | 13.2k | p_packetsys->pf_updatetime( p_packetsys, i_stream_number, i_track_time ); |
334 | 13.2k | } |
335 | | |
336 | 25.3k | if( p_packetsys->pf_updatesendtime ) |
337 | 25.3k | p_packetsys->pf_updatesendtime( p_packetsys, pkt->send_time ); |
338 | | |
339 | 25.3k | vlc_tick_t i_subpayload_delta = 0; |
340 | 52.4k | while (i_payload_data_length && pkt->i_skip < pkt->left ) |
341 | 27.0k | { |
342 | 27.0k | uint32_t i_sub_payload_data_length = i_payload_data_length; |
343 | 27.0k | if( i_replicated_data_length == 1 ) |
344 | 1.71k | { |
345 | 1.71k | i_sub_payload_data_length = pkt->p_peek[pkt->i_skip++]; |
346 | 1.71k | i_payload_data_length--; |
347 | 1.71k | if( i_sub_payload_data_length > i_payload_data_length ) |
348 | 17 | goto skip; |
349 | 1.71k | } |
350 | | |
351 | 27.0k | if (pkt->i_skip && vlc_stream_Read( p_packetsys->s, NULL, pkt->i_skip ) != pkt->i_skip ) |
352 | 0 | { |
353 | 0 | vlc_warning( p_packetsys->logger, "unexpected end of file" ); |
354 | 0 | return -1; |
355 | 0 | } |
356 | | |
357 | 27.0k | vlc_tick_t i_payload_pts; |
358 | 27.0k | i_payload_pts = i_pkt_time + i_subpayload_delta; |
359 | 27.0k | if ( p_tkinfo->p_sp ) |
360 | 27.0k | i_payload_pts -= VLC_TICK_FROM_MSFTIME(p_tkinfo->p_sp->i_time_offset); |
361 | | |
362 | 27.0k | vlc_tick_t i_payload_dts = i_pkt_time; |
363 | | |
364 | 27.0k | if ( p_tkinfo->p_sp ) |
365 | 27.0k | i_payload_dts -= VLC_TICK_FROM_MSFTIME(p_tkinfo->p_sp->i_time_offset); |
366 | | |
367 | 27.0k | if ( i_sub_payload_data_length && |
368 | 27.0k | DemuxSubPayload( p_packetsys, i_stream_number, p_tkinfo, |
369 | 25.8k | i_sub_payload_data_length, i_payload_pts, i_payload_dts, |
370 | 25.8k | i_media_object_number, i_media_object_offset, |
371 | 25.8k | b_packet_keyframe, b_ignore_pts ) < 0) |
372 | 0 | return -1; |
373 | | |
374 | 27.0k | if ( pkt->left > pkt->i_skip + i_sub_payload_data_length ) |
375 | 25.1k | pkt->left -= pkt->i_skip + i_sub_payload_data_length; |
376 | 1.94k | else |
377 | 1.94k | pkt->left = 0; |
378 | 27.0k | pkt->i_skip = 0; |
379 | 27.0k | if( pkt->left > 0 ) |
380 | 25.1k | { |
381 | 25.1k | ssize_t i_return = vlc_stream_Peek( p_packetsys->s, &pkt->p_peek, pkt->left ); |
382 | 25.1k | if ( i_return <= 0 || (size_t) i_return < pkt->left ) |
383 | 0 | { |
384 | 0 | vlc_warning( p_packetsys->logger, "unexpected end of file" ); |
385 | 0 | return -1; |
386 | 0 | } |
387 | 25.1k | } |
388 | | |
389 | 27.0k | if ( i_sub_payload_data_length <= i_payload_data_length ) |
390 | 27.0k | i_payload_data_length -= i_sub_payload_data_length; |
391 | 0 | else |
392 | 0 | i_payload_data_length = 0; |
393 | | |
394 | 27.0k | i_subpayload_delta += i_pkt_time_delta; |
395 | 27.0k | } |
396 | | |
397 | 25.3k | return 0; |
398 | | |
399 | 18.3k | skip: |
400 | 18.3k | pkt->i_skip += i_payload_data_length; |
401 | 18.3k | return 0; |
402 | 25.3k | } |
403 | | |
404 | | int DemuxASFPacket( asf_packet_sys_t *p_packetsys, |
405 | | uint32_t i_data_packet_min, uint32_t i_data_packet_max, |
406 | | uint64_t i_data_begin, uint64_t i_data_end ) |
407 | 776k | { |
408 | 776k | const uint64_t i_read_pos = vlc_stream_Tell( p_packetsys->s ); |
409 | 776k | if( i_read_pos < i_data_begin || |
410 | 776k | (i_data_end && ( i_data_packet_min > i_data_end || |
411 | 775k | i_read_pos > i_data_end - i_data_packet_min ) ) ) |
412 | 1.03k | return 0; |
413 | | |
414 | 775k | const uint8_t *p_peek; |
415 | 775k | ssize_t i_return = vlc_stream_Peek( p_packetsys->s, &p_peek,i_data_packet_min ); |
416 | 775k | if( i_return <= 0 || (size_t) i_return < i_data_packet_min ) |
417 | 32 | { |
418 | 32 | vlc_warning( p_packetsys->logger, "unexpected end of file" ); |
419 | 32 | return 0; |
420 | 32 | } |
421 | 775k | unsigned int i_skip = 0; |
422 | | |
423 | | /* *** parse error correction if present *** */ |
424 | 775k | if( p_peek[0]&0x80 ) |
425 | 317k | { |
426 | 317k | unsigned int i_error_correction_data_length = p_peek[0] & 0x0f; |
427 | 317k | unsigned int i_opaque_data_present = ( p_peek[0] >> 4 )& 0x01; |
428 | 317k | unsigned int i_error_correction_length_type = ( p_peek[0] >> 5 ) & 0x03; |
429 | 317k | i_skip += 1; // skip error correction flags |
430 | | |
431 | 317k | if( i_error_correction_length_type != 0x00 || |
432 | 317k | i_opaque_data_present != 0 || |
433 | 317k | i_error_correction_data_length != 0x02 ) |
434 | 294k | { |
435 | 294k | goto loop_error_recovery; |
436 | 294k | } |
437 | | |
438 | 23.3k | i_skip += i_error_correction_data_length; |
439 | 23.3k | } |
440 | 457k | else |
441 | 775k | vlc_warning( p_packetsys->logger, "no error correction" ); |
442 | | |
443 | | /* sanity check */ |
444 | 480k | if( i_skip + 2 >= i_data_packet_min ) |
445 | 462k | goto loop_error_recovery; |
446 | | |
447 | 18.2k | asf_packet_t pkt; |
448 | 18.2k | int i_packet_flags = p_peek[i_skip]; i_skip++; |
449 | 18.2k | pkt.property = p_peek[i_skip]; i_skip++; |
450 | 18.2k | pkt.multiple = !!(i_packet_flags&0x01); |
451 | | |
452 | 18.2k | pkt.length = i_data_packet_min; |
453 | 18.2k | pkt.padding_length = 0; |
454 | | |
455 | 18.2k | if (GetValue2b(&pkt.length, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 5) < 0) |
456 | 0 | goto loop_error_recovery; |
457 | 18.2k | uint32_t i_packet_sequence; |
458 | 18.2k | if (GetValue2b(&i_packet_sequence, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 1) < 0) |
459 | 0 | goto loop_error_recovery; |
460 | 18.2k | if (GetValue2b(&pkt.padding_length, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 3) < 0) |
461 | 0 | goto loop_error_recovery; |
462 | | |
463 | 18.2k | if( pkt.padding_length > pkt.length ) |
464 | 1.08k | { |
465 | 1.08k | vlc_warning( p_packetsys->logger, "Too large padding: %"PRIu32, pkt.padding_length ); |
466 | 1.08k | goto loop_error_recovery; |
467 | 1.08k | } |
468 | | |
469 | 17.1k | if( pkt.length < i_data_packet_min ) |
470 | 567 | { |
471 | | /* if packet length too short, there is extra padding */ |
472 | 567 | pkt.padding_length += i_data_packet_min - pkt.length; |
473 | 567 | pkt.length = i_data_packet_min; |
474 | 567 | } |
475 | | |
476 | 17.1k | if( i_skip + 4 > i_data_packet_min ) |
477 | 0 | goto loop_error_recovery; |
478 | | |
479 | 17.1k | pkt.send_time = VLC_TICK_FROM_MS(GetDWLE( p_peek + i_skip )); i_skip += 4; |
480 | 17.1k | /* uint16_t i_packet_duration = GetWLE( p_peek + i_skip ); */ i_skip += 2; |
481 | | |
482 | 17.1k | if( i_data_end && |
483 | 17.1k | (pkt.length > i_data_end || |
484 | 16.9k | i_read_pos > i_data_end - pkt.length) ) |
485 | 188 | { |
486 | 188 | vlc_warning( p_packetsys->logger, "pkt size %"PRIu32" at %"PRIu64" does not fit data chunk size %"PRIu32, |
487 | 188 | pkt.length, i_read_pos, i_data_packet_max ); |
488 | 188 | return 0; |
489 | 188 | } |
490 | | |
491 | 16.9k | i_return = vlc_stream_Peek( p_packetsys->s, &p_peek, pkt.length ); |
492 | 16.9k | if( i_return <= 0 || pkt.length == 0 || (size_t)i_return < pkt.length ) |
493 | 18 | { |
494 | 18 | vlc_warning( p_packetsys->logger, "unexpected end of file" ); |
495 | 18 | return 0; |
496 | 18 | } |
497 | | |
498 | 16.9k | int i_payload_count = 1; |
499 | 16.9k | pkt.length_type = 0x02; //unused |
500 | 16.9k | if( pkt.multiple ) |
501 | 9.23k | { |
502 | 9.23k | if( i_skip + 1 >= i_data_packet_min ) |
503 | 0 | goto loop_error_recovery; |
504 | 9.23k | i_payload_count = p_peek[i_skip] & 0x3f; |
505 | 9.23k | pkt.length_type = ( p_peek[i_skip] >> 6 )&0x03; |
506 | 9.23k | i_skip++; |
507 | 9.23k | } |
508 | | |
509 | 16.9k | #ifdef ASF_DEBUG |
510 | 16.9k | vlc_debug( p_packetsys->logger, "%d payloads", i_payload_count); |
511 | 16.9k | #endif |
512 | | |
513 | 16.9k | pkt.i_skip = i_skip; |
514 | 16.9k | pkt.p_peek = p_peek; |
515 | 16.9k | pkt.left = pkt.length; |
516 | | |
517 | 60.6k | for( int i_payload = 0; i_payload < i_payload_count ; i_payload++ ) |
518 | 43.9k | if (DemuxPayload(p_packetsys, &pkt, i_payload) < 0) |
519 | 228 | { |
520 | 228 | vlc_warning( p_packetsys->logger, "payload err %d / %d", i_payload + 1, i_payload_count ); |
521 | 228 | return 0; |
522 | 228 | } |
523 | | |
524 | 16.7k | if( pkt.left > 0 ) |
525 | 14.8k | { |
526 | 14.8k | uint32_t toskip; |
527 | 14.8k | if( pkt.left > pkt.padding_length && |
528 | 14.8k | !p_packetsys->b_can_hold_multiple_packets ) |
529 | 4.70k | { |
530 | 4.70k | toskip = pkt.left; |
531 | 4.70k | #ifdef ASF_DEBUG |
532 | 4.70k | vlc_warning( p_packetsys->logger, "Didn't read %"PRIu32" bytes in the packet at %"PRIu64, |
533 | 4.70k | pkt.left - pkt.padding_length, vlc_stream_Tell(p_packetsys->s) ); |
534 | 4.70k | #endif |
535 | 4.70k | } |
536 | 10.1k | else if( pkt.left < pkt.padding_length ) |
537 | 36 | { |
538 | 36 | toskip = 0; |
539 | 36 | #ifdef ASF_DEBUG |
540 | 36 | vlc_warning( p_packetsys->logger, "Read %"PRIu32" too much bytes from the packet", |
541 | 36 | pkt.padding_length - pkt.left ); |
542 | 36 | #endif |
543 | 36 | } |
544 | 10.0k | else |
545 | 10.0k | { |
546 | 10.0k | toskip = pkt.padding_length; |
547 | 10.0k | } |
548 | | |
549 | 14.8k | if( toskip && vlc_stream_Read( p_packetsys->s, NULL, toskip ) != toskip ) |
550 | 0 | { |
551 | 0 | vlc_error( p_packetsys->logger, "cannot skip data, EOF ?" ); |
552 | 0 | return 0; |
553 | 0 | } |
554 | 14.8k | } |
555 | | |
556 | 16.7k | return 1; |
557 | | |
558 | 758k | loop_error_recovery: |
559 | 758k | vlc_warning( p_packetsys->logger, "unsupported packet header" ); |
560 | 758k | if( i_data_packet_min != i_data_packet_max ) |
561 | 0 | { |
562 | 0 | vlc_error( p_packetsys->logger, "unsupported packet header, fatal error" ); |
563 | 0 | return -1; |
564 | 0 | } |
565 | 758k | if( vlc_stream_Read( p_packetsys->s, NULL, i_data_packet_min ) != i_data_packet_min ) |
566 | 0 | { |
567 | 0 | vlc_warning( p_packetsys->logger, "cannot skip data, EOF ?" ); |
568 | 0 | return 0; |
569 | 0 | } |
570 | | |
571 | 758k | return 1; |
572 | 758k | } |
573 | | |
574 | | void ASFPacketTrackInit( asf_track_info_t *p_ti ) |
575 | 9.45k | { |
576 | 9.45k | p_ti->i_cat = UNKNOWN_ES; |
577 | 9.45k | p_ti->p_esp = NULL; |
578 | 9.45k | p_ti->p_sp = NULL; |
579 | 9.45k | p_ti->p_frame = NULL; |
580 | 9.45k | p_ti->i_pktcount = 0; |
581 | 9.45k | p_ti->i_pkt = 0; |
582 | 9.45k | } |
583 | | |
584 | | void ASFPacketTrackReset( asf_track_info_t *p_ti ) |
585 | 9.45k | { |
586 | 9.45k | if( p_ti->p_frame ) |
587 | 794 | block_ChainRelease( p_ti->p_frame ); |
588 | 9.45k | p_ti->p_frame = NULL; |
589 | 9.45k | p_ti->i_pktcount = 0; |
590 | 9.45k | p_ti->i_pkt = 0; |
591 | 9.45k | } |