/src/vlc/modules/demux/mpeg/ps.c
Line | Count | Source |
1 | | /***************************************************************************** |
2 | | * ps.c: Program Stream demux module for VLC. |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2004-2009 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 | | |
23 | | /***************************************************************************** |
24 | | * Preamble |
25 | | *****************************************************************************/ |
26 | | |
27 | | #ifdef HAVE_CONFIG_H |
28 | | # include "config.h" |
29 | | #endif |
30 | | |
31 | | #include <vlc_common.h> |
32 | | #include <vlc_plugin.h> |
33 | | #include <vlc_demux.h> |
34 | | |
35 | | #include "pes.h" |
36 | | #include "ps.h" |
37 | | |
38 | | /* TODO: |
39 | | * - re-add pre-scanning. |
40 | | * - ... |
41 | | */ |
42 | | |
43 | | #define TIME_TEXT N_("Trust MPEG timestamps") |
44 | | #define TIME_LONGTEXT N_("Normally we use the timestamps of the MPEG files " \ |
45 | | "to calculate position and duration. However sometimes this might not " \ |
46 | | "be usable. Disable this option to calculate from the bitrate instead." ) |
47 | | |
48 | 19.3k | #define PS_PACKET_PROBE 3 |
49 | 461 | #define CDXA_HEADER_SIZE 44 |
50 | 0 | #define CDXA_SECTOR_SIZE 2352 |
51 | 0 | #define CDXA_SECTOR_HEADER_SIZE 24 |
52 | | |
53 | | /***************************************************************************** |
54 | | * Module descriptor |
55 | | *****************************************************************************/ |
56 | | static int Open ( vlc_object_t * ); |
57 | | static void Close ( vlc_object_t * ); |
58 | | |
59 | 134 | vlc_module_begin () |
60 | 67 | set_description( N_("MPEG-PS demuxer") ) |
61 | 67 | set_shortname( N_("PS") ) |
62 | 67 | set_subcategory( SUBCAT_INPUT_DEMUX ) |
63 | 67 | set_capability( "demux", 9 ) |
64 | 134 | set_callbacks( Open, Close ) |
65 | 67 | add_shortcut( "ps" ) |
66 | | |
67 | 67 | add_bool( "ps-trust-timestamps", true, TIME_TEXT, |
68 | 67 | TIME_LONGTEXT ) |
69 | 67 | change_safe () |
70 | 67 | vlc_module_end () |
71 | | |
72 | | /***************************************************************************** |
73 | | * Local prototypes |
74 | | *****************************************************************************/ |
75 | | |
76 | | typedef struct |
77 | | { |
78 | | ps_psm_t psm; |
79 | | ps_track_t tk[PS_TK_COUNT]; |
80 | | |
81 | | vlc_tick_t i_pack_scr; /* current read pack scr value, temp */ |
82 | | vlc_tick_t i_first_scr; /* media offset */ |
83 | | vlc_tick_t i_scr; /* committed, current position */ |
84 | | int64_t i_scr_track_id; |
85 | | int i_mux_rate; |
86 | | vlc_tick_t i_length; |
87 | | int i_time_track_index; |
88 | | vlc_tick_t i_current_pts; |
89 | | uint64_t i_start_byte; |
90 | | uint64_t i_lastpack_byte; |
91 | | |
92 | | int i_aob_mlp_count; |
93 | | |
94 | | bool b_lost_sync; |
95 | | bool b_have_pack; |
96 | | bool b_bad_scr; |
97 | | bool b_seekable; |
98 | | enum |
99 | | { |
100 | | MPEG_PS = 0, |
101 | | CDXA_PS, |
102 | | PSMF_PS, |
103 | | IMKH_PS, |
104 | | } format; |
105 | | enum ps_source source; |
106 | | |
107 | | int current_title; |
108 | | int current_seekpoint; |
109 | | unsigned updates; |
110 | | } demux_sys_t; |
111 | | |
112 | | static int Demux ( demux_t *p_demux ); |
113 | | static int Control( demux_t *p_demux, int i_query, va_list args ); |
114 | | |
115 | | static int ps_pkt_resynch( stream_t *, int, bool ); |
116 | | static block_t *ps_pkt_read ( stream_t * ); |
117 | | |
118 | | static void CreateOrUpdateES( demux_t*p_demux ) |
119 | 7.04k | { |
120 | 7.04k | demux_sys_t *p_sys = p_demux->p_sys; |
121 | | |
122 | 4.12M | for( int i = 0; i < PS_TK_COUNT; i++ ) |
123 | 4.11M | { |
124 | 4.11M | ps_track_t *tk = &p_sys->tk[i]; |
125 | 4.11M | if( !tk->b_updated ) |
126 | 4.10M | continue; |
127 | | |
128 | 8.95k | if( tk->es ) |
129 | 5.14k | es_out_Del( p_demux->out, tk->es ); |
130 | | |
131 | 8.95k | if( tk->fmt.i_cat != UNKNOWN_ES ) |
132 | 8.95k | tk->es = es_out_Add( p_demux->out, &tk->fmt ); |
133 | 8.95k | tk->b_updated = false; |
134 | 8.95k | } |
135 | 7.04k | } |
136 | | |
137 | | /***************************************************************************** |
138 | | * Open |
139 | | *****************************************************************************/ |
140 | | static int Open( vlc_object_t *p_this ) |
141 | 19.3k | { |
142 | 19.3k | demux_t *p_demux = (demux_t*)p_this; |
143 | 19.3k | demux_sys_t *p_sys; |
144 | | |
145 | 19.3k | const uint8_t *p_peek; |
146 | 19.3k | ssize_t i_peek = 0; |
147 | 19.3k | ssize_t i_offset = 0; |
148 | 19.3k | int i_skip = 0; |
149 | 19.3k | unsigned i_max_packets = PS_PACKET_PROBE; |
150 | 19.3k | int format = MPEG_PS; |
151 | 19.3k | int i_mux_rate = 0; |
152 | 19.3k | vlc_tick_t i_length = VLC_TICK_INVALID; |
153 | | |
154 | 19.3k | i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 16 ); |
155 | 19.3k | if( i_peek < 16 ) |
156 | 9 | return VLC_EGENERIC; |
157 | | |
158 | 19.3k | if( !memcmp( p_peek, "PSMF", 4 ) && |
159 | 290 | (GetDWBE( &p_peek[4] ) & 0x30303030) == 0x30303030 ) |
160 | 77 | { |
161 | 77 | i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 100 ); |
162 | 77 | if( i_peek < 100 ) |
163 | 4 | return VLC_EGENERIC; |
164 | 73 | i_skip = i_offset = GetWBE( &p_peek[10] ); |
165 | 73 | format = PSMF_PS; |
166 | 73 | msg_Info( p_demux, "Detected PSMF-PS header"); |
167 | 73 | i_mux_rate = GetDWBE( &p_peek[96] ); |
168 | 73 | if( GetDWBE( &p_peek[86] ) > 0 ) |
169 | 70 | i_length = vlc_tick_from_samples( GetDWBE( &p_peek[92] ), GetDWBE( &p_peek[86] )); |
170 | 73 | } |
171 | 19.2k | else if( !memcmp( p_peek, "IMKH", 4 ) ) |
172 | 644 | { |
173 | 644 | msg_Info( p_demux, "Detected Hikvision PVA header"); |
174 | 644 | i_skip = 40; |
175 | 644 | format = IMKH_PS; |
176 | 644 | i_max_packets = 0; |
177 | 644 | } |
178 | 18.5k | else if( !memcmp( p_peek, "RIFF", 4 ) && !memcmp( &p_peek[8], "CDXA", 4 ) ) |
179 | 461 | { |
180 | 461 | format = CDXA_PS; |
181 | 461 | i_max_packets = 0; /* We can't probe here */ |
182 | 461 | i_skip = CDXA_HEADER_SIZE; |
183 | 461 | msg_Info( p_demux, "Detected CDXA-PS" ); |
184 | | /* FIXME: have a proper way to decap CD sectors or make an access stream filter */ |
185 | 461 | } |
186 | | |
187 | 21.4k | for( unsigned i=0; i<i_max_packets; i++ ) |
188 | 20.2k | { |
189 | 20.2k | if( i_peek < i_offset + 16 ) |
190 | 2.14k | { |
191 | 2.14k | i_peek = vlc_stream_Peek( p_demux->s, &p_peek, i_offset + 16 ); |
192 | 2.14k | if( i_peek < i_offset + 16 ) |
193 | 229 | return VLC_EGENERIC; |
194 | 2.14k | } |
195 | | |
196 | 20.0k | const uint8_t startcode[3] = { 0x00, 0x00, 0x01 }; |
197 | 20.0k | const uint8_t *p_header = &p_peek[i_offset]; |
198 | 20.0k | if( memcmp( p_header, startcode, 3 ) || |
199 | 2.92k | ( (p_header[3] & 0xB0) != 0xB0 && |
200 | 1.32k | !(p_header[3] >= 0xC0 && p_header[3] <= 0xEF) && |
201 | 745 | p_header[3] != STREAM_ID_EXTENDED_STREAM_ID && |
202 | 745 | p_header[3] != STREAM_ID_PROGRAM_STREAM_DIRECTORY ) ) |
203 | 17.8k | return VLC_EGENERIC; |
204 | | |
205 | 2.18k | ssize_t i_pessize = ps_pkt_size( p_header, 16 ); |
206 | 2.18k | if( i_pessize < 5 ) |
207 | 38 | return VLC_EGENERIC; |
208 | 2.14k | i_offset += i_pessize; |
209 | 2.14k | } |
210 | | |
211 | 1.14k | if( i_skip && !p_demux->b_preparsing && |
212 | 1.11k | vlc_stream_Read( p_demux->s, NULL, i_skip ) != i_skip ) |
213 | 8 | return VLC_EGENERIC; |
214 | | |
215 | | /* Fill p_demux field */ |
216 | 1.13k | p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); |
217 | 1.13k | if( !p_sys ) return VLC_ENOMEM; |
218 | | |
219 | 1.13k | p_demux->pf_demux = Demux; |
220 | 1.13k | p_demux->pf_control = Control; |
221 | | |
222 | | /* Init p_sys */ |
223 | 1.13k | p_sys->i_mux_rate = i_mux_rate; |
224 | 1.13k | p_sys->i_pack_scr = VLC_TICK_INVALID; |
225 | 1.13k | p_sys->i_first_scr = VLC_TICK_INVALID; |
226 | 1.13k | p_sys->i_scr = VLC_TICK_INVALID; |
227 | 1.13k | p_sys->i_scr_track_id = 0; |
228 | 1.13k | p_sys->i_length = i_length; |
229 | 1.13k | p_sys->i_current_pts = VLC_TICK_INVALID; |
230 | 1.13k | p_sys->i_time_track_index = -1; |
231 | 1.13k | p_sys->i_aob_mlp_count = 0; |
232 | 1.13k | p_sys->i_start_byte = i_skip; |
233 | 1.13k | p_sys->i_lastpack_byte = i_skip; |
234 | | |
235 | 1.13k | p_sys->b_lost_sync = false; |
236 | 1.13k | p_sys->b_have_pack = false; |
237 | 1.13k | p_sys->b_bad_scr = false; |
238 | 1.13k | p_sys->b_seekable = false; |
239 | 1.13k | p_sys->format = format; |
240 | 1.13k | p_sys->current_title = 0; |
241 | 1.13k | p_sys->current_seekpoint = 0; |
242 | 1.13k | p_sys->updates = 0; |
243 | | |
244 | 1.13k | p_sys->source = PS_SOURCE_UNKNOWN; |
245 | 1.13k | if ( likely(p_demux->s->psz_url != NULL) ) |
246 | 0 | { |
247 | 0 | size_t url_len = strlen( p_demux->s->psz_url ); |
248 | 0 | if ( url_len >= 4 ) |
249 | 0 | { |
250 | 0 | if ( !strncasecmp( &p_demux->s->psz_url[url_len-4], ".AOB", 4 )) |
251 | 0 | p_sys->source = PS_SOURCE_AOB; |
252 | 0 | if ( !strncasecmp( &p_demux->s->psz_url[url_len-4], ".VOB", 4 )) |
253 | 0 | p_sys->source = PS_SOURCE_VOB; |
254 | 0 | } |
255 | 0 | } |
256 | | |
257 | 1.13k | vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &p_sys->b_seekable ); |
258 | | |
259 | 1.13k | ps_psm_init( &p_sys->psm ); |
260 | 1.13k | ps_track_init( p_sys->tk ); |
261 | | |
262 | | /* TODO prescanning of ES */ |
263 | | |
264 | 1.13k | return VLC_SUCCESS; |
265 | 1.13k | } |
266 | | |
267 | | /***************************************************************************** |
268 | | * Close |
269 | | *****************************************************************************/ |
270 | | static void Close( vlc_object_t *p_this ) |
271 | 1.13k | { |
272 | 1.13k | demux_t *p_demux = (demux_t*)p_this; |
273 | 1.13k | demux_sys_t *p_sys = p_demux->p_sys; |
274 | 1.13k | int i; |
275 | | |
276 | 666k | for( i = 0; i < PS_TK_COUNT; i++ ) |
277 | 665k | { |
278 | 665k | ps_track_t *tk = &p_sys->tk[i]; |
279 | 665k | es_format_Clean( &tk->fmt ); |
280 | 665k | if( tk->b_configured && tk->es != NULL ) |
281 | 3.80k | es_out_Del( p_demux->out, tk->es ); |
282 | 665k | } |
283 | | |
284 | 1.13k | ps_psm_destroy( &p_sys->psm ); |
285 | | |
286 | 1.13k | free( p_sys ); |
287 | 1.13k | } |
288 | | |
289 | | static int Probe( demux_t *p_demux, bool b_end ) |
290 | 100k | { |
291 | 100k | demux_sys_t *p_sys = p_demux->p_sys; |
292 | 100k | int i_ret, i_id; |
293 | 100k | block_t *p_pkt; |
294 | | |
295 | 100k | i_ret = ps_pkt_resynch( p_demux->s, p_sys->format, p_sys->b_have_pack ); |
296 | 100k | if( i_ret < 0 ) |
297 | 1.51k | { |
298 | 1.51k | return VLC_DEMUXER_EOF; |
299 | 1.51k | } |
300 | 99.0k | else if( i_ret == 0 ) |
301 | 10.1k | { |
302 | 10.1k | if( !p_sys->b_lost_sync ) |
303 | 10.1k | msg_Warn( p_demux, "garbage at input, trying to resync..." ); |
304 | | |
305 | 10.1k | p_sys->b_lost_sync = true; |
306 | 10.1k | return VLC_DEMUXER_SUCCESS; |
307 | 10.1k | } |
308 | | |
309 | 88.9k | if( p_sys->b_lost_sync ) msg_Warn( p_demux, "found sync code" ); |
310 | 88.9k | p_sys->b_lost_sync = false; |
311 | | |
312 | 88.9k | if( ( p_pkt = ps_pkt_read( p_demux->s ) ) == NULL ) |
313 | 238 | { |
314 | 238 | return VLC_DEMUXER_EOF; |
315 | 238 | } |
316 | | |
317 | 88.6k | i_id = ps_pkt_id( p_pkt->p_buffer, p_pkt->i_buffer, p_sys->source ); |
318 | 88.6k | if( i_id >= 0xc0 ) |
319 | 68.6k | { |
320 | 68.6k | ps_track_t *tk = &p_sys->tk[ps_id_to_tk(i_id)]; |
321 | 68.6k | if( !ps_pkt_parse_pes( VLC_OBJECT(p_demux), p_pkt, tk->i_skip ) && |
322 | 49.0k | p_pkt->i_pts != VLC_TICK_INVALID ) |
323 | 29.6k | { |
324 | 29.6k | if( b_end && (tk->i_last_pts == VLC_TICK_INVALID || p_pkt->i_pts > tk->i_last_pts) ) |
325 | 1.93k | { |
326 | 1.93k | tk->i_last_pts = p_pkt->i_pts; |
327 | 1.93k | } |
328 | 27.6k | else if ( tk->i_first_pts == VLC_TICK_INVALID ) |
329 | 1.83k | { |
330 | 1.83k | tk->i_first_pts = p_pkt->i_pts; |
331 | 1.83k | } |
332 | 29.6k | } |
333 | 68.6k | } |
334 | 20.0k | else if( i_id == PS_STREAM_ID_PACK_HEADER ) |
335 | 2.37k | { |
336 | 2.37k | vlc_tick_t i_scr; int dummy; |
337 | 2.37k | if( !b_end && !ps_pkt_parse_pack( p_pkt->p_buffer, p_pkt->i_buffer, |
338 | 904 | &i_scr, &dummy ) ) |
339 | 628 | { |
340 | 628 | if( p_sys->i_first_scr == VLC_TICK_INVALID ) |
341 | 229 | p_sys->i_first_scr = i_scr; |
342 | 628 | } |
343 | 2.37k | p_sys->b_have_pack = true; |
344 | 2.37k | } |
345 | | |
346 | 88.6k | block_Release( p_pkt ); |
347 | 88.6k | return VLC_DEMUXER_SUCCESS; |
348 | 88.9k | } |
349 | | |
350 | | static bool FindLength( demux_t *p_demux ) |
351 | 1.11k | { |
352 | 1.11k | demux_sys_t *p_sys = p_demux->p_sys; |
353 | | |
354 | 1.11k | if( !var_CreateGetBool( p_demux, "ps-trust-timestamps" ) ) |
355 | 0 | return true; |
356 | | |
357 | 1.11k | if( p_sys->i_length == VLC_TICK_INVALID ) /* First time */ |
358 | 1.11k | { |
359 | 1.11k | p_sys->i_length = VLC_TICK_0; |
360 | | /* Check beginning */ |
361 | 1.11k | int i = 0; |
362 | 1.11k | uint64_t i_current_pos = vlc_stream_Tell( p_demux->s ); |
363 | 23.0k | while( i < 40 && Probe( p_demux, false ) > 0 ) i++; |
364 | | |
365 | | /* Check end */ |
366 | 1.11k | uint64_t i_size; |
367 | 1.11k | if( vlc_stream_GetSize( p_demux->s, &i_size ) != VLC_SUCCESS ) |
368 | 0 | return false; |
369 | 1.11k | uint64_t i_end = VLC_CLIP( i_size, 0, 200000 ); |
370 | 1.11k | if( vlc_stream_Seek( p_demux->s, i_size - i_end ) == VLC_SUCCESS ) |
371 | 1.11k | { |
372 | 1.11k | i = 0; |
373 | 77.9k | while( i < 400 && Probe( p_demux, true ) > 0 ) i++; |
374 | 1.11k | if( vlc_stream_Seek( p_demux->s, i_current_pos ) != VLC_SUCCESS ) |
375 | 0 | return false; |
376 | 1.11k | } |
377 | 0 | else return false; |
378 | 1.11k | } |
379 | | |
380 | | /* Find the longest track */ |
381 | 652k | for( int i = 0; i < PS_TK_COUNT; i++ ) |
382 | 651k | { |
383 | 651k | ps_track_t *tk = &p_sys->tk[i]; |
384 | 651k | if( tk->i_first_pts != VLC_TICK_INVALID && |
385 | 1.83k | tk->i_last_pts > tk->i_first_pts ) |
386 | 146 | { |
387 | 146 | vlc_tick_t i_length = tk->i_last_pts - tk->i_first_pts; |
388 | 146 | if( i_length > p_sys->i_length ) |
389 | 145 | { |
390 | 145 | p_sys->i_length = i_length; |
391 | 145 | p_sys->i_time_track_index = i; |
392 | 145 | msg_Dbg( p_demux, "we found a length of: %"PRId64 "s", SEC_FROM_VLC_TICK(p_sys->i_length) ); |
393 | 145 | } |
394 | 146 | } |
395 | 651k | } |
396 | 1.11k | return true; |
397 | 1.11k | } |
398 | | |
399 | | static void NotifyDiscontinuity( ps_track_t *p_tk, es_out_t *out ) |
400 | 3.39k | { |
401 | 3.39k | bool b_selected; |
402 | 1.98M | for( size_t i = 0; i < PS_TK_COUNT; i++ ) |
403 | 1.98M | { |
404 | 1.98M | ps_track_t *tk = &p_tk[i]; |
405 | 1.98M | if( tk->es && |
406 | 15.7k | es_out_Control( out, ES_OUT_GET_ES_STATE, tk->es, &b_selected ) == VLC_SUCCESS |
407 | 15.7k | && b_selected ) |
408 | 15.7k | { |
409 | 15.7k | tk->i_next_block_flags |= BLOCK_FLAG_DISCONTINUITY; |
410 | 15.7k | } |
411 | 1.98M | } |
412 | 3.39k | } |
413 | | |
414 | | static void CheckPCR( demux_sys_t *p_sys, es_out_t *out, vlc_tick_t i_scr ) |
415 | 7.73k | { |
416 | 7.73k | if( p_sys->i_scr != VLC_TICK_INVALID && |
417 | 7.12k | llabs( p_sys->i_scr - i_scr ) > VLC_TICK_FROM_SEC(1) ) |
418 | 1.42k | NotifyDiscontinuity( p_sys->tk, out ); |
419 | 7.73k | } |
420 | | |
421 | | /***************************************************************************** |
422 | | * Demux: |
423 | | *****************************************************************************/ |
424 | | static int Demux( demux_t *p_demux ) |
425 | 129k | { |
426 | 129k | demux_sys_t *p_sys = p_demux->p_sys; |
427 | 129k | int i_ret, i_mux_rate; |
428 | 129k | block_t *p_pkt; |
429 | | |
430 | 129k | i_ret = ps_pkt_resynch( p_demux->s, p_sys->format, p_sys->b_have_pack ); |
431 | 129k | if( i_ret < 0 ) |
432 | 940 | { |
433 | 940 | return VLC_DEMUXER_EOF; |
434 | 940 | } |
435 | 128k | else if( i_ret == 0 ) |
436 | 11.0k | { |
437 | 11.0k | if( !p_sys->b_lost_sync ) |
438 | 1.96k | { |
439 | 1.96k | msg_Warn( p_demux, "garbage at input from %"PRIu64", trying to resync...", |
440 | 1.96k | vlc_stream_Tell(p_demux->s) ); |
441 | 1.96k | NotifyDiscontinuity( p_sys->tk, p_demux->out ); |
442 | 1.96k | } |
443 | | |
444 | 11.0k | p_sys->b_lost_sync = true; |
445 | 11.0k | return VLC_DEMUXER_SUCCESS; |
446 | 11.0k | } |
447 | | |
448 | 117k | if( p_sys->b_lost_sync ) msg_Warn( p_demux, "found sync code" ); |
449 | 117k | p_sys->b_lost_sync = false; |
450 | | |
451 | 117k | if( p_sys->i_length == VLC_TICK_INVALID && p_sys->b_seekable ) |
452 | 1.11k | { |
453 | 1.11k | if( !FindLength( p_demux ) ) |
454 | 0 | return VLC_DEMUXER_EGENERIC; |
455 | 1.11k | } |
456 | | |
457 | 117k | if( ( p_pkt = ps_pkt_read( p_demux->s ) ) == NULL ) |
458 | 199 | { |
459 | 199 | return VLC_DEMUXER_EOF; |
460 | 199 | } |
461 | | |
462 | 117k | if( p_pkt->i_buffer < 4 ) |
463 | 0 | { |
464 | 0 | block_Release( p_pkt ); |
465 | 0 | return VLC_DEMUXER_EGENERIC; |
466 | 0 | } |
467 | | |
468 | 117k | const uint8_t i_stream_id = p_pkt->p_buffer[3]; |
469 | 117k | switch( i_stream_id ) |
470 | 117k | { |
471 | 2.47k | case PS_STREAM_ID_END_STREAM: |
472 | 2.50k | case STREAM_ID_PADDING: |
473 | 2.50k | block_Release( p_pkt ); |
474 | 2.50k | break; |
475 | | |
476 | 1.54k | case PS_STREAM_ID_PACK_HEADER: |
477 | 1.54k | if( !ps_pkt_parse_pack( p_pkt->p_buffer, p_pkt->i_buffer, |
478 | 1.54k | &p_sys->i_pack_scr, &i_mux_rate ) ) |
479 | 1.00k | { |
480 | 1.00k | if( p_sys->i_first_scr == VLC_TICK_INVALID ) |
481 | 17 | p_sys->i_first_scr = p_sys->i_pack_scr; |
482 | 1.00k | CheckPCR( p_sys, p_demux->out, p_sys->i_pack_scr ); |
483 | 1.00k | p_sys->i_scr = p_sys->i_pack_scr; |
484 | 1.00k | p_sys->i_lastpack_byte = vlc_stream_Tell( p_demux->s ); |
485 | 1.00k | if( !p_sys->b_have_pack ) p_sys->b_have_pack = true; |
486 | | /* done later on to work around bad vcd/svcd streams */ |
487 | | /* es_out_SetPCR( p_demux->out, p_sys->i_scr ); */ |
488 | 1.00k | if( i_mux_rate > 0 ) p_sys->i_mux_rate = i_mux_rate; |
489 | 1.00k | } |
490 | 1.54k | block_Release( p_pkt ); |
491 | 1.54k | break; |
492 | | |
493 | 1.34k | case PS_STREAM_ID_SYSTEM_HEADER: |
494 | 1.34k | ps_pkt_parse_system( p_pkt->p_buffer, p_pkt->i_buffer, |
495 | 1.34k | &p_sys->psm, p_sys->tk ); |
496 | 1.34k | block_Release( p_pkt ); |
497 | 1.34k | break; |
498 | | |
499 | 16.7k | case STREAM_ID_PROGRAM_STREAM_MAP: |
500 | 16.7k | if( p_sys->psm.i_version == 0xFF ) |
501 | 16.7k | msg_Dbg( p_demux, "contains a PSM"); |
502 | | |
503 | 16.7k | ps_psm_fill( &p_sys->psm, |
504 | 16.7k | p_pkt->p_buffer, p_pkt->i_buffer, |
505 | 16.7k | p_sys->tk ); |
506 | 16.7k | block_Release( p_pkt ); |
507 | 16.7k | break; |
508 | | |
509 | 33.8k | default: |
510 | | /* Reject non video/audio nor PES */ |
511 | 33.8k | if( i_stream_id < 0xC0 || i_stream_id > 0xEF ) |
512 | 1.69k | { |
513 | 1.69k | block_Release( p_pkt ); |
514 | 1.69k | break; |
515 | 1.69k | } |
516 | | /* fallthrough */ |
517 | 88.4k | case STREAM_ID_PRIVATE_STREAM_1: |
518 | 93.2k | case STREAM_ID_EXTENDED_STREAM_ID: |
519 | 93.2k | { |
520 | 93.2k | int i_id = ps_pkt_id( p_pkt->p_buffer, p_pkt->i_buffer, p_sys->source ); |
521 | | /* Small heuristic to improve MLP detection from AOB */ |
522 | 93.2k | if( i_id == PS_AOB_PACKET_ID_MLP && |
523 | 0 | p_sys->i_aob_mlp_count < 500 ) |
524 | 0 | { |
525 | 0 | p_sys->i_aob_mlp_count++; |
526 | 0 | } |
527 | 93.2k | else if( i_id == PS_VOB_PACKET_ID_MLP && |
528 | 308 | p_sys->i_aob_mlp_count > 0 ) |
529 | 0 | { |
530 | 0 | p_sys->i_aob_mlp_count--; |
531 | 0 | i_id = PS_AOB_PACKET_ID_MLP; |
532 | 0 | } |
533 | | |
534 | 93.2k | bool b_new = false; |
535 | 93.2k | ps_track_t *tk = &p_sys->tk[ps_id_to_tk(i_id)]; |
536 | | |
537 | 93.2k | if( !tk->b_configured ) |
538 | 11.1k | { |
539 | 11.1k | if( !ps_track_fill( tk, &p_sys->psm, i_id, |
540 | 11.1k | p_pkt->p_buffer, p_pkt->i_buffer, false ) ) |
541 | 3.80k | { |
542 | 3.80k | if( p_sys->format == IMKH_PS ) |
543 | 1.56k | { |
544 | 1.56k | if( ps_id_to_type( &p_sys->psm , i_id ) == 0x91 ) |
545 | 43 | { |
546 | 43 | tk->fmt.i_codec = VLC_CODEC_MULAW; |
547 | 43 | tk->fmt.audio.i_channels = 1; |
548 | 43 | tk->fmt.audio.i_rate = 8000; |
549 | 43 | } |
550 | 1.56k | } |
551 | 2.23k | else |
552 | | /* No PSM and no probing yet */ |
553 | 2.23k | if( p_sys->format == PSMF_PS ) |
554 | 42 | { |
555 | 42 | if( tk->fmt.i_cat == VIDEO_ES ) |
556 | 18 | tk->fmt.i_codec = VLC_CODEC_H264; |
557 | | #if 0 |
558 | | if( i_stream_id == PS_STREAM_ID_PRIVATE_STREAM1 ) |
559 | | { |
560 | | es_format_Change( &tk->fmt, AUDIO_ES, VLC_CODEC_ATRAC3P ); |
561 | | tk->fmt.audio.i_blockalign = 376; |
562 | | tk->fmt.audio.i_channels = 2; |
563 | | tk->fmt.audio.i_rate = 44100; |
564 | | } |
565 | | #endif |
566 | 42 | } |
567 | | |
568 | 3.80k | b_new = true; |
569 | 3.80k | tk->b_configured = true; |
570 | 3.80k | tk->b_updated = true; |
571 | 3.80k | } |
572 | 7.36k | else |
573 | 7.36k | { |
574 | 7.36k | msg_Dbg( p_demux, "es id=0x%x format unknown", i_id ); |
575 | 7.36k | } |
576 | 11.1k | } |
577 | | |
578 | | /* Create all configured/updated ES when seeing a track packet */ |
579 | 93.2k | if( tk->b_updated ) |
580 | 7.04k | CreateOrUpdateES( p_demux ); |
581 | | |
582 | | /* The popular VCD/SVCD subtitling WinSubMux does not |
583 | | * renumber the SCRs when merging subtitles into the PES */ |
584 | 93.2k | if( !p_sys->b_bad_scr && p_sys->format == MPEG_PS && |
585 | 592 | ( tk->fmt.i_codec == VLC_CODEC_OGT || |
586 | 592 | tk->fmt.i_codec == VLC_CODEC_CVD ) ) |
587 | 2 | { |
588 | 2 | p_sys->b_bad_scr = true; |
589 | 2 | p_sys->i_first_scr = VLC_TICK_INVALID; |
590 | 2 | } |
591 | | |
592 | 93.2k | if( p_sys->i_pack_scr != VLC_TICK_INVALID && !p_sys->b_bad_scr ) |
593 | 687 | { |
594 | 687 | if( (tk->fmt.i_cat == AUDIO_ES || tk->fmt.i_cat == VIDEO_ES) && |
595 | 596 | tk->i_first_pts != VLC_TICK_INVALID && tk->i_first_pts - p_sys->i_pack_scr > VLC_TICK_FROM_SEC(2)) |
596 | 17 | { |
597 | 17 | msg_Warn( p_demux, "Incorrect SCR timing offset by of %"PRId64 "ms, disabling", |
598 | 17 | MS_FROM_VLC_TICK(tk->i_first_pts - p_sys->i_pack_scr) ); |
599 | 17 | p_sys->b_bad_scr = true; /* Disable Offset SCR */ |
600 | 17 | p_sys->i_first_scr = VLC_TICK_INVALID; |
601 | 17 | } |
602 | 670 | else |
603 | 670 | es_out_SetPCR( p_demux->out, p_sys->i_pack_scr ); |
604 | 687 | } |
605 | | |
606 | 93.2k | if( tk->b_configured && tk->es && |
607 | 85.9k | !ps_pkt_parse_pes( VLC_OBJECT(p_demux), p_pkt, tk->i_skip ) ) |
608 | 65.4k | { |
609 | 65.4k | if( tk->fmt.i_cat == AUDIO_ES || tk->fmt.i_cat == VIDEO_ES ) |
610 | 41.3k | { |
611 | 41.3k | if( !p_sys->b_bad_scr && p_sys->i_pack_scr != VLC_TICK_INVALID && p_pkt->i_pts != VLC_TICK_INVALID && |
612 | 472 | p_sys->i_pack_scr > p_pkt->i_pts + VLC_TICK_FROM_MS(250) ) |
613 | 116 | { |
614 | 116 | msg_Warn( p_demux, "Incorrect SCR timing in advance of %" PRId64 "ms, disabling", |
615 | 116 | MS_FROM_VLC_TICK(p_sys->i_pack_scr - p_pkt->i_pts) ); |
616 | 116 | p_sys->b_bad_scr = true; |
617 | 116 | p_sys->i_first_scr = VLC_TICK_INVALID; |
618 | 116 | } |
619 | | |
620 | 41.3k | if( (p_sys->b_bad_scr || !p_sys->b_have_pack) && !p_sys->i_scr_track_id ) |
621 | 867 | { |
622 | 867 | p_sys->i_scr_track_id = tk->i_id; |
623 | 867 | } |
624 | 41.3k | } |
625 | | |
626 | 65.4k | if( ((!b_new && !p_sys->b_have_pack) || p_sys->b_bad_scr) && |
627 | 61.8k | p_sys->i_scr_track_id == tk->i_id && |
628 | 10.0k | p_pkt->i_pts != VLC_TICK_INVALID ) |
629 | 6.72k | { |
630 | | /* A hack to sync the A/V on PES files. */ |
631 | 6.72k | msg_Dbg( p_demux, "force SCR: %"PRId64, p_pkt->i_pts ); |
632 | 6.72k | CheckPCR( p_sys, p_demux->out, p_pkt->i_pts ); |
633 | 6.72k | p_sys->i_scr = p_pkt->i_pts; |
634 | 6.72k | if( p_sys->i_first_scr == VLC_TICK_INVALID ) |
635 | 502 | p_sys->i_first_scr = p_sys->i_scr; |
636 | 6.72k | es_out_SetPCR( p_demux->out, p_pkt->i_pts ); |
637 | 6.72k | } |
638 | | |
639 | 65.4k | if( p_sys->format == IMKH_PS ) |
640 | 45.3k | { |
641 | | /* Synchronization on NVR is always broken */ |
642 | 45.3k | if( llabs( p_pkt->i_dts - p_sys->i_scr ) > VLC_TICK_FROM_SEC(2) ) |
643 | 17.6k | { |
644 | 17.6k | p_pkt->i_pts = p_pkt->i_pts - p_pkt->i_dts; |
645 | 17.6k | p_pkt->i_dts = p_sys->i_scr; |
646 | 17.6k | p_pkt->i_pts += p_sys->i_scr; |
647 | 17.6k | } |
648 | 45.3k | } |
649 | | |
650 | 65.4k | if( tk->fmt.i_codec == VLC_CODEC_TELETEXT && |
651 | 1.17k | p_pkt->i_pts == VLC_TICK_INVALID && p_sys->i_scr != VLC_TICK_INVALID ) |
652 | 107 | { |
653 | | /* Teletext may have missing PTS (ETSI EN 300 472 Annexe A) |
654 | | * In this case use the last SCR + 40ms */ |
655 | 107 | p_pkt->i_pts = p_sys->i_scr + VLC_TICK_FROM_MS(40); |
656 | 107 | } |
657 | | |
658 | 65.4k | if( p_pkt->i_pts > p_sys->i_current_pts ) |
659 | 1.05k | { |
660 | 1.05k | p_sys->i_current_pts = p_pkt->i_pts; |
661 | 1.05k | } |
662 | | |
663 | 65.4k | if( tk->i_next_block_flags ) |
664 | 7.46k | { |
665 | 7.46k | p_pkt->i_flags = tk->i_next_block_flags; |
666 | 7.46k | tk->i_next_block_flags = 0; |
667 | 7.46k | } |
668 | | #if 0 |
669 | | if( tk->fmt.i_codec == VLC_CODEC_ATRAC3P ) |
670 | | { |
671 | | p_pkt->p_buffer += 14; |
672 | | p_pkt->i_buffer -= 14; |
673 | | } |
674 | | #endif |
675 | 65.4k | es_out_Send( p_demux->out, tk->es, p_pkt ); |
676 | 65.4k | } |
677 | 27.8k | else |
678 | 27.8k | { |
679 | 27.8k | block_Release( p_pkt ); |
680 | 27.8k | } |
681 | | |
682 | 93.2k | p_sys->i_pack_scr = VLC_TICK_INVALID; |
683 | 93.2k | } |
684 | 93.2k | break; |
685 | 117k | } |
686 | | |
687 | 117k | demux_UpdateTitleFromStream( p_demux ); |
688 | 117k | return VLC_DEMUXER_SUCCESS; |
689 | 117k | } |
690 | | |
691 | | /***************************************************************************** |
692 | | * Control: |
693 | | *****************************************************************************/ |
694 | | static int Control( demux_t *p_demux, int i_query, va_list args ) |
695 | 0 | { |
696 | 0 | demux_sys_t *p_sys = p_demux->p_sys; |
697 | 0 | double f, *pf; |
698 | 0 | uint64_t u64; |
699 | 0 | int i_ret; |
700 | |
|
701 | 0 | switch( i_query ) |
702 | 0 | { |
703 | 0 | case DEMUX_CAN_SEEK: |
704 | 0 | *va_arg( args, bool * ) = p_sys->b_seekable; |
705 | 0 | return VLC_SUCCESS; |
706 | | |
707 | 0 | case DEMUX_GET_TITLE: |
708 | 0 | *va_arg( args, int * ) = p_sys->current_title; |
709 | 0 | return VLC_SUCCESS; |
710 | | |
711 | 0 | case DEMUX_GET_SEEKPOINT: |
712 | 0 | *va_arg( args, int * ) = p_sys->current_seekpoint; |
713 | 0 | return VLC_SUCCESS; |
714 | | |
715 | 0 | case DEMUX_GET_POSITION: |
716 | 0 | pf = va_arg( args, double * ); |
717 | 0 | if( vlc_stream_GetSize( p_demux->s, &u64 ) == VLC_SUCCESS ) |
718 | 0 | { |
719 | 0 | double current = vlc_stream_Tell( p_demux->s ) - p_sys->i_start_byte; |
720 | 0 | u64 = u64 - p_sys->i_start_byte; |
721 | 0 | *pf = current / (double)u64; |
722 | 0 | } |
723 | 0 | else |
724 | 0 | { |
725 | 0 | *pf = 0.0; |
726 | 0 | } |
727 | 0 | return VLC_SUCCESS; |
728 | | |
729 | 0 | case DEMUX_SET_POSITION: |
730 | 0 | f = va_arg( args, double ); |
731 | |
|
732 | 0 | if( vlc_stream_GetSize( p_demux->s, &u64 ) != VLC_SUCCESS ) |
733 | 0 | return VLC_EGENERIC; |
734 | | |
735 | 0 | u64 = u64 - p_sys->i_start_byte; |
736 | 0 | p_sys->i_current_pts = VLC_TICK_INVALID; |
737 | 0 | p_sys->i_scr = VLC_TICK_INVALID; |
738 | |
|
739 | 0 | if( p_sys->format == CDXA_PS ) |
740 | 0 | { |
741 | 0 | u64 = (uint64_t)(u64 * f); /* Align to sector payload */ |
742 | 0 | u64 = p_sys->i_start_byte + u64 - (u64 % CDXA_SECTOR_SIZE) + CDXA_SECTOR_HEADER_SIZE; |
743 | 0 | } |
744 | 0 | else |
745 | 0 | { |
746 | 0 | u64 = p_sys->i_start_byte + (uint64_t)(u64 * f); |
747 | 0 | } |
748 | |
|
749 | 0 | i_ret = vlc_stream_Seek( p_demux->s, u64 ); |
750 | 0 | if( i_ret == VLC_SUCCESS ) |
751 | 0 | { |
752 | 0 | NotifyDiscontinuity( p_sys->tk, p_demux->out ); |
753 | 0 | return i_ret; |
754 | 0 | } |
755 | 0 | break; |
756 | | |
757 | 0 | case DEMUX_GET_TIME: |
758 | 0 | if( p_sys->i_time_track_index >= 0 && p_sys->i_current_pts != VLC_TICK_INVALID ) |
759 | 0 | { |
760 | 0 | *va_arg( args, vlc_tick_t * ) = p_sys->i_current_pts - p_sys->tk[p_sys->i_time_track_index].i_first_pts; |
761 | 0 | return VLC_SUCCESS; |
762 | 0 | } |
763 | 0 | if( p_sys->i_first_scr != VLC_TICK_INVALID && p_sys->i_scr != VLC_TICK_INVALID ) |
764 | 0 | { |
765 | 0 | vlc_tick_t i_time = p_sys->i_scr - p_sys->i_first_scr; |
766 | | /* H.222 2.5.2.2 */ |
767 | 0 | if( p_sys->i_mux_rate > 0 && p_sys->b_have_pack ) |
768 | 0 | { |
769 | 0 | uint64_t i_offset = vlc_stream_Tell( p_demux->s ) - p_sys->i_lastpack_byte; |
770 | 0 | i_time += vlc_tick_from_samples(i_offset, p_sys->i_mux_rate * 50); |
771 | 0 | } |
772 | 0 | *va_arg( args, vlc_tick_t * ) = i_time; |
773 | 0 | return VLC_SUCCESS; |
774 | 0 | } |
775 | 0 | *va_arg( args, vlc_tick_t * ) = 0; |
776 | 0 | break; |
777 | | |
778 | 0 | case DEMUX_GET_LENGTH: |
779 | 0 | if( p_sys->i_length > VLC_TICK_0 ) |
780 | 0 | { |
781 | 0 | *va_arg( args, vlc_tick_t * ) = p_sys->i_length; |
782 | 0 | return VLC_SUCCESS; |
783 | 0 | } |
784 | 0 | else if( p_sys->i_mux_rate > 0 && |
785 | 0 | vlc_stream_GetSize( p_demux->s, &u64 ) == VLC_SUCCESS ) |
786 | 0 | { |
787 | 0 | *va_arg( args, vlc_tick_t * ) = |
788 | 0 | vlc_tick_from_samples( u64 - p_sys->i_start_byte / 50, p_sys->i_mux_rate ); |
789 | 0 | return VLC_SUCCESS; |
790 | 0 | } |
791 | 0 | *va_arg( args, vlc_tick_t * ) = 0; |
792 | 0 | break; |
793 | | |
794 | 0 | case DEMUX_SET_TIME: |
795 | 0 | { |
796 | 0 | if( p_sys->i_time_track_index >= 0 && p_sys->i_current_pts != VLC_TICK_INVALID && |
797 | 0 | p_sys->i_length > VLC_TICK_0) |
798 | 0 | { |
799 | 0 | vlc_tick_t i_time = va_arg( args, vlc_tick_t ); |
800 | 0 | i_time -= p_sys->tk[p_sys->i_time_track_index].i_first_pts; |
801 | 0 | return demux_SetPosition( p_demux, (double) i_time / p_sys->i_length, false ); |
802 | 0 | } |
803 | 0 | break; |
804 | 0 | } |
805 | | |
806 | 0 | case DEMUX_GET_TITLE_INFO: |
807 | 0 | { |
808 | 0 | struct input_title_t ***v = va_arg( args, struct input_title_t*** ); |
809 | 0 | int *c = va_arg( args, int * ); |
810 | |
|
811 | 0 | *va_arg( args, int* ) = 0; /* Title offset */ |
812 | 0 | *va_arg( args, int* ) = 0; /* Chapter offset */ |
813 | 0 | return vlc_stream_Control( p_demux->s, STREAM_GET_TITLE_INFO, v, |
814 | 0 | c ); |
815 | 0 | } |
816 | | |
817 | 0 | case DEMUX_SET_TITLE: |
818 | 0 | return vlc_stream_vaControl( p_demux->s, STREAM_SET_TITLE, args ); |
819 | | |
820 | 0 | case DEMUX_SET_SEEKPOINT: |
821 | 0 | return vlc_stream_vaControl( p_demux->s, STREAM_SET_SEEKPOINT, |
822 | 0 | args ); |
823 | | |
824 | 0 | case DEMUX_TEST_AND_CLEAR_FLAGS: |
825 | 0 | { |
826 | 0 | unsigned *restrict flags = va_arg(args, unsigned *); |
827 | 0 | *flags &= p_sys->updates; |
828 | 0 | p_sys->updates &= ~*flags; |
829 | 0 | return VLC_SUCCESS; |
830 | 0 | } |
831 | | |
832 | 0 | case DEMUX_GET_META: |
833 | 0 | return vlc_stream_vaControl( p_demux->s, STREAM_GET_META, args ); |
834 | | |
835 | 0 | case DEMUX_GET_FPS: |
836 | 0 | break; |
837 | | |
838 | 0 | case DEMUX_CAN_PAUSE: |
839 | 0 | case DEMUX_SET_PAUSE_STATE: |
840 | 0 | case DEMUX_CAN_CONTROL_PACE: |
841 | 0 | case DEMUX_GET_PTS_DELAY: |
842 | 0 | return demux_vaControlHelper( p_demux->s, 0, -1, 0, 1, i_query, args ); |
843 | | |
844 | 0 | default: |
845 | 0 | break; |
846 | |
|
847 | 0 | } |
848 | 0 | return VLC_EGENERIC; |
849 | 0 | } |
850 | | |
851 | | /***************************************************************************** |
852 | | * Divers: |
853 | | *****************************************************************************/ |
854 | | |
855 | | /* PSResynch: resynch on a system startcode |
856 | | * It doesn't skip more than 512 bytes |
857 | | * -1 -> error, 0 -> not synch, 1 -> ok |
858 | | */ |
859 | | static int ps_pkt_resynch( stream_t *s, int format, bool b_pack ) |
860 | 229k | { |
861 | 229k | const uint8_t *p_peek; |
862 | 229k | ssize_t i_peek; |
863 | 229k | unsigned int i_skip; |
864 | | |
865 | 229k | if( vlc_stream_Peek( s, &p_peek, 4 ) < 4 ) |
866 | 2.45k | { |
867 | 2.45k | return -1; |
868 | 2.45k | } |
869 | 227k | if( p_peek[0] == 0 && p_peek[1] == 0 && p_peek[2] == 1 && |
870 | 104k | p_peek[3] >= PS_STREAM_ID_END_STREAM ) |
871 | 102k | { |
872 | 102k | return 1; |
873 | 102k | } |
874 | | |
875 | 124k | if( ( i_peek = vlc_stream_Peek( s, &p_peek, 512 ) ) < 4 ) |
876 | 0 | { |
877 | 0 | return -1; |
878 | 0 | } |
879 | 124k | i_skip = 0; |
880 | | |
881 | 124k | for( ;; ) |
882 | 17.7M | { |
883 | 17.7M | if( i_peek < 4 ) |
884 | 21.1k | { |
885 | 21.1k | break; |
886 | 21.1k | } |
887 | | /* Handle mid stream 24 bytes padding+CRC creating emulated sync codes with incorrect |
888 | | PES sizes and frelling up to UINT16_MAX bytes followed by 24 bytes CDXA Header */ |
889 | 17.6M | if( format == CDXA_PS && i_skip == 0 && i_peek >= 48 ) |
890 | 50.4k | { |
891 | 50.4k | const uint8_t cdxasynccode[12] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, |
892 | 50.4k | 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; |
893 | 50.4k | if( !memcmp( &p_peek[24], cdxasynccode, 12 ) ) |
894 | 257 | { |
895 | 257 | i_peek -= 48; |
896 | 257 | p_peek += 48; |
897 | 257 | i_skip += 48; |
898 | 257 | continue; |
899 | 257 | } |
900 | 50.4k | } |
901 | | |
902 | 17.6M | if( p_peek[0] == 0 && p_peek[1] == 0 && p_peek[2] == 1 && |
903 | 283k | p_peek[3] >= PS_STREAM_ID_END_STREAM && |
904 | 118k | ( !b_pack || p_peek[3] == PS_STREAM_ID_PACK_HEADER ) ) |
905 | 103k | { |
906 | 103k | return vlc_stream_Read( s, NULL, i_skip ) != i_skip ? -1 : 1; |
907 | 103k | } |
908 | | |
909 | 17.5M | p_peek++; |
910 | 17.5M | i_peek--; |
911 | 17.5M | i_skip++; |
912 | 17.5M | } |
913 | 21.1k | return vlc_stream_Read( s, NULL, i_skip ) != i_skip ? -1 : 0; |
914 | 124k | } |
915 | | |
916 | | static block_t *ps_pkt_read( stream_t *s ) |
917 | 206k | { |
918 | 206k | const uint8_t *p_peek; |
919 | 206k | int i_peek = vlc_stream_Peek( s, &p_peek, 14 ); |
920 | 206k | if( i_peek < 4 ) |
921 | 0 | return NULL; |
922 | | |
923 | 206k | int i_size = ps_pkt_size( p_peek, i_peek ); |
924 | 206k | if( i_size <= 6 && p_peek[3] > PS_STREAM_ID_PACK_HEADER ) |
925 | 97.5k | { |
926 | | /* Special case, search the next start code */ |
927 | 97.5k | i_size = 6; |
928 | 97.5k | for( ;; ) |
929 | 111k | { |
930 | 111k | i_peek = vlc_stream_Peek( s, &p_peek, i_size + 1024 ); |
931 | 111k | if( i_peek <= i_size + 4 ) |
932 | 382 | { |
933 | 382 | return NULL; |
934 | 382 | } |
935 | 24.3M | while( i_size <= i_peek - 4 ) |
936 | 24.3M | { |
937 | 24.3M | if( p_peek[i_size] == 0x00 && p_peek[i_size+1] == 0x00 && |
938 | 4.06M | p_peek[i_size+2] == 0x01 && p_peek[i_size+3] >= PS_STREAM_ID_END_STREAM ) |
939 | 97.1k | { |
940 | 97.1k | return vlc_stream_Block( s, i_size ); |
941 | 97.1k | } |
942 | 24.2M | i_size++; |
943 | 24.2M | } |
944 | 111k | } |
945 | 97.5k | } |
946 | 108k | else |
947 | 108k | { |
948 | | /* Normal case */ |
949 | 108k | return vlc_stream_Block( s, i_size ); |
950 | 108k | } |
951 | | |
952 | 0 | return NULL; |
953 | 206k | } |