/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 | 5.07k | { |
50 | 5.07k | switch(bits&0x03) |
51 | 5.07k | { |
52 | 414 | case 1: |
53 | 414 | if (left < 1) |
54 | 114 | return -1; |
55 | 300 | *var = p[*skip]; *skip += 1; |
56 | 300 | return 0; |
57 | 338 | case 2: |
58 | 338 | if (left < 2) |
59 | 338 | return -1; |
60 | 0 | *var = GetWLE(&p[*skip]); *skip += 2; |
61 | 0 | return 0; |
62 | 592 | case 3: |
63 | 592 | if (left < 4) |
64 | 592 | return -1; |
65 | 0 | *var = GetDWLE(&p[*skip]); *skip += 4; |
66 | 0 | return 0; |
67 | 3.73k | case 0: |
68 | 3.73k | default: |
69 | 3.73k | return 0; |
70 | 5.07k | } |
71 | 5.07k | } |
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 | 0 | { |
79 | 0 | block_t **pp_frame = &p_tkinfo->p_frame; |
80 | |
|
81 | 0 | 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 | 0 | if( *pp_frame && i_media_object_offset == 0 ) |
106 | 0 | { |
107 | 0 | p_packetsys->pf_send( p_packetsys, i_stream_number, pp_frame ); |
108 | 0 | } |
109 | |
|
110 | 0 | block_t *p_frag = vlc_stream_Block( p_packetsys->s, i_sub_payload_data_length ); |
111 | 0 | if( p_frag == NULL ) { |
112 | 0 | vlc_warning( p_packetsys->logger, "cannot read data" ); |
113 | 0 | return -1; |
114 | 0 | } |
115 | | |
116 | 0 | p_frag->i_pts = (b_ignore_pts) ? VLC_TICK_INVALID : VLC_TICK_0 + i_pts; |
117 | 0 | p_frag->i_dts = VLC_TICK_0 + i_dts; |
118 | 0 | if ( b_keyframe ) |
119 | 0 | p_frag->i_flags |= BLOCK_FLAG_TYPE_I; |
120 | |
|
121 | 0 | block_ChainAppend( pp_frame, p_frag ); |
122 | |
|
123 | 0 | return 0; |
124 | 0 | } |
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 | 0 | { |
131 | 0 | if ( !p_tkinfo || !p_tkinfo->p_esp || !p_tkinfo->p_esp->p_ext ) |
132 | 0 | return; |
133 | | |
134 | 0 | uint16_t i_payload_extensions_size; |
135 | 0 | asf_payload_extension_system_t *p_ext = NULL; |
136 | | |
137 | | /* Extensions always come in the declared order */ |
138 | 0 | for ( int i=0; i< p_tkinfo->p_esp->i_payload_extension_system_count; i++ ) |
139 | 0 | { |
140 | 0 | p_ext = &p_tkinfo->p_esp->p_ext[i]; |
141 | 0 | 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 | 0 | else |
150 | 0 | { |
151 | 0 | i_payload_extensions_size = p_ext->i_data_size; |
152 | 0 | } |
153 | | |
154 | 0 | if ( i_data < i_payload_extensions_size ) return; |
155 | | |
156 | 0 | if ( guidcmp( &p_ext->i_extension_id, &mfasf_sampleextension_outputcleanpoint_guid ) ) |
157 | 0 | { |
158 | 0 | if ( i_payload_extensions_size != sizeof(uint8_t) ) goto sizeerror; |
159 | 0 | *b_keyframe |= *p_data; |
160 | 0 | } |
161 | 0 | else if ( guidcmp( &p_ext->i_extension_id, &asf_dvr_sampleextension_videoframe_guid ) ) |
162 | 0 | { |
163 | 0 | if ( i_payload_extensions_size != sizeof(uint32_t) ) 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 | 0 | else if ( guidcmp( &p_ext->i_extension_id, &mfasf_sampleextension_pixelaspectratio_guid ) && |
176 | 0 | p_packetsys->pf_setaspectratio ) |
177 | 0 | { |
178 | 0 | if ( i_payload_extensions_size != sizeof(uint16_t) ) 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 | 0 | 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 | 0 | i_data -= i_payload_extensions_size; |
195 | 0 | p_data += i_payload_extensions_size; |
196 | 0 | } |
197 | | |
198 | 0 | return; |
199 | | |
200 | 0 | 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 | 0 | { |
207 | | #ifndef ASF_DEBUG |
208 | | VLC_UNUSED( i_payload ); |
209 | | #endif |
210 | 0 | if( ! pkt->left || pkt->i_skip >= pkt->left ) |
211 | 0 | return -1; |
212 | | |
213 | 0 | bool b_packet_keyframe = pkt->p_peek[pkt->i_skip] >> 7; |
214 | 0 | uint8_t i_stream_number = pkt->p_peek[pkt->i_skip++] & 0x7f; |
215 | |
|
216 | 0 | uint32_t i_media_object_number = 0; |
217 | 0 | if (GetValue2b(&i_media_object_number, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property >> 4) < 0) |
218 | 0 | return -1; |
219 | 0 | uint32_t i_media_object_offset = 0; |
220 | 0 | if (GetValue2b(&i_media_object_offset, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property >> 2) < 0) |
221 | 0 | return -1; |
222 | 0 | uint32_t i_replicated_data_length = 0; |
223 | 0 | if (GetValue2b(&i_replicated_data_length, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->property) < 0) |
224 | 0 | return -1; |
225 | | |
226 | 0 | vlc_tick_t i_pkt_time; |
227 | 0 | vlc_tick_t i_pkt_time_delta = 0; |
228 | 0 | uint32_t i_payload_data_length = 0; |
229 | 0 | uint32_t i_temp_payload_length = 0; |
230 | 0 | *p_packetsys->pi_preroll = __MIN( *p_packetsys->pi_preroll, VLC_TICK_MAX ); |
231 | | |
232 | | /* First packet, in case we do not have index to guess preroll start time */ |
233 | 0 | if ( *p_packetsys->pi_preroll_start == ASFPACKET_PREROLL_FROM_CURRENT ) |
234 | 0 | *p_packetsys->pi_preroll_start = pkt->send_time; |
235 | |
|
236 | 0 | asf_track_info_t *p_tkinfo = p_packetsys->pf_gettrackinfo( p_packetsys, i_stream_number ); |
237 | 0 | if ( !p_tkinfo ) |
238 | 0 | goto skip; |
239 | | |
240 | 0 | bool b_ignore_pts = (p_tkinfo->i_cat == VIDEO_ES); /* ignore PTS delta with video when not set by mux */ |
241 | |
|
242 | 0 | if( pkt->left - pkt->i_skip < i_replicated_data_length ) |
243 | 0 | return -1; |
244 | | |
245 | | /* Non compressed */ |
246 | 0 | if( i_replicated_data_length > 7 ) // should be at least 8 bytes |
247 | 0 | { |
248 | | /* Followed by 2 optional DWORDS, offset in media and *media* presentation time */ |
249 | 0 | i_pkt_time = VLC_TICK_FROM_MS(GetDWLE( pkt->p_peek + pkt->i_skip + 4 )); |
250 | | |
251 | | /* Parsing extensions, See 7.3.1 */ |
252 | 0 | ParsePayloadExtensions( p_packetsys, p_tkinfo, |
253 | 0 | &pkt->p_peek[pkt->i_skip + 8], |
254 | 0 | i_replicated_data_length - 8, |
255 | 0 | &b_packet_keyframe ); |
256 | 0 | i_pkt_time -= *p_packetsys->pi_preroll; |
257 | 0 | pkt->i_skip += i_replicated_data_length; |
258 | 0 | } |
259 | 0 | else if ( i_replicated_data_length == 0 ) |
260 | 0 | { |
261 | | /* optional DWORDS missing */ |
262 | 0 | i_pkt_time = pkt->send_time; |
263 | 0 | } |
264 | | /* Compressed payload */ |
265 | 0 | else if( i_replicated_data_length == 1 ) |
266 | 0 | { |
267 | | /* i_media_object_offset is *media* presentation time */ |
268 | | /* Next byte is *media* Presentation Time Delta */ |
269 | 0 | i_pkt_time_delta = VLC_TICK_FROM_MS(pkt->p_peek[pkt->i_skip]); |
270 | 0 | b_ignore_pts = false; |
271 | 0 | i_pkt_time = VLC_TICK_FROM_MS(i_media_object_offset); |
272 | 0 | i_pkt_time -= *p_packetsys->pi_preroll; |
273 | 0 | pkt->i_skip++; |
274 | 0 | i_media_object_offset = 0; |
275 | 0 | } |
276 | 0 | else |
277 | 0 | { |
278 | | /* >1 && <8 Invalid replicated length ! */ |
279 | 0 | vlc_warning( p_packetsys->logger, "Invalid replicated data length detected." ); |
280 | 0 | if( pkt->length - pkt->i_skip < pkt->padding_length ) |
281 | 0 | return -1; |
282 | | |
283 | 0 | i_payload_data_length = pkt->length - pkt->padding_length - pkt->i_skip; |
284 | 0 | goto skip; |
285 | 0 | } |
286 | | |
287 | 0 | if( ! pkt->left || pkt->i_skip >= pkt->left ) |
288 | 0 | return -1; |
289 | | |
290 | 0 | bool b_preroll_done = ( pkt->send_time > (*p_packetsys->pi_preroll_start + *p_packetsys->pi_preroll) ); |
291 | |
|
292 | 0 | if (i_pkt_time < 0) i_pkt_time = 0; // FIXME? |
293 | |
|
294 | 0 | if( pkt->multiple ) { |
295 | 0 | if (GetValue2b(&i_temp_payload_length, pkt->p_peek, &pkt->i_skip, pkt->left - pkt->i_skip, pkt->length_type) < 0) |
296 | 0 | return -1; |
297 | 0 | } |
298 | 0 | else |
299 | 0 | { |
300 | 0 | if( pkt->length - pkt->i_skip < pkt->padding_length ) |
301 | 0 | return -1; |
302 | 0 | i_temp_payload_length = pkt->length - pkt->padding_length - pkt->i_skip; |
303 | 0 | } |
304 | | |
305 | 0 | i_payload_data_length = i_temp_payload_length; |
306 | |
|
307 | 0 | #ifdef ASF_DEBUG |
308 | 0 | vlc_debug( p_packetsys->logger, |
309 | 0 | "payload(%d) stream_number:%"PRIu8" media_object_number:%d media_object_offset:%"PRIu32 |
310 | 0 | " replicated_data_length:%"PRIu32" payload_data_length %"PRIu32, |
311 | 0 | i_payload + 1, i_stream_number, i_media_object_number, |
312 | 0 | i_media_object_offset, i_replicated_data_length, i_payload_data_length ); |
313 | 0 | vlc_debug( p_packetsys->logger, |
314 | 0 | " pkttime=%"PRId64" st=%"PRId64, |
315 | 0 | i_pkt_time, MS_FROM_VLC_TICK(pkt->send_time) ); |
316 | 0 | #endif |
317 | |
|
318 | 0 | if( ! i_payload_data_length || i_payload_data_length > pkt->left ) |
319 | 0 | { |
320 | 0 | vlc_debug( p_packetsys->logger, " payload length problem %d %"PRIu32 |
321 | 0 | " %"PRIu32, pkt->multiple, i_payload_data_length, pkt->left ); |
322 | 0 | return -1; |
323 | 0 | } |
324 | | |
325 | 0 | if ( p_packetsys->pf_doskip && |
326 | 0 | p_packetsys->pf_doskip( p_packetsys, i_stream_number, b_packet_keyframe ) ) |
327 | 0 | goto skip; |
328 | | |
329 | 0 | if ( b_preroll_done ) |
330 | 0 | { |
331 | 0 | vlc_tick_t i_track_time = i_pkt_time; |
332 | |
|
333 | 0 | if ( p_packetsys->pf_updatetime ) |
334 | 0 | p_packetsys->pf_updatetime( p_packetsys, i_stream_number, i_track_time ); |
335 | 0 | } |
336 | |
|
337 | 0 | if( p_packetsys->pf_updatesendtime ) |
338 | 0 | p_packetsys->pf_updatesendtime( p_packetsys, pkt->send_time ); |
339 | |
|
340 | 0 | uint32_t i_subpayload_count = 0; |
341 | 0 | while (i_payload_data_length && pkt->i_skip < pkt->left ) |
342 | 0 | { |
343 | 0 | uint32_t i_sub_payload_data_length = i_payload_data_length; |
344 | 0 | if( i_replicated_data_length == 1 ) |
345 | 0 | { |
346 | 0 | i_sub_payload_data_length = pkt->p_peek[pkt->i_skip++]; |
347 | 0 | i_payload_data_length--; |
348 | 0 | if( i_sub_payload_data_length > i_payload_data_length ) |
349 | 0 | goto skip; |
350 | 0 | } |
351 | | |
352 | 0 | if (pkt->i_skip && vlc_stream_Read( p_packetsys->s, NULL, pkt->i_skip ) != pkt->i_skip ) |
353 | 0 | { |
354 | 0 | vlc_warning( p_packetsys->logger, "unexpected end of file" ); |
355 | 0 | return -1; |
356 | 0 | } |
357 | | |
358 | 0 | vlc_tick_t i_payload_pts; |
359 | 0 | i_payload_pts = i_pkt_time + i_pkt_time_delta * i_subpayload_count; |
360 | 0 | if ( p_tkinfo->p_sp ) |
361 | 0 | i_payload_pts -= VLC_TICK_FROM_MSFTIME(p_tkinfo->p_sp->i_time_offset); |
362 | |
|
363 | 0 | vlc_tick_t i_payload_dts = i_pkt_time; |
364 | |
|
365 | 0 | if ( p_tkinfo->p_sp ) |
366 | 0 | i_payload_dts -= VLC_TICK_FROM_MSFTIME(p_tkinfo->p_sp->i_time_offset); |
367 | |
|
368 | 0 | if ( i_sub_payload_data_length && |
369 | 0 | DemuxSubPayload( p_packetsys, i_stream_number, p_tkinfo, |
370 | 0 | i_sub_payload_data_length, i_payload_pts, i_payload_dts, |
371 | 0 | i_media_object_number, i_media_object_offset, |
372 | 0 | b_packet_keyframe, b_ignore_pts ) < 0) |
373 | 0 | return -1; |
374 | | |
375 | 0 | if ( pkt->left > pkt->i_skip + i_sub_payload_data_length ) |
376 | 0 | pkt->left -= pkt->i_skip + i_sub_payload_data_length; |
377 | 0 | else |
378 | 0 | pkt->left = 0; |
379 | 0 | pkt->i_skip = 0; |
380 | 0 | if( pkt->left > 0 ) |
381 | 0 | { |
382 | 0 | ssize_t i_return = vlc_stream_Peek( p_packetsys->s, &pkt->p_peek, pkt->left ); |
383 | 0 | if ( i_return <= 0 || (size_t) i_return < pkt->left ) |
384 | 0 | { |
385 | 0 | vlc_warning( p_packetsys->logger, "unexpected end of file" ); |
386 | 0 | return -1; |
387 | 0 | } |
388 | 0 | } |
389 | | |
390 | 0 | if ( i_sub_payload_data_length <= i_payload_data_length ) |
391 | 0 | i_payload_data_length -= i_sub_payload_data_length; |
392 | 0 | else |
393 | 0 | i_payload_data_length = 0; |
394 | |
|
395 | 0 | i_subpayload_count++; |
396 | 0 | } |
397 | | |
398 | 0 | return 0; |
399 | | |
400 | 0 | skip: |
401 | 0 | pkt->i_skip += i_payload_data_length; |
402 | 0 | return 0; |
403 | 0 | } |
404 | | |
405 | | int DemuxASFPacket( asf_packet_sys_t *p_packetsys, |
406 | | uint32_t i_data_packet_min, uint32_t i_data_packet_max, |
407 | | uint64_t i_data_begin, uint64_t i_data_end ) |
408 | 6.73k | { |
409 | 6.73k | const uint64_t i_read_pos = vlc_stream_Tell( p_packetsys->s ); |
410 | 6.73k | if( i_read_pos < i_data_begin || |
411 | 6.73k | (i_data_end && ( i_data_packet_min > i_data_end || |
412 | 6.73k | i_read_pos > i_data_end - i_data_packet_min ) ) ) |
413 | 1 | return 0; |
414 | | |
415 | 6.73k | const uint8_t *p_peek; |
416 | 6.73k | ssize_t i_return = vlc_stream_Peek( p_packetsys->s, &p_peek,i_data_packet_min ); |
417 | 6.73k | if( i_return <= 0 || (size_t) i_return < i_data_packet_min ) |
418 | 0 | { |
419 | 0 | vlc_warning( p_packetsys->logger, "unexpected end of file" ); |
420 | 0 | return 0; |
421 | 0 | } |
422 | 6.73k | unsigned int i_skip = 0; |
423 | | |
424 | | /* *** parse error correction if present *** */ |
425 | 6.73k | if( p_peek[0]&0x80 ) |
426 | 4.59k | { |
427 | 4.59k | unsigned int i_error_correction_data_length = p_peek[0] & 0x0f; |
428 | 4.59k | unsigned int i_opaque_data_present = ( p_peek[0] >> 4 )& 0x01; |
429 | 4.59k | unsigned int i_error_correction_length_type = ( p_peek[0] >> 5 ) & 0x03; |
430 | 4.59k | i_skip += 1; // skip error correction flags |
431 | | |
432 | 4.59k | if( i_error_correction_length_type != 0x00 || |
433 | 4.59k | i_opaque_data_present != 0 || |
434 | 4.59k | i_error_correction_data_length != 0x02 ) |
435 | 4.59k | { |
436 | 4.59k | goto loop_error_recovery; |
437 | 4.59k | } |
438 | | |
439 | 0 | i_skip += i_error_correction_data_length; |
440 | 0 | } |
441 | 2.13k | else |
442 | 6.73k | vlc_warning( p_packetsys->logger, "no error correction" ); |
443 | | |
444 | | /* sanity check */ |
445 | 2.13k | if( i_skip + 2 >= i_data_packet_min ) |
446 | 0 | goto loop_error_recovery; |
447 | | |
448 | 2.13k | asf_packet_t pkt; |
449 | 2.13k | int i_packet_flags = p_peek[i_skip]; i_skip++; |
450 | 2.13k | pkt.property = p_peek[i_skip]; i_skip++; |
451 | 2.13k | pkt.multiple = !!(i_packet_flags&0x01); |
452 | | |
453 | 2.13k | pkt.length = i_data_packet_min; |
454 | 2.13k | pkt.padding_length = 0; |
455 | | |
456 | 2.13k | if (GetValue2b(&pkt.length, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 5) < 0) |
457 | 587 | goto loop_error_recovery; |
458 | 1.54k | uint32_t i_packet_sequence; |
459 | 1.54k | if (GetValue2b(&i_packet_sequence, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 1) < 0) |
460 | 155 | goto loop_error_recovery; |
461 | 1.39k | if (GetValue2b(&pkt.padding_length, p_peek, &i_skip, i_data_packet_min - i_skip, i_packet_flags >> 3) < 0) |
462 | 302 | goto loop_error_recovery; |
463 | | |
464 | 1.09k | if( pkt.padding_length > pkt.length ) |
465 | 5 | { |
466 | 5 | vlc_warning( p_packetsys->logger, "Too large padding: %"PRIu32, pkt.padding_length ); |
467 | 5 | goto loop_error_recovery; |
468 | 5 | } |
469 | | |
470 | 1.08k | if( pkt.length < i_data_packet_min ) |
471 | 10 | { |
472 | | /* if packet length too short, there is extra padding */ |
473 | 10 | pkt.padding_length += i_data_packet_min - pkt.length; |
474 | 10 | pkt.length = i_data_packet_min; |
475 | 10 | } |
476 | | |
477 | 1.08k | if( i_skip + 4 > i_data_packet_min ) |
478 | 1.08k | goto loop_error_recovery; |
479 | | |
480 | 0 | pkt.send_time = VLC_TICK_FROM_MS(GetDWLE( p_peek + i_skip )); i_skip += 4; |
481 | 0 | /* uint16_t i_packet_duration = GetWLE( p_peek + i_skip ); */ i_skip += 2; |
482 | |
|
483 | 0 | if( i_data_end && |
484 | 0 | (pkt.length > i_data_end || |
485 | 0 | i_read_pos > i_data_end - pkt.length) ) |
486 | 0 | { |
487 | 0 | vlc_warning( p_packetsys->logger, "pkt size %"PRIu32" at %"PRIu64" does not fit data chunk size %"PRIu32, |
488 | 0 | pkt.length, i_read_pos, i_data_packet_max ); |
489 | 0 | return 0; |
490 | 0 | } |
491 | | |
492 | 0 | i_return = vlc_stream_Peek( p_packetsys->s, &p_peek, pkt.length ); |
493 | 0 | if( i_return <= 0 || pkt.length == 0 || (size_t)i_return < pkt.length ) |
494 | 0 | { |
495 | 0 | vlc_warning( p_packetsys->logger, "unexpected end of file" ); |
496 | 0 | return 0; |
497 | 0 | } |
498 | | |
499 | 0 | int i_payload_count = 1; |
500 | 0 | pkt.length_type = 0x02; //unused |
501 | 0 | if( pkt.multiple ) |
502 | 0 | { |
503 | 0 | if( i_skip + 1 >= i_data_packet_min ) |
504 | 0 | goto loop_error_recovery; |
505 | 0 | i_payload_count = p_peek[i_skip] & 0x3f; |
506 | 0 | pkt.length_type = ( p_peek[i_skip] >> 6 )&0x03; |
507 | 0 | i_skip++; |
508 | 0 | } |
509 | | |
510 | 0 | #ifdef ASF_DEBUG |
511 | 0 | vlc_debug( p_packetsys->logger, "%d payloads", i_payload_count); |
512 | 0 | #endif |
513 | |
|
514 | 0 | pkt.i_skip = i_skip; |
515 | 0 | pkt.p_peek = p_peek; |
516 | 0 | pkt.left = pkt.length; |
517 | |
|
518 | 0 | for( int i_payload = 0; i_payload < i_payload_count ; i_payload++ ) |
519 | 0 | if (DemuxPayload(p_packetsys, &pkt, i_payload) < 0) |
520 | 0 | { |
521 | 0 | vlc_warning( p_packetsys->logger, "payload err %d / %d", i_payload + 1, i_payload_count ); |
522 | 0 | return 0; |
523 | 0 | } |
524 | | |
525 | 0 | if( pkt.left > 0 ) |
526 | 0 | { |
527 | 0 | uint32_t toskip; |
528 | 0 | if( pkt.left > pkt.padding_length && |
529 | 0 | !p_packetsys->b_can_hold_multiple_packets ) |
530 | 0 | { |
531 | 0 | toskip = pkt.left; |
532 | 0 | #ifdef ASF_DEBUG |
533 | 0 | vlc_warning( p_packetsys->logger, "Didn't read %"PRIu32" bytes in the packet at %"PRIu64, |
534 | 0 | pkt.left - pkt.padding_length, vlc_stream_Tell(p_packetsys->s) ); |
535 | 0 | #endif |
536 | 0 | } |
537 | 0 | else if( pkt.left < pkt.padding_length ) |
538 | 0 | { |
539 | 0 | toskip = 0; |
540 | 0 | #ifdef ASF_DEBUG |
541 | 0 | vlc_warning( p_packetsys->logger, "Read %"PRIu32" too much bytes from the packet", |
542 | 0 | pkt.padding_length - pkt.left ); |
543 | 0 | #endif |
544 | 0 | } |
545 | 0 | else |
546 | 0 | { |
547 | 0 | toskip = pkt.padding_length; |
548 | 0 | } |
549 | |
|
550 | 0 | if( toskip && vlc_stream_Read( p_packetsys->s, NULL, toskip ) != toskip ) |
551 | 0 | { |
552 | 0 | vlc_error( p_packetsys->logger, "cannot skip data, EOF ?" ); |
553 | 0 | return 0; |
554 | 0 | } |
555 | 0 | } |
556 | | |
557 | 0 | return 1; |
558 | | |
559 | 6.73k | loop_error_recovery: |
560 | 6.73k | vlc_warning( p_packetsys->logger, "unsupported packet header" ); |
561 | 6.73k | if( i_data_packet_min != i_data_packet_max ) |
562 | 0 | { |
563 | 0 | vlc_error( p_packetsys->logger, "unsupported packet header, fatal error" ); |
564 | 0 | return -1; |
565 | 0 | } |
566 | 6.73k | if( vlc_stream_Read( p_packetsys->s, NULL, i_data_packet_min ) != i_data_packet_min ) |
567 | 0 | { |
568 | 0 | vlc_warning( p_packetsys->logger, "cannot skip data, EOF ?" ); |
569 | 0 | return 0; |
570 | 0 | } |
571 | | |
572 | 6.73k | return 1; |
573 | 6.73k | } |
574 | | |
575 | | void ASFPacketTrackInit( asf_track_info_t *p_ti ) |
576 | 22 | { |
577 | 22 | p_ti->i_cat = UNKNOWN_ES; |
578 | 22 | p_ti->p_esp = NULL; |
579 | 22 | p_ti->p_sp = NULL; |
580 | 22 | p_ti->p_frame = NULL; |
581 | 22 | p_ti->i_pktcount = 0; |
582 | 22 | p_ti->i_pkt = 0; |
583 | 22 | } |
584 | | |
585 | | void ASFPacketTrackReset( asf_track_info_t *p_ti ) |
586 | 22 | { |
587 | 22 | if( p_ti->p_frame ) |
588 | 0 | block_ChainRelease( p_ti->p_frame ); |
589 | 22 | p_ti->p_frame = NULL; |
590 | 22 | p_ti->i_pktcount = 0; |
591 | 22 | p_ti->i_pkt = 0; |
592 | 22 | } |