11 #include <sys/types.h>
17 #include "img_format.h"
22 #include "libswscale/swscale.h"
24 #ifdef USE_LIBAVCODEC_SO
25 #include <ffmpeg/avcodec.h>
27 #include "libavcodec/avcodec.h"
33 /// shot stores current screenshot mode:
34 /// 0: don't take screenshots
35 /// 1: take single screenshot, reset to 0 afterwards
36 /// 2: take screenshots of each frame
37 int shot
, store_slices
;
40 struct SwsContext
*ctx
;
41 AVCodecContext
*avctx
;
46 //===========================================================================//
48 static int config(struct vf_instance_s
* vf
,
49 int width
, int height
, int d_width
, int d_height
,
50 unsigned int flags
, unsigned int outfmt
)
52 vf
->priv
->ctx
=sws_getContextFromCmdLine(width
, height
, outfmt
,
53 d_width
, d_height
, IMGFMT_RGB24
);
55 vf
->priv
->outbuffer_size
= d_width
* d_height
* 3 * 2;
56 vf
->priv
->outbuffer
= realloc(vf
->priv
->outbuffer
, vf
->priv
->outbuffer_size
);
57 vf
->priv
->avctx
->width
= d_width
;
58 vf
->priv
->avctx
->height
= d_height
;
59 vf
->priv
->avctx
->pix_fmt
= PIX_FMT_RGB24
;
60 vf
->priv
->avctx
->compression_level
= 0;
61 vf
->priv
->dw
= d_width
;
62 vf
->priv
->dh
= d_height
;
63 vf
->priv
->stride
= (3*vf
->priv
->dw
+15)&~15;
65 if (vf
->priv
->buffer
) free(vf
->priv
->buffer
); // probably reconfigured
66 vf
->priv
->buffer
= NULL
;
68 return vf_next_config(vf
,width
,height
,d_width
,d_height
,flags
,outfmt
);
71 static void write_png(struct vf_priv_s
*priv
)
73 char *fname
= priv
->fname
;
78 fp
= fopen (fname
, "wb");
80 mp_msg(MSGT_VFILTER
,MSGL_ERR
,"\nPNG Error opening %s for writing!\n", fname
);
84 pic
.data
[0] = priv
->buffer
;
85 pic
.linesize
[0] = priv
->stride
;
86 size
= avcodec_encode_video(priv
->avctx
, priv
->outbuffer
, priv
->outbuffer_size
, &pic
);
88 fwrite(priv
->outbuffer
, size
, 1, fp
);
93 static int fexists(char *fname
)
96 if (stat(fname
, &dummy
) == 0) return 1;
100 static void gen_fname(struct vf_priv_s
* priv
)
103 snprintf (priv
->fname
, 100, "shot%04d.png", ++priv
->frameno
);
104 } while (fexists(priv
->fname
) && priv
->frameno
< 100000);
105 if (fexists(priv
->fname
)) {
106 priv
->fname
[0] = '\0';
110 mp_msg(MSGT_VFILTER
,MSGL_INFO
,"*** screenshot '%s' ***\n",priv
->fname
);
114 static void scale_image(struct vf_priv_s
* priv
, mp_image_t
*mpi
)
119 dst_stride
[0] = priv
->stride
;
120 dst_stride
[1] = dst_stride
[2] = 0;
122 priv
->buffer
= (uint8_t*)memalign(16, dst_stride
[0]*priv
->dh
);
124 dst
[0] = priv
->buffer
;
126 sws_scale_ordered(priv
->ctx
, mpi
->planes
, mpi
->stride
, 0, priv
->dh
, dst
, dst_stride
);
129 static void start_slice(struct vf_instance_s
* vf
, mp_image_t
*mpi
){
130 vf
->dmpi
=vf_get_image(vf
->next
,mpi
->imgfmt
,
131 mpi
->type
, mpi
->flags
, mpi
->width
, mpi
->height
);
132 if (vf
->priv
->shot
) {
133 vf
->priv
->store_slices
= 1;
134 if (!vf
->priv
->buffer
)
135 vf
->priv
->buffer
= (uint8_t*)memalign(16, vf
->priv
->stride
*vf
->priv
->dh
);
140 static void draw_slice(struct vf_instance_s
* vf
,
141 unsigned char** src
, int* stride
, int w
,int h
, int x
, int y
){
142 if (vf
->priv
->store_slices
) {
145 dst_stride
[0] = vf
->priv
->stride
;
146 dst_stride
[1] = dst_stride
[2] = 0;
147 dst
[0] = vf
->priv
->buffer
;
149 sws_scale_ordered(vf
->priv
->ctx
, src
, stride
, y
, h
, dst
, dst_stride
);
151 vf_next_draw_slice(vf
,src
,stride
,w
,h
,x
,y
);
154 static void get_image(struct vf_instance_s
* vf
, mp_image_t
*mpi
){
155 // FIXME: should vf.c really call get_image when using slices??
156 if (mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)
158 vf
->dmpi
= vf_get_image(vf
->next
, mpi
->imgfmt
,
159 mpi
->type
, mpi
->flags
/* | MP_IMGFLAG_READABLE*/, mpi
->width
, mpi
->height
);
161 mpi
->planes
[0]=vf
->dmpi
->planes
[0];
162 mpi
->stride
[0]=vf
->dmpi
->stride
[0];
163 if(mpi
->flags
&MP_IMGFLAG_PLANAR
){
164 mpi
->planes
[1]=vf
->dmpi
->planes
[1];
165 mpi
->planes
[2]=vf
->dmpi
->planes
[2];
166 mpi
->stride
[1]=vf
->dmpi
->stride
[1];
167 mpi
->stride
[2]=vf
->dmpi
->stride
[2];
169 mpi
->width
=vf
->dmpi
->width
;
171 mpi
->flags
|=MP_IMGFLAG_DIRECT
;
173 mpi
->priv
=(void*)vf
->dmpi
;
176 static int put_image(struct vf_instance_s
* vf
, mp_image_t
*mpi
, double pts
)
178 mp_image_t
*dmpi
= (mp_image_t
*)mpi
->priv
;
180 if (mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)
183 if(!(mpi
->flags
&MP_IMGFLAG_DIRECT
)){
184 dmpi
=vf_get_image(vf
->next
,mpi
->imgfmt
,
185 MP_IMGTYPE_EXPORT
, 0,
186 mpi
->width
, mpi
->height
);
187 vf_clone_mpi_attributes(dmpi
, mpi
);
188 dmpi
->planes
[0]=mpi
->planes
[0];
189 dmpi
->planes
[1]=mpi
->planes
[1];
190 dmpi
->planes
[2]=mpi
->planes
[2];
191 dmpi
->stride
[0]=mpi
->stride
[0];
192 dmpi
->stride
[1]=mpi
->stride
[1];
193 dmpi
->stride
[2]=mpi
->stride
[2];
194 dmpi
->width
=mpi
->width
;
195 dmpi
->height
=mpi
->height
;
199 if (vf
->priv
->shot
==1)
202 if (vf
->priv
->fname
[0]) {
203 if (!vf
->priv
->store_slices
)
204 scale_image(vf
->priv
, dmpi
);
207 vf
->priv
->store_slices
= 0;
210 return vf_next_put_image(vf
, dmpi
, pts
);
213 int control (vf_instance_t
*vf
, int request
, void *data
)
215 /** data contains an integer argument
216 * 0: take screenshot with the next frame
217 * 1: take screenshots with each frame until the same command is given once again
219 if(request
==VFCTRL_SCREENSHOT
) {
220 if (data
&& *(int*)data
) { // repeated screenshot mode
221 if (vf
->priv
->shot
==2)
225 } else { // single screenshot
231 return vf_next_control (vf
, request
, data
);
235 //===========================================================================//
237 static int query_format(struct vf_instance_s
* vf
, unsigned int fmt
)
258 return vf_next_query_format(vf
, fmt
);
263 static void uninit(vf_instance_t
*vf
);
264 // open conflicts with stdio.h at least under MinGW
265 static int screenshot_open(vf_instance_t
*vf
, char* args
)
269 vf
->put_image
=put_image
;
270 vf
->query_format
=query_format
;
271 vf
->start_slice
=start_slice
;
272 vf
->draw_slice
=draw_slice
;
273 vf
->get_image
=get_image
;
275 vf
->priv
=malloc(sizeof(struct vf_priv_s
));
278 vf
->priv
->store_slices
=0;
280 vf
->priv
->outbuffer
=0;
282 vf
->priv
->avctx
= avcodec_alloc_context();
283 avcodec_register_all();
284 if (avcodec_open(vf
->priv
->avctx
, avcodec_find_encoder(CODEC_ID_PNG
))) {
285 mp_msg(MSGT_VFILTER
, MSGL_FATAL
, "Could not open libavcodec PNG encoder\n");
291 static void uninit(vf_instance_t
*vf
)
293 av_freep(&vf
->priv
->avctx
);
294 if(vf
->priv
->ctx
) sws_freeContext(vf
->priv
->ctx
);
295 if (vf
->priv
->buffer
) free(vf
->priv
->buffer
);
296 free(vf
->priv
->outbuffer
);
301 const vf_info_t vf_info_screenshot
= {
302 "screenshot to file",
304 "A'rpi, Jindrich Makovicka",
310 //===========================================================================//