2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include <sys/types.h>
30 #include <libswscale/swscale.h>
31 #include <libavcodec/avcodec.h>
34 #include "img_format.h"
38 #include "fmt-conversion.h"
44 /// shot stores current screenshot mode:
45 /// 0: don't take screenshots
46 /// 1: take single screenshot, reset to 0 afterwards
47 /// 2: take screenshots of each frame
48 int shot
, store_slices
;
51 struct SwsContext
*ctx
;
52 AVCodecContext
*avctx
;
57 //===========================================================================//
59 static int config(struct vf_instance
*vf
,
60 int width
, int height
, int d_width
, int d_height
,
61 unsigned int flags
, unsigned int outfmt
)
63 vf
->priv
->ctx
=sws_getContextFromCmdLine(width
, height
, outfmt
,
64 d_width
, d_height
, IMGFMT_RGB24
);
66 vf
->priv
->outbuffer_size
= d_width
* d_height
* 3 * 2;
67 vf
->priv
->outbuffer
= realloc(vf
->priv
->outbuffer
, vf
->priv
->outbuffer_size
);
68 vf
->priv
->avctx
->width
= d_width
;
69 vf
->priv
->avctx
->height
= d_height
;
70 vf
->priv
->avctx
->pix_fmt
= PIX_FMT_RGB24
;
71 vf
->priv
->avctx
->compression_level
= 0;
72 vf
->priv
->dw
= d_width
;
73 vf
->priv
->dh
= d_height
;
74 vf
->priv
->stride
= (3*vf
->priv
->dw
+15)&~15;
76 free(vf
->priv
->buffer
); // probably reconfigured
77 vf
->priv
->buffer
= NULL
;
79 return vf_next_config(vf
,width
,height
,d_width
,d_height
,flags
,outfmt
);
82 static void write_png(struct vf_priv_s
*priv
)
84 char *fname
= priv
->fname
;
89 fp
= fopen (fname
, "wb");
91 mp_msg(MSGT_VFILTER
,MSGL_ERR
,"\nPNG Error opening %s for writing!\n", fname
);
95 pic
.data
[0] = priv
->buffer
;
96 pic
.linesize
[0] = priv
->stride
;
97 size
= avcodec_encode_video(priv
->avctx
, priv
->outbuffer
, priv
->outbuffer_size
, &pic
);
99 fwrite(priv
->outbuffer
, size
, 1, fp
);
104 static int fexists(char *fname
)
107 if (stat(fname
, &dummy
) == 0) return 1;
111 static void gen_fname(struct vf_priv_s
* priv
)
114 snprintf (priv
->fname
, 100, "shot%04d.png", ++priv
->frameno
);
115 } while (fexists(priv
->fname
) && priv
->frameno
< 100000);
116 if (fexists(priv
->fname
)) {
117 priv
->fname
[0] = '\0';
121 mp_msg(MSGT_VFILTER
,MSGL_INFO
,"*** screenshot '%s' ***\n",priv
->fname
);
125 static void scale_image(struct vf_priv_s
* priv
, mp_image_t
*mpi
)
127 uint8_t *dst
[MP_MAX_PLANES
] = {NULL
};
128 int dst_stride
[MP_MAX_PLANES
] = {0};
130 dst_stride
[0] = priv
->stride
;
132 priv
->buffer
= av_malloc(dst_stride
[0]*priv
->dh
);
134 dst
[0] = priv
->buffer
;
135 sws_scale(priv
->ctx
, (const uint8_t **)mpi
->planes
, mpi
->stride
, 0, priv
->dh
, dst
, dst_stride
);
138 static void start_slice(struct vf_instance
*vf
, mp_image_t
*mpi
)
140 vf
->dmpi
=vf_get_image(vf
->next
,mpi
->imgfmt
,
141 mpi
->type
, mpi
->flags
, mpi
->width
, mpi
->height
);
142 if (vf
->priv
->shot
) {
143 vf
->priv
->store_slices
= 1;
144 if (!vf
->priv
->buffer
)
145 vf
->priv
->buffer
= av_malloc(vf
->priv
->stride
*vf
->priv
->dh
);
150 static void draw_slice(struct vf_instance
*vf
, unsigned char** src
,
151 int* stride
, int w
,int h
, int x
, int y
)
153 if (vf
->priv
->store_slices
) {
154 uint8_t *dst
[MP_MAX_PLANES
] = {NULL
};
155 int dst_stride
[MP_MAX_PLANES
] = {0};
156 dst_stride
[0] = vf
->priv
->stride
;
157 dst
[0] = vf
->priv
->buffer
;
158 sws_scale(vf
->priv
->ctx
, (const uint8_t **)src
, stride
, y
, h
, dst
, dst_stride
);
160 vf_next_draw_slice(vf
,src
,stride
,w
,h
,x
,y
);
163 static void get_image(struct vf_instance
*vf
, mp_image_t
*mpi
)
165 // FIXME: should vf.c really call get_image when using slices??
166 if (mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)
168 vf
->dmpi
= vf_get_image(vf
->next
, mpi
->imgfmt
,
169 mpi
->type
, mpi
->flags
/* | MP_IMGFLAG_READABLE*/, mpi
->width
, mpi
->height
);
171 for (int i
= 0; i
< MP_MAX_PLANES
; i
++) {
172 mpi
->planes
[i
]=vf
->dmpi
->planes
[i
];
173 mpi
->stride
[i
]=vf
->dmpi
->stride
[i
];
175 mpi
->width
=vf
->dmpi
->width
;
177 mpi
->flags
|=MP_IMGFLAG_DIRECT
;
179 mpi
->priv
=(void*)vf
->dmpi
;
182 static int put_image(struct vf_instance
*vf
, mp_image_t
*mpi
, double pts
)
184 mp_image_t
*dmpi
= (mp_image_t
*)mpi
->priv
;
186 if (mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)
189 if(!(mpi
->flags
&MP_IMGFLAG_DIRECT
)){
190 dmpi
=vf_get_image(vf
->next
,mpi
->imgfmt
,
191 MP_IMGTYPE_EXPORT
, 0,
192 mpi
->width
, mpi
->height
);
193 vf_clone_mpi_attributes(dmpi
, mpi
);
194 for (int i
= 0; i
< MP_MAX_PLANES
; i
++) {
195 dmpi
->planes
[i
]=mpi
->planes
[i
];
196 dmpi
->stride
[i
]=mpi
->stride
[i
];
198 dmpi
->width
=mpi
->width
;
199 dmpi
->height
=mpi
->height
;
203 if (vf
->priv
->shot
==1)
206 if (vf
->priv
->fname
[0]) {
207 if (!vf
->priv
->store_slices
)
208 scale_image(vf
->priv
, dmpi
);
211 vf
->priv
->store_slices
= 0;
214 return vf_next_put_image(vf
, dmpi
, pts
);
217 static int control (vf_instance_t
*vf
, int request
, void *data
)
219 /** data contains an integer argument
220 * 0: take screenshot with the next frame
221 * 1: take screenshots with each frame until the same command is given once again
223 if(request
==VFCTRL_SCREENSHOT
) {
224 if (data
&& *(int*)data
) { // repeated screenshot mode
225 if (vf
->priv
->shot
==2)
229 } else { // single screenshot
235 return vf_next_control (vf
, request
, data
);
239 //===========================================================================//
241 static int query_format(struct vf_instance
*vf
, unsigned int fmt
)
243 enum PixelFormat av_format
= imgfmt2pixfmt(fmt
);
245 if (av_format
!= PIX_FMT_NONE
&& sws_isSupportedInput(av_format
))
246 return vf_next_query_format(vf
, fmt
);
250 static void uninit(vf_instance_t
*vf
)
252 avcodec_close(vf
->priv
->avctx
);
253 av_freep(&vf
->priv
->avctx
);
254 if(vf
->priv
->ctx
) sws_freeContext(vf
->priv
->ctx
);
255 av_free(vf
->priv
->buffer
);
256 free(vf
->priv
->outbuffer
);
260 static int vf_open(vf_instance_t
*vf
, char *args
)
264 vf
->put_image
=put_image
;
265 vf
->query_format
=query_format
;
266 vf
->start_slice
=start_slice
;
267 vf
->draw_slice
=draw_slice
;
268 vf
->get_image
=get_image
;
270 vf
->priv
=malloc(sizeof(struct vf_priv_s
));
273 vf
->priv
->store_slices
=0;
275 vf
->priv
->outbuffer
=0;
277 vf
->priv
->avctx
= avcodec_alloc_context();
278 if (avcodec_open(vf
->priv
->avctx
, avcodec_find_encoder(CODEC_ID_PNG
))) {
279 mp_msg(MSGT_VFILTER
, MSGL_FATAL
, "Could not open libavcodec PNG encoder\n");
286 const vf_info_t vf_info_screenshot
= {
287 "screenshot to file",
289 "A'rpi, Jindrich Makovicka",
295 //===========================================================================//