]> git.sesse.net Git - vlc/blob - src/video_output/snapshot.c
sftp: change item b_net
[vlc] / src / video_output / snapshot.c
1 /*****************************************************************************
2  * snapshot.c : vout internal snapshot
3  *****************************************************************************
4  * Copyright (C) 2009 Laurent Aimar
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin _AT_ videolan _DOT_ org>
8  *          Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
9  *
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.
14  *
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.
19  *
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  *****************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <assert.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <sys/time.h>
33 #include <dirent.h>
34 #include <time.h>
35
36 #include <vlc_common.h>
37 #include <vlc_fs.h>
38 #include <vlc_strings.h>
39 #include <vlc_block.h>
40 #include <vlc_vout.h>
41
42 #include "snapshot.h"
43 #include "vout_internal.h"
44
45 /* */
46 void vout_snapshot_Init(vout_snapshot_t *snap)
47 {
48     vlc_mutex_init(&snap->lock);
49     vlc_cond_init(&snap->wait);
50
51     snap->is_available = true;
52     snap->request_count = 0;
53     snap->picture = NULL;
54 }
55 void vout_snapshot_Clean(vout_snapshot_t *snap)
56 {
57     picture_t *picture = snap->picture;
58     while (picture) {
59         picture_t *next = picture->p_next;
60         picture_Release(picture);
61         picture = next;
62     }
63
64     vlc_cond_destroy(&snap->wait);
65     vlc_mutex_destroy(&snap->lock);
66 }
67
68 void vout_snapshot_End(vout_snapshot_t *snap)
69 {
70     vlc_mutex_lock(&snap->lock);
71
72     snap->is_available = false;
73
74     vlc_cond_broadcast(&snap->wait);
75     vlc_mutex_unlock(&snap->lock);
76 }
77
78 /* */
79 picture_t *vout_snapshot_Get(vout_snapshot_t *snap, mtime_t timeout)
80 {
81     vlc_mutex_lock(&snap->lock);
82
83     /* */
84     snap->request_count++;
85
86     /* */
87     const mtime_t deadline = mdate() + timeout;
88     while (snap->is_available && !snap->picture && mdate() < deadline)
89         vlc_cond_timedwait(&snap->wait, &snap->lock, deadline);
90
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--;
97
98     vlc_mutex_unlock(&snap->lock);
99
100     return picture;
101 }
102
103 /* */
104 bool vout_snapshot_IsRequested(vout_snapshot_t *snap)
105 {
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);
110     }
111     return has_request;
112 }
113 void vout_snapshot_Set(vout_snapshot_t *snap,
114                        const video_format_t *fmt,
115                        const picture_t *picture)
116 {
117     if (!fmt)
118         fmt = &picture->format;
119
120     vlc_mutex_lock(&snap->lock);
121     while (snap->request_count > 0) {
122         picture_t *dup = picture_NewFromFormat(fmt);
123         if (!dup)
124             break;
125
126         picture_Copy(dup, picture);
127
128         dup->p_next = snap->picture;
129         snap->picture = dup;
130         snap->request_count--;
131     }
132     vlc_cond_broadcast(&snap->wait);
133     vlc_mutex_unlock(&snap->lock);
134 }
135 /* */
136 char *vout_snapshot_GetDirectory(void)
137 {
138     return config_GetUserDir(VLC_PICTURES_DIR);
139 }
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)
145 {
146     /* */
147     char *filename;
148     DIR *pathdir = vlc_opendir(cfg->path);
149     input_thread_t *input = (input_thread_t*)p_vout->p->input;
150     if (pathdir != NULL) {
151         /* The use specified a directory path */
152         closedir(pathdir);
153
154         /* */
155         char *prefix = NULL;
156         if (cfg->prefix_fmt)
157             prefix = str_format(input, cfg->prefix_fmt);
158         if (prefix)
159             filename_sanitize(prefix);
160         else {
161             prefix = strdup("vlcsnap-");
162             if (!prefix)
163                 goto error;
164         }
165
166         if (cfg->is_sequential) {
167             for (int num = cfg->sequence; ; num++) {
168                 struct stat st;
169
170                 if (asprintf(&filename, "%s" DIR_SEP "%s%05d.%s",
171                              cfg->path, prefix, num, cfg->format) < 0) {
172                     free(prefix);
173                     goto error;
174                 }
175                 if (vlc_stat(filename, &st)) {
176                     *sequential = num;
177                     break;
178                 }
179                 free(filename);
180             }
181         } else {
182             struct timeval tv;
183             struct tm curtime;
184             char buffer[128];
185
186             gettimeofday(&tv, NULL);
187             if (localtime_r(&tv.tv_sec, &curtime) == NULL)
188                 gmtime_r(&tv.tv_sec, &curtime);
189             if (strftime(buffer, sizeof(buffer), "%Y-%m-%d-%Hh%Mm%Ss",
190                          &curtime) == 0)
191                 strcpy(buffer, "error");
192
193             if (asprintf(&filename, "%s" DIR_SEP "%s%s%03u.%s",
194                          cfg->path, prefix, buffer,
195                          (unsigned)tv.tv_usec / 1000, cfg->format) < 0)
196                 filename = NULL;
197         }
198         free(prefix);
199     } else {
200         /* The user specified a full path name (including file name) */
201         filename = str_format(input, cfg->path);
202         path_sanitize(filename);
203     }
204
205     if (!filename)
206         goto error;
207
208     /* Save the snapshot */
209     FILE *file = vlc_fopen(filename, "wb");
210     if (!file) {
211         msg_Err(p_vout, "Failed to open '%s'", filename);
212         free(filename);
213         goto error;
214     }
215     if (fwrite(image->p_buffer, image->i_buffer, 1, file) != 1) {
216         msg_Err(p_vout, "Failed to write to '%s'", filename);
217         fclose(file);
218         free(filename);
219         goto error;
220     }
221     fclose(file);
222
223     /* */
224     if (name)
225         *name = filename;
226     else
227         free(filename);
228
229     return VLC_SUCCESS;
230
231 error:
232     msg_Err(p_vout, "could not save snapshot");
233     return VLC_EGENERIC;
234 }
235