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