]> git.sesse.net Git - vlc/blob - modules/demux/ps.c
* modules/access/vcd/vcd.c, modules/demux/ps.c: fixed vcd.
[vlc] / modules / demux / ps.c
1 /*****************************************************************************
2  * ps.c
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31
32 #include "ps.h"
33
34 /* TODO:
35  *  - re-add pre-scanning.
36  *  - ...
37  */
38
39 /*****************************************************************************
40  * Module descriptor
41  *****************************************************************************/
42 static int  Open    ( vlc_object_t * );
43 static void Close  ( vlc_object_t * );
44
45 vlc_module_begin();
46     set_description( _("PS demuxer") );
47     set_capability( "demux2", 1 );
48     set_callbacks( Open, Close );
49     add_shortcut( "ps" );
50 vlc_module_end();
51
52 /*****************************************************************************
53  * Local prototypes
54  *****************************************************************************/
55
56 struct demux_sys_t
57 {
58     ps_track_t   tk[PS_TK_COUNT];
59
60     int64_t     i_scr;
61     int         i_mux_rate;
62 };
63
64 static int Demux  ( demux_t *p_demux );
65 static int Control( demux_t *p_demux, int i_query, va_list args );
66
67 static int      ps_pkt_resynch( stream_t *, uint32_t *pi_code );
68 static block_t *ps_pkt_read   ( stream_t *, uint32_t i_code );
69
70 /*****************************************************************************
71  * Open
72  *****************************************************************************/
73 static int Open( vlc_object_t *p_this )
74 {
75     demux_t     *p_demux = (demux_t*)p_this;
76     demux_sys_t *p_sys;
77
78     uint8_t     *p_peek;
79
80     if( stream_Peek( p_demux->s, &p_peek, 4 ) < 4 )
81     {
82         msg_Err( p_demux, "cannot peek" );
83         return VLC_EGENERIC;
84     }
85
86     if( p_peek[0] != 0 || p_peek[1] != 0 || p_peek[2] != 1 || p_peek[3] < 0xb9 )
87     {
88         msg_Warn( p_demux, "this does not look like an MPEG PS stream, continuing anyway" );
89     }
90
91     /* Fill p_demux field */
92     p_demux->pf_demux = Demux;
93     p_demux->pf_control = Control;
94     p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
95
96     /* Init p_sys */
97     p_sys->i_mux_rate = 0;
98     p_sys->i_scr      = -1;
99
100     ps_track_init( p_sys->tk );
101
102     /* TODO prescanning of ES */
103
104     return VLC_SUCCESS;
105 }
106
107 /*****************************************************************************
108  * Close
109  *****************************************************************************/
110 static void Close( vlc_object_t *p_this )
111 {
112     demux_t     *p_demux = (demux_t*)p_this;
113     demux_sys_t *p_sys = p_demux->p_sys;
114
115     free( p_sys );
116 }
117
118 /*****************************************************************************
119  * Demux:
120  *****************************************************************************/
121 static int Demux( demux_t *p_demux )
122 {
123     demux_sys_t *p_sys = p_demux->p_sys;
124     int i_ret;
125     uint32_t i_code;
126     block_t  *p_pkt;
127
128     i_ret = ps_pkt_resynch( p_demux->s, &i_code );
129     if( i_ret < 0 )
130     {
131         return 0;
132     }
133     else if( i_ret == 0 )
134     {
135         msg_Warn( p_demux, "garbage at input" );
136         return 1;
137     }
138
139     if( ( p_pkt = ps_pkt_read( p_demux->s, i_code ) ) == NULL )
140     {
141         return 0;
142     }
143
144     switch( i_code )
145     {
146         case 0x1b9:
147             block_Release( p_pkt );
148             break;
149         case 0x1ba:
150         {
151             int i_mux_rate;
152
153             if( !ps_pkt_parse_pack( p_pkt, &p_sys->i_scr, &i_mux_rate ) )
154             {
155                 es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_scr );
156                 if( i_mux_rate > 0 )
157                 {
158                     p_sys->i_mux_rate = i_mux_rate;
159                 }
160             }
161             block_Release( p_pkt );
162             break;
163         }
164         case 0x1bb:
165             if( !ps_pkt_parse_system( p_pkt, p_sys->tk ) )
166             {
167                 int i;
168                 for( i = 0; i < PS_TK_COUNT; i++ )
169                 {
170                     ps_track_t *tk = &p_sys->tk[i];
171
172                     if( tk->b_seen && !tk->es && tk->fmt.i_cat != UNKNOWN_ES )
173                     {
174                         tk->es = es_out_Add( p_demux->out, &tk->fmt );
175                     }
176                 }
177             }
178             block_Release( p_pkt );
179             break;
180         case 0x1bc:
181             /* TODO PSM */
182             block_Release( p_pkt );
183             break;
184
185         default:
186         {
187             int        i_id = ps_pkt_id( p_pkt );
188             if( i_id >= 0xc0 )
189             {
190                 ps_track_t *tk = &p_sys->tk[PS_ID_TO_TK(i_id)];
191
192                 if( !tk->b_seen )
193                 {
194                     if( !ps_track_fill( tk, i_id ) )
195                     {
196                         tk->es = es_out_Add( p_demux->out, &tk->fmt );
197                     }
198                     tk->b_seen = VLC_TRUE;
199                 }
200                 if( tk->b_seen && tk->es && !ps_pkt_parse_pes( p_pkt, tk->i_skip ) )
201                 {
202                     es_out_Send( p_demux->out, tk->es, p_pkt );
203                 }
204                 else
205                 {
206                     block_Release( p_pkt );
207                 }
208             }
209             else
210             {
211                 block_Release( p_pkt );
212             }
213             break;
214         }
215     }
216     return 1;
217 }
218
219 /*****************************************************************************
220  * Control:
221  *****************************************************************************/
222 static int Control( demux_t *p_demux, int i_query, va_list args )
223 {
224     demux_sys_t *p_sys = p_demux->p_sys;
225     double f, *pf;
226     int64_t i64, *pi64;
227
228     switch( i_query )
229     {
230         case DEMUX_GET_POSITION:
231             pf = (double*) va_arg( args, double* );
232             i64 = stream_Size( p_demux->s );
233             if( i64 > 0 )
234             {
235                 *pf = (double)stream_Tell( p_demux->s ) / (double)i64;
236             }
237             else
238             {
239                 *pf = 0.0;
240             }
241             return VLC_SUCCESS;
242         case DEMUX_SET_POSITION:
243             f = (double) va_arg( args, double );
244             i64 = stream_Size( p_demux->s );
245
246             es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
247
248             return stream_Seek( p_demux->s, (int64_t)(i64 * f) );
249
250         case DEMUX_GET_TIME:
251             pi64 = (int64_t*)va_arg( args, int64_t * );
252             if( p_sys->i_mux_rate > 0 )
253             {
254                 *pi64 = (int64_t)1000000 * ( stream_Tell( p_demux->s ) / 50 ) / p_sys->i_mux_rate;
255                 return VLC_SUCCESS;
256             }
257             *pi64 = 0;
258             return VLC_EGENERIC;
259
260         case DEMUX_GET_LENGTH:
261             pi64 = (int64_t*)va_arg( args, int64_t * );
262             if( p_sys->i_mux_rate > 0 )
263             {
264                 *pi64 = (int64_t)1000000 * ( stream_Size( p_demux->s ) / 50 ) / p_sys->i_mux_rate;
265                 return VLC_SUCCESS;
266             }
267             *pi64 = 0;
268             return VLC_EGENERIC;
269
270         case DEMUX_SET_TIME:
271         case DEMUX_GET_FPS:
272         default:
273             return VLC_EGENERIC;
274     }
275 }
276
277 /*****************************************************************************
278  * Divers:
279  *****************************************************************************/
280
281 /* PSResynch: resynch on a systeme starcode
282  *  It doesn't skip more than 512 bytes
283  *  -1 -> error, 0 -> not synch, 1 -> ok
284  */
285 static int ps_pkt_resynch( stream_t *s, uint32_t *pi_code )
286 {
287     uint8_t *p_peek;
288     int     i_peek;
289     int     i_skip;
290
291     if( stream_Peek( s, &p_peek, 4 ) < 4 )
292     {
293         return -1;
294     }
295     if( p_peek[0] == 0 && p_peek[1] == 0 && p_peek[2] == 1 && p_peek[3] >= 0xb9 )
296     {
297         *pi_code = 0x100 | p_peek[3];
298         return 1;
299     }
300
301     if( ( i_peek = stream_Peek( s, &p_peek, 512 ) ) < 4 )
302     {
303         return -1;
304     }
305     i_skip = 0;
306
307     for( ;; )
308     {
309         if( i_peek < 4 )
310         {
311             break;
312         }
313         if( p_peek[0] == 0 && p_peek[1] == 0 && p_peek[2] == 1 && p_peek[3] >= 0xb9 )
314         {
315             *pi_code = 0x100 | p_peek[3];
316             return stream_Read( s, NULL, i_skip ) == i_skip ? 1 : -1;
317         }
318
319         p_peek++;
320         i_peek--;
321         i_skip++;
322     }
323     return stream_Read( s, NULL, i_skip ) == i_skip ? 0 : -1;
324 }
325
326 static block_t *ps_pkt_read( stream_t *s, uint32_t i_code )
327 {
328     uint8_t *p_peek;
329     int      i_peek = stream_Peek( s, &p_peek, 14 );
330     int      i_size = ps_pkt_size( p_peek, i_peek );
331
332     if( i_size > 0 )
333     {
334         return  stream_Block( s, i_size );
335     }
336     return NULL;
337 }