strings: add an input_item_t arg to vlc_strfinput()
[vlc.git] / src / video_output / snapshot.c
blob8d32ddad950da0b229761f8acff19eafae63f34c
1 /*****************************************************************************
2 * snapshot.c : vout internal snapshot
3 *****************************************************************************
4 * Copyright (C) 2009 Laurent Aimar
5 * $Id$
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 it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
29 #include <assert.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <dirent.h>
33 #include <time.h>
35 #include <vlc_common.h>
36 #include <vlc_fs.h>
37 #include <vlc_strings.h>
38 #include <vlc_block.h>
39 #include <vlc_vout.h>
41 #include "snapshot.h"
42 #include "vout_internal.h"
44 /* */
45 void vout_snapshot_Init(vout_snapshot_t *snap)
47 vlc_mutex_init(&snap->lock);
48 vlc_cond_init(&snap->wait);
50 snap->is_available = true;
51 snap->request_count = 0;
52 snap->picture = NULL;
54 void vout_snapshot_Clean(vout_snapshot_t *snap)
56 picture_t *picture = snap->picture;
57 while (picture) {
58 picture_t *next = picture->p_next;
59 picture_Release(picture);
60 picture = next;
63 vlc_cond_destroy(&snap->wait);
64 vlc_mutex_destroy(&snap->lock);
67 void vout_snapshot_End(vout_snapshot_t *snap)
69 vlc_mutex_lock(&snap->lock);
71 snap->is_available = false;
73 vlc_cond_broadcast(&snap->wait);
74 vlc_mutex_unlock(&snap->lock);
77 /* */
78 picture_t *vout_snapshot_Get(vout_snapshot_t *snap, vlc_tick_t timeout)
80 const vlc_tick_t deadline = vlc_tick_now() + timeout;
82 vlc_mutex_lock(&snap->lock);
84 /* */
85 snap->request_count++;
87 /* */
88 while (snap->is_available && !snap->picture &&
89 vlc_cond_timedwait(&snap->wait, &snap->lock, deadline) == 0);
91 /* */
92 picture_t *picture = snap->picture;
93 if (picture)
94 snap->picture = picture->p_next;
95 else if (snap->request_count > 0)
96 snap->request_count--;
98 vlc_mutex_unlock(&snap->lock);
100 return picture;
103 /* */
104 bool vout_snapshot_IsRequested(vout_snapshot_t *snap)
106 bool has_request = false;
107 if (!vlc_mutex_trylock(&snap->lock)) {
108 has_request = snap->request_count > 0;
109 vlc_mutex_unlock(&snap->lock);
111 return has_request;
113 void vout_snapshot_Set(vout_snapshot_t *snap,
114 const video_format_t *fmt,
115 picture_t *picture)
117 if (!fmt)
118 fmt = &picture->format;
120 vlc_mutex_lock(&snap->lock);
121 while (snap->request_count > 0) {
122 picture_t *dup = picture_Clone(picture);
123 if (!dup)
124 break;
126 video_format_CopyCrop( &dup->format, fmt );
128 dup->p_next = snap->picture;
129 snap->picture = dup;
130 snap->request_count--;
132 vlc_cond_broadcast(&snap->wait);
133 vlc_mutex_unlock(&snap->lock);
135 /* */
136 char *vout_snapshot_GetDirectory(void)
138 return config_GetUserDir(VLC_PICTURES_DIR);
140 /* */
141 int vout_snapshot_SaveImage(char **name, int *sequential,
142 const block_t *image,
143 vout_thread_t *p_vout,
144 const vout_snapshot_save_cfg_t *cfg)
146 /* */
147 char *filename;
148 input_thread_t *input = (input_thread_t*)p_vout->p->input;
150 /* */
151 char *prefix = NULL;
152 if (cfg->prefix_fmt)
153 prefix = str_format(input, NULL, cfg->prefix_fmt);
154 if (prefix)
155 filename_sanitize(prefix);
156 else {
157 prefix = strdup("vlcsnap-");
158 if (prefix == NULL)
159 goto error;
162 struct stat st;
163 bool b_is_folder = false;
165 if ( vlc_stat( cfg->path, &st ) == 0 )
166 b_is_folder = S_ISDIR( st.st_mode );
167 if ( b_is_folder ) {
168 if (cfg->is_sequential) {
169 for (int num = cfg->sequence; ; num++) {
170 if (asprintf(&filename, "%s" DIR_SEP "%s%05d.%s",
171 cfg->path, prefix, num, cfg->format) < 0) {
172 free(prefix);
173 goto error;
175 if (vlc_stat(filename, &st)) {
176 *sequential = num;
177 break;
179 free(filename);
181 } else {
182 struct timespec ts;
183 struct tm curtime;
184 char buffer[128];
186 timespec_get(&ts, TIME_UTC);
187 if (localtime_r(&ts.tv_sec, &curtime) == NULL)
188 gmtime_r(&ts.tv_sec, &curtime);
189 if (strftime(buffer, sizeof(buffer), "%Y-%m-%d-%Hh%Mm%Ss",
190 &curtime) == 0)
191 strcpy(buffer, "error");
193 if (asprintf(&filename, "%s" DIR_SEP "%s%s%03lu.%s",
194 cfg->path, prefix, buffer, ts.tv_nsec / 1000000,
195 cfg->format) < 0)
196 filename = NULL;
198 } else {
199 filename = strdup( cfg->path );
201 free(prefix);
203 if (!filename)
204 goto error;
206 /* Save the snapshot */
207 FILE *file = vlc_fopen(filename, "wb");
208 if (!file) {
209 msg_Err(p_vout, "Failed to open '%s'", filename);
210 free(filename);
211 goto error;
213 if (fwrite(image->p_buffer, image->i_buffer, 1, file) != 1) {
214 msg_Err(p_vout, "Failed to write to '%s'", filename);
215 fclose(file);
216 free(filename);
217 goto error;
219 fclose(file);
221 /* */
222 if (name)
223 *name = filename;
224 else
225 free(filename);
227 return VLC_SUCCESS;
229 error:
230 msg_Err(p_vout, "could not save snapshot");
231 return VLC_EGENERIC;