00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <stdlib.h>
00025 #include <vlc/vlc.h>
00026 #include <vlc/input.h>
00027
00028 #include "input_internal.h"
00029
00030 static void SkipID3Tag( demux_t * );
00031
00032
00033
00034
00035
00036 demux_t *__demux2_New( vlc_object_t *p_obj,
00037 char *psz_access, char *psz_demux, char *psz_path,
00038 stream_t *s, es_out_t *out, vlc_bool_t b_quick )
00039 {
00040 demux_t *p_demux = vlc_object_create( p_obj, VLC_OBJECT_DEMUX );
00041 char *psz_module;
00042
00043 if( p_demux == NULL ) return NULL;
00044
00045
00046 p_demux->psz_access = strdup( psz_access );
00047 p_demux->psz_demux = strdup( psz_demux );
00048 p_demux->psz_path = strdup( psz_path );
00049
00050
00051 if( *p_demux->psz_demux == '\0' )
00052 {
00053 free( p_demux->psz_demux );
00054 p_demux->psz_demux = var_GetString( p_obj, "demux" );
00055 }
00056
00057 if( !b_quick )
00058 {
00059 msg_Dbg( p_obj, "creating demux: access='%s' demux='%s' path='%s'",
00060 p_demux->psz_access, p_demux->psz_demux, p_demux->psz_path );
00061 }
00062
00063 p_demux->s = s;
00064 p_demux->out = out;
00065
00066 p_demux->pf_demux = NULL;
00067 p_demux->pf_control = NULL;
00068 p_demux->p_sys = NULL;
00069 p_demux->info.i_update = 0;
00070 p_demux->info.i_title = 0;
00071 p_demux->info.i_seekpoint = 0;
00072
00073 if( s ) psz_module = p_demux->psz_demux;
00074 else psz_module = p_demux->psz_access;
00075
00076 if( s && *psz_module == '\0' && strrchr( p_demux->psz_path, '.' ) )
00077 {
00078
00079
00080
00081
00082 static struct { char *ext; char *demux; } exttodemux[] =
00083 {
00084 { "aac", "aac" },
00085 { "aiff", "aiff" },
00086 { "asf", "asf" }, { "wmv", "asf" }, { "wma", "asf" },
00087 { "avi", "avi" },
00088 { "au", "au" },
00089 { "flac", "flac" },
00090 { "dv", "dv" },
00091 { "m3u", "playlist" },
00092 { "mkv", "mkv" }, { "mka", "mkv" }, { "mks", "mkv" },
00093 { "mp4", "mp4" }, { "m4a", "mp4" }, { "mov", "mp4" }, { "moov", "mp4" },
00094 { "mod", "mod" }, { "xm", "mod" },
00095 { "nsv", "nsv" },
00096 { "ogg", "ogg" }, { "ogm", "ogg" },
00097 { "pva", "pva" },
00098 { "rm", "rm" },
00099 { NULL, NULL },
00100 };
00101
00102 static struct { char *ext; char *demux; } exttodemux_quick[] =
00103 {
00104 { "mp3", "mpga" },
00105 { "ogg", "ogg" },
00106 { "wma", "asf" },
00107 { NULL, NULL }
00108 };
00109
00110 char *psz_ext = strrchr( p_demux->psz_path, '.' ) + 1;
00111 int i;
00112
00113 if( !b_quick )
00114 {
00115 for( i = 0; exttodemux[i].ext != NULL; i++ )
00116 {
00117 if( !strcasecmp( psz_ext, exttodemux[i].ext ) )
00118 {
00119 psz_module = exttodemux[i].demux;
00120 break;
00121 }
00122 }
00123 }
00124 else
00125 {
00126 for( i = 0; exttodemux_quick[i].ext != NULL; i++ )
00127 {
00128 if( !strcasecmp( psz_ext, exttodemux_quick[i].ext ) )
00129 {
00130 psz_module = exttodemux_quick[i].demux;
00131 break;
00132 }
00133 }
00134
00135 }
00136 }
00137
00138
00139 vlc_object_attach( p_demux, p_obj );
00140
00141 if( s )
00142 {
00143
00144
00145
00146 SkipID3Tag( p_demux );
00147
00148 p_demux->p_module =
00149 module_Need( p_demux, "demux2", psz_module,
00150 !strcmp( psz_module, p_demux->psz_demux ) ?
00151 VLC_TRUE : VLC_FALSE );
00152 }
00153 else
00154 {
00155 p_demux->p_module =
00156 module_Need( p_demux, "access_demux", psz_module,
00157 !strcmp( psz_module, p_demux->psz_access ) ?
00158 VLC_TRUE : VLC_FALSE );
00159 }
00160
00161 if( p_demux->p_module == NULL )
00162 {
00163 vlc_object_detach( p_demux );
00164 free( p_demux->psz_path );
00165 free( p_demux->psz_demux );
00166 free( p_demux->psz_access );
00167 vlc_object_destroy( p_demux );
00168 return NULL;
00169 }
00170
00171 return p_demux;
00172 }
00173
00174
00175
00176
00177 void demux2_Delete( demux_t *p_demux )
00178 {
00179 module_Unneed( p_demux, p_demux->p_module );
00180 vlc_object_detach( p_demux );
00181
00182 free( p_demux->psz_path );
00183 free( p_demux->psz_demux );
00184 free( p_demux->psz_access );
00185
00186 vlc_object_destroy( p_demux );
00187 }
00188
00189
00190
00191
00192 int demux2_vaControlHelper( stream_t *s,
00193 int64_t i_start, int64_t i_end,
00194 int i_bitrate, int i_align,
00195 int i_query, va_list args )
00196 {
00197 int64_t i_tell;
00198 double f, *pf;
00199 int64_t i64, *pi64;
00200
00201 if( i_end < 0 ) i_end = stream_Size( s );
00202 if( i_start < 0 ) i_start = 0;
00203 if( i_align <= 0 ) i_align = 1;
00204 i_tell = stream_Tell( s );
00205
00206 switch( i_query )
00207 {
00208 case DEMUX_GET_LENGTH:
00209 pi64 = (int64_t*)va_arg( args, int64_t * );
00210 if( i_bitrate > 0 && i_end > i_start )
00211 {
00212 *pi64 = I64C(8000000) * (i_end - i_start) / i_bitrate;
00213 return VLC_SUCCESS;
00214 }
00215 return VLC_EGENERIC;
00216
00217 case DEMUX_GET_TIME:
00218 pi64 = (int64_t*)va_arg( args, int64_t * );
00219 if( i_bitrate > 0 && i_end > i_start )
00220 {
00221 *pi64 = I64C(8000000) * (i_tell - i_start) / i_bitrate;
00222 return VLC_SUCCESS;
00223 }
00224 return VLC_EGENERIC;
00225
00226 case DEMUX_GET_POSITION:
00227 pf = (double*)va_arg( args, double * );
00228 if( i_start < i_end )
00229 {
00230 *pf = (double)( i_tell - i_start ) /
00231 (double)( i_end - i_start );
00232 return VLC_SUCCESS;
00233 }
00234 return VLC_EGENERIC;
00235
00236
00237 case DEMUX_SET_POSITION:
00238 f = (double)va_arg( args, double );
00239 if( i_start < i_end && f >= 0.0 && f <= 1.0 )
00240 {
00241 int64_t i_block = (f * ( i_end - i_start )) / i_align;
00242
00243 if( stream_Seek( s, i_start + i_block * i_align ) )
00244 {
00245 return VLC_EGENERIC;
00246 }
00247 return VLC_SUCCESS;
00248 }
00249 return VLC_EGENERIC;
00250
00251 case DEMUX_SET_TIME:
00252 i64 = (int64_t)va_arg( args, int64_t );
00253 if( i_bitrate > 0 && i64 >= 0 )
00254 {
00255 int64_t i_block = i64 * i_bitrate / I64C(8000000) / i_align;
00256 if( stream_Seek( s, i_start + i_block * i_align ) )
00257 {
00258 return VLC_EGENERIC;
00259 }
00260 return VLC_SUCCESS;
00261 }
00262 return VLC_EGENERIC;
00263
00264 case DEMUX_GET_FPS:
00265 case DEMUX_GET_META:
00266 case DEMUX_SET_NEXT_DEMUX_TIME:
00267 case DEMUX_GET_TITLE_INFO:
00268 case DEMUX_SET_GROUP:
00269 return VLC_EGENERIC;
00270
00271 default:
00272 msg_Err( s, "unknown query in demux_vaControlDefault" );
00273 return VLC_EGENERIC;
00274 }
00275 }
00276
00277
00278
00279
00280 typedef struct
00281 {
00282
00283 block_fifo_t *p_fifo;
00284 block_t *p_block;
00285
00286 int64_t i_pos;
00287
00288
00289 char *psz_name;
00290 es_out_t *out;
00291 demux_t *p_demux;
00292
00293 } d_stream_sys_t;
00294
00295 static int DStreamRead ( stream_t *, void *p_read, int i_read );
00296 static int DStreamPeek ( stream_t *, uint8_t **pp_peek, int i_peek );
00297 static int DStreamControl( stream_t *, int i_query, va_list );
00298 static int DStreamThread ( stream_t * );
00299
00300
00301 stream_t *__stream_DemuxNew( vlc_object_t *p_obj, char *psz_demux,
00302 es_out_t *out )
00303 {
00304
00305 stream_t *s;
00306 d_stream_sys_t *p_sys;
00307
00308 if( psz_demux == NULL || *psz_demux == '\0' ) return NULL;
00309
00310 s = vlc_object_create( p_obj, VLC_OBJECT_STREAM );
00311 s->pf_block = NULL;
00312 s->pf_read = DStreamRead;
00313 s->pf_peek = DStreamPeek;
00314 s->pf_control= DStreamControl;
00315
00316 s->p_sys = malloc( sizeof( d_stream_sys_t) );
00317 p_sys = (d_stream_sys_t*)s->p_sys;
00318
00319 p_sys->i_pos = 0;
00320 p_sys->out = out;
00321 p_sys->p_demux = NULL;
00322 p_sys->p_block = NULL;
00323 p_sys->psz_name = strdup( psz_demux );
00324
00325
00326 if( ( p_sys->p_fifo = block_FifoNew( s ) ) == NULL )
00327 {
00328 msg_Err( s, "out of memory" );
00329 vlc_object_destroy( s );
00330 free( p_sys );
00331 return NULL;
00332 }
00333
00334 if( vlc_thread_create( s, "stream out", DStreamThread,
00335 VLC_THREAD_PRIORITY_INPUT, VLC_FALSE ) )
00336 {
00337 vlc_object_destroy( s );
00338 free( p_sys );
00339 return NULL;
00340 }
00341
00342 return s;
00343 }
00344
00345 void stream_DemuxSend( stream_t *s, block_t *p_block )
00346 {
00347 d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
00348 if( p_block ) block_FifoPut( p_sys->p_fifo, p_block );
00349 }
00350
00351 void stream_DemuxDelete( stream_t *s )
00352 {
00353 d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
00354 block_t *p_empty;
00355
00356 s->b_die = VLC_TRUE;
00357 if( p_sys->p_demux ) p_sys->p_demux->b_die = VLC_TRUE;
00358 p_empty = block_New( s, 1 ); p_empty->i_buffer = 0;
00359 block_FifoPut( p_sys->p_fifo, p_empty );
00360 vlc_thread_join( s );
00361
00362 if( p_sys->p_demux ) demux2_Delete( p_sys->p_demux );
00363 if( p_sys->p_block ) block_Release( p_sys->p_block );
00364
00365 block_FifoRelease( p_sys->p_fifo );
00366 free( p_sys->psz_name );
00367 free( p_sys );
00368
00369 vlc_object_destroy( s );
00370 }
00371
00372
00373 static int DStreamRead( stream_t *s, void *p_read, int i_read )
00374 {
00375 d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
00376 uint8_t *p_out = p_read;
00377 int i_out = 0;
00378
00379
00380
00381 while( !s->b_die && !s->b_error && i_read )
00382 {
00383 block_t *p_block = p_sys->p_block;
00384 int i_copy;
00385
00386 if( !p_block )
00387 {
00388 p_block = block_FifoGet( p_sys->p_fifo );
00389 if( !p_block ) s->b_error = 1;
00390 p_sys->p_block = p_block;
00391 }
00392
00393 if( p_block && i_read )
00394 {
00395 i_copy = __MIN( i_read, p_block->i_buffer );
00396 if( p_out && i_copy ) memcpy( p_out, p_block->p_buffer, i_copy );
00397 i_read -= i_copy;
00398 i_out += i_copy;
00399 p_block->i_buffer -= i_copy;
00400 p_block->p_buffer += i_copy;
00401
00402 if( !p_block->i_buffer )
00403 {
00404 block_Release( p_block );
00405 p_sys->p_block = NULL;
00406 }
00407 }
00408 }
00409
00410 p_sys->i_pos += i_out;
00411 return i_out;
00412 }
00413
00414 static int DStreamPeek( stream_t *s, uint8_t **pp_peek, int i_peek )
00415 {
00416 d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
00417 block_t **pp_block = &p_sys->p_block;
00418 int i_out = 0;
00419 *pp_peek = 0;
00420
00421
00422
00423 while( !s->b_die && !s->b_error && i_peek )
00424 {
00425 int i_copy;
00426
00427 if( !*pp_block )
00428 {
00429 *pp_block = block_FifoGet( p_sys->p_fifo );
00430 if( !*pp_block ) s->b_error = 1;
00431 }
00432
00433 if( *pp_block && i_peek )
00434 {
00435 i_copy = __MIN( i_peek, (*pp_block)->i_buffer );
00436 i_peek -= i_copy;
00437 i_out += i_copy;
00438
00439 if( i_peek ) pp_block = &(*pp_block)->p_next;
00440 }
00441 }
00442
00443 if( p_sys->p_block )
00444 {
00445 p_sys->p_block = block_ChainGather( p_sys->p_block );
00446 *pp_peek = p_sys->p_block->p_buffer;
00447 }
00448
00449 return i_out;
00450 }
00451
00452 static int DStreamControl( stream_t *s, int i_query, va_list args )
00453 {
00454 d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
00455 int64_t *p_i64;
00456 vlc_bool_t *p_b;
00457 int *p_int;
00458
00459 switch( i_query )
00460 {
00461 case STREAM_GET_SIZE:
00462 p_i64 = (int64_t*) va_arg( args, int64_t * );
00463 *p_i64 = 0;
00464 return VLC_SUCCESS;
00465
00466 case STREAM_CAN_SEEK:
00467 p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
00468 *p_b = VLC_FALSE;
00469 return VLC_SUCCESS;
00470
00471 case STREAM_CAN_FASTSEEK:
00472 p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
00473 *p_b = VLC_FALSE;
00474 return VLC_SUCCESS;
00475
00476 case STREAM_GET_POSITION:
00477 p_i64 = (int64_t*) va_arg( args, int64_t * );
00478 *p_i64 = p_sys->i_pos;
00479 return VLC_SUCCESS;
00480
00481 case STREAM_SET_POSITION:
00482 {
00483 int64_t i64 = (int64_t)va_arg( args, int64_t );
00484 int i_skip;
00485 if( i64 < p_sys->i_pos ) return VLC_EGENERIC;
00486 i_skip = i64 - p_sys->i_pos;
00487
00488 while( i_skip > 0 )
00489 {
00490 int i_read = DStreamRead( s, NULL, i_skip );
00491 if( i_read <= 0 ) return VLC_EGENERIC;
00492 i_skip -= i_read;
00493 }
00494 return VLC_SUCCESS;
00495 }
00496
00497 case STREAM_GET_MTU:
00498 p_int = (int*) va_arg( args, int * );
00499 *p_int = 0;
00500 return VLC_SUCCESS;
00501
00502 case STREAM_CONTROL_ACCESS:
00503 return VLC_EGENERIC;
00504
00505 default:
00506 msg_Err( s, "invalid DStreamControl query=0x%x", i_query );
00507 return VLC_EGENERIC;
00508 }
00509 }
00510
00511 static int DStreamThread( stream_t *s )
00512 {
00513 d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
00514 demux_t *p_demux;
00515
00516
00517 if( !(p_demux = demux2_New( s, "", p_sys->psz_name, "", s, p_sys->out,
00518 VLC_FALSE )) )
00519 {
00520 return VLC_EGENERIC;
00521 }
00522
00523 p_sys->p_demux = p_demux;
00524
00525
00526 while( !s->b_die && !p_demux->b_die )
00527 {
00528 if( p_demux->pf_demux( p_demux ) <= 0 ) break;
00529 }
00530
00531 p_demux->b_die = VLC_TRUE;
00532 return VLC_SUCCESS;
00533 }
00534
00535
00536
00537
00538 static void SkipID3Tag( demux_t *p_demux )
00539 {
00540 uint8_t *p_peek;
00541 uint8_t version, revision;
00542 int i_size;
00543 int b_footer;
00544
00545 if( !p_demux->s ) return;
00546
00547
00548 if( stream_Peek( p_demux->s, &p_peek, 10 ) < 10 ) return;
00549
00550 if( p_peek[0] != 'I' || p_peek[1] != 'D' || p_peek[2] != '3' ) return;
00551
00552 version = p_peek[3];
00553 revision = p_peek[4];
00554 b_footer = p_peek[5] & 0x10;
00555 i_size = (p_peek[6]<<21) + (p_peek[7]<<14) + (p_peek[8]<<7) + p_peek[9];
00556
00557 if( b_footer ) i_size += 10;
00558 i_size += 10;
00559
00560
00561 stream_Read( p_demux->s, NULL, i_size );
00562
00563 msg_Dbg( p_demux, "ID3v2.%d revision %d tag found, skiping %d bytes",
00564 version, revision, i_size );
00565
00566 return;
00567 }