X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Fdemux.c;h=2712f96d0064706dc6798cde3dfa358a142f56cd;hb=40785cad487daf4df6418b07f28bdd03d1ca3f03;hp=f05c7d392780fc0a6633e1b5eb079825dfc8390f;hpb=68d217865aee3a510ae8e309b384056444212c44;p=vlc diff --git a/src/input/demux.c b/src/input/demux.c index f05c7d3927..2712f96d00 100644 --- a/src/input/demux.c +++ b/src/input/demux.c @@ -1,7 +1,7 @@ /***************************************************************************** * demux.c ***************************************************************************** - * Copyright (C) 1999-2004 VideoLAN + * Copyright (C) 1999-2004 the VideoLAN team * $Id$ * * Author: Laurent Aimar @@ -18,38 +18,47 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ #include #include -#include #include "input_internal.h" +static void SkipID3Tag( demux_t * ); + /***************************************************************************** * demux2_New: * if s is NULL then load a access_demux *****************************************************************************/ demux_t *__demux2_New( vlc_object_t *p_obj, - char *psz_access, char *psz_demux, char *psz_path, - stream_t *s, es_out_t *out ) + const char *psz_access, const char *psz_demux, + const char *psz_path, + stream_t *s, es_out_t *out, vlc_bool_t b_quick ) { demux_t *p_demux = vlc_object_create( p_obj, VLC_OBJECT_DEMUX ); - char *psz_module; + const char *psz_module; - if( p_demux == NULL ) - { - return NULL; - } + if( p_demux == NULL ) return NULL; /* Parse URL */ p_demux->psz_access = strdup( psz_access ); p_demux->psz_demux = strdup( psz_demux ); p_demux->psz_path = strdup( psz_path ); - msg_Dbg( p_obj, "demux2_New: access='%s' demux='%s' path='%s'", - p_demux->psz_access, p_demux->psz_demux, p_demux->psz_path ); + /* Take into account "demux" to be able to do :demux=dump */ + if( *p_demux->psz_demux == '\0' ) + { + free( p_demux->psz_demux ); + p_demux->psz_demux = var_GetString( p_obj, "demux" ); + } + + if( !b_quick ) + { + msg_Dbg( p_obj, "creating demux: access='%s' demux='%s' path='%s'", + p_demux->psz_access, p_demux->psz_demux, p_demux->psz_path ); + } p_demux->s = s; p_demux->out = out; @@ -61,19 +70,18 @@ demux_t *__demux2_New( vlc_object_t *p_obj, p_demux->info.i_title = 0; p_demux->info.i_seekpoint = 0; - if( s ) - psz_module = p_demux->psz_demux; - else - psz_module = p_demux->psz_access; + if( s ) psz_module = p_demux->psz_demux; + else psz_module = p_demux->psz_access; if( s && *psz_module == '\0' && strrchr( p_demux->psz_path, '.' ) ) { - /* XXX: add only file without any problem here and with strong detection. - * - no .mp3, .a52, ... (aac is added as it works only by file ext anyway - * - wav can't be added 'cause of a52 and dts in them as raw audio + /* XXX: add only file without any problem here and with strong detection. + * - no .mp3, .a52, ... (aac is added as it works only by file ext + * anyway + * - wav can't be added 'cause of a52 and dts in them as raw audio */ - static struct { char *ext; char *demux; } exttodemux[] = - { + static const struct { char ext[5]; char demux[9]; } exttodemux[] = + { { "aac", "aac" }, { "aiff", "aiff" }, { "asf", "asf" }, { "wmv", "asf" }, { "wma", "asf" }, @@ -81,7 +89,7 @@ demux_t *__demux2_New( vlc_object_t *p_obj, { "au", "au" }, { "flac", "flac" }, { "dv", "dv" }, - { "m3u", "m3u" }, + { "m3u", "playlist" }, { "mkv", "mkv" }, { "mka", "mkv" }, { "mks", "mkv" }, { "mp4", "mp4" }, { "m4a", "mp4" }, { "mov", "mp4" }, { "moov", "mp4" }, { "mod", "mod" }, { "xm", "mod" }, @@ -89,20 +97,45 @@ demux_t *__demux2_New( vlc_object_t *p_obj, { "ogg", "ogg" }, { "ogm", "ogg" }, { "pva", "pva" }, { "rm", "rm" }, + { "m4v", "m4v" }, + { "h264", "h264" }, { "", "" }, }; + /* Here, we don't mind if it does not work, it must be quick */ + static const struct { char ext[4]; char demux[5]; } exttodemux_quick[] = + { + { "mp3", "mpga" }, + { "ogg", "ogg" }, + { "wma", "asf" }, + { "", "" } + }; - char *psz_ext = strrchr( p_demux->psz_path, '.' ) + 1; + const char *psz_ext = strrchr( p_demux->psz_path, '.' ) + 1; int i; - for( i = 0; exttodemux[i].ext != NULL; i++ ) + if( !b_quick ) { - if( !strcasecmp( psz_ext, exttodemux[i].ext ) ) + for( i = 0; exttodemux[i].ext[0]; i++ ) { - psz_module = exttodemux[i].demux; - break; + if( !strcasecmp( psz_ext, exttodemux[i].ext ) ) + { + psz_module = exttodemux[i].demux; + break; + } } } + else + { + for( i = 0; exttodemux_quick[i].ext[0]; i++ ) + { + if( !strcasecmp( psz_ext, exttodemux_quick[i].ext ) ) + { + psz_module = exttodemux_quick[i].demux; + break; + } + } + + } } /* Before module_Need (for var_Create...) */ @@ -110,15 +143,22 @@ demux_t *__demux2_New( vlc_object_t *p_obj, if( s ) { + /* ID3 tags will mess-up demuxer probing so we skip it here. + * ID3 parsers will called later on in the demuxer to access the + * skipped info. */ + SkipID3Tag( p_demux ); + p_demux->p_module = module_Need( p_demux, "demux2", psz_module, - !strcmp( psz_module, p_demux->psz_demux ) ? VLC_TRUE : VLC_FALSE ); + !strcmp( psz_module, p_demux->psz_demux ) ? + VLC_TRUE : VLC_FALSE ); } else { p_demux->p_module = module_Need( p_demux, "access_demux", psz_module, - !strcmp( psz_module, p_demux->psz_access ) ? VLC_TRUE : VLC_FALSE ); + !strcmp( psz_module, p_demux->psz_access ) ? + VLC_TRUE : VLC_FALSE ); } if( p_demux->p_module == NULL ) @@ -226,6 +266,10 @@ int demux2_vaControlHelper( stream_t *s, case DEMUX_GET_FPS: case DEMUX_GET_META: + case DEMUX_SET_NEXT_DEMUX_TIME: + case DEMUX_GET_TITLE_INFO: + case DEMUX_SET_GROUP: + case DEMUX_GET_ATTACHMENTS: return VLC_EGENERIC; default: @@ -240,10 +284,8 @@ int demux2_vaControlHelper( stream_t *s, typedef struct { /* Data buffer */ - vlc_mutex_t lock; - int i_buffer; - int i_buffer_size; - uint8_t *p_buffer; + block_fifo_t *p_fifo; + block_t *p_block; int64_t i_pos; @@ -251,46 +293,54 @@ typedef struct char *psz_name; es_out_t *out; demux_t *p_demux; + } d_stream_sys_t; static int DStreamRead ( stream_t *, void *p_read, int i_read ); -static int DStreamPeek ( stream_t *, uint8_t **pp_peek, int i_peek ); +static int DStreamPeek ( stream_t *, const uint8_t **pp_peek, int i_peek ); static int DStreamControl( stream_t *, int i_query, va_list ); static int DStreamThread ( stream_t * ); -stream_t *__stream_DemuxNew( vlc_object_t *p_obj, char *psz_demux, es_out_t *out ) +stream_t *__stream_DemuxNew( vlc_object_t *p_obj, const char *psz_demux, + es_out_t *out ) { /* We create a stream reader, and launch a thread */ stream_t *s; d_stream_sys_t *p_sys; - if( psz_demux == NULL || *psz_demux == '\0' ) - { - return NULL; - } + if( psz_demux == NULL || *psz_demux == '\0' ) return NULL; - s = vlc_object_create( p_obj, VLC_OBJECT_STREAM ); + s = vlc_stream_create( p_obj ); s->pf_block = NULL; s->pf_read = DStreamRead; s->pf_peek = DStreamPeek; s->pf_control= DStreamControl; + s->i_char_width = 1; + s->b_little_endian = VLC_FALSE; + s->p_sys = malloc( sizeof( d_stream_sys_t) ); p_sys = (d_stream_sys_t*)s->p_sys; - vlc_mutex_init( s, &p_sys->lock ); - p_sys->i_buffer = 0; - p_sys->i_buffer_size = 1000000; - p_sys->p_buffer = malloc( p_sys->i_buffer_size ); p_sys->i_pos = 0; - p_sys->psz_name = strdup( psz_demux ); p_sys->out = out; p_sys->p_demux = NULL; + p_sys->p_block = NULL; + p_sys->psz_name = strdup( psz_demux ); - if( vlc_thread_create( s, "stream out", DStreamThread, VLC_THREAD_PRIORITY_INPUT, VLC_FALSE ) ) + /* decoder fifo */ + if( ( p_sys->p_fifo = block_FifoNew( s ) ) == NULL ) + { + msg_Err( s, "out of memory" ); + vlc_object_destroy( s ); + free( p_sys ); + return NULL; + } + + if( vlc_thread_create( s, "stream out", DStreamThread, + VLC_THREAD_PRIORITY_INPUT, VLC_FALSE ) ) { - vlc_mutex_destroy( &p_sys->lock ); vlc_object_destroy( s ); free( p_sys ); return NULL; @@ -299,138 +349,121 @@ stream_t *__stream_DemuxNew( vlc_object_t *p_obj, char *psz_demux, es_out_t *out return s; } -void stream_DemuxSend( stream_t *s, block_t *p_block ) +void stream_DemuxSend( stream_t *s, block_t *p_block ) { d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys; - - if( p_block->i_buffer > 0 ) - { - vlc_mutex_lock( &p_sys->lock ); - /* Realloc if needed */ - if( p_sys->i_buffer + p_block->i_buffer > p_sys->i_buffer_size ) - { - if( p_sys->i_buffer_size > 5000000 ) - { - vlc_mutex_unlock( &p_sys->lock ); - msg_Err( s, "stream_DemuxSend: buffer size > 5000000" ); - block_Release( p_block ); - return; - } - /* I know, it's more than needed but that's perfect */ - p_sys->i_buffer_size += p_block->i_buffer; - /* FIXME won't work with PEEK -> segfault */ - p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size ); - msg_Dbg( s, "stream_DemuxSend: realloc to %d", p_sys->i_buffer_size ); - } - - /* copy data */ - memcpy( &p_sys->p_buffer[p_sys->i_buffer], p_block->p_buffer, p_block->i_buffer ); - p_sys->i_buffer += p_block->i_buffer; - - vlc_mutex_unlock( &p_sys->lock ); - } - - block_Release( p_block ); + if( p_block ) block_FifoPut( p_sys->p_fifo, p_block ); } -void stream_DemuxDelete( stream_t *s ) +void stream_DemuxDelete( stream_t *s ) { d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys; + block_t *p_empty; - s->b_die = VLC_TRUE; - - vlc_mutex_lock( &p_sys->lock ); + vlc_object_kill( s ); if( p_sys->p_demux ) - { - p_sys->p_demux->b_die = VLC_TRUE; - } - vlc_mutex_unlock( &p_sys->lock ); - + vlc_object_kill( p_sys->p_demux ); + p_empty = block_New( s, 1 ); p_empty->i_buffer = 0; + block_FifoPut( p_sys->p_fifo, p_empty ); vlc_thread_join( s ); - if( p_sys->p_demux ) - { - demux2_Delete( p_sys->p_demux ); - } - vlc_mutex_destroy( &p_sys->lock ); + if( p_sys->p_demux ) demux2_Delete( p_sys->p_demux ); + if( p_sys->p_block ) block_Release( p_sys->p_block ); + + block_FifoRelease( p_sys->p_fifo ); free( p_sys->psz_name ); - free( p_sys->p_buffer ); free( p_sys ); + vlc_object_destroy( s ); } -static int DStreamRead ( stream_t *s, void *p_read, int i_read ) +static int DStreamRead( stream_t *s, void *p_read, int i_read ) { d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys; - int i_copy; + uint8_t *p_out = p_read; + int i_out = 0; //msg_Dbg( s, "DStreamRead: wanted %d bytes", i_read ); - for( ;; ) - { - vlc_mutex_lock( &p_sys->lock ); - //msg_Dbg( s, "DStreamRead: buffer %d", p_sys->i_buffer ); - if( p_sys->i_buffer >= i_read || s->b_die ) - { - break; - } - vlc_mutex_unlock( &p_sys->lock ); - msleep( 10000 ); - } - //msg_Dbg( s, "DStreamRead: read %d buffer %d", i_read, p_sys->i_buffer ); - - i_copy = __MIN( i_read, p_sys->i_buffer ); - if( i_copy > 0 ) + while( !s->b_die && !s->b_error && i_read ) { - if( p_read ) + block_t *p_block = p_sys->p_block; + int i_copy; + + if( !p_block ) { - memcpy( p_read, p_sys->p_buffer, i_copy ); + p_block = block_FifoGet( p_sys->p_fifo ); + if( !p_block ) s->b_error = 1; + p_sys->p_block = p_block; } - p_sys->i_buffer -= i_copy; - p_sys->i_pos += i_copy; - if( p_sys->i_buffer > 0 ) + if( p_block && i_read ) { - memmove( p_sys->p_buffer, &p_sys->p_buffer[i_copy], p_sys->i_buffer ); + i_copy = __MIN( i_read, p_block->i_buffer ); + if( p_out && i_copy ) memcpy( p_out, p_block->p_buffer, i_copy ); + i_read -= i_copy; + i_out += i_copy; + p_block->i_buffer -= i_copy; + p_block->p_buffer += i_copy; + + if( !p_block->i_buffer ) + { + block_Release( p_block ); + p_sys->p_block = NULL; + } } - } - vlc_mutex_unlock( &p_sys->lock ); - return i_copy; + p_sys->i_pos += i_out; + return i_out; } -static int DStreamPeek ( stream_t *s, uint8_t **pp_peek, int i_peek ) + +static int DStreamPeek( stream_t *s, const uint8_t **pp_peek, int i_peek ) { d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys; - int i_copy; + block_t **pp_block = &p_sys->p_block; + int i_out = 0; + *pp_peek = 0; //msg_Dbg( s, "DStreamPeek: wanted %d bytes", i_peek ); - for( ;; ) + + while( !s->b_die && !s->b_error && i_peek ) { - vlc_mutex_lock( &p_sys->lock ); - //msg_Dbg( s, "DStreamPeek: buffer %d", p_sys->i_buffer ); - if( p_sys->i_buffer >= i_peek || s->b_die ) + int i_copy; + + if( !*pp_block ) { - break; + *pp_block = block_FifoGet( p_sys->p_fifo ); + if( !*pp_block ) s->b_error = 1; + } + + if( *pp_block && i_peek ) + { + i_copy = __MIN( i_peek, (*pp_block)->i_buffer ); + i_peek -= i_copy; + i_out += i_copy; + + if( i_peek ) pp_block = &(*pp_block)->p_next; } - vlc_mutex_unlock( &p_sys->lock ); - msleep( 10000 ); } - *pp_peek = p_sys->p_buffer; - i_copy = __MIN( i_peek, p_sys->i_buffer ); - vlc_mutex_unlock( &p_sys->lock ); + if( p_sys->p_block ) + { + p_sys->p_block = block_ChainGather( p_sys->p_block ); + *pp_peek = p_sys->p_block->p_buffer; + } - return i_copy; + return i_out; } -static int DStreamControl( stream_t *s, int i_query, va_list args ) +static int DStreamControl( stream_t *s, int i_query, va_list args ) { d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys; int64_t *p_i64; vlc_bool_t *p_b; int *p_int; + switch( i_query ) { case STREAM_GET_SIZE: @@ -454,43 +487,89 @@ static int DStreamControl( stream_t *s, int i_query, va_list args ) return VLC_SUCCESS; case STREAM_SET_POSITION: - return VLC_EGENERIC; + { + int64_t i64 = (int64_t)va_arg( args, int64_t ); + int i_skip; + if( i64 < p_sys->i_pos ) return VLC_EGENERIC; + i_skip = i64 - p_sys->i_pos; + + while( i_skip > 0 ) + { + int i_read = DStreamRead( s, NULL, i_skip ); + if( i_read <= 0 ) return VLC_EGENERIC; + i_skip -= i_read; + } + return VLC_SUCCESS; + } case STREAM_GET_MTU: p_int = (int*) va_arg( args, int * ); *p_int = 0; return VLC_SUCCESS; + case STREAM_CONTROL_ACCESS: + return VLC_EGENERIC; + default: msg_Err( s, "invalid DStreamControl query=0x%x", i_query ); return VLC_EGENERIC; } } -static int DStreamThread ( stream_t *s ) +static int DStreamThread( stream_t *s ) { d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys; - demux_t *p_demux; + demux_t *p_demux; /* Create the demuxer */ - - if( ( p_demux = demux2_New( s, "", p_sys->psz_name, "", s, p_sys->out ) ) == NULL ) + if( !(p_demux = demux2_New( s, "", p_sys->psz_name, "", s, p_sys->out, + VLC_FALSE )) ) { return VLC_EGENERIC; } - vlc_mutex_lock( &p_sys->lock ); p_sys->p_demux = p_demux; - vlc_mutex_unlock( &p_sys->lock ); /* Main loop */ while( !s->b_die && !p_demux->b_die ) { - if( p_demux->pf_demux( p_demux ) <= 0 ) - { - break; - } + if( p_demux->pf_demux( p_demux ) <= 0 ) break; } - p_demux->b_die = VLC_TRUE; + + vlc_object_kill( p_demux ); return VLC_SUCCESS; } + +/**************************************************************************** + * Utility functions + ****************************************************************************/ +static void SkipID3Tag( demux_t *p_demux ) +{ + const uint8_t *p_peek; + uint8_t version, revision; + int i_size; + int b_footer; + + if( !p_demux->s ) return; + + /* Get 10 byte id3 header */ + if( stream_Peek( p_demux->s, &p_peek, 10 ) < 10 ) return; + + if( p_peek[0] != 'I' || p_peek[1] != 'D' || p_peek[2] != '3' ) return; + + version = p_peek[3]; + revision = p_peek[4]; + b_footer = p_peek[5] & 0x10; + i_size = (p_peek[6]<<21) + (p_peek[7]<<14) + (p_peek[8]<<7) + p_peek[9]; + + if( b_footer ) i_size += 10; + i_size += 10; + + /* Skip the entire tag */ + stream_Read( p_demux->s, NULL, i_size ); + + msg_Dbg( p_demux, "ID3v2.%d revision %d tag found, skipping %d bytes", + version, revision, i_size ); + + return; +}