]> git.sesse.net Git - vlc/blob - modules/video_output/snapshot.c
Use var_InheritString for --decklink-video-connection.
[vlc] / modules / video_output / snapshot.c
1 /*****************************************************************************
2  * snapshot.c : snapshot plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2002 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Olivier Aubert <oaubert@lisi.univ-lyon1.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * This module is a pseudo video output that offers the possibility to
26  * keep a cache of low-res snapshots.
27  * The snapshot structure is defined in include/snapshot.h
28  * In order to access the current snapshot cache, object variables are used:
29  *   vout-snapshot-list-pointer : the pointer on the first element in the list
30  *   vout-snapshot-datasize     : size of a snapshot
31  *                           (also available in snapshot_t->i_datasize)
32  *   vout-snapshot-cache-size   : size of the cache list
33  *
34  * It is used for the moment by the CORBA module and a specialized
35  * python-vlc binding.
36  *****************************************************************************/
37
38 /*****************************************************************************
39  * Preamble
40  *****************************************************************************/
41
42 #ifdef HAVE_CONFIG_H
43 # include "config.h"
44 #endif
45
46 #include <vlc_common.h>
47 #include <vlc_plugin.h>
48 #include <vlc_vout_display.h>
49 #include <vlc_picture_pool.h>
50 #include <vlc_input.h>
51
52 /*****************************************************************************
53  * Module descriptor
54  *****************************************************************************/
55 #define WIDTH_TEXT N_("Snapshot width")
56 #define WIDTH_LONGTEXT N_("Width of the snapshot image.")
57
58 #define HEIGHT_TEXT N_("Snapshot height")
59 #define HEIGHT_LONGTEXT N_("Height of the snapshot image.")
60
61 #define CHROMA_TEXT N_("Chroma")
62 #define CHROMA_LONGTEXT N_("Output chroma for the snapshot image " \
63                             "(a 4 character string, like \"RV32\").")
64
65 #define CACHE_TEXT N_("Cache size (number of images)")
66 #define CACHE_LONGTEXT N_("Snapshot cache size (number of images to keep).")
67
68 static int  Open (vlc_object_t *);
69 static void Close(vlc_object_t *);
70
71 vlc_module_begin ()
72     set_description(N_("Snapshot output"))
73     set_shortname(N_("Snapshot"))
74
75     set_category(CAT_VIDEO)
76     set_subcategory(SUBCAT_VIDEO_VOUT)
77     set_capability("vout display", 0)
78
79     add_integer("vout-snapshot-width", 320, NULL, WIDTH_TEXT, WIDTH_LONGTEXT, false)
80     add_integer("vout-snapshot-height", 200, NULL, HEIGHT_TEXT, HEIGHT_LONGTEXT, false)
81     add_string("vout-snapshot-chroma", "RV32", NULL, CHROMA_TEXT, CHROMA_LONGTEXT, true)
82         add_deprecated_alias("snapshot-chroma")
83     add_integer("vout-snapshot-cache-size", 50, NULL, CACHE_TEXT, CACHE_LONGTEXT, true)
84         add_deprecated_alias("snapshot-cache-size")
85
86     set_callbacks(Open, Close)
87 vlc_module_end ()
88
89
90 /*****************************************************************************
91  * Local prototypes
92  *****************************************************************************/
93 static picture_pool_t *Pool  (vout_display_t *, unsigned);
94 static void           Display(vout_display_t *, picture_t *);
95 static int            Control(vout_display_t *, int, va_list);
96 static void           Manage (vout_display_t *);
97
98 typedef struct {
99   mtime_t date;         /* Presentation time */
100   int     width;          /* In pixels */
101   int     height;         /* In pixels */
102   int     data_size;    /* In bytes */
103   uint8_t *data;        /* Data area */
104 } snapshot_t;
105
106 struct vout_display_sys_t {
107     int            count;  /* Size of the cache */
108     snapshot_t     **snapshot;      /* List of available snapshots */
109     int            index;           /* Index of the next available list member */
110     int            data_size;       /* Size of an image */
111     picture_pool_t *pool;
112
113     input_thread_t *input;          /* The input thread */
114 };
115
116 /* */
117 static int Open(vlc_object_t *object)
118 {
119     vout_display_t *vd = (vout_display_t *)object;
120     vout_display_sys_t *sys;
121
122     /* Allocate instance and initialize some members */
123     vd->sys = sys = malloc(sizeof(*sys));
124     if (!sys)
125         return VLC_ENOMEM;
126
127     char *chroma_fmt = var_InheritString(vd, "vout-snapshot-chroma");
128     const vlc_fourcc_t chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, chroma_fmt);
129     free(chroma_fmt);
130
131     if (!chroma) {
132         msg_Err(vd, "snapshot-chroma should be 4 characters long");
133         free(sys);
134         return VLC_EGENERIC;
135     }
136
137     const int width  = var_InheritInteger(vd, "vout-snapshot-width");
138     const int height = var_InheritInteger(vd, "vout-snapshot-height");
139     if (width <= 0 || height <= 0) {
140         msg_Err(vd, "snapshot-width/height are invalid");
141         free(sys);
142         return VLC_EGENERIC;
143     }
144
145     /* */
146     video_format_t fmt = vd->fmt;
147     fmt.i_chroma = chroma;
148     fmt.i_width  = width;
149     fmt.i_height = height;
150     fmt.i_rmask  = 0;
151     fmt.i_gmask  = 0;
152     fmt.i_bmask  = 0;
153     video_format_FixRgb(&fmt);
154
155     picture_t *picture = picture_NewFromFormat(&fmt);
156     if (!picture) {
157         free(sys);
158         return VLC_EGENERIC;
159     }
160     sys->pool = picture_pool_New(1, &picture);
161     if (!sys->pool) {
162         picture_Release(picture);
163         free(sys);
164         return VLC_EGENERIC;
165     }
166     sys->data_size = 0;
167     for (int i = 0; i < picture->i_planes; i++) {
168         const plane_t *plane = &picture->p[i];
169         sys->data_size += plane->i_visible_pitch *
170                           plane->i_visible_lines *
171                           plane->i_pixel_pitch;
172     }
173
174     sys->index = 0;
175     sys->count = var_InheritInteger(vd, "vout-snapshot-cache-size");
176
177     /* FIXME following code leaks in case of error */
178
179     if (sys->count < 2) {
180         msg_Err(vd, "vout-snapshot-cache-size must be at least 1.");
181         return VLC_EGENERIC;
182     }
183
184     sys->snapshot = calloc(sys->count, sizeof(*sys->snapshot));
185
186     if (!sys->snapshot)
187         return VLC_ENOMEM;
188
189     /* Initialize the structures for the circular buffer */
190     for (int index = 0; index < sys->count; index++) {
191         snapshot_t *snapshot = malloc(sizeof(*snapshot));
192
193         if (!snapshot)
194             return VLC_ENOMEM;
195
196         snapshot->date      = VLC_TS_INVALID;
197         snapshot->width     = fmt.i_width;
198         snapshot->height    = fmt.i_height;
199         snapshot->data_size = sys->data_size;
200         snapshot->data      = malloc(sys->data_size);
201         if (!snapshot->data) {
202             free(snapshot);
203             return VLC_ENOMEM;
204         }
205         sys->snapshot[index] = snapshot;
206     }
207
208     /* */
209     var_Create(vd, "vout-snapshot-width", VLC_VAR_INTEGER);
210     var_Create(vd, "vout-snapshot-height", VLC_VAR_INTEGER);
211     var_Create(vd, "vout-snapshot-datasize", VLC_VAR_INTEGER);
212     var_Create(vd, "vout-snapshot-cache-size", VLC_VAR_INTEGER);
213     var_Create(vd, "vout-snapshot-list-pointer", VLC_VAR_ADDRESS);
214
215     var_SetInteger(vd, "vout-snapshot-width", fmt.i_width);
216     var_SetInteger(vd, "vout-snapshot-height", fmt.i_height);
217     var_SetInteger(vd, "vout-snapshot-datasize", sys->data_size);
218     var_SetInteger(vd, "vout-snapshot-cache-size", sys->count);
219     var_SetAddress(vd, "vout-snapshot-list-pointer", sys->snapshot);
220
221     /* Get the p_input pointer (to access video times) */
222     sys->input = vlc_object_find(vd, VLC_OBJECT_INPUT, FIND_PARENT);
223     if (!sys->input)
224         return VLC_ENOOBJ;
225
226     if (var_Create(sys->input, "vout-snapshot-id", VLC_VAR_ADDRESS)) {
227         msg_Err(vd, "Cannot create vout-snapshot-id variable in p_input(%p).",
228                  sys->input);
229         return VLC_EGENERIC;
230     }
231
232     /* Register the snapshot vout module at the input level */
233     if (var_SetAddress(sys->input, "vout-snapshot-id", vd)) {
234         msg_Err(vd, "Cannot register vout-snapshot-id in p_input(%p).",
235                  sys->input);
236         return VLC_EGENERIC;
237     }
238
239     /* */
240     vout_display_info_t info = vd->info;
241     info.has_hide_mouse = true;
242
243     /* */
244     vd->fmt     = fmt;
245     vd->info    = info;
246     vd->pool    = Pool;
247     vd->prepare = NULL;
248     vd->display = Display;
249     vd->control = Control;
250     vd->manage  = Manage;
251
252     /* */
253     vout_display_SendEventFullscreen(vd, false);
254     return VLC_SUCCESS;
255 }
256
257 /* */
258 static void Close(vlc_object_t *object)
259 {
260     vout_display_t *vd = (vout_display_t *)object;
261     vout_display_sys_t *sys = vd->sys;
262
263     var_Destroy(sys->input, "vout-snapshot-id");
264
265     vlc_object_release(sys->input);
266     var_Destroy(vd, "vout-snapshot-width");
267     var_Destroy(vd, "vout-snapshot-height");
268     var_Destroy(vd, "vout-snapshot-datasize");
269
270     for (int index = 0 ; index < sys->count; index++) {
271         free(sys->snapshot[index]->data);
272         free(sys->snapshot[index]);
273     }
274     free(sys->snapshot);
275
276     picture_pool_Delete(sys->pool);
277
278     free(sys);
279 }
280
281 /*****************************************************************************
282  *
283  *****************************************************************************/
284 static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
285 {
286     VLC_UNUSED(count);
287     return vd->sys->pool;
288 }
289
290 /* Return the position in ms from the start of the movie */
291 static mtime_t snapshot_GetMovietime(vout_display_t *vd)
292 {
293     vout_display_sys_t *sys = vd->sys;
294
295     if (!sys->input)
296         return VLC_TS_INVALID;
297     return var_GetTime(sys->input, "time") / 1000;
298 }
299
300 static void Display(vout_display_t *vd, picture_t *picture)
301 {
302     vout_display_sys_t *sys = vd->sys;
303
304     const int index = sys->index;
305
306     /* FIXME a lock or an event of some sort would be needed to protect
307      * the content of sys->snapshot vs external users */
308     uint8_t *p_dst = sys->snapshot[index]->data;
309     for (int i = 0; i < picture->i_planes; i++) {
310         const plane_t *plane = &picture->p[i];
311         for( int y = 0; y < plane->i_visible_lines; y++) {
312             vlc_memcpy(p_dst, &plane->p_pixels[y*plane->i_pitch],
313                        plane->i_visible_pitch);
314             p_dst += plane->i_visible_pitch;
315         }
316     }
317     sys->snapshot[index]->date = snapshot_GetMovietime(vd);
318
319     sys->index = (index + 1) % sys->count;
320 }
321
322 static int Control(vout_display_t *vd, int query, va_list args)
323 {
324     VLC_UNUSED(vd);
325     switch (query) {
326     case VOUT_DISPLAY_CHANGE_FULLSCREEN: {
327         const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t *);
328         if (cfg->is_fullscreen)
329             return VLC_EGENERIC;
330         return VLC_SUCCESS;
331     }
332     default:
333         return VLC_EGENERIC;
334     }
335 }
336
337 static void Manage (vout_display_t *vd)
338 {
339     VLC_UNUSED(vd);
340 }
341