1 /*****************************************************************************
2 * scene.c : scene video filter (based on modules/video_output/image.c)
3 *****************************************************************************
4 * Copyright (C) 2004-2008 VLC authors and VideoLAN
7 * Authors: Jean-Paul Saman <jpsaman@videolan.org>
8 * Clément Stenac <zorglub@videolan.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 /*****************************************************************************
27 *****************************************************************************/
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
38 #include <vlc_filter.h>
39 #include <vlc_picture.h>
40 #include "filter_picture.h"
41 #include <vlc_image.h>
42 #include <vlc_strings.h>
45 /*****************************************************************************
47 *****************************************************************************/
48 static int Create ( vlc_object_t
* );
49 static void Destroy ( vlc_object_t
* );
51 static picture_t
*Filter( filter_t
*, picture_t
* );
53 static void SnapshotRatio( filter_t
*p_filter
, picture_t
*p_pic
);
54 static void SavePicture( filter_t
*, picture_t
* );
56 /*****************************************************************************
58 *****************************************************************************/
59 #define FORMAT_TEXT N_( "Image format" )
60 #define FORMAT_LONGTEXT N_( "Format of the output images (png, jpeg, ...)." )
62 #define WIDTH_TEXT N_( "Image width" )
63 #define WIDTH_LONGTEXT N_( "You can enforce the image width. By default " \
64 "(-1) VLC will adapt to the video " \
67 #define HEIGHT_TEXT N_( "Image height" )
68 #define HEIGHT_LONGTEXT N_( "You can enforce the image height. By default " \
69 "(-1) VLC will adapt to the video " \
72 #define RATIO_TEXT N_( "Recording ratio" )
73 #define RATIO_LONGTEXT N_( "Ratio of images to record. "\
74 "3 means that one image out of three is recorded." )
76 #define PREFIX_TEXT N_( "Filename prefix" )
77 #define PREFIX_LONGTEXT N_( "Prefix of the output images filenames. Output " \
78 "filenames will have the \"prefixNUMBER.format\" "\
79 "form if replace is not true." )
81 #define PATH_TEXT N_( "Directory path prefix" )
82 #define PATH_LONGTEXT N_( "Directory path where images files should be saved. " \
83 "If not set, then images will be automatically saved in " \
86 #define REPLACE_TEXT N_( "Always write to the same file" )
87 #define REPLACE_LONGTEXT N_( "Always write to the same file instead of " \
88 "creating one file per image. In this case, " \
89 "the number is not appended to the filename." )
91 #define SCENE_HELP N_("Send your video to picture files")
92 #define CFG_PREFIX "scene-"
95 set_shortname( N_( "Scene filter" ) )
96 set_description( N_( "Scene video filter" ) )
98 set_category( CAT_VIDEO
)
99 set_subcategory( SUBCAT_VIDEO_VFILTER
)
100 set_capability( "video filter", 0 )
102 /* General options */
103 add_string( CFG_PREFIX
"format", "png",
104 FORMAT_TEXT
, FORMAT_LONGTEXT
, false )
105 add_integer( CFG_PREFIX
"width", -1,
106 WIDTH_TEXT
, WIDTH_LONGTEXT
, true )
107 add_integer( CFG_PREFIX
"height", -1,
108 HEIGHT_TEXT
, HEIGHT_LONGTEXT
, true )
109 add_string( CFG_PREFIX
"prefix", "scene",
110 PREFIX_TEXT
, PREFIX_LONGTEXT
, false )
111 add_string( CFG_PREFIX
"path", NULL
,
112 PATH_TEXT
, PATH_LONGTEXT
, false )
113 add_bool( CFG_PREFIX
"replace", false,
114 REPLACE_TEXT
, REPLACE_LONGTEXT
, false )
116 /* Snapshot method */
117 add_integer_with_range( CFG_PREFIX
"ratio", 50, 1, INT_MAX
,
118 RATIO_TEXT
, RATIO_LONGTEXT
, false )
120 set_callbacks( Create
, Destroy
)
123 static const char *const ppsz_vfilter_options
[] = {
124 "format", "width", "height", "ratio", "prefix", "path", "replace", NULL
127 typedef struct scene_t
{
129 video_format_t format
;
132 /*****************************************************************************
133 * filter_sys_t: private data
134 *****************************************************************************/
137 image_handler_t
*p_image
;
143 vlc_fourcc_t i_format
;
146 int32_t i_ratio
; /* save every n-th frame */
147 int32_t i_frames
; /* frames count */
151 /*****************************************************************************
152 * Create: initialize and set pf_video_filter()
153 *****************************************************************************/
154 static int Create( vlc_object_t
*p_this
)
156 filter_t
*p_filter
= (filter_t
*)p_this
;
159 const vlc_chroma_description_t
*p_chroma
=
160 vlc_fourcc_GetChromaDescription( p_filter
->fmt_in
.video
.i_chroma
);
161 if( p_chroma
== NULL
|| p_chroma
->plane_count
== 0 )
164 config_ChainParse( p_filter
, CFG_PREFIX
, ppsz_vfilter_options
,
167 p_filter
->p_sys
= p_sys
= calloc( 1, sizeof( filter_sys_t
) );
168 if( p_filter
->p_sys
== NULL
)
171 p_sys
->p_image
= image_HandlerCreate( p_this
);
172 if( !p_sys
->p_image
)
174 msg_Err( p_this
, "Couldn't get handle to image conversion routines." );
179 p_sys
->psz_format
= var_CreateGetString( p_this
, CFG_PREFIX
"format" );
180 p_sys
->i_format
= image_Type2Fourcc( p_sys
->psz_format
);
181 if( !p_sys
->i_format
)
183 msg_Err( p_filter
, "Could not find FOURCC for image type '%s'",
185 image_HandlerDelete( p_sys
->p_image
);
186 free( p_sys
->psz_format
);
190 p_sys
->i_width
= var_CreateGetInteger( p_this
, CFG_PREFIX
"width" );
191 p_sys
->i_height
= var_CreateGetInteger( p_this
, CFG_PREFIX
"height" );
192 p_sys
->i_ratio
= var_CreateGetInteger( p_this
, CFG_PREFIX
"ratio" );
193 if( p_sys
->i_ratio
<= 0)
195 p_sys
->b_replace
= var_CreateGetBool( p_this
, CFG_PREFIX
"replace" );
196 p_sys
->psz_prefix
= var_CreateGetString( p_this
, CFG_PREFIX
"prefix" );
197 p_sys
->psz_path
= var_GetNonEmptyString( p_this
, CFG_PREFIX
"path" );
198 if( p_sys
->psz_path
== NULL
)
199 p_sys
->psz_path
= config_GetUserDir( VLC_PICTURES_DIR
);
201 p_filter
->pf_video_filter
= Filter
;
206 /*****************************************************************************
207 * Destroy: destroy video filter method
208 *****************************************************************************/
209 static void Destroy( vlc_object_t
*p_this
)
211 filter_t
*p_filter
= (filter_t
*)p_this
;
212 filter_sys_t
*p_sys
= (filter_sys_t
*) p_filter
->p_sys
;
214 image_HandlerDelete( p_sys
->p_image
);
216 if( p_sys
->scene
.p_pic
)
217 picture_Release( p_sys
->scene
.p_pic
);
218 free( p_sys
->psz_format
);
219 free( p_sys
->psz_prefix
);
220 free( p_sys
->psz_path
);
224 /*****************************************************************************
225 * Filter: Apply filtering logic to picture.
226 *****************************************************************************/
227 static picture_t
*Filter( filter_t
*p_filter
, picture_t
*p_pic
)
229 /* TODO: think of some funky algorithm to detect scene changes. */
230 SnapshotRatio( p_filter
, p_pic
);
234 static void SnapshotRatio( filter_t
*p_filter
, picture_t
*p_pic
)
236 filter_sys_t
*p_sys
= (filter_sys_t
*)p_filter
->p_sys
;
240 if( p_sys
->i_frames
% p_sys
->i_ratio
!= 0 )
247 if( p_sys
->scene
.p_pic
)
248 picture_Release( p_sys
->scene
.p_pic
);
250 if( (p_sys
->i_width
<= 0) && (p_sys
->i_height
> 0) )
252 p_sys
->i_width
= (p_pic
->format
.i_width
* p_sys
->i_height
) / p_pic
->format
.i_height
;
254 else if( (p_sys
->i_height
<= 0) && (p_sys
->i_width
> 0) )
256 p_sys
->i_height
= (p_pic
->format
.i_height
* p_sys
->i_width
) / p_pic
->format
.i_width
;
258 else if( (p_sys
->i_width
<= 0) && (p_sys
->i_height
<= 0) )
260 p_sys
->i_width
= p_pic
->format
.i_width
;
261 p_sys
->i_height
= p_pic
->format
.i_height
;
264 p_sys
->scene
.p_pic
= picture_NewFromFormat( &p_pic
->format
);
265 if( p_sys
->scene
.p_pic
)
267 picture_Copy( p_sys
->scene
.p_pic
, p_pic
);
268 SavePicture( p_filter
, p_sys
->scene
.p_pic
);
272 /*****************************************************************************
273 * Save Picture to disk
274 *****************************************************************************/
275 static void SavePicture( filter_t
*p_filter
, picture_t
*p_pic
)
277 filter_sys_t
*p_sys
= (filter_sys_t
*)p_filter
->p_sys
;
278 video_format_t fmt_in
, fmt_out
;
279 char *psz_filename
= NULL
;
280 char *psz_temp
= NULL
;
283 memset( &fmt_out
, 0, sizeof(video_format_t
) );
285 /* Save snapshot psz_format to a memory zone */
286 fmt_in
= p_pic
->format
;
287 fmt_out
.i_sar_num
= fmt_out
.i_sar_den
= 1;
288 fmt_out
.i_width
= p_sys
->i_width
;
289 fmt_out
.i_height
= p_sys
->i_height
;
290 fmt_out
.i_chroma
= p_sys
->i_format
;
293 * Save the snapshot to a temporary file and
294 * switch it to the real name afterwards.
296 if( p_sys
->b_replace
)
297 i_ret
= asprintf( &psz_filename
, "%s" DIR_SEP
"%s.%s",
298 p_sys
->psz_path
, p_sys
->psz_prefix
,
301 i_ret
= asprintf( &psz_filename
, "%s" DIR_SEP
"%s%05d.%s",
302 p_sys
->psz_path
, p_sys
->psz_prefix
,
303 p_sys
->i_frames
, p_sys
->psz_format
);
307 msg_Err( p_filter
, "could not create snapshot %s", psz_filename
);
311 i_ret
= asprintf( &psz_temp
, "%s.swp", psz_filename
);
314 msg_Err( p_filter
, "could not create snapshot temporarily file %s", psz_temp
);
319 i_ret
= image_WriteUrl( p_sys
->p_image
, p_pic
, &fmt_in
, &fmt_out
,
321 if( i_ret
!= VLC_SUCCESS
)
323 msg_Err( p_filter
, "could not create snapshot %s", psz_temp
);
327 /* switch to the final destination */
328 #if defined (_WIN32) || defined(__OS2__)
329 vlc_unlink( psz_filename
);
331 i_ret
= vlc_rename( psz_temp
, psz_filename
);
334 msg_Err( p_filter
, "could not rename snapshot %s: %s",
335 psz_filename
, vlc_strerror_c(errno
) );
342 free( psz_filename
);