vf_screenshot.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * This file is part of MPlayer.
  3. *
  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.
  8. *
  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.
  13. *
  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.
  17. */
  18. #include "config.h"
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #if HAVE_MALLOC_H
  22. #include <malloc.h>
  23. #endif
  24. #include <string.h>
  25. #include <inttypes.h>
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <unistd.h>
  29. #include "mp_msg.h"
  30. #include "img_format.h"
  31. #include "mp_image.h"
  32. #include "vf.h"
  33. #include "vf_scale.h"
  34. #include "libswscale/swscale.h"
  35. #include "libavcodec/avcodec.h"
  36. struct vf_priv_s {
  37. int frameno;
  38. char fname[102];
  39. /// shot stores current screenshot mode:
  40. /// 0: don't take screenshots
  41. /// 1: take single screenshot, reset to 0 afterwards
  42. /// 2: take screenshots of each frame
  43. int shot, store_slices;
  44. int dw, dh, stride;
  45. uint8_t *buffer;
  46. struct SwsContext *ctx;
  47. AVCodecContext *avctx;
  48. uint8_t *outbuffer;
  49. int outbuffer_size;
  50. };
  51. //===========================================================================//
  52. static int config(struct vf_instance *vf,
  53. int width, int height, int d_width, int d_height,
  54. unsigned int flags, unsigned int outfmt)
  55. {
  56. vf->priv->ctx=sws_getContextFromCmdLine(width, height, outfmt,
  57. d_width, d_height, IMGFMT_RGB24);
  58. vf->priv->outbuffer_size = d_width * d_height * 3 * 2;
  59. vf->priv->outbuffer = realloc(vf->priv->outbuffer, vf->priv->outbuffer_size);
  60. vf->priv->avctx->width = d_width;
  61. vf->priv->avctx->height = d_height;
  62. vf->priv->avctx->pix_fmt = PIX_FMT_RGB24;
  63. vf->priv->avctx->compression_level = 0;
  64. vf->priv->dw = d_width;
  65. vf->priv->dh = d_height;
  66. vf->priv->stride = (3*vf->priv->dw+15)&~15;
  67. free(vf->priv->buffer); // probably reconfigured
  68. vf->priv->buffer = NULL;
  69. return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt);
  70. }
  71. static void write_png(struct vf_priv_s *priv)
  72. {
  73. char *fname = priv->fname;
  74. FILE * fp;
  75. AVFrame pic;
  76. int size;
  77. fp = fopen (fname, "wb");
  78. if (fp == NULL) {
  79. mp_msg(MSGT_VFILTER,MSGL_ERR,"\nPNG Error opening %s for writing!\n", fname);
  80. return;
  81. }
  82. pic.data[0] = priv->buffer;
  83. pic.linesize[0] = priv->stride;
  84. size = avcodec_encode_video(priv->avctx, priv->outbuffer, priv->outbuffer_size, &pic);
  85. if (size > 0)
  86. fwrite(priv->outbuffer, size, 1, fp);
  87. fclose (fp);
  88. }
  89. static int fexists(char *fname)
  90. {
  91. struct stat dummy;
  92. if (stat(fname, &dummy) == 0) return 1;
  93. else return 0;
  94. }
  95. static void gen_fname(struct vf_priv_s* priv)
  96. {
  97. do {
  98. snprintf (priv->fname, 100, "shot%04d.png", ++priv->frameno);
  99. } while (fexists(priv->fname) && priv->frameno < 100000);
  100. if (fexists(priv->fname)) {
  101. priv->fname[0] = '\0';
  102. return;
  103. }
  104. mp_msg(MSGT_VFILTER,MSGL_INFO,"*** screenshot '%s' ***\n",priv->fname);
  105. }
  106. static void scale_image(struct vf_priv_s* priv, mp_image_t *mpi)
  107. {
  108. uint8_t *dst[MP_MAX_PLANES] = {NULL};
  109. int dst_stride[MP_MAX_PLANES] = {0};
  110. dst_stride[0] = priv->stride;
  111. if (!priv->buffer)
  112. priv->buffer = av_malloc(dst_stride[0]*priv->dh);
  113. dst[0] = priv->buffer;
  114. sws_scale(priv->ctx, mpi->planes, mpi->stride, 0, priv->dh, dst, dst_stride);
  115. }
  116. static void start_slice(struct vf_instance *vf, mp_image_t *mpi)
  117. {
  118. vf->dmpi=vf_get_image(vf->next,mpi->imgfmt,
  119. mpi->type, mpi->flags, mpi->width, mpi->height);
  120. if (vf->priv->shot) {
  121. vf->priv->store_slices = 1;
  122. if (!vf->priv->buffer)
  123. vf->priv->buffer = av_malloc(vf->priv->stride*vf->priv->dh);
  124. }
  125. }
  126. static void draw_slice(struct vf_instance *vf, unsigned char** src,
  127. int* stride, int w,int h, int x, int y)
  128. {
  129. if (vf->priv->store_slices) {
  130. uint8_t *dst[MP_MAX_PLANES] = {NULL};
  131. int dst_stride[MP_MAX_PLANES] = {0};
  132. dst_stride[0] = vf->priv->stride;
  133. dst[0] = vf->priv->buffer;
  134. sws_scale(vf->priv->ctx, src, stride, y, h, dst, dst_stride);
  135. }
  136. vf_next_draw_slice(vf,src,stride,w,h,x,y);
  137. }
  138. static void get_image(struct vf_instance *vf, mp_image_t *mpi)
  139. {
  140. // FIXME: should vf.c really call get_image when using slices??
  141. if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)
  142. return;
  143. vf->dmpi= vf_get_image(vf->next, mpi->imgfmt,
  144. mpi->type, mpi->flags/* | MP_IMGFLAG_READABLE*/, mpi->width, mpi->height);
  145. mpi->planes[0]=vf->dmpi->planes[0];
  146. mpi->stride[0]=vf->dmpi->stride[0];
  147. if(mpi->flags&MP_IMGFLAG_PLANAR){
  148. mpi->planes[1]=vf->dmpi->planes[1];
  149. mpi->planes[2]=vf->dmpi->planes[2];
  150. mpi->stride[1]=vf->dmpi->stride[1];
  151. mpi->stride[2]=vf->dmpi->stride[2];
  152. }
  153. mpi->width=vf->dmpi->width;
  154. mpi->flags|=MP_IMGFLAG_DIRECT;
  155. mpi->priv=(void*)vf->dmpi;
  156. }
  157. static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
  158. {
  159. mp_image_t *dmpi = (mp_image_t *)mpi->priv;
  160. if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)
  161. dmpi = vf->dmpi;
  162. else
  163. if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
  164. dmpi=vf_get_image(vf->next,mpi->imgfmt,
  165. MP_IMGTYPE_EXPORT, 0,
  166. mpi->width, mpi->height);
  167. vf_clone_mpi_attributes(dmpi, mpi);
  168. dmpi->planes[0]=mpi->planes[0];
  169. dmpi->planes[1]=mpi->planes[1];
  170. dmpi->planes[2]=mpi->planes[2];
  171. dmpi->stride[0]=mpi->stride[0];
  172. dmpi->stride[1]=mpi->stride[1];
  173. dmpi->stride[2]=mpi->stride[2];
  174. dmpi->width=mpi->width;
  175. dmpi->height=mpi->height;
  176. }
  177. if(vf->priv->shot) {
  178. if (vf->priv->shot==1)
  179. vf->priv->shot=0;
  180. gen_fname(vf->priv);
  181. if (vf->priv->fname[0]) {
  182. if (!vf->priv->store_slices)
  183. scale_image(vf->priv, dmpi);
  184. write_png(vf->priv);
  185. }
  186. vf->priv->store_slices = 0;
  187. }
  188. return vf_next_put_image(vf, dmpi, pts);
  189. }
  190. static int control (vf_instance_t *vf, int request, void *data)
  191. {
  192. /** data contains an integer argument
  193. * 0: take screenshot with the next frame
  194. * 1: take screenshots with each frame until the same command is given once again
  195. **/
  196. if(request==VFCTRL_SCREENSHOT) {
  197. if (data && *(int*)data) { // repeated screenshot mode
  198. if (vf->priv->shot==2)
  199. vf->priv->shot=0;
  200. else
  201. vf->priv->shot=2;
  202. } else { // single screenshot
  203. if (!vf->priv->shot)
  204. vf->priv->shot=1;
  205. }
  206. return CONTROL_TRUE;
  207. }
  208. return vf_next_control (vf, request, data);
  209. }
  210. //===========================================================================//
  211. static int query_format(struct vf_instance *vf, unsigned int fmt)
  212. {
  213. switch(fmt){
  214. case IMGFMT_YV12:
  215. case IMGFMT_I420:
  216. case IMGFMT_IYUV:
  217. case IMGFMT_UYVY:
  218. case IMGFMT_YUY2:
  219. case IMGFMT_BGR32:
  220. case IMGFMT_BGR24:
  221. case IMGFMT_BGR16:
  222. case IMGFMT_BGR15:
  223. case IMGFMT_BGR12:
  224. case IMGFMT_RGB32:
  225. case IMGFMT_RGB24:
  226. case IMGFMT_Y800:
  227. case IMGFMT_Y8:
  228. case IMGFMT_YVU9:
  229. case IMGFMT_IF09:
  230. case IMGFMT_444P:
  231. case IMGFMT_422P:
  232. case IMGFMT_411P:
  233. return vf_next_query_format(vf, fmt);
  234. }
  235. return 0;
  236. }
  237. static void uninit(vf_instance_t *vf)
  238. {
  239. avcodec_close(vf->priv->avctx);
  240. av_freep(&vf->priv->avctx);
  241. if(vf->priv->ctx) sws_freeContext(vf->priv->ctx);
  242. av_free(vf->priv->buffer);
  243. free(vf->priv->outbuffer);
  244. free(vf->priv);
  245. }
  246. static int vf_open(vf_instance_t *vf, char *args)
  247. {
  248. vf->config=config;
  249. vf->control=control;
  250. vf->put_image=put_image;
  251. vf->query_format=query_format;
  252. vf->start_slice=start_slice;
  253. vf->draw_slice=draw_slice;
  254. vf->get_image=get_image;
  255. vf->uninit=uninit;
  256. vf->priv=malloc(sizeof(struct vf_priv_s));
  257. vf->priv->frameno=0;
  258. vf->priv->shot=0;
  259. vf->priv->store_slices=0;
  260. vf->priv->buffer=0;
  261. vf->priv->outbuffer=0;
  262. vf->priv->ctx=0;
  263. vf->priv->avctx = avcodec_alloc_context();
  264. avcodec_register_all();
  265. if (avcodec_open(vf->priv->avctx, avcodec_find_encoder(CODEC_ID_PNG))) {
  266. mp_msg(MSGT_VFILTER, MSGL_FATAL, "Could not open libavcodec PNG encoder\n");
  267. return 0;
  268. }
  269. return 1;
  270. }
  271. const vf_info_t vf_info_screenshot = {
  272. "screenshot to file",
  273. "screenshot",
  274. "A'rpi, Jindrich Makovicka",
  275. "",
  276. vf_open,
  277. NULL
  278. };
  279. //===========================================================================//