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 return config_GetUserDir(VLC_PICTURES_DIR
);
137 int vout_snapshot_SaveImage(char **name
, int *sequential
,
138 const block_t
*image
,
139 vlc_object_t
*object
,
140 const vout_snapshot_save_cfg_t
*cfg
)
144 DIR *pathdir
= utf8_opendir(cfg
->path
);
145 if (pathdir
!= NULL
) {
146 /* The use specified a directory path */
152 prefix
= str_format(object
, cfg
->prefix_fmt
);
154 prefix
= strdup("vlcsnap-");
159 if (cfg
->is_sequential
) {
160 for (int num
= cfg
->sequence
; ; num
++) {
163 if (asprintf(&filename
, "%s" DIR_SEP
"%s%05d.%s",
164 cfg
->path
, prefix
, num
, cfg
->format
) < 0) {
168 if (utf8_stat(filename
, &st
)) {
176 time_t lcurtime
= time(NULL
) ;
178 if (!localtime_r(&lcurtime
, &curtime
)) {
179 const unsigned int id
= (image
->i_pts
/ 100000) & 0xFFFFFF;
181 msg_Warn(object
, "failed to get current time. Falling back to legacy snapshot naming");
183 if (asprintf(&filename
, "%s" DIR_SEP
"%s%u.%s",
184 cfg
->path
, prefix
, id
, cfg
->format
) < 0)
187 /* suffix with the last decimal digit in 10s of seconds resolution
189 const int id
= (image
->i_pts
/ (100*1000)) & 0xFF;
192 if (!strftime(buffer
, sizeof(buffer
), "%Y-%m-%d-%Hh%Mm%Ss", &curtime
))
193 strcpy(buffer
, "error");
195 if (asprintf(&filename
, "%s" DIR_SEP
"%s%s%1u.%s",
196 cfg
->path
, prefix
, buffer
, id
, cfg
->format
) < 0)
202 /* The user specified a full path name (including file name) */
203 filename
= str_format(object
, cfg
->path
);
204 path_sanitize(filename
);
210 /* Save the snapshot */
211 FILE *file
= utf8_fopen(filename
, "wb");
213 msg_Err(object
, "Failed to open '%s'", filename
);
217 if (fwrite(image
->p_buffer
, image
->i_buffer
, 1, file
) != 1) {
218 msg_Err(object
, "Failed to write to '%s'", filename
);
234 msg_Err(object
, "could not save snapshot");