1 /*****************************************************************************
2 * snapshot.c : vout internal snapshot
3 *****************************************************************************
4 * Copyright (C) 2009 Laurent Aimar
7 * Authors: Gildas Bazin <gbazin _AT_ videolan _DOT_ org>
8 * Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
29 #include <vlc_common.h>
30 #include <vlc_charset.h>
31 #include <vlc_strings.h>
32 #include <vlc_block.h>
37 #include <sys/types.h>
42 void vout_snapshot_Init(vout_snapshot_t *snap)
44 vlc_mutex_init(&snap->lock);
45 vlc_cond_init(&snap->wait);
47 snap->is_available = true;
48 snap->request_count = 0;
51 void vout_snapshot_Clean(vout_snapshot_t *snap)
53 picture_t *picture = snap->picture;
55 picture_t *next = picture->p_next;
56 picture_Release(picture);
60 vlc_cond_destroy(&snap->wait);
61 vlc_mutex_destroy(&snap->lock);
64 void vout_snapshot_End(vout_snapshot_t *snap)
66 vlc_mutex_lock(&snap->lock);
68 snap->is_available = false;
70 vlc_cond_broadcast(&snap->wait);
71 vlc_mutex_unlock(&snap->lock);
75 picture_t *vout_snapshot_Get(vout_snapshot_t *snap, mtime_t timeout)
77 vlc_mutex_lock(&snap->lock);
80 snap->request_count++;
83 const mtime_t deadline = mdate() + timeout;
84 while (snap->is_available && !snap->picture && mdate() < deadline)
85 vlc_cond_timedwait(&snap->wait, &snap->lock, deadline);
88 picture_t *picture = snap->picture;
90 snap->picture = picture->p_next;
91 else if (snap->request_count > 0)
92 snap->request_count--;
94 vlc_mutex_unlock(&snap->lock);
100 bool vout_snapshot_IsRequested(vout_snapshot_t *snap)
102 bool has_request = false;
103 if (!vlc_mutex_trylock(&snap->lock)) {
104 has_request = snap->request_count > 0;
105 vlc_mutex_unlock(&snap->lock);
109 void vout_snapshot_Set(vout_snapshot_t *snap,
110 const video_format_t *fmt,
111 const picture_t *picture)
114 fmt = &picture->format;
116 vlc_mutex_lock(&snap->lock);
117 while (snap->request_count > 0) {
118 picture_t *dup = picture_NewFromFormat(fmt);
122 picture_Copy(dup, picture);
124 dup->p_next = snap->picture;
126 snap->request_count--;
128 vlc_cond_broadcast(&snap->wait);
129 vlc_mutex_unlock(&snap->lock);
132 char *vout_snapshot_GetDirectory(void)
134 char *psz_path = NULL;
135 #if defined(__APPLE__) || defined(SYS_BEOS)
137 if (asprintf(&psz_path, "%s/Desktop",
138 config_GetHomeDir()) == -1)
141 #elif defined(WIN32) && !defined(UNDER_CE)
143 /* Get the My Pictures folder path */
144 char *p_mypicturesdir = NULL;
145 typedef HRESULT (WINAPI *SHGETFOLDERPATH)(HWND, int, HANDLE, DWORD,
147 #ifndef CSIDL_FLAG_CREATE
148 # define CSIDL_FLAG_CREATE 0x8000
150 #ifndef CSIDL_MYPICTURES
151 # define CSIDL_MYPICTURES 0x27
153 #ifndef SHGFP_TYPE_CURRENT
154 # define SHGFP_TYPE_CURRENT 0
157 HINSTANCE shfolder_dll;
158 SHGETFOLDERPATH SHGetFolderPath ;
160 /* load the shfolder dll to retrieve SHGetFolderPath */
161 if ((shfolder_dll = LoadLibrary(_T("SHFolder.dll"))) != NULL)
163 wchar_t wdir[PATH_MAX];
164 SHGetFolderPath = (void *)GetProcAddress(shfolder_dll,
165 _T("SHGetFolderPathW"));
166 if ((SHGetFolderPath != NULL)
167 && SUCCEEDED (SHGetFolderPath (NULL,
168 CSIDL_MYPICTURES | CSIDL_FLAG_CREATE,
169 NULL, SHGFP_TYPE_CURRENT,
171 p_mypicturesdir = FromWide (wdir);
173 FreeLibrary(shfolder_dll);
176 if (p_mypicturesdir == NULL)
177 psz_path = strdup(config_GetHomeDir());
179 psz_path = p_mypicturesdir;
183 /* XXX: This saves in the data directory. Shouldn't we try saving
184 * to psz_homedir/Desktop or something nicer ? */
185 char *psz_datadir = config_GetUserDataDir();
188 if (asprintf(&psz_path, "%s", psz_datadir) == -1)
197 int vout_snapshot_SaveImage(char **name, int *sequential,
198 const block_t *image,
199 vlc_object_t *object,
200 const vout_snapshot_save_cfg_t *cfg)
204 DIR *pathdir = utf8_opendir(cfg->path);
205 if (pathdir != NULL) {
206 /* The use specified a directory path */
212 prefix = str_format(object, cfg->prefix_fmt);
214 prefix = strdup("vlcsnap-");
219 if (cfg->is_sequential) {
220 for (int num = cfg->sequence; ; num++) {
223 if (asprintf(&filename, "%s" DIR_SEP "%s%05d.%s",
224 cfg->path, prefix, num, cfg->format) < 0) {
228 if (utf8_stat(filename, &st)) {
236 time_t lcurtime = time(NULL) ;
238 if (!localtime_r(&lcurtime, &curtime)) {
239 const unsigned int id = (image->i_pts / 100000) & 0xFFFFFF;
241 msg_Warn(object, "failed to get current time. Falling back to legacy snapshot naming");
243 if (asprintf(&filename, "%s" DIR_SEP "%s%u.%s",
244 cfg->path, prefix, id, cfg->format) < 0)
247 /* suffix with the last decimal digit in 10s of seconds resolution
249 const int id = (image->i_pts / (100*1000)) & 0xFF;
252 if (!strftime(buffer, sizeof(buffer), "%Y-%m-%d-%Hh%Mm%Ss", &curtime))
253 strcpy(buffer, "error");
255 if (asprintf(&filename, "%s" DIR_SEP "%s%s%1u.%s",
256 cfg->path, prefix, buffer, id, cfg->format) < 0)
262 /* The user specified a full path name (including file name) */
263 filename = str_format(object, cfg->path);
264 path_sanitize(filename);
270 /* Save the snapshot */
271 FILE *file = utf8_fopen(filename, "wb");
273 msg_Err(object, "Failed to open '%s'", filename);
277 if (fwrite(image->p_buffer, image->i_buffer, 1, file) != 1) {
278 msg_Err(object, "Failed to write to '%s'", filename);
294 msg_Err(object, "could not save snapshot");