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.
25 #include <libswscale/swscale.h>
26 #include <libavcodec/avcodec.h>
30 #include "screenshot.h"
34 #include "libmpcodecs/img_format.h"
35 #include "libmpcodecs/mp_image.h"
36 #include "libmpcodecs/dec_video.h"
37 #include "libmpcodecs/vf.h"
38 #include "libvo/video_out.h"
40 #include "fmt-conversion.h"
42 //for sws_getContextFromCmdLine_hq and mp_sws_set_colorspace
43 #include "libmpcodecs/vf_scale.h"
44 #include "libvo/csputils.h"
46 typedef struct screenshot_ctx
{
50 int using_vf_screenshot
;
56 static int destroy_ctx(void *ptr
)
58 struct screenshot_ctx
*ctx
= ptr
;
63 static screenshot_ctx
*screenshot_get_ctx(MPContext
*mpctx
)
65 if (!mpctx
->screenshot_ctx
) {
66 struct screenshot_ctx
*ctx
= talloc_zero(mpctx
, screenshot_ctx
);
67 talloc_set_destructor(ctx
, destroy_ctx
);
68 ctx
->pic
= avcodec_alloc_frame();
70 mpctx
->screenshot_ctx
= ctx
;
72 return mpctx
->screenshot_ctx
;
75 static int write_png(screenshot_ctx
*ctx
, struct mp_image
*image
)
77 char *fname
= ctx
->fname
;
79 void *outbuffer
= NULL
;
82 struct AVCodec
*png_codec
= avcodec_find_encoder(CODEC_ID_PNG
);
83 AVCodecContext
*avctx
= NULL
;
86 avctx
= avcodec_alloc_context3(png_codec
);
90 avctx
->time_base
= AV_TIME_BASE_Q
;
91 avctx
->width
= image
->width
;
92 avctx
->height
= image
->height
;
93 avctx
->pix_fmt
= PIX_FMT_RGB24
;
94 avctx
->compression_level
= 0;
96 if (avcodec_open2(avctx
, png_codec
, NULL
) < 0) {
98 mp_msg(MSGT_CPLAYER
, MSGL_INFO
, "Could not open libavcodec PNG encoder"
99 " for saving screenshot\n");
103 size_t outbuffer_size
= image
->width
* image
->height
* 3 * 2;
104 outbuffer
= malloc(outbuffer_size
);
108 AVFrame
*pic
= ctx
->pic
;
109 avcodec_get_frame_defaults(pic
);
110 for (int n
= 0; n
< 4; n
++) {
111 pic
->data
[n
] = image
->planes
[n
];
112 pic
->linesize
[n
] = image
->stride
[n
];
114 int size
= avcodec_encode_video(avctx
, outbuffer
, outbuffer_size
, pic
);
118 fp
= fopen(fname
, "wb");
120 mp_msg(MSGT_CPLAYER
, MSGL_ERR
, "\nPNG Error opening %s for writing!\n",
125 fwrite(outbuffer
, size
, 1, fp
);
134 avcodec_close(avctx
);
142 static int fexists(char *fname
)
144 return mp_path_exists(fname
);
147 static void gen_fname(screenshot_ctx
*ctx
)
150 snprintf(ctx
->fname
, 100, "shot%04d.png", ++ctx
->frameno
);
151 } while (fexists(ctx
->fname
) && ctx
->frameno
< 100000);
152 if (fexists(ctx
->fname
)) {
153 ctx
->fname
[0] = '\0';
157 mp_msg(MSGT_CPLAYER
, MSGL_INFO
, "*** screenshot '%s' ***\n", ctx
->fname
);
161 void screenshot_save(struct MPContext
*mpctx
, struct mp_image
*image
)
163 screenshot_ctx
*ctx
= screenshot_get_ctx(mpctx
);
164 struct mp_image
*dst
= alloc_mpi(image
->w
, image
->h
, IMGFMT_RGB24
);
166 struct SwsContext
*sws
= sws_getContextFromCmdLine_hq(image
->width
,
173 struct mp_csp_details colorspace
;
174 get_detected_video_colorspace(mpctx
->sh_video
, &colorspace
);
175 // this is a property of the output device; images always use full-range RGB
176 colorspace
.levels_out
= MP_CSP_LEVELS_PC
;
177 mp_sws_set_colorspace(sws
, &colorspace
);
179 sws_scale(sws
, (const uint8_t **)image
->planes
, image
->stride
, 0,
180 image
->height
, dst
->planes
, dst
->stride
);
185 sws_freeContext(sws
);
189 static void vf_screenshot_callback(void *pctx
, struct mp_image
*image
)
191 struct MPContext
*mpctx
= (struct MPContext
*)pctx
;
192 screenshot_ctx
*ctx
= screenshot_get_ctx(mpctx
);
193 screenshot_save(mpctx
, image
);
195 screenshot_request(mpctx
, 0, ctx
->full_window
);
198 void screenshot_request(struct MPContext
*mpctx
, bool each_frame
,
201 if (mpctx
->video_out
&& mpctx
->video_out
->config_ok
) {
202 screenshot_ctx
*ctx
= screenshot_get_ctx(mpctx
);
204 ctx
->using_vf_screenshot
= 0;
207 ctx
->each_frame
= !ctx
->each_frame
;
208 ctx
->full_window
= full_window
;
209 if (!ctx
->each_frame
)
213 struct voctrl_screenshot_args args
= { .full_window
= full_window
};
214 if (vo_control(mpctx
->video_out
, VOCTRL_SCREENSHOT
, &args
) == true) {
215 screenshot_save(mpctx
, args
.out_image
);
216 free_mp_image(args
.out_image
);
218 mp_msg(MSGT_CPLAYER
, MSGL_INFO
, "No VO support for taking"
219 " screenshots, trying VFCTRL_SCREENSHOT!\n");
220 ctx
->using_vf_screenshot
= 1;
221 struct vf_ctrl_screenshot cmd
= {
222 .image_callback
= vf_screenshot_callback
,
223 .image_callback_ctx
= mpctx
,
225 struct vf_instance
*vfilter
= mpctx
->sh_video
->vfilter
;
226 if (vfilter
->control(vfilter
, VFCTRL_SCREENSHOT
, &cmd
) !=
228 mp_msg(MSGT_CPLAYER
, MSGL_INFO
,
229 "...failed (need --vf=screenshot?)\n");
234 void screenshot_flip(struct MPContext
*mpctx
)
236 screenshot_ctx
*ctx
= screenshot_get_ctx(mpctx
);
238 if (!ctx
->each_frame
)
241 // screenshot_flip is called when the VO presents a new frame. vf_screenshot
242 // can behave completely different (consider filters inserted between
243 // vf_screenshot and vf_vo, that add or remove frames), so handle this case
245 if (ctx
->using_vf_screenshot
)
248 screenshot_request(mpctx
, 0, ctx
->full_window
);