Commit 7e676a02 authored by Laurent Aimar's avatar Laurent Aimar

Added initial skeleton for es_out timeshift support.

It is not yet functionnal.
parent cdf95dd2
......@@ -309,6 +309,7 @@ SOURCES_libvlc_common = \
input/decoder_synchro.c \
input/demux.c \
input/es_out.c \
input/es_out_timeshift.c \
input/input.c \
input/meta.c \
input/access.h \
......@@ -316,6 +317,7 @@ SOURCES_libvlc_common = \
input/decoder.h \
input/demux.h \
input/es_out.h \
input/es_out_timeshift.h \
input/stream.h \
input/input_internal.h \
input/vlm_internal.h \
......
......@@ -2210,7 +2210,7 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
return VLC_EGENERIC;
}
case ES_OUT_SET_FMT:
case ES_OUT_SET_ES_FMT:
{
/* This ain't pretty but is need by some demuxers (eg. Ogg )
* to update the p_extra data */
......
/*****************************************************************************
* es_out_timeshift.c: Es Out timeshift.
*****************************************************************************
* Copyright (C) 2008 Laurent Aimar
* $Id$
*
* Authors: Laurent Aimar < fenrir _AT_ via _DOT_ ecp _DOT_ fr>
*
* 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 <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#if defined (WIN32) && !defined (UNDER_CE)
# include <direct.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <vlc_common.h>
#include <vlc_charset.h>
#include <vlc_input.h>
#include <vlc_es_out.h>
#include <vlc_block.h>
#include "input_internal.h"
#include "es_out.h"
#include "es_out_timeshift.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
enum
{
C_ADD,
C_SEND,
C_DEL,
C_CONTROL,
};
typedef struct
{
int i_type;
union
{
struct
{
es_out_id_t *p_es;
es_format_t *p_fmt;
} add;
struct
{
es_out_id_t *p_es;
} del;
struct
{
es_out_id_t *p_es;
block_t *p_block;
} send;
struct
{
int i_query;
bool b_bool;
bool *pb_bool;
int i_int;
int *pi_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;
} control;
};
} ts_cmd_t;
struct es_out_id_t
{
es_out_id_t *p_es;
};
struct es_out_sys_t
{
input_thread_t *p_input;
es_out_t *p_out;
/* Configuration */
int64_t i_tmp_size_max; /* Maximal temporary file size in byte */
char *psz_tmp_path; /* Path for temporary files */
/* Lock for all following fields */
vlc_mutex_t lock;
/* */
bool b_delayed;
/* */
int i_es;
es_out_id_t **pp_es;
/* */
int i_cmd;
ts_cmd_t **pp_cmd;
};
static es_out_id_t *Add ( es_out_t *, const es_format_t * );
static int Send ( es_out_t *, es_out_id_t *, block_t * );
static void Del ( es_out_t *, es_out_id_t * );
static int Control( es_out_t *, int i_query, va_list );
static void Destroy( es_out_t * );
static void CmdPush( es_out_t *, const ts_cmd_t * );
static int CmdPop( es_out_t *p_out, ts_cmd_t *p_cmd );
static int CmdInitAdd ( ts_cmd_t *, es_out_id_t *, const es_format_t *, bool b_copy );
static void CmdInitSend ( ts_cmd_t *, es_out_id_t *, block_t * );
static int CmdInitDel ( ts_cmd_t *, es_out_id_t * );
static int CmdInitControl( ts_cmd_t *, int i_query, va_list, bool b_copy );
static void CmdExecuteAdd ( es_out_t *, ts_cmd_t * );
static int CmdExecuteSend ( es_out_t *, ts_cmd_t * );
static void CmdExecuteDel ( es_out_t *, ts_cmd_t * );
static int CmdExecuteControl( es_out_t *, ts_cmd_t * );
static void CmdCleanAdd ( ts_cmd_t * );
static void CmdCleanSend ( ts_cmd_t * );
static void CmdCleanControl( ts_cmd_t *p_cmd );
static char *GetTmpPath( char *psz_path );
static FILE *GetTmpFile( const char *psz_path );
/*****************************************************************************
* input_EsOutTimeshiftNew:
*****************************************************************************/
es_out_t *input_EsOutTimeshiftNew( input_thread_t *p_input, es_out_t *p_next_out )
{
es_out_t *p_out = malloc( sizeof(*p_out) );
if( !p_out )
return NULL;
es_out_sys_t *p_sys = malloc( sizeof(*p_sys) );
if( !p_sys )
{
free( p_out );
return NULL;
}
/* */
p_out->pf_add = Add;
p_out->pf_send = Send;
p_out->pf_del = Del;
p_out->pf_control = Control;
p_out->pf_destroy = Destroy;
p_out->p_sys = p_sys;
p_out->b_sout = p_input->p->p_sout != NULL;
/* */
p_sys->p_input = p_input;
p_sys->p_out = p_next_out;
vlc_mutex_init_recursive( &p_sys->lock );
p_sys->b_delayed = false;
TAB_INIT( p_sys->i_es, p_sys->pp_es );
TAB_INIT( p_sys->i_cmd, p_sys->pp_cmd );
/* TODO config
* timeshift-granularity
* timeshift-path
*/
p_sys->i_tmp_size_max = 50 * 1024*1024;
p_sys->psz_tmp_path = GetTmpPath( NULL );
return p_out;
}
/*****************************************************************************
* Internal functions
*****************************************************************************/
static void Destroy( es_out_t *p_out )
{
es_out_sys_t *p_sys = p_out->p_sys;
while( p_sys->i_cmd > 0 )
{
ts_cmd_t cmd;
if( CmdPop( p_out, &cmd ) )
break;
switch( cmd.i_type )
{
case C_ADD:
CmdCleanAdd( &cmd );
break;
case C_SEND:
CmdCleanSend( &cmd );
break;
case C_CONTROL:
CmdCleanControl( &cmd );
break;
case C_DEL:
break;
default:
assert(0);
break;
}
}
TAB_CLEAN( p_sys->i_cmd, p_sys->pp_cmd );
while( p_sys->i_es > 0 )
Del( p_out, p_sys->pp_es[0] );
TAB_CLEAN( p_sys->i_es, p_sys->pp_es );
free( p_sys->psz_tmp_path );
vlc_mutex_destroy( &p_sys->lock );
free( p_sys );
free( p_out );
}
static es_out_id_t *Add( es_out_t *p_out, const es_format_t *p_fmt )
{
es_out_sys_t *p_sys = p_out->p_sys;
ts_cmd_t cmd;
es_out_id_t *p_es = malloc( sizeof( *p_es ) );
if( !p_es )
return NULL;
vlc_mutex_lock( &p_sys->lock );
if( CmdInitAdd( &cmd, p_es, p_fmt, p_sys->b_delayed ) )
{
vlc_mutex_unlock( &p_sys->lock );
free( p_es );
return NULL;
}
TAB_APPEND( p_sys->i_es, p_sys->pp_es, p_es );
if( p_sys->b_delayed )
CmdPush( p_out, &cmd );
else
CmdExecuteAdd( p_out, &cmd );
vlc_mutex_unlock( &p_sys->lock );
return p_es;
}
static int Send( es_out_t *p_out, es_out_id_t *p_es, block_t *p_block )
{
es_out_sys_t *p_sys = p_out->p_sys;
ts_cmd_t cmd;
int i_ret = VLC_SUCCESS;
vlc_mutex_lock( &p_sys->lock );
CmdInitSend( &cmd, p_es, p_block );
if( p_sys->b_delayed )
CmdPush( p_out, &cmd );
else
i_ret = CmdExecuteSend( p_out, &cmd) ;
vlc_mutex_unlock( &p_sys->lock );
return i_ret;
}
static void Del( es_out_t *p_out, es_out_id_t *p_es )
{
es_out_sys_t *p_sys = p_out->p_sys;
ts_cmd_t cmd;
vlc_mutex_lock( &p_sys->lock );
CmdInitDel( &cmd, p_es );
if( p_sys->b_delayed )
CmdPush( p_out, &cmd );
else
CmdExecuteDel( p_out, &cmd );
TAB_REMOVE( p_sys->i_es, p_sys->pp_es, p_es );
vlc_mutex_unlock( &p_sys->lock );
}
static int ControlLocked( es_out_t *p_out, int i_query, va_list args )
{
es_out_sys_t *p_sys = p_out->p_sys;
switch( i_query )
{
/* Invalid query for this es_out level */
case ES_OUT_SET_ES_BY_ID:
case ES_OUT_RESTART_ES_BY_ID:
case ES_OUT_SET_ES_DEFAULT_BY_ID:
case ES_OUT_SET_DELAY:
case ES_OUT_SET_RECORD_STATE:
assert(0);
return VLC_EGENERIC;
/* TODO ? or to remove ? */
case ES_OUT_GET_TS:
return VLC_EGENERIC;
/* Pass-through control */
case ES_OUT_SET_ACTIVE:
case ES_OUT_GET_ACTIVE:
case ES_OUT_SET_MODE:
case ES_OUT_GET_MODE:
case ES_OUT_SET_GROUP:
case ES_OUT_GET_GROUP:
case ES_OUT_SET_PCR:
case ES_OUT_SET_GROUP_PCR:
case ES_OUT_RESET_PCR:
case ES_OUT_SET_NEXT_DISPLAY_TIME:
case ES_OUT_SET_GROUP_META:
case ES_OUT_SET_GROUP_EPG:
case ES_OUT_DEL_GROUP:
case ES_OUT_SET_ES:
case ES_OUT_RESTART_ES:
case ES_OUT_SET_ES_DEFAULT:
case ES_OUT_SET_ES_STATE:
case ES_OUT_GET_ES_STATE:
case ES_OUT_SET_ES_FMT:
{
ts_cmd_t cmd;
if( CmdInitControl( &cmd, i_query, args, p_sys->b_delayed ) )
return VLC_EGENERIC;
if( p_sys->b_delayed )
{
CmdPush( p_out, &cmd );
return VLC_SUCCESS;
}
return CmdExecuteControl( p_out, &cmd );
}
/* Special control */
case ES_OUT_GET_WAKE_UP: /* TODO ? */
case ES_OUT_GET_BUFFERING:
case ES_OUT_GET_EMPTY:
case ES_OUT_SET_PAUSE_STATE:
case ES_OUT_SET_RATE:
case ES_OUT_SET_TIME:
case ES_OUT_SET_FRAME_NEXT:
if( p_sys->b_delayed )
{
/* TODO */
}
return es_out_vaControl( p_sys->p_out, i_query, args );
default:
msg_Err( p_sys->p_input, "Unknown es_out_Control query !" );
assert(0);
return VLC_EGENERIC;
}
}
static int Control( es_out_t *p_out, int i_query, va_list args )
{
es_out_sys_t *p_sys = p_out->p_sys;
int i_ret;
vlc_mutex_lock( &p_sys->lock );
i_ret = ControlLocked( p_out, i_query, args );
vlc_mutex_unlock( &p_sys->lock );
return i_ret;
}
/*****************************************************************************
*
*****************************************************************************/
static void CmdPush( es_out_t *p_out, const ts_cmd_t *p_cmd )
{
es_out_sys_t *p_sys = p_out->p_sys;
ts_cmd_t *p_dup = malloc( sizeof(*p_dup) );
if( p_dup )
{
*p_dup = *p_cmd;
TAB_APPEND( p_sys->i_cmd, p_sys->pp_cmd, p_dup );
}
}
static int CmdPop( es_out_t *p_out, ts_cmd_t *p_cmd )
{
es_out_sys_t *p_sys = p_out->p_sys;
if( p_sys->i_cmd <= 0 )
return VLC_EGENERIC;
*p_cmd = *p_sys->pp_cmd[0];
free( p_sys->pp_cmd[0] );
TAB_REMOVE( p_sys->i_cmd, p_sys->pp_cmd, p_sys->pp_cmd[0] );
return VLC_SUCCESS;
}
static int CmdInitAdd( ts_cmd_t *p_cmd, es_out_id_t *p_es, const es_format_t *p_fmt, bool b_copy )
{
p_cmd->i_type = C_ADD;
p_cmd->add.p_es = p_es;
if( b_copy )
{
p_cmd->add.p_fmt = malloc( sizeof(*p_fmt) );
if( !p_cmd->add.p_fmt )
return VLC_EGENERIC;
es_format_Copy( p_cmd->add.p_fmt, p_fmt );
}
else
{
p_cmd->add.p_fmt = (es_format_t*)p_fmt;
}
return VLC_SUCCESS;
}
static void CmdExecuteAdd( es_out_t *p_out, ts_cmd_t *p_cmd )
{
es_out_sys_t *p_sys = p_out->p_sys;
p_cmd->add.p_es->p_es = es_out_Add( p_sys->p_out, p_cmd->add.p_fmt );
}
static void CmdCleanAdd( ts_cmd_t *p_cmd )
{
es_format_Clean( p_cmd->add.p_fmt );
free( p_cmd->add.p_fmt );
}
static void CmdInitSend( ts_cmd_t *p_cmd, es_out_id_t *p_es, block_t *p_block )
{
p_cmd->i_type = C_SEND;
p_cmd->send.p_es = p_es;
p_cmd->send.p_block = p_block;
}
static int CmdExecuteSend( es_out_t *p_out, ts_cmd_t *p_cmd )
{
es_out_sys_t *p_sys = p_out->p_sys;
block_t *p_block = p_cmd->send.p_block;
p_cmd->send.p_block = NULL;
if( p_block )
{
if( p_cmd->send.p_es->p_es )
return es_out_Send( p_sys->p_out, p_cmd->send.p_es->p_es, p_block );
block_Release( p_block );
}
return VLC_EGENERIC;
}
static void CmdCleanSend( ts_cmd_t *p_cmd )
{
if( p_cmd->send.p_block )
block_Release( p_cmd->send.p_block );
}
static int CmdInitDel( ts_cmd_t *p_cmd, es_out_id_t *p_es )
{
p_cmd->i_type = C_DEL;
p_cmd->del.p_es = p_es;
return VLC_SUCCESS;
}
static void CmdExecuteDel( es_out_t *p_out, ts_cmd_t *p_cmd )
{
es_out_sys_t *p_sys = p_out->p_sys;
if( p_cmd->del.p_es->p_es )
es_out_Del( p_sys->p_out, p_cmd->del.p_es->p_es );
free( p_cmd->del.p_es );
}
static int CmdInitControl( ts_cmd_t *p_cmd, int i_query, va_list args, bool b_copy )
{
p_cmd->i_type = C_CONTROL;
p_cmd->control.i_query = i_query;
switch( i_query )
{
/* Pass-through control */
case ES_OUT_SET_ACTIVE: /* arg1= bool */
p_cmd->control.b_bool = (bool)va_arg( args, int );
break;
case ES_OUT_GET_ACTIVE: /* arg1= bool* */
p_cmd->control.pb_bool = (bool*)va_arg( args, bool * );
break;
case ES_OUT_SET_MODE: /* arg1= int */
case ES_OUT_SET_GROUP: /* arg1= int */
case ES_OUT_DEL_GROUP: /* arg1=int i_group */
p_cmd->control.i_int = (int)va_arg( args, int );
break;
case ES_OUT_GET_MODE: /* arg2= int* */
case ES_OUT_GET_GROUP: /* arg1= int* */
p_cmd->control.pi_int = (int*)va_arg( args, int * );
break;
case ES_OUT_SET_PCR: /* arg1=int64_t i_pcr(microsecond!) (using default group 0)*/
case ES_OUT_SET_NEXT_DISPLAY_TIME: /* arg1=int64_t i_pts(microsecond) */
p_cmd->control.i_i64 = (int64_t)va_arg( args, int64_t );
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 );
break;
case ES_OUT_RESET_PCR: /* no arg */
break;
case ES_OUT_SET_GROUP_META: /* arg1=int i_group arg2=vlc_meta_t* */
{
p_cmd->control.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 )
return VLC_EGENERIC;
vlc_meta_Merge( p_cmd->control.p_meta, p_meta );
}
else
{
p_cmd->control.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 );
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 )
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,
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,
p_epg->p_current ? p_epg->p_current->i_start : -1 );
}
else
{
p_cmd->control.p_epg = p_epg;
}
break;
}
/* Modified control */
case ES_OUT_SET_ES: /* arg1= es_out_id_t* */
case ES_OUT_RESTART_ES: /* arg1= es_out_id_t* */
case ES_OUT_SET_ES_DEFAULT: /* arg1= es_out_id_t* */
p_cmd->control.p_es = (es_out_id_t*)va_arg( args, es_out_id_t * );
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 );
break;
case ES_OUT_GET_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.pb_bool = (bool*)va_arg( args, bool * );
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 * );
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 )
return VLC_EGENERIC;
es_format_Copy( p_cmd->control.p_fmt, p_fmt );
}
else
{
p_cmd->control.p_fmt = p_fmt;
}
break;
}
default:
assert(0);
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
static int CmdExecuteControl( es_out_t *p_out, ts_cmd_t *p_cmd )
{
es_out_sys_t *p_sys = p_out->p_sys;
const int i_query = p_cmd->control.i_query;
switch( i_query )
{
/* Pass-through control */
case ES_OUT_SET_ACTIVE: /* arg1= bool */
return es_out_Control( p_sys->p_out, i_query, p_cmd->control.b_bool );
case ES_OUT_GET_ACTIVE: /* arg1= bool* */
return es_out_Control( p_sys->p_out, i_query, p_cmd->control.pb_bool );
case ES_OUT_SET_MODE: /* arg1= int */
case ES_OUT_SET_GROUP: /* arg1= int */
case ES_OUT_DEL_GROUP: /* arg1=int i_group */
return es_out_Control( p_sys->p_out, i_query, p_cmd->control.i_int );
case ES_OUT_GET_MODE: /* arg2= int* */
case ES_OUT_GET_GROUP: /* arg1= int* */
return es_out_Control( p_sys->p_out, i_query, p_cmd->control.pi_int );
case ES_OUT_SET_PCR: /* arg1=int64_t i_pcr(microsecond!) (using default group 0)*/
case ES_OUT_SET_NEXT_DISPLAY_TIME: /* arg1=int64_t i_pts(microsecond) */
return es_out_Control( p_sys->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_sys->p_out, i_query, p_cmd->control.i_int, p_cmd->control.i_i64 );
case ES_OUT_RESET_PCR: /* no arg */
return es_out_Control( p_sys->p_out, i_query );
case ES_OUT_SET_GROUP_META: /* arg1=int i_group arg2=vlc_meta_t* */
return es_out_Control( p_sys->p_out, i_query, p_cmd->control.i_int, p_cmd->control.p_meta );
case ES_OUT_SET_GROUP_EPG: /* arg1=int i_group arg2=vlc_epg_t* */
return es_out_Control( p_sys->p_out, i_query, p_cmd->control.i_int, p_cmd->control.p_epg );
/* Modified control */
case ES_OUT_SET_ES: /* arg1= es_out_id_t* */
case ES_OUT_RESTART_ES: /* arg1= es_out_id_t* */
case ES_OUT_SET_ES_DEFAULT: /* arg1= es_out_id_t* */
return es_out_Control( p_sys->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_sys->p_out, i_query, p_cmd->control.p_es->p_es, p_cmd->control.b_bool );
case ES_OUT_GET_ES_STATE:/* arg1= es_out_id_t* arg2=bool* */
return es_out_Control( p_sys->p_out, i_query, p_cmd->control.p_es->p_es, p_cmd->control.pb_bool );
case ES_OUT_SET_ES_FMT: /* arg1= es_out_id_t* arg2=es_format_t* */
return es_out_Control( p_sys->p_out, i_query, p_cmd->control.p_es->p_es, p_cmd->control.p_fmt );
default:
assert(0);
msg_Err( p_sys->p_input, "Unknown es_out_Control query in CmdExecuteControl!" );
return VLC_EGENERIC;
}
}
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 )
{
es_format_Clean( p_cmd->control.p_fmt );
free( p_cmd->control.p_fmt );
}
}
/*****************************************************************************
* GetTmpFile/Path:
*****************************************************************************/
static char *GetTmpPath( char *psz_path )
{
if( psz_path && *psz_path )
{
/* Make sure that the path exists and is a directory */
struct stat s;
const int i_ret = utf8_stat( psz_path, &s );
if( i_ret < 0 && !utf8_mkdir( psz_path, 0600 ) )
return psz_path;
else if( i_ret == 0 && ( s.st_mode & S_IFDIR ) )
return psz_path;
}
free( psz_path );
/* Create a suitable path */
#if defined (WIN32) && !defined (UNDER_CE)
const DWORD dwCount = GetTempPathW( 0, NULL );
wchar_t *psw_path = calloc( dwCount + 1, sizeof(wchar_t) );
if( psw_path )
{
if( GetTempPathW( dwCount + 1, psw_path ) <= 0 )
{
free( psw_path );
psw_path = _wgetcwd( NULL, 0 );
}
}
psz_path = NULL;
if( psw_path )
{
psz_path = FromWide( psw_path );
while( psz_path && *psz_path && psz_path[strlen( psz_path ) - 1] == '\\' )
psz_path[strlen( psz_path ) - 1] = '\0';
free( psw_path );
}
if( !psz_path || *psz_path == '\0' )
{
free( psz_path );
return strdup( "C:" );
}
#else
psz_path = strdup( "/tmp" );
#endif
return psz_path;
}
static FILE *GetTmpFile( const char *psz_path )
{
char *psz_name;
int fd;
FILE *f;
/* */
if( asprintf( &psz_name, "%s/vlc-timeshift.XXXXXX", psz_path ) < 0 )
return NULL;
/* */
fd = mkstemp( psz_name );
free( psz_name );
if( fd < 0 )
return NULL;
/* */
f = fdopen( fd, "rw+" );
if( !f )
close( fd );
return f;
}
/*****************************************************************************
* es_out_timeshift.h: Es Out timeshift.
*****************************************************************************
* Copyright (C) 2008 Laurent Aimar
* $Id$
*
* Authors: Laurent Aimar < fenrir _AT_ via _DOT_ ecp _DOT_ fr>
*
* 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.
*****************************************************************************/
#if defined(__PLUGIN__) || defined(__BUILTIN__) || !defined(__LIBVLC__)
# error This header file can only be included from LibVLC.
#endif
#ifndef _INPUT_ES_OUT_TIMESHIFT_H
#define _INPUT_ES_OUT_TIMESHIFT_H 1
#include <vlc_common.h>
es_out_t *input_EsOutTimeshiftNew( input_thread_t *, es_out_t * );
#endif
......@@ -37,6 +37,7 @@
#include "input_internal.h"
#include "es_out.h"
#include "es_out_timeshift.h"
#include "access.h"
#include "demux.h"
#include "stream.h"
......@@ -200,7 +201,7 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
p_input->p->b_recording = false;
TAB_INIT( p_input->p->i_bookmark, p_input->p->bookmark );
TAB_INIT( p_input->p->i_attachment, p_input->p->attachment );
p_input->p->p_es_out_display =
p_input->p->p_es_out_display = NULL;
p_input->p->p_es_out = NULL;
p_input->p->p_sout = NULL;
p_input->p->b_out_pace_control = false;
......@@ -1183,8 +1184,8 @@ static int Init( input_thread_t * p_input )
#endif
/* Create es out */
p_input->p->p_es_out =
p_input->p->p_es_out_display = input_EsOutNew( p_input, p_input->p->i_rate );
p_input->p->p_es_out = input_EsOutTimeshiftNew( p_input, p_input->p->p_es_out_display );
es_out_Control( p_input->p->p_es_out, ES_OUT_SET_ACTIVE, false );
es_out_Control( p_input->p->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
......@@ -1264,12 +1265,10 @@ static int Init( input_thread_t * p_input )
error:
input_ChangeState( p_input, ERROR_S );
if( p_input->p->p_es_out_display )
{
//TODO
}
if( p_input->p->p_es_out )
es_out_Delete( p_input->p->p_es_out );
if( p_input->p->p_es_out_display )
es_out_Delete( p_input->p->p_es_out_display );
#ifdef ENABLE_SOUT
if( p_input->p->p_sout )
{
......@@ -1357,12 +1356,10 @@ static void End( input_thread_t * p_input )
free( p_input->p->slave );
/* Unload all modules */
if( p_input->p->p_es_out_display )
{
//TODO
}
if( p_input->p->p_es_out )
es_out_Delete( p_input->p->p_es_out );
if( p_input->p->p_es_out_display )
es_out_Delete( p_input->p->p_es_out_display );
if( !p_input->b_preparsing )
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment