00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "config.h"
00020
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #if HAVE_MALLOC_H
00024 #include <malloc.h>
00025 #endif
00026 #include <string.h>
00027 #include <inttypes.h>
00028
00029 #include <sys/types.h>
00030 #include <sys/stat.h>
00031 #include <unistd.h>
00032
00033 #include "mp_msg.h"
00034
00035 #include "img_format.h"
00036 #include "mp_image.h"
00037 #include "vf.h"
00038 #include "vf_scale.h"
00039
00040 #include "libswscale/swscale.h"
00041 #include "libavcodec/avcodec.h"
00042
00043 struct vf_priv_s {
00044 int frameno;
00045 char fname[102];
00050 int shot, store_slices;
00051 int dw, dh, stride;
00052 uint8_t *buffer;
00053 struct SwsContext *ctx;
00054 AVCodecContext *avctx;
00055 uint8_t *outbuffer;
00056 int outbuffer_size;
00057 };
00058
00059
00060
00061 static int config(struct vf_instance *vf,
00062 int width, int height, int d_width, int d_height,
00063 unsigned int flags, unsigned int outfmt)
00064 {
00065 vf->priv->ctx=sws_getContextFromCmdLine(width, height, outfmt,
00066 d_width, d_height, IMGFMT_RGB24);
00067
00068 vf->priv->outbuffer_size = d_width * d_height * 3 * 2;
00069 vf->priv->outbuffer = realloc(vf->priv->outbuffer, vf->priv->outbuffer_size);
00070 vf->priv->avctx->width = d_width;
00071 vf->priv->avctx->height = d_height;
00072 vf->priv->avctx->pix_fmt = PIX_FMT_RGB24;
00073 vf->priv->avctx->compression_level = 0;
00074 vf->priv->dw = d_width;
00075 vf->priv->dh = d_height;
00076 vf->priv->stride = (3*vf->priv->dw+15)&~15;
00077
00078 free(vf->priv->buffer);
00079 vf->priv->buffer = NULL;
00080
00081 return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
00082 }
00083
00084 static void write_png(struct vf_priv_s *priv)
00085 {
00086 char *fname = priv->fname;
00087 FILE * fp;
00088 AVFrame pic;
00089 int size;
00090
00091 fp = fopen (fname, "wb");
00092 if (fp == NULL) {
00093 mp_msg(MSGT_VFILTER,MSGL_ERR,"\nPNG Error opening %s for writing!\n", fname);
00094 return;
00095 }
00096
00097 pic.data[0] = priv->buffer;
00098 pic.linesize[0] = priv->stride;
00099 size = avcodec_encode_video(priv->avctx, priv->outbuffer, priv->outbuffer_size, &pic);
00100 if (size > 0)
00101 fwrite(priv->outbuffer, size, 1, fp);
00102
00103 fclose (fp);
00104 }
00105
00106 static int fexists(char *fname)
00107 {
00108 struct stat dummy;
00109 if (stat(fname, &dummy) == 0) return 1;
00110 else return 0;
00111 }
00112
00113 static void gen_fname(struct vf_priv_s* priv)
00114 {
00115 do {
00116 snprintf (priv->fname, 100, "shot%04d.png", ++priv->frameno);
00117 } while (fexists(priv->fname) && priv->frameno < 100000);
00118 if (fexists(priv->fname)) {
00119 priv->fname[0] = '\0';
00120 return;
00121 }
00122
00123 mp_msg(MSGT_VFILTER,MSGL_INFO,"*** screenshot '%s' ***\n",priv->fname);
00124
00125 }
00126
00127 static void scale_image(struct vf_priv_s* priv, mp_image_t *mpi)
00128 {
00129 uint8_t *dst[MP_MAX_PLANES] = {NULL};
00130 int dst_stride[MP_MAX_PLANES] = {0};
00131
00132 dst_stride[0] = priv->stride;
00133 if (!priv->buffer)
00134 priv->buffer = av_malloc(dst_stride[0]*priv->dh);
00135
00136 dst[0] = priv->buffer;
00137 sws_scale(priv->ctx, mpi->planes, mpi->stride, 0, priv->dh, dst, dst_stride);
00138 }
00139
00140 static void start_slice(struct vf_instance *vf, mp_image_t *mpi)
00141 {
00142 vf->dmpi=vf_get_image(vf->next,mpi->imgfmt,
00143 mpi->type, mpi->flags, mpi->width, mpi->height);
00144 if (vf->priv->shot) {
00145 vf->priv->store_slices = 1;
00146 if (!vf->priv->buffer)
00147 vf->priv->buffer = av_malloc(vf->priv->stride*vf->priv->dh);
00148 }
00149
00150 }
00151
00152 static void draw_slice(struct vf_instance *vf, unsigned char** src,
00153 int* stride, int w,int h, int x, int y)
00154 {
00155 if (vf->priv->store_slices) {
00156 uint8_t *dst[MP_MAX_PLANES] = {NULL};
00157 int dst_stride[MP_MAX_PLANES] = {0};
00158 dst_stride[0] = vf->priv->stride;
00159 dst[0] = vf->priv->buffer;
00160 sws_scale(vf->priv->ctx, src, stride, y, h, dst, dst_stride);
00161 }
00162 vf_next_draw_slice(vf,src,stride,w,h,x,y);
00163 }
00164
00165 static void get_image(struct vf_instance *vf, mp_image_t *mpi)
00166 {
00167
00168 if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)
00169 return;
00170 vf->dmpi= vf_get_image(vf->next, mpi->imgfmt,
00171 mpi->type, mpi->flags, mpi->width, mpi->height);
00172
00173 mpi->planes[0]=vf->dmpi->planes[0];
00174 mpi->stride[0]=vf->dmpi->stride[0];
00175 if(mpi->flags&MP_IMGFLAG_PLANAR){
00176 mpi->planes[1]=vf->dmpi->planes[1];
00177 mpi->planes[2]=vf->dmpi->planes[2];
00178 mpi->stride[1]=vf->dmpi->stride[1];
00179 mpi->stride[2]=vf->dmpi->stride[2];
00180 }
00181 mpi->width=vf->dmpi->width;
00182
00183 mpi->flags|=MP_IMGFLAG_DIRECT;
00184
00185 mpi->priv=(void*)vf->dmpi;
00186 }
00187
00188 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
00189 {
00190 mp_image_t *dmpi = (mp_image_t *)mpi->priv;
00191
00192 if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)
00193 dmpi = vf->dmpi;
00194 else
00195 if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
00196 dmpi=vf_get_image(vf->next,mpi->imgfmt,
00197 MP_IMGTYPE_EXPORT, 0,
00198 mpi->width, mpi->height);
00199 vf_clone_mpi_attributes(dmpi, mpi);
00200 dmpi->planes[0]=mpi->planes[0];
00201 dmpi->planes[1]=mpi->planes[1];
00202 dmpi->planes[2]=mpi->planes[2];
00203 dmpi->stride[0]=mpi->stride[0];
00204 dmpi->stride[1]=mpi->stride[1];
00205 dmpi->stride[2]=mpi->stride[2];
00206 dmpi->width=mpi->width;
00207 dmpi->height=mpi->height;
00208 }
00209
00210 if(vf->priv->shot) {
00211 if (vf->priv->shot==1)
00212 vf->priv->shot=0;
00213 gen_fname(vf->priv);
00214 if (vf->priv->fname[0]) {
00215 if (!vf->priv->store_slices)
00216 scale_image(vf->priv, dmpi);
00217 write_png(vf->priv);
00218 }
00219 vf->priv->store_slices = 0;
00220 }
00221
00222 return vf_next_put_image(vf, dmpi, pts);
00223 }
00224
00225 static int control (vf_instance_t *vf, int request, void *data)
00226 {
00231 if(request==VFCTRL_SCREENSHOT) {
00232 if (data && *(int*)data) {
00233 if (vf->priv->shot==2)
00234 vf->priv->shot=0;
00235 else
00236 vf->priv->shot=2;
00237 } else {
00238 if (!vf->priv->shot)
00239 vf->priv->shot=1;
00240 }
00241 return CONTROL_TRUE;
00242 }
00243 return vf_next_control (vf, request, data);
00244 }
00245
00246
00247
00248
00249 static int query_format(struct vf_instance *vf, unsigned int fmt)
00250 {
00251 switch(fmt){
00252 case IMGFMT_YV12:
00253 case IMGFMT_I420:
00254 case IMGFMT_IYUV:
00255 case IMGFMT_UYVY:
00256 case IMGFMT_YUY2:
00257 case IMGFMT_BGR32:
00258 case IMGFMT_BGR24:
00259 case IMGFMT_BGR16:
00260 case IMGFMT_BGR15:
00261 case IMGFMT_BGR12:
00262 case IMGFMT_RGB32:
00263 case IMGFMT_RGB24:
00264 case IMGFMT_Y800:
00265 case IMGFMT_Y8:
00266 case IMGFMT_YVU9:
00267 case IMGFMT_IF09:
00268 case IMGFMT_444P:
00269 case IMGFMT_422P:
00270 case IMGFMT_411P:
00271 return vf_next_query_format(vf, fmt);
00272 }
00273 return 0;
00274 }
00275
00276 static void uninit(vf_instance_t *vf)
00277 {
00278 avcodec_close(vf->priv->avctx);
00279 av_freep(&vf->priv->avctx);
00280 if(vf->priv->ctx) sws_freeContext(vf->priv->ctx);
00281 av_free(vf->priv->buffer);
00282 free(vf->priv->outbuffer);
00283 free(vf->priv);
00284 }
00285
00286 static int vf_open(vf_instance_t *vf, char *args)
00287 {
00288 vf->config=config;
00289 vf->control=control;
00290 vf->put_image=put_image;
00291 vf->query_format=query_format;
00292 vf->start_slice=start_slice;
00293 vf->draw_slice=draw_slice;
00294 vf->get_image=get_image;
00295 vf->uninit=uninit;
00296 vf->priv=malloc(sizeof(struct vf_priv_s));
00297 vf->priv->frameno=0;
00298 vf->priv->shot=0;
00299 vf->priv->store_slices=0;
00300 vf->priv->buffer=0;
00301 vf->priv->outbuffer=0;
00302 vf->priv->ctx=0;
00303 vf->priv->avctx = avcodec_alloc_context();
00304 avcodec_register_all();
00305 if (avcodec_open(vf->priv->avctx, avcodec_find_encoder(CODEC_ID_PNG))) {
00306 mp_msg(MSGT_VFILTER, MSGL_FATAL, "Could not open libavcodec PNG encoder\n");
00307 return 0;
00308 }
00309 return 1;
00310 }
00311
00312
00313 const vf_info_t vf_info_screenshot = {
00314 "screenshot to file",
00315 "screenshot",
00316 "A'rpi, Jindrich Makovicka",
00317 "",
00318 vf_open,
00319 NULL
00320 };
00321
00322