2 * This file is part of mplayer2.
4 * mplayer2 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 * mplayer2 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 mplayer2; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <sys/types.h>
28 #include <libswscale/swscale.h>
29 #include <libavcodec/avcodec.h>
33 #include "screenshot.h"
36 #include "libmpcodecs/img_format.h"
37 #include "libmpcodecs/mp_image.h"
38 #include "libmpcodecs/dec_video.h"
39 #include "libmpcodecs/vf.h"
40 #include "libvo/video_out.h"
42 #include "fmt-conversion.h"
44 //for sws_getContextFromCmdLine and mp_sws_set_colorspace
45 #include "libmpcodecs/vf_scale.h"
46 #include "libvo/csputils.h"
48 typedef struct screenshot_ctx
{
51 int using_vf_screenshot
;
57 static screenshot_ctx
*screenshot_get_ctx(MPContext
*mpctx
)
59 if (!mpctx
->screenshot_ctx
)
60 mpctx
->screenshot_ctx
= talloc_zero(mpctx
, screenshot_ctx
);
61 return mpctx
->screenshot_ctx
;
64 static int write_png(screenshot_ctx
*ctx
, struct mp_image
*image
)
66 char *fname
= ctx
->fname
;
68 void *outbuffer
= NULL
;
71 AVCodecContext
*avctx
= avcodec_alloc_context();
75 if (avcodec_open(avctx
, avcodec_find_encoder(CODEC_ID_PNG
))) {
76 mp_msg(MSGT_CPLAYER
, MSGL_INFO
, "Could not open libavcodec PNG encoder"
77 " for saving screenshot\n");
81 avctx
->width
= image
->width
;
82 avctx
->height
= image
->height
;
83 avctx
->pix_fmt
= PIX_FMT_RGB24
;
84 avctx
->compression_level
= 0;
86 size_t outbuffer_size
= image
->width
* image
->height
* 3 * 2;
87 outbuffer
= malloc(outbuffer_size
);
92 pic
.data
[0] = image
->planes
[0];
93 pic
.linesize
[0] = image
->stride
[0];
94 int size
= avcodec_encode_video(avctx
, outbuffer
, outbuffer_size
, &pic
);
98 fp
= fopen(fname
, "wb");
100 avcodec_close(avctx
);
101 mp_msg(MSGT_CPLAYER
, MSGL_ERR
, "\nPNG Error opening %s for writing!\n",
106 fwrite(outbuffer
, size
, 1, fp
);
115 avcodec_close(avctx
);
122 static int fexists(char *fname
)
125 if (stat(fname
, &dummy
) == 0)
131 static void gen_fname(screenshot_ctx
*ctx
)
134 snprintf(ctx
->fname
, 100, "shot%04d.png", ++ctx
->frameno
);
135 } while (fexists(ctx
->fname
) && ctx
->frameno
< 100000);
136 if (fexists(ctx
->fname
)) {
137 ctx
->fname
[0] = '\0';
141 mp_msg(MSGT_CPLAYER
, MSGL_INFO
, "*** screenshot '%s' ***\n", ctx
->fname
);
145 void screenshot_save(struct MPContext
*mpctx
, struct mp_image
*image
)
147 screenshot_ctx
*ctx
= screenshot_get_ctx(mpctx
);
148 struct mp_image
*dst
= alloc_mpi(image
->w
, image
->h
, IMGFMT_RGB24
);
150 struct SwsContext
*sws
= sws_getContextFromCmdLine(image
->width
,
157 struct mp_csp_details colorspace
;
158 get_detected_video_colorspace(mpctx
->sh_video
, &colorspace
);
159 // this is a property of the output device; images always use full-range RGB
160 colorspace
.levels_out
= MP_CSP_LEVELS_PC
;
161 mp_sws_set_colorspace(sws
, &colorspace
);
163 sws_scale(sws
, (const uint8_t **)image
->planes
, image
->stride
, 0,
164 image
->height
, dst
->planes
, dst
->stride
);
169 sws_freeContext(sws
);
173 static void vf_screenshot_callback(void *pctx
, struct mp_image
*image
)
175 struct MPContext
*mpctx
= (struct MPContext
*)pctx
;
176 screenshot_ctx
*ctx
= screenshot_get_ctx(mpctx
);
177 screenshot_save(mpctx
, image
);
179 screenshot_request(mpctx
, 0, ctx
->full_window
);
182 void screenshot_request(struct MPContext
*mpctx
, bool each_frame
,
185 if (mpctx
->video_out
&& mpctx
->video_out
->config_ok
) {
186 screenshot_ctx
*ctx
= screenshot_get_ctx(mpctx
);
188 ctx
->using_vf_screenshot
= 0;
191 ctx
->each_frame
= !ctx
->each_frame
;
192 ctx
->full_window
= full_window
;
193 if (!ctx
->each_frame
)
197 struct voctrl_screenshot_args args
= { .full_window
= full_window
};
198 if (vo_control(mpctx
->video_out
, VOCTRL_SCREENSHOT
, &args
) == true) {
199 screenshot_save(mpctx
, args
.out_image
);
200 free_mp_image(args
.out_image
);
202 mp_msg(MSGT_CPLAYER
, MSGL_INFO
, "No VO support for taking"
203 " screenshots, trying VFCTRL_SCREENSHOT!\n");
204 ctx
->using_vf_screenshot
= 1;
205 struct vf_ctrl_screenshot cmd
= {
206 .image_callback
= vf_screenshot_callback
,
207 .image_callback_ctx
= mpctx
,
209 struct vf_instance
*vfilter
= mpctx
->sh_video
->vfilter
;
210 if (vfilter
->control(vfilter
, VFCTRL_SCREENSHOT
, &cmd
) !=
212 mp_msg(MSGT_CPLAYER
, MSGL_INFO
,
213 "...failed (need --vf=screenshot?)\n");
218 void screenshot_flip(struct MPContext
*mpctx
)
220 screenshot_ctx
*ctx
= screenshot_get_ctx(mpctx
);
222 if (!ctx
->each_frame
)
225 // screenshot_flip is called when the VO presents a new frame. vf_screenshot
226 // can behave completely different (consider filters inserted between
227 // vf_screenshot and vf_vo, that add or remove frames), so handle this case
229 if (ctx
->using_vf_screenshot
)
232 screenshot_request(mpctx
, 0, ctx
->full_window
);