input/stream_memory.c \
input/subtitles.c \
input/var.c \
+ video_output/snapshot.c \
+ video_output/snapshot.h \
video_output/video_output.c \
video_output/vout_pictures.c \
video_output/vout_pictures.h \
--- /dev/null
+/*****************************************************************************
+ * snapshot.c : vout internal snapshot
+ *****************************************************************************
+ * Copyright (C) 2009 Laurent Aimar
+ * $Id$
+ *
+ * Authors: Gildas Bazin <gbazin _AT_ videolan _DOT_ org>
+ * 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.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_charset.h>
+#include <vlc_strings.h>
+#include <vlc_block.h>
+
+#include "snapshot.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <time.h>
+
+/* */
+void vout_snapshot_Init(vout_snapshot_t *snap)
+{
+ vlc_mutex_init(&snap->lock);
+ vlc_cond_init(&snap->wait);
+
+ snap->is_available = true;
+ snap->request_count = 0;
+ snap->picture = NULL;
+}
+void vout_snapshot_Clean(vout_snapshot_t *snap)
+{
+ picture_t *picture = snap->picture;
+ while (picture) {
+ picture_t *next = picture->p_next;
+ picture_Release(picture);
+ picture = next;
+ }
+
+ vlc_cond_destroy(&snap->wait);
+ vlc_mutex_destroy(&snap->lock);
+}
+
+void vout_snapshot_End(vout_snapshot_t *snap)
+{
+ vlc_mutex_lock(&snap->lock);
+
+ snap->is_available = false;
+
+ vlc_cond_broadcast(&snap->wait);
+ vlc_mutex_unlock(&snap->lock);
+}
+
+/* */
+picture_t *vout_snapshot_Get(vout_snapshot_t *snap, mtime_t timeout)
+{
+ vlc_mutex_lock(&snap->lock);
+
+ /* */
+ snap->request_count++;
+
+ /* */
+ const mtime_t deadline = mdate() + timeout;
+ while (snap->is_available && !snap->picture && mdate() < deadline)
+ vlc_cond_timedwait(&snap->wait, &snap->lock, deadline);
+
+ /* */
+ picture_t *picture = snap->picture;
+ if (picture)
+ snap->picture = picture->p_next;
+ else if (snap->request_count > 0)
+ snap->request_count--;
+
+ vlc_mutex_unlock(&snap->lock);
+
+ return picture;
+}
+
+/* */
+bool vout_snapshot_IsRequested(vout_snapshot_t *snap)
+{
+ bool has_request = false;
+ if (!vlc_mutex_trylock(&snap->lock)) {
+ has_request = snap->request_count > 0;
+ vlc_mutex_unlock(&snap->lock);
+ }
+ return has_request;
+}
+void vout_snapshot_Set(vout_snapshot_t *snap,
+ const video_format_t *fmt,
+ const picture_t *picture)
+{
+ if (!fmt)
+ fmt = &picture->format;
+
+ vlc_mutex_lock(&snap->lock);
+ while (snap->request_count > 0) {
+ picture_t *dup = picture_NewFromFormat(fmt);
+ if (!dup)
+ break;
+
+ picture_Copy(dup, picture);
+
+ dup->p_next = snap->picture;
+ snap->picture = dup;
+ snap->request_count--;
+ }
+ vlc_cond_broadcast(&snap->wait);
+ vlc_mutex_unlock(&snap->lock);
+}
+/* */
+char *vout_snapshot_GetDirectory(void)
+{
+ char *psz_path = NULL;
+#if defined(__APPLE__) || defined(SYS_BEOS)
+
+ if (asprintf(&psz_path, "%s/Desktop",
+ config_GetHomeDir()) == -1)
+ psz_path = NULL;
+
+#elif defined(WIN32) && !defined(UNDER_CE)
+
+ /* Get the My Pictures folder path */
+ char *p_mypicturesdir = NULL;
+ typedef HRESULT (WINAPI *SHGETFOLDERPATH)(HWND, int, HANDLE, DWORD,
+ LPWSTR);
+ #ifndef CSIDL_FLAG_CREATE
+ # define CSIDL_FLAG_CREATE 0x8000
+ #endif
+ #ifndef CSIDL_MYPICTURES
+ # define CSIDL_MYPICTURES 0x27
+ #endif
+ #ifndef SHGFP_TYPE_CURRENT
+ # define SHGFP_TYPE_CURRENT 0
+ #endif
+
+ HINSTANCE shfolder_dll;
+ SHGETFOLDERPATH SHGetFolderPath ;
+
+ /* load the shfolder dll to retrieve SHGetFolderPath */
+ if ((shfolder_dll = LoadLibrary(_T("SHFolder.dll"))) != NULL)
+ {
+ wchar_t wdir[PATH_MAX];
+ SHGetFolderPath = (void *)GetProcAddress(shfolder_dll,
+ _T("SHGetFolderPathW"));
+ if ((SHGetFolderPath != NULL)
+ && SUCCEEDED (SHGetFolderPath (NULL,
+ CSIDL_MYPICTURES | CSIDL_FLAG_CREATE,
+ NULL, SHGFP_TYPE_CURRENT,
+ wdir)))
+ p_mypicturesdir = FromWide (wdir);
+
+ FreeLibrary(shfolder_dll);
+ }
+
+ if (p_mypicturesdir == NULL)
+ psz_path = strdup(config_GetHomeDir());
+ else
+ psz_path = p_mypicturesdir;
+
+#else
+
+ /* XXX: This saves in the data directory. Shouldn't we try saving
+ * to psz_homedir/Desktop or something nicer ? */
+ char *psz_datadir = config_GetUserDataDir();
+ if (psz_datadir)
+ {
+ if (asprintf(&psz_path, "%s", psz_datadir) == -1)
+ psz_path = NULL;
+ free(psz_datadir);
+ }
+
+#endif
+ return psz_path;
+}
+/* */
+int vout_snapshot_SaveImage(char **name, int *sequential,
+ const block_t *image,
+ vlc_object_t *object,
+ const vout_snapshot_save_cfg_t *cfg)
+{
+ /* */
+ char *filename;
+ DIR *pathdir = utf8_opendir(cfg->path);
+ if (pathdir != NULL) {
+ /* The use specified a directory path */
+ closedir(pathdir);
+
+ /* */
+ char *prefix = NULL;
+ if (cfg->prefix_fmt)
+ prefix = str_format(object, cfg->prefix_fmt);
+ if (!prefix) {
+ prefix = strdup("vlcsnap-");
+ if (!prefix)
+ goto error;
+ }
+
+ if (cfg->is_sequential) {
+ for (int num = cfg->sequence; ; num++) {
+ struct stat st;
+
+ if (asprintf(&filename, "%s" DIR_SEP "%s%05d.%s",
+ cfg->path, prefix, num, cfg->format) < 0) {
+ free(prefix);
+ goto error;
+ }
+ if (utf8_stat(filename, &st)) {
+ *sequential = num;
+ break;
+ }
+ free(filename);
+ }
+ } else {
+ struct tm curtime;
+ time_t lcurtime = time(NULL) ;
+
+ if (!localtime_r(&lcurtime, &curtime)) {
+ const unsigned int id = (image->i_pts / 100000) & 0xFFFFFF;
+
+ msg_Warn(object, "failed to get current time. Falling back to legacy snapshot naming");
+
+ if (asprintf(&filename, "%s" DIR_SEP "%s%u.%s",
+ cfg->path, prefix, id, cfg->format) < 0)
+ filename = NULL;
+ } else {
+ /* suffix with the last decimal digit in 10s of seconds resolution
+ * FIXME gni ? */
+ const int id = (image->i_pts / (100*1000)) & 0xFF;
+ char buffer[128];
+
+ if (!strftime(buffer, sizeof(buffer), "%Y-%m-%d-%Hh%Mm%Ss", &curtime))
+ strcpy(buffer, "error");
+
+ if (asprintf(&filename, "%s" DIR_SEP "%s%s%1u.%s",
+ cfg->path, prefix, buffer, id, cfg->format) < 0)
+ filename = NULL;
+ }
+ }
+ free(prefix);
+ } else {
+ /* The user specified a full path name (including file name) */
+ filename = str_format(object, cfg->path);
+ path_sanitize(filename);
+ }
+
+ if (!filename)
+ goto error;
+
+ /* Save the snapshot */
+ FILE *file = utf8_fopen(filename, "wb");
+ if (!file) {
+ msg_Err(object, "Failed to open '%s'", filename);
+ free(filename);
+ goto error;
+ }
+ if (fwrite(image->p_buffer, image->i_buffer, 1, file) != 1) {
+ msg_Err(object, "Failed to write to '%s'", filename);
+ fclose(file);
+ free(filename);
+ goto error;
+ }
+ fclose(file);
+
+ /* */
+ if (name)
+ *name = filename;
+ else
+ free(filename);
+
+ return VLC_SUCCESS;
+
+error:
+ msg_Err(object, "could not save snapshot");
+ return VLC_EGENERIC;
+}
+
--- /dev/null
+/*****************************************************************************
+ * snapshot.h : vout internal snapshot
+ *****************************************************************************
+ * Copyright (C) 2009 Laurent Aimar
+ * $Id$
+ *
+ * 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
+ * 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 _VOUT_INTERNAL_SNAPSHOT_H
+#define _VOUT_INTERNAL_SNAPSHOT_H
+
+#include <vlc_picture.h>
+
+typedef struct {
+ vlc_mutex_t lock;
+ vlc_cond_t wait;
+
+ bool is_available;
+ int request_count;
+ picture_t *picture;
+
+} vout_snapshot_t;
+
+/* */
+void vout_snapshot_Init(vout_snapshot_t *);
+void vout_snapshot_Clean(vout_snapshot_t *);
+
+void vout_snapshot_End(vout_snapshot_t *);
+
+/* */
+picture_t *vout_snapshot_Get(vout_snapshot_t *, mtime_t timeout);
+
+/**
+ * It tells if they are pending snapshot request
+ */
+bool vout_snapshot_IsRequested(vout_snapshot_t *);
+
+/**
+ * It set the picture used to create the snapshots.
+ *
+ * The given picture is only copied and not released.
+ * If p_fmt is non NULL it will override the format of the p_picture (mainly
+ * used because of aspect/crop problems).
+ */
+void vout_snapshot_Set(vout_snapshot_t *, const video_format_t *, const picture_t *);
+
+/**
+ * This function will return the directory used for snapshots
+ */
+char *vout_snapshot_GetDirectory(void);
+
+typedef struct {
+ bool is_sequential;
+ int sequence;
+ char *path;
+ char *format;
+ char *prefix_fmt;
+} vout_snapshot_save_cfg_t;
+
+/**
+ * This function will write an image to the disk an return the file name created.
+ */
+int vout_snapshot_SaveImage(char **name, int *sequential,
+ const block_t *image,
+ vlc_object_t *object,
+ const vout_snapshot_save_cfg_t *cfg);
+
+#endif
+
p_vout->p->b_picture_empty = false;
p_vout->p->i_picture_qtype = QTYPE_NONE;
- p_vout->p->snapshot.b_available = true;
- p_vout->p->snapshot.i_request = 0;
- p_vout->p->snapshot.p_picture = NULL;
- vlc_mutex_init( &p_vout->p->snapshot.lock );
- vlc_cond_init( &p_vout->p->snapshot.wait );
+ vout_snapshot_Init( &p_vout->p->snapshot );
/* Initialize locks */
vlc_mutex_init( &p_vout->picture_lock );
vlc_cond_signal( &p_vout->p->change_wait );
vlc_mutex_unlock( &p_vout->change_lock );
- vlc_mutex_lock( &p_vout->p->snapshot.lock );
- p_vout->p->snapshot.b_available = false;
- vlc_cond_broadcast( &p_vout->p->snapshot.wait );
- vlc_mutex_unlock( &p_vout->p->snapshot.lock );
+ vout_snapshot_End( &p_vout->p->snapshot );
vlc_join( p_vout->p->thread, NULL );
module_unneed( p_vout, p_vout->p_module );
vlc_mutex_destroy( &p_vout->p->vfilter_lock );
/* */
- for( ;; )
- {
- picture_t *p_picture = p_vout->p->snapshot.p_picture;
- if( !p_picture )
- break;
-
- p_vout->p->snapshot.p_picture = p_picture->p_next;
-
- picture_Release( p_picture );
- }
- vlc_cond_destroy( &p_vout->p->snapshot.wait );
- vlc_mutex_destroy( &p_vout->p->snapshot.lock );
+ vout_snapshot_Clean( &p_vout->p->snapshot );
/* */
free( p_vout->p->psz_filter_chain );
p_filtered_picture = filter_chain_VideoFilter( p_vout->p->p_vf2_chain,
p_picture );
- bool b_snapshot = false;
- if( vlc_mutex_trylock( &p_vout->p->snapshot.lock ) == 0 )
- {
- b_snapshot = p_vout->p->snapshot.i_request > 0
- && p_picture != NULL;
- vlc_mutex_unlock( &p_vout->p->snapshot.lock );
- }
+ const bool b_snapshot = vout_snapshot_IsRequested( &p_vout->p->snapshot );
/*
* Check for subpictures to display
* Take a snapshot if requested
*/
if( p_directbuffer && b_snapshot )
- {
- vlc_mutex_lock( &p_vout->p->snapshot.lock );
- assert( p_vout->p->snapshot.i_request > 0 );
- while( p_vout->p->snapshot.i_request > 0 )
- {
- picture_t *p_pic = picture_New( p_vout->fmt_out.i_chroma,
- p_vout->fmt_out.i_width,
- p_vout->fmt_out.i_height,
- p_vout->fmt_out.i_aspect );
- if( !p_pic )
- break;
-
- picture_Copy( p_pic, p_directbuffer );
-
- p_pic->format.i_sar_num = p_vout->fmt_out.i_sar_num;
- p_pic->format.i_sar_den = p_vout->fmt_out.i_sar_den;
-
- p_pic->p_next = p_vout->p->snapshot.p_picture;
- p_vout->p->snapshot.p_picture = p_pic;
- p_vout->p->snapshot.i_request--;
- }
- vlc_cond_broadcast( &p_vout->p->snapshot.wait );
- vlc_mutex_unlock( &p_vout->p->snapshot.lock );
- }
+ vout_snapshot_Set( &p_vout->p->snapshot,
+ &p_vout->fmt_out, p_directbuffer );
/*
* Call the plugin-specific rendering method if there is one
#define _VOUT_INTERNAL_H 1
#include "vout_control.h"
+#include "snapshot.h"
/* Number of pictures required to computes the FPS rate */
#define VOUT_FPS_SAMPLES 20
char *psz_vf2;
/* Snapshot interface */
- struct
- {
- bool b_available;
- int i_request;
- picture_t *p_picture;
- vlc_mutex_t lock;
- vlc_cond_t wait;
- } snapshot;
+ vout_snapshot_t snapshot;
/* Show media title on videoutput */
bool b_title_show;
spu_DisplaySubpicture( p_vout->p_spu, p_subpic );
return VLC_SUCCESS;
}
-/**
- * This function will return the default directory used for snapshots
- */
-static char *VoutSnapshotGetDefaultDirectory( void )
-{
- char *psz_path = NULL;
-#if defined(__APPLE__) || defined(SYS_BEOS)
-
- if( asprintf( &psz_path, "%s/Desktop",
- config_GetHomeDir() ) == -1 )
- psz_path = NULL;
-
-#elif defined(WIN32) && !defined(UNDER_CE)
-
- /* Get the My Pictures folder path */
- char *p_mypicturesdir = NULL;
- typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD,
- LPWSTR );
- #ifndef CSIDL_FLAG_CREATE
- # define CSIDL_FLAG_CREATE 0x8000
- #endif
- #ifndef CSIDL_MYPICTURES
- # define CSIDL_MYPICTURES 0x27
- #endif
- #ifndef SHGFP_TYPE_CURRENT
- # define SHGFP_TYPE_CURRENT 0
- #endif
-
- HINSTANCE shfolder_dll;
- SHGETFOLDERPATH SHGetFolderPath ;
-
- /* load the shfolder dll to retrieve SHGetFolderPath */
- if( ( shfolder_dll = LoadLibrary( _T("SHFolder.dll") ) ) != NULL )
- {
- wchar_t wdir[PATH_MAX];
- SHGetFolderPath = (void *)GetProcAddress( shfolder_dll,
- _T("SHGetFolderPathW") );
- if ((SHGetFolderPath != NULL )
- && SUCCEEDED (SHGetFolderPath (NULL,
- CSIDL_MYPICTURES | CSIDL_FLAG_CREATE,
- NULL, SHGFP_TYPE_CURRENT,
- wdir)))
- p_mypicturesdir = FromWide (wdir);
-
- FreeLibrary( shfolder_dll );
- }
-
- if( p_mypicturesdir == NULL )
- psz_path = strdup( config_GetHomeDir() );
- else
- psz_path = p_mypicturesdir;
-
-#else
-
- /* XXX: This saves in the data directory. Shouldn't we try saving
- * to psz_homedir/Desktop or something nicer ? */
- psz_path = config_GetUserDataDir();
-
-#endif
-
- return psz_path;
-}
-/**
- * This function will save a video snapshot to a file
- */
-static int VoutWriteSnapshot( vout_thread_t *p_vout, char **ppsz_filename,
- const block_t *p_image,
- const char *psz_path,
- const char *psz_format,
- const char *psz_prefix_fmt )
-{
- /* */
- char *psz_filename;
- DIR *p_path = utf8_opendir( psz_path );
- if( p_path != NULL )
- {
- /* The use specified a directory path */
- closedir( p_path );
-
- /* */
- char *psz_prefix = NULL;
- if( psz_prefix_fmt )
- psz_prefix = str_format( p_vout, psz_prefix_fmt );
- if( !psz_prefix )
- {
- psz_prefix = strdup( "vlcsnap-" );
- if( !psz_prefix )
- goto error;
- }
-
- if( var_GetBool( p_vout, "snapshot-sequential" ) )
- {
- int i_num = var_GetInteger( p_vout, "snapshot-num" );
- for( ; ; i_num++ )
- {
- struct stat st;
-
- if( asprintf( &psz_filename, "%s" DIR_SEP "%s%05d.%s",
- psz_path, psz_prefix, i_num++, psz_format ) < 0 )
- {
- free( psz_prefix );
- goto error;
- }
- if( utf8_stat( psz_filename, &st ) )
- break;
- free( psz_filename );
- }
-
- var_SetInteger( p_vout, "snapshot-num", i_num );
- }
- else
- {
- struct tm curtime;
- time_t lcurtime = time( NULL ) ;
-
- if( !localtime_r( &lcurtime, &curtime ) )
- {
- const unsigned int i_id = (p_image->i_pts / 100000) & 0xFFFFFF;
-
- msg_Warn( p_vout, "failed to get current time. Falling back to legacy snapshot naming" );
-
- if( asprintf( &psz_filename, "%s" DIR_SEP "%s%u.%s",
- psz_path, psz_prefix, i_id, psz_format ) < 0 )
- psz_filename = NULL;
- }
- else
- {
- /* suffix with the last decimal digit in 10s of seconds resolution
- * FIXME gni ? */
- const int i_id = (p_image->i_pts / (100*1000)) & 0xFF;
- char psz_curtime[128];
-
- if( !strftime( psz_curtime, sizeof(psz_curtime), "%Y-%m-%d-%Hh%Mm%Ss", &curtime ) )
- strcpy( psz_curtime, "error" );
-
- if( asprintf( &psz_filename, "%s" DIR_SEP "%s%s%1u.%s",
- psz_path, psz_prefix, psz_curtime, i_id, psz_format ) < 0 )
- psz_filename = NULL;
- }
- }
- free( psz_prefix );
- }
- else
- {
- /* The user specified a full path name (including file name) */
- psz_filename = str_format( p_vout, psz_path );
- path_sanitize( psz_filename );
- }
-
- if( !psz_filename )
- goto error;
-
- /* Save the snapshot */
- FILE *p_file = utf8_fopen( psz_filename, "wb" );
- if( !p_file )
- {
- msg_Err( p_vout, "Failed to open '%s'", psz_filename );
- free( psz_filename );
- goto error;
- }
- if( fwrite( p_image->p_buffer, p_image->i_buffer, 1, p_file ) != 1 )
- {
- msg_Err( p_vout, "Failed to write to '%s'", psz_filename );
- fclose( p_file );
- free( psz_filename );
- goto error;
- }
- fclose( p_file );
-
- /* */
- if( ppsz_filename )
- *ppsz_filename = psz_filename;
- else
- free( psz_filename );
-
- return VLC_SUCCESS;
-
-error:
- msg_Err( p_vout, "could not save snapshot" );
- return VLC_EGENERIC;
-}
/**
* This function will display the name and a PIP of the provided snapshot
video_format_t *p_fmt,
const char *psz_format, mtime_t i_timeout )
{
- vout_thread_sys_t *p_sys = p_vout->p;
-
- vlc_mutex_lock( &p_sys->snapshot.lock );
- p_sys->snapshot.i_request++;
-
- const mtime_t i_deadline = mdate() + i_timeout;
- while( p_sys->snapshot.b_available && !p_sys->snapshot.p_picture )
- {
- if( vlc_cond_timedwait( &p_sys->snapshot.wait, &p_sys->snapshot.lock,
- i_deadline ) )
- break;
- }
-
- picture_t *p_picture = p_sys->snapshot.p_picture;
- if( p_picture )
- p_sys->snapshot.p_picture = p_picture->p_next;
- else if( p_sys->snapshot.i_request > 0 )
- p_sys->snapshot.i_request--;
- vlc_mutex_unlock( &p_sys->snapshot.lock );
-
+ picture_t *p_picture = vout_snapshot_Get( &p_vout->p->snapshot, i_timeout );
if( !p_picture )
{
msg_Err( p_vout, "Failed to grab a snapshot" );
if( !psz_path )
{
- psz_path = VoutSnapshotGetDefaultDirectory();
+ psz_path = vout_snapshot_GetDirectory();
if( !psz_path )
{
msg_Err( p_vout, "no path specified for snapshots" );
}
}
+ vout_snapshot_save_cfg_t cfg;
+ memset( &cfg, 0, sizeof(cfg) );
+ cfg.is_sequential = var_GetBool( p_vout, "snapshot-sequential" );
+ cfg.sequence = var_GetInteger( p_vout, "snapshot-num" );
+ cfg.path = psz_path;
+ cfg.format = psz_format;
+ cfg.prefix_fmt = psz_prefix;
+
char *psz_filename;
- if( VoutWriteSnapshot( p_vout, &psz_filename,
- p_image,
- psz_path, psz_format, psz_prefix ) )
+ int i_sequence;
+ if (vout_snapshot_SaveImage( &psz_filename, &i_sequence,
+ p_image, VLC_OBJECT(p_vout), &cfg ) )
goto exit;
+ if( cfg.is_sequential )
+ var_SetInteger( p_vout, "snapshot-num", i_sequence + 1 );
VoutOsdSnapshot( p_vout, p_picture, psz_filename );