Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

ps.c

00001 /*****************************************************************************
00002  * ps.c: Program Stream demux module for VLC.
00003  *****************************************************************************
00004  * Copyright (C) 2004 the VideoLAN team
00005  * $Id: ps.c 13186 2005-11-10 19:23:12Z gbazin $
00006  *
00007  * Authors: Laurent Aimar <[email protected]>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 /*****************************************************************************
00025  * Preamble
00026  *****************************************************************************/
00027 #include <stdlib.h>                                      /* malloc(), free() */
00028 
00029 #include <vlc/vlc.h>
00030 #include <vlc/input.h>
00031 
00032 #include "ps.h"
00033 
00034 /* TODO:
00035  *  - re-add pre-scanning.
00036  *  - ...
00037  */
00038 
00039 /*****************************************************************************
00040  * Module descriptor
00041  *****************************************************************************/
00042 static int  Open   ( vlc_object_t * );
00043 static int  OpenAlt( vlc_object_t * );
00044 static void Close  ( vlc_object_t * );
00045 
00046 vlc_module_begin();
00047     set_description( _("PS demuxer") );
00048     set_category( CAT_INPUT );
00049     set_subcategory( SUBCAT_INPUT_DEMUX );
00050     set_capability( "demux2", 1 );
00051     set_callbacks( Open, Close );
00052     add_shortcut( "ps" );
00053 
00054     add_submodule();
00055     set_description( _("PS demuxer") );
00056     set_capability( "demux2", 9 );
00057     set_callbacks( OpenAlt, Close );
00058 vlc_module_end();
00059 
00060 /*****************************************************************************
00061  * Local prototypes
00062  *****************************************************************************/
00063 
00064 struct demux_sys_t
00065 {
00066     ps_psm_t    psm;
00067     ps_track_t  tk[PS_TK_COUNT];
00068 
00069     int64_t     i_scr;
00070     int         i_mux_rate;
00071 
00072     vlc_bool_t  b_lost_sync;
00073 };
00074 
00075 static int Demux  ( demux_t *p_demux );
00076 static int Control( demux_t *p_demux, int i_query, va_list args );
00077 
00078 static int      ps_pkt_resynch( stream_t *, uint32_t *pi_code );
00079 static block_t *ps_pkt_read   ( stream_t *, uint32_t i_code );
00080 
00081 /*****************************************************************************
00082  * Open
00083  *****************************************************************************/
00084 static int Open( vlc_object_t *p_this )
00085 {
00086     demux_t     *p_demux = (demux_t*)p_this;
00087     demux_sys_t *p_sys;
00088 
00089     uint8_t     *p_peek;
00090 
00091     if( stream_Peek( p_demux->s, &p_peek, 4 ) < 4 )
00092     {
00093         msg_Err( p_demux, "cannot peek" );
00094         return VLC_EGENERIC;
00095     }
00096 
00097     if( p_peek[0] != 0 || p_peek[1] != 0 ||
00098         p_peek[2] != 1 || p_peek[3] < 0xb9 )
00099     {
00100         msg_Warn( p_demux, "this does not look like an MPEG PS stream, "
00101                   "continuing anyway" );
00102     }
00103 
00104     /* Fill p_demux field */
00105     p_demux->pf_demux = Demux;
00106     p_demux->pf_control = Control;
00107     p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
00108 
00109     /* Init p_sys */
00110     p_sys->i_mux_rate = 0;
00111     p_sys->i_scr      = -1;
00112     p_sys->b_lost_sync = VLC_FALSE;
00113 
00114     ps_psm_init( &p_sys->psm );
00115     ps_track_init( p_sys->tk );
00116 
00117     /* TODO prescanning of ES */
00118 
00119     return VLC_SUCCESS;
00120 }
00121 
00122 static int OpenAlt( vlc_object_t *p_this )
00123 {
00124     demux_t *p_demux = (demux_t*)p_this;
00125     uint8_t *p_peek;
00126 
00127     if( stream_Peek( p_demux->s, &p_peek, 4 ) < 4 )
00128     {
00129         msg_Err( p_demux, "cannot peek" );
00130         return VLC_EGENERIC;
00131     }
00132 
00133     if( p_peek[0] != 0 || p_peek[1] != 0 ||
00134         p_peek[2] != 1 || p_peek[3] < 0xb9 )
00135     {
00136         if( !p_demux->b_force ) return VLC_EGENERIC;
00137     }
00138 
00139     return Open( p_this );
00140 }
00141 
00142 /*****************************************************************************
00143  * Close
00144  *****************************************************************************/
00145 static void Close( vlc_object_t *p_this )
00146 {
00147     demux_t     *p_demux = (demux_t*)p_this;
00148     demux_sys_t *p_sys = p_demux->p_sys;
00149     int i;
00150 
00151     for( i = 0; i < PS_TK_COUNT; i++ )
00152     {
00153         ps_track_t *tk = &p_sys->tk[i];
00154         if( tk->b_seen )
00155         {
00156             es_format_Clean( &tk->fmt );
00157             if( tk->es ) es_out_Del( p_demux->out, tk->es );
00158         }
00159     }
00160 
00161     ps_psm_destroy( &p_sys->psm );
00162 
00163     free( p_sys );
00164 }
00165 
00166 /*****************************************************************************
00167  * Demux:
00168  *****************************************************************************/
00169 static int Demux( demux_t *p_demux )
00170 {
00171     demux_sys_t *p_sys = p_demux->p_sys;
00172     int i_ret, i_id, i_mux_rate;
00173     uint32_t i_code;
00174     block_t *p_pkt;
00175 
00176     i_ret = ps_pkt_resynch( p_demux->s, &i_code );
00177     if( i_ret < 0 )
00178     {
00179         return 0;
00180     }
00181     else if( i_ret == 0 )
00182     {
00183         if( !p_sys->b_lost_sync )
00184             msg_Warn( p_demux, "garbage at input, trying to resync..." );
00185 
00186         p_sys->b_lost_sync = VLC_TRUE;
00187         return 1;
00188     }
00189 
00190     if( p_sys->b_lost_sync ) msg_Warn( p_demux, "found sync code" );
00191     p_sys->b_lost_sync = VLC_FALSE;
00192 
00193     if( ( p_pkt = ps_pkt_read( p_demux->s, i_code ) ) == NULL )
00194     {
00195         return 0;
00196     }
00197 
00198     switch( i_code )
00199     {
00200     case 0x1b9:
00201         block_Release( p_pkt );
00202         break;
00203 
00204     case 0x1ba:
00205         if( !ps_pkt_parse_pack( p_pkt, &p_sys->i_scr, &i_mux_rate ) )
00206         {
00207             /* done later on to work around bad vcd/svcd streams */
00208             /* es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_scr ); */
00209             if( i_mux_rate > 0 ) p_sys->i_mux_rate = i_mux_rate;
00210         }
00211         block_Release( p_pkt );
00212         break;
00213 
00214     case 0x1bb:
00215         if( !ps_pkt_parse_system( p_pkt, &p_sys->psm, p_sys->tk ) )
00216         {
00217             int i;
00218             for( i = 0; i < PS_TK_COUNT; i++ )
00219             {
00220                 ps_track_t *tk = &p_sys->tk[i];
00221 
00222                 if( tk->b_seen && !tk->es && tk->fmt.i_cat != UNKNOWN_ES )
00223                 {
00224                     tk->es = es_out_Add( p_demux->out, &tk->fmt );
00225                 }
00226             }
00227         }
00228         block_Release( p_pkt );
00229         break;
00230 
00231     case 0x1bc:
00232         if( p_sys->psm.i_version == 0xFFFF )
00233             msg_Dbg( p_demux, "contains a PSM");
00234 
00235         ps_psm_fill( &p_sys->psm, p_pkt, p_sys->tk, p_demux->out );
00236         block_Release( p_pkt );
00237         break;
00238 
00239     default:
00240         if( (i_id = ps_pkt_id( p_pkt )) >= 0xc0 )
00241         {
00242             ps_track_t *tk = &p_sys->tk[PS_ID_TO_TK(i_id)];
00243 
00244             if( !tk->b_seen )
00245             {
00246                 if( !ps_track_fill( tk, &p_sys->psm, i_id ) )
00247                 {
00248                     tk->es = es_out_Add( p_demux->out, &tk->fmt );
00249                 }
00250                 else
00251                 {
00252                     msg_Dbg( p_demux, "es id=0x%x format unknown", i_id );
00253                 }
00254                 tk->b_seen = VLC_TRUE;
00255             }
00256 
00257             /* The popular VCD/SVCD subtitling WinSubMux does not
00258              * renumber the SCRs when merging subtitles into the PES */
00259             if( tk->b_seen &&
00260                 ( tk->fmt.i_codec == VLC_FOURCC('o','g','t',' ') ||
00261                   tk->fmt.i_codec == VLC_FOURCC('c','v','d',' ') ) )
00262             {
00263                 p_sys->i_scr = -1;
00264             }
00265 
00266             if( p_sys->i_scr > 0 )
00267                 es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_scr );
00268 
00269             p_sys->i_scr = -1;
00270 
00271             if( tk->b_seen && tk->es &&
00272                 !ps_pkt_parse_pes( p_pkt, tk->i_skip ) )
00273             {
00274                 es_out_Send( p_demux->out, tk->es, p_pkt );
00275             }
00276             else
00277             {
00278                 block_Release( p_pkt );
00279             }
00280         }
00281         else
00282         {
00283             block_Release( p_pkt );
00284         }
00285         break;
00286     }
00287 
00288     return 1;
00289 }
00290 
00291 /*****************************************************************************
00292  * Control:
00293  *****************************************************************************/
00294 static int Control( demux_t *p_demux, int i_query, va_list args )
00295 {
00296     demux_sys_t *p_sys = p_demux->p_sys;
00297     double f, *pf;
00298     int64_t i64, *pi64;
00299 
00300     switch( i_query )
00301     {
00302         case DEMUX_GET_POSITION:
00303             pf = (double*) va_arg( args, double* );
00304             i64 = stream_Size( p_demux->s );
00305             if( i64 > 0 )
00306             {
00307                 *pf = (double)stream_Tell( p_demux->s ) / (double)i64;
00308             }
00309             else
00310             {
00311                 *pf = 0.0;
00312             }
00313             return VLC_SUCCESS;
00314 
00315         case DEMUX_SET_POSITION:
00316             f = (double) va_arg( args, double );
00317             i64 = stream_Size( p_demux->s );
00318 
00319             es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
00320 
00321             return stream_Seek( p_demux->s, (int64_t)(i64 * f) );
00322 
00323         case DEMUX_GET_TIME:
00324             pi64 = (int64_t*)va_arg( args, int64_t * );
00325             if( p_sys->i_mux_rate > 0 )
00326             {
00327                 *pi64 = (int64_t)1000000 * ( stream_Tell( p_demux->s ) / 50 ) /
00328                     p_sys->i_mux_rate;
00329                 return VLC_SUCCESS;
00330             }
00331             *pi64 = 0;
00332             return VLC_EGENERIC;
00333 
00334         case DEMUX_GET_LENGTH:
00335             pi64 = (int64_t*)va_arg( args, int64_t * );
00336             if( p_sys->i_mux_rate > 0 )
00337             {
00338                 *pi64 = (int64_t)1000000 * ( stream_Size( p_demux->s ) / 50 ) /
00339                     p_sys->i_mux_rate;
00340                 return VLC_SUCCESS;
00341             }
00342             *pi64 = 0;
00343             return VLC_EGENERIC;
00344 
00345         case DEMUX_SET_TIME:
00346         case DEMUX_GET_FPS:
00347         default:
00348             return VLC_EGENERIC;
00349     }
00350 }
00351 
00352 /*****************************************************************************
00353  * Divers:
00354  *****************************************************************************/
00355 
00356 /* PSResynch: resynch on a system starcode
00357  *  It doesn't skip more than 512 bytes
00358  *  -1 -> error, 0 -> not synch, 1 -> ok
00359  */
00360 static int ps_pkt_resynch( stream_t *s, uint32_t *pi_code )
00361 {
00362     uint8_t *p_peek;
00363     int     i_peek;
00364     int     i_skip;
00365 
00366     if( stream_Peek( s, &p_peek, 4 ) < 4 )
00367     {
00368         return -1;
00369     }
00370     if( p_peek[0] == 0 && p_peek[1] == 0 && p_peek[2] == 1 &&
00371         p_peek[3] >= 0xb9 )
00372     {
00373         *pi_code = 0x100 | p_peek[3];
00374         return 1;
00375     }
00376 
00377     if( ( i_peek = stream_Peek( s, &p_peek, 512 ) ) < 4 )
00378     {
00379         return -1;
00380     }
00381     i_skip = 0;
00382 
00383     for( ;; )
00384     {
00385         if( i_peek < 4 )
00386         {
00387             break;
00388         }
00389         if( p_peek[0] == 0 && p_peek[1] == 0 && p_peek[2] == 1 &&
00390             p_peek[3] >= 0xb9 )
00391         {
00392             *pi_code = 0x100 | p_peek[3];
00393             return stream_Read( s, NULL, i_skip ) == i_skip ? 1 : -1;
00394         }
00395 
00396         p_peek++;
00397         i_peek--;
00398         i_skip++;
00399     }
00400     return stream_Read( s, NULL, i_skip ) == i_skip ? 0 : -1;
00401 }
00402 
00403 static block_t *ps_pkt_read( stream_t *s, uint32_t i_code )
00404 {
00405     uint8_t *p_peek;
00406     int      i_peek = stream_Peek( s, &p_peek, 14 );
00407     int      i_size = ps_pkt_size( p_peek, i_peek );
00408 
00409     if( i_size <= 6 && p_peek[3] > 0xba )
00410     {
00411         /* Special case, search the next start code */
00412         i_size = 6;
00413         for( ;; )
00414         {
00415             i_peek = stream_Peek( s, &p_peek, i_size + 1024 );
00416             if( i_peek <= i_size + 4 )
00417             {
00418                 return NULL;
00419             }
00420             while( i_size <= i_peek - 4 )
00421             {
00422                 if( p_peek[i_size] == 0x00 && p_peek[i_size+1] == 0x00 &&
00423                     p_peek[i_size+2] == 0x01 && p_peek[i_size+3] >= 0xb9 )
00424                 {
00425                     return stream_Block( s, i_size );
00426                 }
00427                 i_size++;
00428             }
00429         }
00430     }
00431     else
00432     {
00433         /* Normal case */
00434         return stream_Block( s, i_size );
00435     }
00436 
00437     return NULL;
00438 }

Generated on Tue Dec 20 10:14:35 2005 for vlc-0.8.4a by  doxygen 1.4.2