X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Fes_out_timeshift.c;h=d8327f391d50bd0077e32f2fec5febbbfb1b65dd;hb=b8525bc7b21f2e2dce05c94077c4c555068b9ea2;hp=7d3aff311e0ca6b60d220b7f397b3fb2e32cbb95;hpb=19c98153b45cbf299cd47d69b0a2e93bb3973fc9;p=vlc diff --git a/src/input/es_out_timeshift.c b/src/input/es_out_timeshift.c index 7d3aff311e..d8327f391d 100644 --- a/src/input/es_out_timeshift.c +++ b/src/input/es_out_timeshift.c @@ -4,7 +4,7 @@ * Copyright (C) 2008 Laurent Aimar * $Id$ * - * Authors: Laurent Aimar < fenrir _AT_ via _DOT_ ecp _DOT_ fr> + * Authors: 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 @@ -53,6 +53,13 @@ * Local prototypes *****************************************************************************/ +/* XXX attribute_packed is (and MUST be) used ONLY to reduce memory usage */ +#ifdef HAVE_ATTRIBUTE_PACKED +# define attribute_packed __attribute__((__packed__)) +#else +# define attribute_packed +#endif + enum { C_ADD, @@ -61,39 +68,65 @@ enum C_CONTROL, }; -typedef struct +typedef struct attribute_packed { es_out_id_t *p_es; es_format_t *p_fmt; } ts_cmd_add_t; -typedef struct +typedef struct attribute_packed { es_out_id_t *p_es; } ts_cmd_del_t; -typedef struct +typedef struct attribute_packed { es_out_id_t *p_es; block_t *p_block; + int i_offset; /* We do not use file > INT_MAX */ } ts_cmd_send_t; -typedef struct +typedef struct attribute_packed { int i_query; - bool b_bool; - int i_int; - int64_t i_i64; - vlc_meta_t *p_meta; - vlc_epg_t *p_epg; - es_out_id_t *p_es; - es_format_t *p_fmt; + union + { + bool b_bool; + int i_int; + int64_t i_i64; + es_out_id_t *p_es; + struct + { + int i_int; + int64_t i_i64; + } int_i64; + struct + { + int i_int; + vlc_meta_t *p_meta; + } int_meta; + struct + { + int i_int; + vlc_epg_t *p_epg; + } int_epg; + struct + { + es_out_id_t *p_es; + bool b_bool; + } es_bool; + struct + { + es_out_id_t *p_es; + es_format_t *p_fmt; + } es_fmt; + }; } ts_cmd_control_t; -typedef struct +typedef struct attribute_packed { - int i_type; + int8_t i_type; mtime_t i_date; union { @@ -104,6 +137,25 @@ typedef struct }; } ts_cmd_t; +typedef struct ts_storage_t ts_storage_t; +struct ts_storage_t +{ + ts_storage_t *p_next; + + /* */ + char *psz_file; /* Filename */ + size_t i_file_max; /* Max size in bytes */ + int64_t i_file_size;/* Current size in bytes */ + FILE *p_filew; /* FILE handle for data writing */ + FILE *p_filer; /* FILE handle for data reading */ + + /* */ + int i_cmd_r; + int i_cmd_w; + int i_cmd_max; + ts_cmd_t *p_cmd; +}; + typedef struct { VLC_COMMON_MEMBERS @@ -111,6 +163,8 @@ typedef struct /* */ input_thread_t *p_input; es_out_t *p_out; + int64_t i_tmp_size_max; + const char *psz_tmp_path; /* Lock for all following fields */ vlc_mutex_t lock; @@ -127,8 +181,12 @@ typedef struct mtime_t i_rate_delay; /* */ - int i_cmd; - ts_cmd_t **pp_cmd; + mtime_t i_buffering_delay; + + /* */ + ts_storage_t *p_storage_r; + ts_storage_t *p_storage_w; + mtime_t i_cmd_delay; } ts_thread_t; @@ -175,7 +233,7 @@ static int TsStart( es_out_t * ); static void TsAutoStop( es_out_t * ); static void TsStop( ts_thread_t * ); -static void TsPushCmd( ts_thread_t *, const ts_cmd_t * ); +static void TsPushCmd( ts_thread_t *, ts_cmd_t * ); static int TsPopCmdLocked( ts_thread_t *, ts_cmd_t * ); static bool TsHasCmd( ts_thread_t * ); static bool TsIsUnused( ts_thread_t * ); @@ -184,6 +242,14 @@ static int TsChangeRate( ts_thread_t *, int i_src_rate, int i_rate ); static void *TsRun( vlc_object_t * ); +static ts_storage_t *TsStorageNew( const char *psz_path, int64_t i_tmp_size_max ); +static void TsStorageDelete( ts_storage_t * ); +static void TsStoragePack( ts_storage_t *p_storage ); +static bool TsStorageIsFull( ts_storage_t *, const ts_cmd_t *p_cmd ); +static bool TsStorageIsEmpty( ts_storage_t * ); +static void TsStoragePushCmd( ts_storage_t *, const ts_cmd_t *p_cmd, bool b_flush ); +static void TsStoragePopCmd( ts_storage_t *p_storage, ts_cmd_t *p_cmd ); + static void CmdClean( ts_cmd_t * ); static void cmd_cleanup_routine( void *p ) { CmdClean( p ); } @@ -205,7 +271,7 @@ static int CmdExecuteControl( es_out_t *, ts_cmd_t * ); /* File helpers */ static char *GetTmpPath( char *psz_path ); -static FILE *GetTmpFile( const char *psz_path ); +static FILE *GetTmpFile( char **ppsz_file, const char *psz_path ); /***************************************************************************** * input_EsOutTimeshiftNew: @@ -247,12 +313,28 @@ es_out_t *input_EsOutTimeshiftNew( input_thread_t *p_input, es_out_t *p_next_out TAB_INIT( p_sys->i_es, p_sys->pp_es ); - /* TODO config - * timeshift-granularity - * timeshift-path - */ - p_sys->i_tmp_size_max = 50 * 1024*1024; - p_sys->psz_tmp_path = GetTmpPath( NULL ); + /* */ + const int i_tmp_size_max = var_CreateGetInteger( p_input, "input-timeshift-granularity" ); + if( i_tmp_size_max < 0 ) + p_sys->i_tmp_size_max = 50*1024*1024; + else + p_sys->i_tmp_size_max = __MAX( i_tmp_size_max, 1*1024*1024 ); + msg_Dbg( p_input, "using timeshift granularity of %d bytes", + (int)p_sys->i_tmp_size_max ); + + char *psz_tmp_path = var_CreateGetNonEmptyString( p_input, "input-timeshift-path" ); + p_sys->psz_tmp_path = GetTmpPath( psz_tmp_path ); + msg_Dbg( p_input, "using timeshift path '%s'", p_sys->psz_tmp_path ); + +#if 0 +#define S(t) msg_Err( p_input, "SIZEOF("#t")=%d", sizeof(t) ) + S(ts_cmd_t); + S(ts_cmd_control_t); + S(ts_cmd_send_t); + S(ts_cmd_del_t); + S(ts_cmd_add_t); +#undef S +#endif return p_out; } @@ -475,12 +557,7 @@ static int ControlLockedSetFrameNext( es_out_t *p_out ) { es_out_sys_t *p_sys = p_out->p_sys; - if( !p_sys->b_delayed ) - return es_out_SetFrameNext( p_sys->p_out ); - - /* TODO */ - msg_Err( p_sys->p_input, "EsOutTimeshift does not yet support frame next" ); - return VLC_EGENERIC; + return es_out_SetFrameNext( p_sys->p_out ); } static int ControlLocked( es_out_t *p_out, int i_query, va_list args ) @@ -541,7 +618,7 @@ static int ControlLocked( es_out_t *p_out, int i_query, va_list args ) *pb_enabled = true; return VLC_SUCCESS; } - return es_out_Control( p_sys->p_out, ES_OUT_GET_ES_STATE, p_es, pb_enabled ); + return es_out_Control( p_sys->p_out, ES_OUT_GET_ES_STATE, p_es->p_es, pb_enabled ); } /* Special internal input control */ @@ -630,6 +707,8 @@ static int TsStart( es_out_t *p_out ) if( !p_ts ) return VLC_EGENERIC; + p_ts->i_tmp_size_max = p_sys->i_tmp_size_max; + p_ts->psz_tmp_path = p_sys->psz_tmp_path; p_ts->p_input = p_sys->p_input; p_ts->p_out = p_sys->p_out; vlc_mutex_init( &p_ts->lock ); @@ -640,8 +719,10 @@ static int TsStart( es_out_t *p_out ) p_ts->i_rate = p_sys->i_input_rate; p_ts->i_rate_date = -1; p_ts->i_rate_delay = 0; + p_ts->i_buffering_delay = 0; p_ts->i_cmd_delay = 0; - TAB_INIT( p_ts->i_cmd, p_ts->pp_cmd ); + p_ts->p_storage_r = NULL; + p_ts->p_storage_w = NULL; vlc_object_set_destructor( p_ts, TsDestructor ); @@ -686,38 +767,67 @@ static void TsStop( ts_thread_t *p_ts ) CmdClean( &cmd ); } + assert( !p_ts->p_storage_r || !p_ts->p_storage_r->p_next ); + if( p_ts->p_storage_r ) + TsStorageDelete( p_ts->p_storage_r ); vlc_mutex_unlock( &p_ts->lock ); - TAB_CLEAN( p_ts->i_cmd, p_ts->pp_cmd ); vlc_object_release( p_ts ); } -static void TsPushCmd( ts_thread_t *p_ts, const ts_cmd_t *p_cmd ) +static void TsPushCmd( ts_thread_t *p_ts, ts_cmd_t *p_cmd ) { - ts_cmd_t *p_dup = malloc( sizeof(*p_dup) ); + vlc_mutex_lock( &p_ts->lock ); - if( p_dup ) + if( !p_ts->p_storage_w || TsStorageIsFull( p_ts->p_storage_w, p_cmd ) ) { - *p_dup = *p_cmd; - - vlc_mutex_lock( &p_ts->lock ); + ts_storage_t *p_storage = TsStorageNew( p_ts->psz_tmp_path, p_ts->i_tmp_size_max ); - TAB_APPEND( p_ts->i_cmd, p_ts->pp_cmd, p_dup ); - vlc_cond_signal( &p_ts->wait ); + if( !p_storage ) + { + CmdClean( p_cmd ); + vlc_mutex_unlock( &p_ts->lock ); + /* TODO warn the user (but only once) */ + return; + } - vlc_mutex_unlock( &p_ts->lock ); + if( !p_ts->p_storage_w ) + { + p_ts->p_storage_r = p_ts->p_storage_w = p_storage; + } + else + { + TsStoragePack( p_ts->p_storage_w ); + p_ts->p_storage_w->p_next = p_storage; + p_ts->p_storage_w = p_storage; + } } + + /* TODO return error and warn the user (but only once) */ + TsStoragePushCmd( p_ts->p_storage_w, p_cmd, p_ts->p_storage_r == p_ts->p_storage_w ); + + vlc_cond_signal( &p_ts->wait ); + + vlc_mutex_unlock( &p_ts->lock ); } static int TsPopCmdLocked( ts_thread_t *p_ts, ts_cmd_t *p_cmd ) { vlc_assert_locked( &p_ts->lock ); - if( p_ts->i_cmd <= 0 ) + if( TsStorageIsEmpty( p_ts->p_storage_r ) ) return VLC_EGENERIC; - *p_cmd = *p_ts->pp_cmd[0]; + TsStoragePopCmd( p_ts->p_storage_r, p_cmd ); + + while( p_ts->p_storage_r && TsStorageIsEmpty( p_ts->p_storage_r ) ) + { + ts_storage_t *p_next = p_ts->p_storage_r->p_next; + if( !p_next ) + break; + + TsStorageDelete( p_ts->p_storage_r ); + p_ts->p_storage_r = p_next; + } - free( p_ts->pp_cmd[0] ); - TAB_REMOVE( p_ts->i_cmd, p_ts->pp_cmd, p_ts->pp_cmd[0] ); return VLC_SUCCESS; } static bool TsHasCmd( ts_thread_t *p_ts ) @@ -725,7 +835,7 @@ static bool TsHasCmd( ts_thread_t *p_ts ) bool b_cmd; vlc_mutex_lock( &p_ts->lock ); - b_cmd = p_ts->i_cmd > 0; + b_cmd = TsStorageIsEmpty( p_ts->p_storage_r ); vlc_mutex_unlock( &p_ts->lock ); return b_cmd; @@ -737,7 +847,7 @@ static bool TsIsUnused( ts_thread_t *p_ts ) vlc_mutex_lock( &p_ts->lock ); b_unused = !p_ts->b_paused && p_ts->i_rate == p_ts->i_rate_source && - p_ts->i_cmd <= 0; + TsStorageIsEmpty( p_ts->p_storage_r ); vlc_mutex_unlock( &p_ts->lock ); return b_unused; @@ -795,18 +905,45 @@ static int TsChangeRate( ts_thread_t *p_ts, int i_src_rate, int i_rate ) static void *TsRun( vlc_object_t *p_thread ) { ts_thread_t *p_ts = (ts_thread_t*)p_thread; + mtime_t i_buffering_date = -1; for( ;; ) { ts_cmd_t cmd; mtime_t i_deadline; + bool b_buffering; /* Pop a command to execute */ vlc_mutex_lock( &p_ts->lock ); mutex_cleanup_push( &p_ts->lock ); - while( p_ts->b_paused || TsPopCmdLocked( p_ts, &cmd ) ) + for( ;; ) + { + const int canc = vlc_savecancel(); + b_buffering = es_out_GetBuffering( p_ts->p_out ); + + if( ( !p_ts->b_paused || b_buffering ) && !TsPopCmdLocked( p_ts, &cmd ) ) + { + vlc_restorecancel( canc ); + break; + } + vlc_restorecancel( canc ); + vlc_cond_wait( &p_ts->wait, &p_ts->lock ); + } + + if( b_buffering && i_buffering_date < 0 ) + { + i_buffering_date = cmd.i_date; + } + else if( i_buffering_date > 0 ) + { + p_ts->i_buffering_delay += i_buffering_date - cmd.i_date; /* It is < 0 */ + if( b_buffering ) + i_buffering_date = cmd.i_date; + else + i_buffering_date = -1; + } if( p_ts->i_rate_date < 0 ) p_ts->i_rate_date = cmd.i_date; @@ -817,7 +954,7 @@ static void *TsRun( vlc_object_t *p_thread ) const mtime_t i_duration = cmd.i_date - p_ts->i_rate_date; p_ts->i_rate_delay = i_duration * p_ts->i_rate / p_ts->i_rate_source - i_duration; } - if( p_ts->i_cmd_delay + p_ts->i_rate_delay < 0 ) + if( p_ts->i_cmd_delay + p_ts->i_rate_delay + p_ts->i_buffering_delay < 0 && p_ts->i_rate != p_ts->i_rate_source ) { const int canc = vlc_savecancel(); @@ -825,9 +962,10 @@ static void *TsRun( vlc_object_t *p_thread ) msg_Warn( p_ts->p_input, "es out timeshift: auto reset rate to %d", p_ts->i_rate_source ); p_ts->i_cmd_delay = 0; + p_ts->i_buffering_delay = 0; - p_ts->i_rate_date = -1; p_ts->i_rate_delay = 0; + p_ts->i_rate_date = -1; p_ts->i_rate = p_ts->i_rate_source; if( !es_out_SetRate( p_ts->p_out, p_ts->i_rate_source, p_ts->i_rate ) ) @@ -841,7 +979,7 @@ static void *TsRun( vlc_object_t *p_thread ) vlc_restorecancel( canc ); } - i_deadline = cmd.i_date + p_ts->i_cmd_delay + p_ts->i_rate_delay; + i_deadline = cmd.i_date + p_ts->i_cmd_delay + p_ts->i_rate_delay + p_ts->i_buffering_delay; vlc_cleanup_run(); @@ -882,6 +1020,159 @@ static void *TsRun( vlc_object_t *p_thread ) return NULL; } +/***************************************************************************** + * + *****************************************************************************/ +static ts_storage_t *TsStorageNew( const char *psz_tmp_path, int64_t i_tmp_size_max ) +{ + ts_storage_t *p_storage = calloc( 1, sizeof(ts_storage_t) ); + if( !p_storage ) + return NULL; + + /* */ + p_storage->p_next = NULL; + + /* */ + p_storage->i_file_max = i_tmp_size_max; + p_storage->i_file_size = 0; + p_storage->p_filew = GetTmpFile( &p_storage->psz_file, psz_tmp_path ); + if( p_storage->psz_file ) + p_storage->p_filer = utf8_fopen( p_storage->psz_file, "rb" ); + + /* */ + p_storage->i_cmd_w = 0; + p_storage->i_cmd_r = 0; + p_storage->i_cmd_max = 30000; + p_storage->p_cmd = malloc( p_storage->i_cmd_max * sizeof(*p_storage->p_cmd) ); + //fprintf( stderr, "\nSTORAGE name=%s size=%d kbytes\n", p_storage->psz_file, p_storage->i_cmd_max * sizeof(*p_storage->p_cmd) /1024 ); + + if( !p_storage->p_cmd || !p_storage->p_filew || !p_storage->p_filer ) + { + TsStorageDelete( p_storage ); + return NULL; + } + return p_storage; +} +static void TsStorageDelete( ts_storage_t *p_storage ) +{ + while( p_storage->i_cmd_r < p_storage->i_cmd_w ) + { + ts_cmd_t cmd; + + TsStoragePopCmd( p_storage, &cmd ); + + CmdClean( &cmd ); + } + free( p_storage->p_cmd ); + + if( p_storage->p_filer ) + fclose( p_storage->p_filer ); + if( p_storage->p_filew ) + fclose( p_storage->p_filew ); + + if( p_storage->psz_file ) + { + utf8_unlink( p_storage->psz_file ); + free( p_storage->psz_file ); + } + + free( p_storage ); +} +static void TsStoragePack( ts_storage_t *p_storage ) +{ + /* Try to release a bit of memory */ + if( p_storage->i_cmd_w >= p_storage->i_cmd_max ) + return; + + p_storage->i_cmd_max = __MAX( p_storage->i_cmd_w, 1 ); + + ts_cmd_t *p_new = realloc( p_storage->p_cmd, p_storage->i_cmd_max * sizeof(*p_storage->p_cmd) ); + if( p_new ) + p_storage->p_cmd = p_new; +} +static bool TsStorageIsFull( ts_storage_t *p_storage, const ts_cmd_t *p_cmd ) +{ + if( p_cmd && p_cmd->i_type == C_SEND && p_storage->i_cmd_w > 0 ) + { + size_t i_size = sizeof(*p_cmd->send.p_block) + p_cmd->send.p_block->i_buffer; + + if( p_storage->i_file_size + i_size >= p_storage->i_file_max ) + return true; + } + return p_storage->i_cmd_w >= p_storage->i_cmd_max; +} +static bool TsStorageIsEmpty( ts_storage_t *p_storage ) +{ + return !p_storage || p_storage->i_cmd_r >= p_storage->i_cmd_w; +} +static void TsStoragePushCmd( ts_storage_t *p_storage, const ts_cmd_t *p_cmd, bool b_flush ) +{ + ts_cmd_t cmd = *p_cmd; + + assert( !TsStorageIsFull( p_storage, p_cmd ) ); + + if( cmd.i_type == C_SEND ) + { + block_t *p_block = cmd.send.p_block; + + cmd.send.p_block = NULL; + cmd.send.i_offset = ftell( p_storage->p_filew ); + + if( fwrite( p_block, sizeof(*p_block), 1, p_storage->p_filew ) != 1 ) + { + block_Release( p_block ); + return; + } + p_storage->i_file_size += sizeof(*p_block); + if( p_block->i_buffer > 0 ) + { + if( fwrite( p_block->p_buffer, p_block->i_buffer, 1, p_storage->p_filew ) != 1 ) + { + block_Release( p_block ); + return; + } + } + p_storage->i_file_size += p_block->i_buffer; + block_Release( p_block ); + + if( b_flush ) + fflush( p_storage->p_filew ); + } + p_storage->p_cmd[p_storage->i_cmd_w++] = cmd; +} +static void TsStoragePopCmd( ts_storage_t *p_storage, ts_cmd_t *p_cmd ) +{ + assert( !TsStorageIsEmpty( p_storage ) ); + + *p_cmd = p_storage->p_cmd[p_storage->i_cmd_r++]; + if( p_cmd->i_type == C_SEND ) + { + block_t block; + + if( !fseek( p_storage->p_filer, p_cmd->send.i_offset, SEEK_SET ) && + fread( &block, sizeof(block), 1, p_storage->p_filer ) == 1 ) + { + block_t *p_block = block_Alloc( block.i_buffer ); + if( p_block ) + { + p_block->i_dts = block.i_dts; + p_block->i_pts = block.i_pts; + p_block->i_flags = block.i_flags; + p_block->i_length = block.i_length; + p_block->i_rate = block.i_rate; + p_block->i_samples = block.i_samples; + p_block->i_buffer = fread( p_block->p_buffer, 1, block.i_buffer, p_storage->p_filer ); + } + p_cmd->send.p_block = p_block; + } + else + { + //fprintf( stderr, "TsStoragePopCmd: %m\n" ); + p_cmd->send.p_block = block_Alloc( 1 ); + } + } +} + /***************************************************************************** * *****************************************************************************/ @@ -980,9 +1271,6 @@ static int CmdInitControl( ts_cmd_t *p_cmd, int i_query, va_list args, bool b_co p_cmd->i_type = C_CONTROL; p_cmd->i_date = mdate(); p_cmd->control.i_query = i_query; - p_cmd->control.p_meta = NULL; - p_cmd->control.p_epg = NULL; - p_cmd->control.p_fmt = NULL; switch( i_query ) { @@ -1003,8 +1291,8 @@ static int CmdInitControl( ts_cmd_t *p_cmd, int i_query, va_list args, bool b_co break; case ES_OUT_SET_GROUP_PCR: /* arg1= int i_group, arg2=int64_t i_pcr(microsecond!)*/ - p_cmd->control.i_int = (int)va_arg( args, int ); - p_cmd->control.i_i64 = (int64_t)va_arg( args, int64_t ); + p_cmd->control.int_i64.i_int = (int)va_arg( args, int ); + p_cmd->control.int_i64.i_i64 = (int64_t)va_arg( args, int64_t ); break; case ES_OUT_RESET_PCR: /* no arg */ @@ -1012,48 +1300,48 @@ static int CmdInitControl( ts_cmd_t *p_cmd, int i_query, va_list args, bool b_co case ES_OUT_SET_GROUP_META: /* arg1=int i_group arg2=vlc_meta_t* */ { - p_cmd->control.i_int = (int)va_arg( args, int ); + p_cmd->control.int_meta.i_int = (int)va_arg( args, int ); vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t * ); if( b_copy ) { - p_cmd->control.p_meta = vlc_meta_New(); - if( !p_cmd->control.p_meta ) + p_cmd->control.int_meta.p_meta = vlc_meta_New(); + if( !p_cmd->control.int_meta.p_meta ) return VLC_EGENERIC; - vlc_meta_Merge( p_cmd->control.p_meta, p_meta ); + vlc_meta_Merge( p_cmd->control.int_meta.p_meta, p_meta ); } else { - p_cmd->control.p_meta = p_meta; + p_cmd->control.int_meta.p_meta = p_meta; } break; } case ES_OUT_SET_GROUP_EPG: /* arg1=int i_group arg2=vlc_epg_t* */ { - p_cmd->control.i_int = (int)va_arg( args, int ); + p_cmd->control.int_epg.i_int = (int)va_arg( args, int ); vlc_epg_t *p_epg = (vlc_epg_t*)va_arg( args, vlc_epg_t * ); if( b_copy ) { - p_cmd->control.p_epg = vlc_epg_New( p_epg->psz_name ); - if( !p_cmd->control.p_epg ) + p_cmd->control.int_epg.p_epg = vlc_epg_New( p_epg->psz_name ); + if( !p_cmd->control.int_epg.p_epg ) return VLC_EGENERIC; for( int i = 0; i < p_epg->i_event; i++ ) { vlc_epg_event_t *p_evt = p_epg->pp_event[i]; - vlc_epg_AddEvent( p_cmd->control.p_epg, + vlc_epg_AddEvent( p_cmd->control.int_epg.p_epg, p_evt->i_start, p_evt->i_duration, p_evt->psz_name, p_evt->psz_short_description, p_evt->psz_description ); } - vlc_epg_SetCurrent( p_cmd->control.p_epg, + vlc_epg_SetCurrent( p_cmd->control.int_epg.p_epg, p_epg->p_current ? p_epg->p_current->i_start : -1 ); } else { - p_cmd->control.p_epg = p_epg; + p_cmd->control.int_epg.p_epg = p_epg; } break; } @@ -1066,25 +1354,25 @@ static int CmdInitControl( ts_cmd_t *p_cmd, int i_query, va_list args, bool b_co break; case ES_OUT_SET_ES_STATE:/* arg1= es_out_id_t* arg2=bool */ - p_cmd->control.p_es = (es_out_id_t*)va_arg( args, es_out_id_t * ); - p_cmd->control.b_bool = (bool)va_arg( args, int ); + p_cmd->control.es_bool.p_es = (es_out_id_t*)va_arg( args, es_out_id_t * ); + p_cmd->control.es_bool.b_bool = (bool)va_arg( args, int ); break; case ES_OUT_SET_ES_FMT: /* arg1= es_out_id_t* arg2=es_format_t* */ { - p_cmd->control.p_es = (es_out_id_t*)va_arg( args, es_out_id_t * ); + p_cmd->control.es_fmt.p_es = (es_out_id_t*)va_arg( args, es_out_id_t * ); es_format_t *p_fmt = (es_format_t*)va_arg( args, es_format_t * ); if( b_copy ) { - p_cmd->control.p_fmt = malloc( sizeof(*p_fmt) ); - if( !p_cmd->control.p_fmt ) + p_cmd->control.es_fmt.p_fmt = malloc( sizeof(*p_fmt) ); + if( !p_cmd->control.es_fmt.p_fmt ) return VLC_EGENERIC; - es_format_Copy( p_cmd->control.p_fmt, p_fmt ); + es_format_Copy( p_cmd->control.es_fmt.p_fmt, p_fmt ); } else { - p_cmd->control.p_fmt = p_fmt; + p_cmd->control.es_fmt.p_fmt = p_fmt; } break; } @@ -1116,16 +1404,16 @@ static int CmdExecuteControl( es_out_t *p_out, ts_cmd_t *p_cmd ) return es_out_Control( p_out, i_query, p_cmd->control.i_i64 ); case ES_OUT_SET_GROUP_PCR: /* arg1= int i_group, arg2=int64_t i_pcr(microsecond!)*/ - return es_out_Control( p_out, i_query, p_cmd->control.i_int, p_cmd->control.i_i64 ); + return es_out_Control( p_out, i_query, p_cmd->control.int_i64.i_int, p_cmd->control.int_i64.i_i64 ); case ES_OUT_RESET_PCR: /* no arg */ return es_out_Control( p_out, i_query ); case ES_OUT_SET_GROUP_META: /* arg1=int i_group arg2=vlc_meta_t* */ - return es_out_Control( p_out, i_query, p_cmd->control.i_int, p_cmd->control.p_meta ); + return es_out_Control( p_out, i_query, p_cmd->control.int_meta.i_int, p_cmd->control.int_meta.p_meta ); case ES_OUT_SET_GROUP_EPG: /* arg1=int i_group arg2=vlc_epg_t* */ - return es_out_Control( p_out, i_query, p_cmd->control.i_int, p_cmd->control.p_epg ); + return es_out_Control( p_out, i_query, p_cmd->control.int_epg.i_int, p_cmd->control.int_epg.p_epg ); /* Modified control */ case ES_OUT_SET_ES: /* arg1= es_out_id_t* */ @@ -1134,10 +1422,10 @@ static int CmdExecuteControl( es_out_t *p_out, ts_cmd_t *p_cmd ) return es_out_Control( p_out, i_query, p_cmd->control.p_es->p_es ); case ES_OUT_SET_ES_STATE:/* arg1= es_out_id_t* arg2=bool */ - return es_out_Control( p_out, i_query, p_cmd->control.p_es->p_es, p_cmd->control.b_bool ); + return es_out_Control( p_out, i_query, p_cmd->control.es_bool.p_es->p_es, p_cmd->control.es_bool.b_bool ); case ES_OUT_SET_ES_FMT: /* arg1= es_out_id_t* arg2=es_format_t* */ - return es_out_Control( p_out, i_query, p_cmd->control.p_es->p_es, p_cmd->control.p_fmt ); + return es_out_Control( p_out, i_query, p_cmd->control.es_fmt.p_es->p_es, p_cmd->control.es_fmt.p_fmt ); default: assert(0); @@ -1146,14 +1434,21 @@ static int CmdExecuteControl( es_out_t *p_out, ts_cmd_t *p_cmd ) } static void CmdCleanControl( ts_cmd_t *p_cmd ) { - if( p_cmd->control.p_meta ) - vlc_meta_Delete( p_cmd->control.p_meta ); - if( p_cmd->control.p_epg ) - vlc_epg_Delete( p_cmd->control.p_epg ); - if( p_cmd->control.p_fmt ) + if( p_cmd->control.i_query == ES_OUT_SET_GROUP_META && + p_cmd->control.int_meta.p_meta ) + { + vlc_meta_Delete( p_cmd->control.int_meta.p_meta ); + } + else if( p_cmd->control.i_query == ES_OUT_SET_GROUP_EPG && + p_cmd->control.int_epg.p_epg ) + { + vlc_epg_Delete( p_cmd->control.int_epg.p_epg ); + } + else if( p_cmd->control.i_query == ES_OUT_SET_ES_FMT && + p_cmd->control.es_fmt.p_fmt ) { - es_format_Clean( p_cmd->control.p_fmt ); - free( p_cmd->control.p_fmt ); + es_format_Clean( p_cmd->control.es_fmt.p_fmt ); + free( p_cmd->control.es_fmt.p_fmt ); } } @@ -1212,19 +1507,20 @@ static char *GetTmpPath( char *psz_path ) return psz_path; } -static FILE *GetTmpFile( const char *psz_path ) +static FILE *GetTmpFile( char **ppsz_file, const char *psz_path ) { char *psz_name; int fd; FILE *f; /* */ + *ppsz_file = NULL; if( asprintf( &psz_name, "%s/vlc-timeshift.XXXXXX", psz_path ) < 0 ) return NULL; /* */ - fd = mkstemp( psz_name ); - free( psz_name ); + fd = utf8_mkstemp( psz_name ); + *ppsz_file = psz_name; if( fd < 0 ) return NULL;