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
*****************************************************************************/
*/
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
+SOURCES_stream_filter_record = record.c
+
+libvlc_LTLIBRARIES += \
+ libstream_filter_record_plugin.la \
+ $(NULL)
--- /dev/null
+/*****************************************************************************
+ * record.c
+ *****************************************************************************
+ * Copyright (C) 2008 Laurent Aimar
+ * $Id$
+ *
+ * Author: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
+ *
+ * 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 <vlc_common.h>
+#include <vlc_plugin.h>
+
+#include <assert.h>
+#include <vlc_stream.h>
+#include <vlc_input.h>
+#include <vlc_charset.h>
+
+
+/*****************************************************************************
+ * 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)" );
+ }
+}
}
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 )
{
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
/* 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: */
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
else
p_sys->method = STREAM_METHOD_STREAM;
- p_sys->record.b_active = false;
-
p_sys->i_pos = p_access->info.i_pos;
/* Stats */
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
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 )
{
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;
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:
****************************************************************************/
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 */
}
}
- 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;
}
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 */
}
}
- 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;
}
InitMD5
input_Control
__input_CreateThread
+input_CreateFilename
input_DecoderDecode
input_DecoderDelete
input_DecoderNew