From 44a1dd652ea0d1ffe596561c9cce69e64fb47da1 Mon Sep 17 00:00:00 2001 From: Laurent Aimar Date: Tue, 9 Dec 2008 21:06:12 +0100 Subject: [PATCH] Moved stream record to its own module. --- include/vlc_input.h | 11 ++ modules/stream_filter/Modules.am | 5 + modules/stream_filter/record.c | 245 +++++++++++++++++++++++++++++++ src/input/input.c | 12 ++ src/input/input_internal.h | 5 - src/input/stream.c | 148 +------------------ src/libvlccore.sym | 1 + 7 files changed, 277 insertions(+), 150 deletions(-) create mode 100644 modules/stream_filter/record.c diff --git a/include/vlc_input.h b/include/vlc_input.h index 912abdff13..048be2d6af 100644 --- a/include/vlc_input.h +++ b/include/vlc_input.h @@ -423,6 +423,12 @@ struct input_thread_t input_thread_private_t *p; }; +/** + * Record prefix string. + * TODO make it configurable. + */ +#define INPUT_RECORD_PREFIX "vlc-record-%Y-%m-%d-%H:%M:%S-$ N-$ p" + /***************************************************************************** * Input events and variables *****************************************************************************/ @@ -689,4 +695,9 @@ VLC_EXPORT( void, input_DecoderDecode,( decoder_t *, block_t * ) ); */ VLC_EXPORT( void, input_SplitMRL, ( const char **ppsz_access, const char **ppsz_demux, char **ppsz_path, char *psz_dup ) ); +/** + * This function creates a sane filename path. + */ +VLC_EXPORT( char *, input_CreateFilename, ( vlc_object_t *, const char *psz_path, const char *psz_prefix, const char *psz_extension ) ); + #endif diff --git a/modules/stream_filter/Modules.am b/modules/stream_filter/Modules.am index 8b13789179..59e31023ad 100644 --- a/modules/stream_filter/Modules.am +++ b/modules/stream_filter/Modules.am @@ -1 +1,6 @@ +SOURCES_stream_filter_record = record.c + +libvlc_LTLIBRARIES += \ + libstream_filter_record_plugin.la \ + $(NULL) diff --git a/modules/stream_filter/record.c b/modules/stream_filter/record.c new file mode 100644 index 0000000000..2ab138fd45 --- /dev/null +++ b/modules/stream_filter/record.c @@ -0,0 +1,245 @@ +/***************************************************************************** + * record.c + ***************************************************************************** + * Copyright (C) 2008 Laurent Aimar + * $Id$ + * + * Author: Laurent Aimar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include + + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close( vlc_object_t * ); + +vlc_module_begin() + set_category( CAT_INPUT ) + set_subcategory( SUBCAT_INPUT_STREAM_FILTER ) + set_description( N_("Internal stream record") ) + set_capability( "stream_filter", 0 ) + set_callbacks( Open, Close ) +vlc_module_end() + +/***************************************************************************** + * + *****************************************************************************/ +struct stream_sys_t +{ + bool b_active; + + FILE *f; /* TODO it could be replaced by access_output_t one day */ + bool b_error; +}; + + +/**************************************************************************** + * Local prototypes + ****************************************************************************/ +static int Read ( stream_t *, void *p_read, unsigned int i_read ); +static int Peek ( stream_t *, const uint8_t **pp_peek, unsigned int i_peek ); +static int Control( stream_t *, int i_query, va_list ); + +static int Start ( stream_t *, const char *psz_extension ); +static int Stop ( stream_t * ); +static void Write ( stream_t *, const uint8_t *p_buffer, size_t i_buffer ); + +/**************************************************************************** + * Open + ****************************************************************************/ +static int Open ( vlc_object_t *p_this ) +{ + stream_t *s = (stream_t*)p_this; + stream_sys_t *p_sys; + + /* */ + s->p_sys = p_sys = malloc( sizeof( *p_sys ) ); + if( !p_sys ) + return VLC_ENOMEM; + + p_sys->b_active = false; + + /* */ + s->pf_read = Read; + s->pf_peek = Peek; + s->pf_control = Control; + + return VLC_SUCCESS; +} + +/**************************************************************************** + * Close + ****************************************************************************/ +static void Close( vlc_object_t *p_this ) +{ + stream_t *s = (stream_t*)p_this; + stream_sys_t *p_sys = s->p_sys; + + if( p_sys->b_active ) + Stop( s ); + + free( p_sys ); +} + +/**************************************************************************** + * Stream filters functions + ****************************************************************************/ +static int Read( stream_t *s, void *p_read, unsigned int i_read ) +{ + stream_sys_t *p_sys = s->p_sys; + void *p_record = p_read; + + /* Allocate a temporary buffer for record when no p_read */ + if( p_sys->b_active && !p_record ) + p_record = malloc( i_read ); + + /* */ + const int i_record = stream_Read( s->p_source, p_record, i_read ); + + /* Dump read data */ + if( p_sys->b_active ) + { + if( p_record && i_record > 0 ) + Write( s, p_record, i_record ); + if( !p_read ) + free( p_record ); + } + + return i_record; +} + +static int Peek( stream_t *s, const uint8_t **pp_peek, unsigned int i_peek ) +{ + return stream_Peek( s->p_source, pp_peek, i_peek ); +} + +static int Control( stream_t *s, int i_query, va_list args ) +{ + if( i_query != STREAM_SET_RECORD_STATE ) + return stream_vaControl( s->p_source, i_query, args ); + + bool b_active = (bool)va_arg( args, int ); + const char *psz_extension = NULL; + if( b_active ) + psz_extension = (const char*)va_arg( args, const char* ); + + if( !s->p_sys->b_active == !b_active ) + return VLC_SUCCESS; + + if( b_active ) + return Start( s, psz_extension ); + else + return Stop( s ); +} + +/**************************************************************************** + * Helpers + ****************************************************************************/ +static int Start( stream_t *s, const char *psz_extension ) +{ + stream_sys_t *p_sys = s->p_sys; + + char *psz_file; + FILE *f; + + /* */ + if( !psz_extension ) + psz_extension = "dat"; + + /* Retreive path */ + char *psz_path = var_CreateGetString( s, "input-record-path" ); + if( !psz_path || *psz_path == '\0' ) + { + free( psz_path ); + psz_path = strdup( config_GetHomeDir() ); + } + + if( !psz_path ) + return VLC_ENOMEM; + + /* Create file name + * TODO allow prefix configuration */ + psz_file = input_CreateFilename( VLC_OBJECT(s), psz_path, INPUT_RECORD_PREFIX, psz_extension ); + + free( psz_path ); + + if( !psz_file ) + return VLC_ENOMEM; + + f = utf8_fopen( psz_file, "wb" ); + if( !f ) + { + free( psz_file ); + return VLC_EGENERIC; + } + msg_Dbg( s, "Recording into %s", psz_file ); + free( psz_file ); + + /* */ + p_sys->f = f; + p_sys->b_active = true; + p_sys->b_error = false; + return VLC_SUCCESS; +} +static int Stop( stream_t *s ) +{ + stream_sys_t *p_sys = s->p_sys; + + assert( p_sys->b_active ); + + msg_Dbg( s, "Recording completed" ); + fclose( p_sys->f ); + p_sys->b_active = false; + return VLC_SUCCESS; +} + +static void Write( stream_t *s, const uint8_t *p_buffer, size_t i_buffer ) +{ + stream_sys_t *p_sys = s->p_sys; + + assert( p_sys->b_active ); + + if( i_buffer > 0 ) + { + const bool b_previous_error = p_sys->b_error; + const size_t i_written = fwrite( p_buffer, 1, i_buffer, p_sys->f ); + + p_sys->b_error = i_written != i_buffer; + + /* TODO maybe a intf_UserError or something like that ? */ + if( p_sys->b_error && !b_previous_error ) + msg_Err( s, "Failed to record data (begin)" ); + else if( !p_sys->b_error && b_previous_error ) + msg_Err( s, "Failed to record data (end)" ); + } +} diff --git a/src/input/input.c b/src/input/input.c index 9e76bb82ee..b026ee6071 100644 --- a/src/input/input.c +++ b/src/input/input.c @@ -2573,6 +2573,18 @@ static int InputSourceInit( input_thread_t *p_input, } free( psz_tmp ); + /* Add record filter if usefull */ + if( var_GetBool( p_input, "input-record-native" ) ) + { + stream_t *p_filter; + + p_filter = stream_FilterNew( in->p_stream, "stream_filter_record" ); + if( p_filter ) + in->p_stream = p_filter; + else + var_SetBool( p_input, "input-record-native", false ); + } + /* Open a demuxer */ if( *psz_demux == '\0' && *in->p_access->psz_demux ) { diff --git a/src/input/input_internal.h b/src/input/input_internal.h index b0b43a8f63..978de5d833 100644 --- a/src/input/input_internal.h +++ b/src/input/input_internal.h @@ -231,9 +231,4 @@ void input_ConfigVarInit ( input_thread_t * ); char **subtitles_Detect( input_thread_t *, char* path, const char *fname ); int subtitles_Filter( const char *); -/* Helpers FIXME to export without input_ prefix */ -char *input_CreateFilename( vlc_object_t *p_obj, const char *psz_path, const char *psz_prefix, const char *psz_extension ); - -#define INPUT_RECORD_PREFIX "vlc-record-%Y-%m-%d-%H:%M:%S-$ N-$ p" - #endif diff --git a/src/input/stream.c b/src/input/stream.c index f7e3f432ff..b50a1a3bb3 100644 --- a/src/input/stream.c +++ b/src/input/stream.c @@ -185,15 +185,6 @@ struct stream_sys_t /* Preparse mode ? */ bool b_quick; - - /* */ - struct - { - bool b_active; - - FILE *f; /* TODO it could be replaced by access_output_t one day */ - bool b_error; - } record; }; /* Method 1: */ @@ -215,8 +206,6 @@ static int AStreamControl( stream_t *s, int i_query, va_list ); static void AStreamDestroy( stream_t *s ); static void UStreamDestroy( stream_t *s ); static int ASeek( stream_t *s, int64_t i_pos ); -static int ARecordSetState( stream_t *s, bool b_record, const char *psz_extension ); -static void ARecordWrite( stream_t *s, const uint8_t *p_buffer, size_t i_buffer ); /**************************************************************************** * stream_CommonNew: create an empty stream structure @@ -321,8 +310,6 @@ stream_t *stream_AccessNew( access_t *p_access, bool b_quick ) else p_sys->method = STREAM_METHOD_STREAM; - p_sys->record.b_active = false; - p_sys->i_pos = p_access->info.i_pos; /* Stats */ @@ -498,9 +485,6 @@ static void AStreamDestroy( stream_t *s ) vlc_object_detach( s ); - if( p_sys->record.b_active ) - ARecordSetState( s, false, NULL ); - if( p_sys->method == STREAM_METHOD_BLOCK ) block_ChainRelease( p_sys->block.p_first ); else @@ -604,11 +588,9 @@ static int AStreamControl( stream_t *s, int i_query, va_list args ) stream_sys_t *p_sys = s->p_sys; access_t *p_access = p_sys->p_access; - bool *p_bool; - bool b_bool; - const char *psz_string; - int64_t *pi_64, i_64; - int i_int; + bool *p_bool; + int64_t *pi_64, i_64; + int i_int; switch( i_query ) { @@ -683,12 +665,6 @@ static int AStreamControl( stream_t *s, int i_query, va_list args ) return access_Control( p_access, ACCESS_GET_CONTENT_TYPE, va_arg( args, char ** ) ); case STREAM_SET_RECORD_STATE: - b_bool = (bool)va_arg( args, int ); - psz_string = NULL; - if( b_bool ) - psz_string = (const char*)va_arg( args, const char* ); - return ARecordSetState( s, b_bool, psz_string ); - default: msg_Err( s, "invalid stream_vaControl query=0x%x", i_query ); return VLC_EGENERIC; @@ -696,100 +672,6 @@ static int AStreamControl( stream_t *s, int i_query, va_list args ) return VLC_SUCCESS; } -/**************************************************************************** - * ARecord*: record stream functions - ****************************************************************************/ -static int ARecordStart( stream_t *s, const char *psz_extension ) -{ - stream_sys_t *p_sys = s->p_sys; - - char *psz_file; - FILE *f; - - /* */ - if( !psz_extension ) - psz_extension = "dat"; - - /* Retreive path */ - char *psz_path = var_CreateGetString( s, "input-record-path" ); - if( !psz_path || *psz_path == '\0' ) - { - free( psz_path ); - psz_path = strdup( config_GetHomeDir() ); - } - - if( !psz_path ) - return VLC_ENOMEM; - - /* Create file name - * TODO allow prefix configuration */ - psz_file = input_CreateFilename( VLC_OBJECT(s), psz_path, INPUT_RECORD_PREFIX, psz_extension ); - - free( psz_path ); - - if( !psz_file ) - return VLC_ENOMEM; - - f = utf8_fopen( psz_file, "wb" ); - if( !f ) - { - free( psz_file ); - return VLC_EGENERIC; - } - msg_Dbg( s, "Recording into %s", psz_file ); - free( psz_file ); - - /* */ - p_sys->record.f = f; - p_sys->record.b_active = true; - p_sys->record.b_error = false; - return VLC_SUCCESS; -} -static int ARecordStop( stream_t *s ) -{ - stream_sys_t *p_sys = s->p_sys; - - assert( p_sys->record.b_active ); - - msg_Dbg( s, "Recording completed" ); - fclose( p_sys->record.f ); - p_sys->record.b_active = false; - return VLC_SUCCESS; -} - -static int ARecordSetState( stream_t *s, bool b_record, const char *psz_extension ) -{ - stream_sys_t *p_sys = s->p_sys; - - if( !!p_sys->record.b_active == !!b_record ) - return VLC_SUCCESS; - - if( b_record ) - return ARecordStart( s, psz_extension ); - else - return ARecordStop( s ); -} -static void ARecordWrite( stream_t *s, const uint8_t *p_buffer, size_t i_buffer ) -{ - stream_sys_t *p_sys = s->p_sys; - - assert( p_sys->record.b_active ); - - if( i_buffer > 0 ) - { - const bool b_previous_error = p_sys->record.b_error; - const size_t i_written = fwrite( p_buffer, 1, i_buffer, p_sys->record.f ); - - p_sys->record.b_error = i_written != i_buffer; - - /* TODO maybe a intf_UserError or something like that ? */ - if( p_sys->record.b_error && !b_previous_error ) - msg_Err( s, "Failed to record data (begin)" ); - else if( !p_sys->record.b_error && b_previous_error ) - msg_Err( s, "Failed to record data (end)" ); - } -} - /**************************************************************************** * Method 1: ****************************************************************************/ @@ -864,16 +746,12 @@ static int AStreamReadBlock( stream_t *s, void *p_read, unsigned int i_read ) stream_sys_t *p_sys = s->p_sys; uint8_t *p_data = p_read; - uint8_t *p_record = p_data; unsigned int i_data = 0; /* It means EOF */ if( p_sys->block.p_current == NULL ) return 0; - if( p_sys->record.b_active && !p_data ) - p_record = p_data = malloc( i_read ); - if( p_data == NULL ) { /* seek within this stream if possible, else use plain old read and discard */ @@ -918,14 +796,6 @@ static int AStreamReadBlock( stream_t *s, void *p_read, unsigned int i_read ) } } - if( p_sys->record.b_active ) - { - if( i_data > 0 && p_record != NULL) - ARecordWrite( s, p_record, i_data ); - if( !p_read ) - free( p_record ); - } - p_sys->i_pos += i_data; return i_data; } @@ -1205,15 +1075,11 @@ static int AStreamReadStream( stream_t *s, void *p_read, unsigned int i_read ) stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk]; uint8_t *p_data = (uint8_t *)p_read; - uint8_t *p_record = p_data; unsigned int i_data = 0; if( tk->i_start >= tk->i_end ) return 0; /* EOF */ - if( p_sys->record.b_active && !p_data ) - p_record = p_data = malloc( i_read ); - if( p_data == NULL ) { /* seek within this stream if possible, else use plain old read and discard */ @@ -1277,14 +1143,6 @@ static int AStreamReadStream( stream_t *s, void *p_read, unsigned int i_read ) } } - if( p_sys->record.b_active ) - { - if( i_data > 0 && p_record != NULL) - ARecordWrite( s, p_record, i_data ); - if( !p_read ) - free( p_record ); - } - return i_data; } diff --git a/src/libvlccore.sym b/src/libvlccore.sym index 83920897c9..ccfaa270ba 100644 --- a/src/libvlccore.sym +++ b/src/libvlccore.sym @@ -156,6 +156,7 @@ image_HandlerDelete InitMD5 input_Control __input_CreateThread +input_CreateFilename input_DecoderDecode input_DecoderDelete input_DecoderNew -- 2.39.2