]> git.sesse.net Git - vlc/commitdiff
Moved out snapshot code to a standalone file.
authorLaurent Aimar <fenrir@videolan.org>
Fri, 31 Jul 2009 22:06:41 +0000 (00:06 +0200)
committerLaurent Aimar <fenrir@videolan.org>
Sat, 1 Aug 2009 10:07:12 +0000 (12:07 +0200)
src/Makefile.am
src/video_output/snapshot.c [new file with mode: 0644]
src/video_output/snapshot.h [new file with mode: 0644]
src/video_output/video_output.c
src/video_output/vout_internal.h
src/video_output/vout_intf.c

index 5397b559293591a53c77a8d252100c95ad74bb96..f4f52afb8c1ac23b9db9e4574fdc7f08a06cce63 100644 (file)
@@ -344,6 +344,8 @@ SOURCES_libvlc_common = \
        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 \
diff --git a/src/video_output/snapshot.c b/src/video_output/snapshot.c
new file mode 100644 (file)
index 0000000..f6beb19
--- /dev/null
@@ -0,0 +1,297 @@
+/*****************************************************************************
+ * 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;
+}
+
diff --git a/src/video_output/snapshot.h b/src/video_output/snapshot.h
new file mode 100644 (file)
index 0000000..8669377
--- /dev/null
@@ -0,0 +1,88 @@
+/*****************************************************************************
+ * 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
+
index 418c7a7f61e662d5f9b98702462f77c33cbb7d67..691e144064b91334005ed7e8fe141e0cfae6d92e 100644 (file)
@@ -398,11 +398,7 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt )
     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 );
@@ -563,10 +559,7 @@ void vout_Close( vout_thread_t *p_vout )
     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 );
@@ -593,18 +586,7 @@ static void vout_Destructor( vlc_object_t * p_this )
     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 );
@@ -1166,13 +1148,7 @@ static void* RunThread( void *p_this )
             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
@@ -1200,30 +1176,8 @@ static void* RunThread( void *p_this )
          * 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
index 773008ee9e98b903e407a5ad7c6cfda91885175f..12a57302b5eb44584f9317227cc4b0086abba1bc 100644 (file)
@@ -31,6 +31,7 @@
 #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
@@ -88,14 +89,7 @@ struct vout_thread_sys_t
     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;
index c4ea45c9e18c6cbbbf24a9a563f83da12e6f7c47..f8e7db6fbdf38739c331e89b2a1ddaf6eff08d2a 100644 (file)
@@ -400,187 +400,6 @@ static int VoutSnapshotPip( vout_thread_t *p_vout, picture_t *p_pic )
     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
@@ -603,26 +422,7 @@ int vout_GetSnapshot( vout_thread_t *p_vout,
                       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" );
@@ -678,7 +478,7 @@ static void VoutSaveSnapshot( vout_thread_t *p_vout )
 
     if( !psz_path )
     {
-        psz_path = VoutSnapshotGetDefaultDirectory();
+        psz_path = vout_snapshot_GetDirectory();
         if( !psz_path )
         {
             msg_Err( p_vout, "no path specified for snapshots" );
@@ -686,11 +486,21 @@ static void VoutSaveSnapshot( vout_thread_t *p_vout )
         }
     }
 
+    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 );