00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <stdlib.h>
00028
00029 #include <vlc/vlc.h>
00030 #include <vlc/input.h>
00031
00032
00033
00034
00035
00036
00037
00038
00039 static int Open ( vlc_object_t * );
00040 static void Close ( vlc_object_t * );
00041
00042 vlc_module_begin();
00043 set_description( _("PVA demuxer" ) );
00044 set_capability( "demux2", 10 );
00045 set_category( CAT_INPUT );
00046 set_subcategory( SUBCAT_INPUT_DEMUX );
00047 set_callbacks( Open, Close );
00048 add_shortcut( "pva" );
00049 vlc_module_end();
00050
00051
00052
00053
00054
00055 struct demux_sys_t
00056 {
00057 es_out_id_t *p_video;
00058 es_out_id_t *p_audio;
00059
00060
00061 int i_vc;
00062 int i_ac;
00063
00064
00065 block_t *p_pes;
00066 block_t *p_es;
00067
00068 int64_t b_pcr_audio;
00069 };
00070
00071 static int Demux ( demux_t *p_demux );
00072 static int Control ( demux_t *p_demux, int i_query, va_list args );
00073
00074 static int ReSynch ( demux_t * );
00075 static void ParsePES( demux_t * );
00076
00077
00078
00079
00080 static int Open( vlc_object_t *p_this )
00081 {
00082 demux_t *p_demux = (demux_t*)p_this;
00083 demux_sys_t *p_sys;
00084 es_format_t fmt;
00085 uint8_t *p_peek;
00086
00087 if( stream_Peek( p_demux->s, &p_peek, 5 ) < 5 ) return VLC_EGENERIC;
00088 if( p_peek[0] != 'A' || p_peek[1] != 'V' || p_peek[4] != 0x55 )
00089 {
00090
00091 if( strcasecmp( p_demux->psz_demux, "pva" ) || ReSynch( p_demux ) )
00092 {
00093 return VLC_EGENERIC;
00094 }
00095 }
00096
00097
00098 p_demux->pf_demux = Demux;
00099 p_demux->pf_control = Control;
00100 p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
00101
00102
00103 es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( 'm', 'p', 'g', 'a' ) );
00104 p_sys->p_audio = es_out_Add( p_demux->out, &fmt );
00105
00106 es_format_Init( &fmt, VIDEO_ES, VLC_FOURCC( 'm', 'p', 'g', 'v' ) );
00107 p_sys->p_video = es_out_Add( p_demux->out, &fmt );
00108
00109 p_sys->i_vc = -1;
00110 p_sys->i_ac = -1;
00111 p_sys->p_pes = NULL;
00112 p_sys->p_es = NULL;
00113
00114 p_sys->b_pcr_audio = VLC_FALSE;
00115
00116 return VLC_SUCCESS;
00117 }
00118
00119
00120
00121
00122 static void Close( vlc_object_t *p_this )
00123 {
00124 demux_t *p_demux = (demux_t*)p_this;
00125 demux_sys_t *p_sys = p_demux->p_sys;
00126
00127 if( p_sys->p_es ) block_Release( p_sys->p_es );
00128 if( p_sys->p_pes ) block_Release( p_sys->p_pes );
00129
00130 free( p_sys );
00131 }
00132
00133
00134
00135
00136
00137 static int Demux( demux_t *p_demux )
00138 {
00139 demux_sys_t *p_sys = p_demux->p_sys;
00140
00141 uint8_t *p_peek;
00142 int i_size;
00143 block_t *p_frame;
00144 int64_t i_pts;
00145 int i_skip;
00146
00147 if( stream_Peek( p_demux->s, &p_peek, 8 ) < 8 )
00148 {
00149 msg_Warn( p_demux, "eof ?" );
00150 return 0;
00151 }
00152 if( p_peek[0] != 'A' || p_peek[1] != 'V' || p_peek[4] != 0x55 )
00153 {
00154 msg_Warn( p_demux, "lost synchro" );
00155 if( ReSynch( p_demux ) )
00156 {
00157 return -1;
00158 }
00159 if( stream_Peek( p_demux->s, &p_peek, 8 ) < 8 )
00160 {
00161 msg_Warn( p_demux, "eof ?" );
00162 return 0;
00163 }
00164 }
00165
00166 i_size = GetWBE( &p_peek[6] );
00167 switch( p_peek[2] )
00168 {
00169 case 0x01:
00170 if( p_sys->i_vc < 0 )
00171 {
00172 msg_Dbg( p_demux, "first packet for video" );
00173 }
00174 else if( ((p_sys->i_vc + 1)&0xff) != p_peek[3] )
00175 {
00176 msg_Dbg( p_demux, "packet lost (video)" );
00177 if( p_sys->p_es )
00178 {
00179 block_ChainRelease( p_sys->p_es );
00180 p_sys->p_es = NULL;
00181 }
00182 }
00183 p_sys->i_vc = p_peek[3];
00184
00185
00186 i_pts = -1;
00187 i_skip = 8;
00188 if( p_peek[5]&0x10 )
00189 {
00190 int i_pre = p_peek[5]&0x3;
00191
00192 if( ( p_frame = stream_Block( p_demux->s, 8 + 4 + i_pre ) ) )
00193 {
00194 i_pts = GetDWBE( &p_frame->p_buffer[8] );
00195 if( p_frame->i_buffer > 12 )
00196 {
00197 p_frame->p_buffer += 12;
00198 p_frame->i_buffer -= 12;
00199 block_ChainAppend( &p_sys->p_es, p_frame );
00200 }
00201 else
00202 {
00203 block_Release( p_frame );
00204 }
00205 }
00206 i_size -= 4 + i_pre;
00207 i_skip = 0;
00208
00209 if( ( p_frame = p_sys->p_es ) )
00210 {
00211
00212 if( p_frame->i_pts > 0 && !p_sys->b_pcr_audio )
00213 {
00214 es_out_Control( p_demux->out, ES_OUT_SET_PCR, (int64_t)p_frame->i_pts);
00215 }
00216 es_out_Send( p_demux->out, p_sys->p_video, p_frame );
00217
00218 p_sys->p_es = NULL;
00219 }
00220 }
00221
00222 if( ( p_frame = stream_Block( p_demux->s, i_size + i_skip ) ) )
00223 {
00224 p_frame->p_buffer += i_skip;
00225 p_frame->i_buffer -= i_skip;
00226 if( i_pts > 0 ) p_frame->i_pts = i_pts * 100 / 9;
00227 block_ChainAppend( &p_sys->p_es, p_frame );
00228 }
00229 break;
00230
00231 case 0x02:
00232 if( p_sys->i_ac < 0 )
00233 {
00234 msg_Dbg( p_demux, "first packet for audio" );
00235 }
00236 else if( ((p_sys->i_ac + 1)&0xff) != p_peek[3] )
00237 {
00238 msg_Dbg( p_demux, "packet lost (audio)" );
00239 if( p_sys->p_pes )
00240 {
00241 block_ChainRelease( p_sys->p_pes );
00242 p_sys->p_pes = NULL;
00243 }
00244 }
00245 p_sys->i_ac = p_peek[3];
00246
00247 if( p_peek[5]&0x10 && p_sys->p_pes )
00248 {
00249 ParsePES( p_demux );
00250 }
00251 if( ( p_frame = stream_Block( p_demux->s, i_size + 8 ) ) )
00252 {
00253 p_frame->p_buffer += 8;
00254 p_frame->i_buffer -= 8;
00255
00256
00257 if( p_sys->p_pes && p_frame->i_buffer > 4 &&
00258 p_frame->p_buffer[0] == 0x00 &&
00259 p_frame->p_buffer[1] == 0x00 &&
00260 p_frame->p_buffer[2] == 0x01 )
00261 {
00262 ParsePES( p_demux );
00263 }
00264 block_ChainAppend( &p_sys->p_pes, p_frame );
00265 }
00266 break;
00267
00268 default:
00269 msg_Warn( p_demux, "unknown id=0x%x", p_peek[2] );
00270 stream_Read( p_demux->s, NULL, i_size + 8 );
00271 break;
00272 }
00273 return 1;
00274 }
00275
00276
00277
00278
00279 static int Control( demux_t *p_demux, int i_query, va_list args )
00280 {
00281
00282 double f, *pf;
00283 int64_t i64;
00284 switch( i_query )
00285 {
00286 case DEMUX_GET_POSITION:
00287 if( ( i64 = stream_Size( p_demux->s ) ) > 0 )
00288 {
00289 pf = (double*) va_arg( args, double* );
00290 *pf = (double)stream_Tell( p_demux->s ) / (double)i64;
00291 return VLC_SUCCESS;
00292 }
00293 return VLC_EGENERIC;
00294
00295 case DEMUX_SET_POSITION:
00296 f = (double) va_arg( args, double );
00297 i64 = stream_Size( p_demux->s );
00298
00299 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
00300 if( stream_Seek( p_demux->s, (int64_t)(i64 * f) ) || ReSynch( p_demux ) )
00301 {
00302 return VLC_EGENERIC;
00303 }
00304 return VLC_SUCCESS;
00305
00306 #if 0
00307 case DEMUX_GET_TIME:
00308 pi64 = (int64_t*)va_arg( args, int64_t * );
00309 if( p_sys->i_time < 0 )
00310 {
00311 *pi64 = 0;
00312 return VLC_EGENERIC;
00313 }
00314 *pi64 = p_sys->i_time;
00315 return VLC_SUCCESS;
00316
00317 #if 0
00318 case DEMUX_GET_LENGTH:
00319 pi64 = (int64_t*)va_arg( args, int64_t * );
00320 if( p_sys->i_mux_rate > 0 )
00321 {
00322 *pi64 = (int64_t)1000000 * ( stream_Size( p_demux->s ) / 50 ) / p_sys->i_mux_rate;
00323 return VLC_SUCCESS;
00324 }
00325 *pi64 = 0;
00326 return VLC_EGENERIC;
00327
00328 #endif
00329 case DEMUX_GET_FPS:
00330 pf = (double*)va_arg( args, double * );
00331 *pf = (double)1000000.0 / (double)p_sys->i_pcr_inc;
00332 return VLC_SUCCESS;
00333 #endif
00334 case DEMUX_SET_TIME:
00335 default:
00336 return VLC_EGENERIC;
00337 }
00338 }
00339
00340
00341
00342
00343 static int ReSynch( demux_t *p_demux )
00344 {
00345 uint8_t *p_peek;
00346 int i_skip;
00347 int i_peek;
00348
00349 while( !p_demux->b_die )
00350 {
00351 if( ( i_peek = stream_Peek( p_demux->s, &p_peek, 1024 ) ) < 8 )
00352 {
00353 return VLC_EGENERIC;
00354 }
00355 i_skip = 0;
00356
00357 while( i_skip < i_peek - 5 )
00358 {
00359 if( p_peek[0] == 'A' && p_peek[1] == 'V' && p_peek[4] == 0x55 )
00360 {
00361 if( i_skip > 0 )
00362 {
00363 stream_Read( p_demux->s, NULL, i_skip );
00364 }
00365 return VLC_SUCCESS;
00366 }
00367 p_peek++;
00368 i_skip++;
00369 }
00370
00371 stream_Read( p_demux->s, NULL, i_skip );
00372 }
00373
00374 return VLC_EGENERIC;
00375 }
00376
00377 static void ParsePES( demux_t *p_demux )
00378 {
00379 demux_sys_t *p_sys = p_demux->p_sys;
00380 block_t *p_pes = p_sys->p_pes;
00381 uint8_t hdr[30];
00382 int i_pes_size;
00383
00384 int i_skip;
00385 mtime_t i_dts = -1;
00386 mtime_t i_pts = -1;
00387
00388 p_sys->p_pes = NULL;
00389
00390
00391 block_ChainExtract( p_pes, hdr, 30 );
00392
00393 if( hdr[0] != 0 || hdr[1] != 0 || hdr[2] != 1 )
00394 {
00395 msg_Warn( p_demux, "invalid hdr [0x%2.2x:%2.2x:%2.2x:%2.2x]",
00396 hdr[0], hdr[1],hdr[2],hdr[3] );
00397 block_ChainRelease( p_pes );
00398 return;
00399 }
00400 i_pes_size = GetWBE( &hdr[4] );
00401
00402
00403 i_skip = hdr[8] + 9;
00404 if( hdr[7]&0x80 )
00405 {
00406 i_pts = ((mtime_t)(hdr[ 9]&0x0e ) << 29)|
00407 (mtime_t)(hdr[10] << 22)|
00408 ((mtime_t)(hdr[11]&0xfe) << 14)|
00409 (mtime_t)(hdr[12] << 7)|
00410 (mtime_t)(hdr[12] >> 1);
00411
00412 if( hdr[7]&0x40 )
00413 {
00414 i_dts = ((mtime_t)(hdr[14]&0x0e ) << 29)|
00415 (mtime_t)(hdr[15] << 22)|
00416 ((mtime_t)(hdr[16]&0xfe) << 14)|
00417 (mtime_t)(hdr[17] << 7)|
00418 (mtime_t)(hdr[18] >> 1);
00419 }
00420 }
00421
00422 p_pes = block_ChainGather( p_pes );
00423 if( p_pes->i_buffer <= i_skip )
00424 {
00425 block_ChainRelease( p_pes );
00426 return;
00427 }
00428
00429 p_pes->i_buffer -= i_skip;
00430 p_pes->p_buffer += i_skip;
00431
00432 if( i_dts >= 0 ) p_pes->i_dts = i_dts * 100 / 9;
00433 if( i_pts >= 0 ) p_pes->i_pts = i_pts * 100 / 9;
00434
00435
00436 if( p_pes->i_pts > 0 )
00437 {
00438 es_out_Control( p_demux->out, ES_OUT_SET_PCR, (int64_t)p_pes->i_pts);
00439 p_sys->b_pcr_audio = VLC_TRUE;
00440 }
00441 es_out_Send( p_demux->out, p_sys->p_audio, p_pes );
00442 }
00443