snapshot.c 6.21 KB
Newer Older
1
2
3
4
5
6
7
8
9
/*****************************************************************************
 * 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>
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
10
11
12
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
13
14
15
16
 * (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
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
17
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
19
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
20
21
22
 * You should have received a copy of the GNU Lesser 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.
23
24
25
26
27
28
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

29
30
#include <sys/stat.h>
#include <sys/types.h>
31
#include <sys/time.h>
32
33
34
#include <dirent.h>
#include <time.h>

35
#include <vlc_common.h>
36
#include <vlc_fs.h>
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <vlc_strings.h>
#include <vlc_block.h>

#include "snapshot.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)
{
135
    return config_GetUserDir(VLC_PICTURES_DIR);
136
137
138
139
140
141
142
143
144
}
/* */
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;
145
    DIR *pathdir = vlc_opendir(cfg->path);
146
147
148
149
150
151
152
    if (pathdir != NULL) {
        /* The use specified a directory path */
        closedir(pathdir);

        /* */
        char *prefix = NULL;
        if (cfg->prefix_fmt)
153
            prefix = str_format_time(cfg->prefix_fmt);
154
155
        if (prefix)
            filename_sanitize(prefix);
156
        else {
157
158
159
160
161
162
163
164
165
166
167
168
169
170
            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;
                }
171
                if (vlc_stat(filename, &st)) {
172
173
174
175
176
177
                    *sequential = num;
                    break;
                }
                free(filename);
            }
        } else {
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
            struct timeval tv;
            struct tm curtime;
            char buffer[128];

            gettimeofday(&tv, NULL);
            if (localtime_r(&tv.tv_sec, &curtime) == NULL)
                gmtime_r(&tv.tv_sec, &curtime);
            if (strftime(buffer, sizeof(buffer), "%Y-%m-%d-%Hh%Mm%Ss",
                         &curtime) == 0)
                strcpy(buffer, "error");

            if (asprintf(&filename, "%s" DIR_SEP "%s%s%03lu.%s",
                         cfg->path, prefix, buffer, tv.tv_usec / 1000,
                         cfg->format) < 0)
                filename = NULL;
193
194
195
196
        }
        free(prefix);
    } else {
        /* The user specified a full path name (including file name) */
197
        filename = str_format_time(cfg->path);
198
199
200
201
202
203
204
        path_sanitize(filename);
    }

    if (!filename)
        goto error;

    /* Save the snapshot */
205
    FILE *file = vlc_fopen(filename, "wb");
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
    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;
}