ppm.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /*
  2. * PPM Video Hook
  3. * Copyright (c) 2003 Charles Yates
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * FFmpeg is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with FFmpeg; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include <stdio.h>
  22. #include <unistd.h>
  23. #include <fcntl.h>
  24. #include <sys/types.h>
  25. #include <sys/wait.h>
  26. #include <ctype.h>
  27. #include "framehook.h"
  28. #include "avformat.h"
  29. #include "swscale.h"
  30. #include "avstring.h"
  31. static int sws_flags = SWS_BICUBIC;
  32. /** Bi-directional pipe structure.
  33. */
  34. typedef struct rwpipe
  35. {
  36. int pid;
  37. FILE *reader;
  38. FILE *writer;
  39. }
  40. rwpipe;
  41. /** Create a bidirectional pipe for the given command.
  42. */
  43. static rwpipe *rwpipe_open( int argc, char *argv[] )
  44. {
  45. rwpipe *this = av_mallocz( sizeof( rwpipe ) );
  46. if ( this != NULL )
  47. {
  48. int input[ 2 ];
  49. int output[ 2 ];
  50. pipe( input );
  51. pipe( output );
  52. this->pid = fork();
  53. if ( this->pid == 0 )
  54. {
  55. #define COMMAND_SIZE 10240
  56. char *command = av_mallocz( COMMAND_SIZE );
  57. int i;
  58. strcpy( command, "" );
  59. for ( i = 0; i < argc; i ++ )
  60. {
  61. av_strlcat( command, argv[ i ], COMMAND_SIZE );
  62. av_strlcat( command, " ", COMMAND_SIZE );
  63. }
  64. dup2( output[ 0 ], STDIN_FILENO );
  65. dup2( input[ 1 ], STDOUT_FILENO );
  66. close( input[ 0 ] );
  67. close( input[ 1 ] );
  68. close( output[ 0 ] );
  69. close( output[ 1 ] );
  70. execl("/bin/sh", "sh", "-c", command, (char*)NULL );
  71. _exit( 255 );
  72. }
  73. else
  74. {
  75. close( input[ 1 ] );
  76. close( output[ 0 ] );
  77. this->reader = fdopen( input[ 0 ], "r" );
  78. this->writer = fdopen( output[ 1 ], "w" );
  79. }
  80. }
  81. return this;
  82. }
  83. /** Read data from the pipe.
  84. */
  85. static FILE *rwpipe_reader( rwpipe *this )
  86. {
  87. if ( this != NULL )
  88. return this->reader;
  89. else
  90. return NULL;
  91. }
  92. /** Write data to the pipe.
  93. */
  94. static FILE *rwpipe_writer( rwpipe *this )
  95. {
  96. if ( this != NULL )
  97. return this->writer;
  98. else
  99. return NULL;
  100. }
  101. /* Read a number from the pipe - assumes PNM style headers.
  102. */
  103. static int rwpipe_read_number( rwpipe *rw )
  104. {
  105. int value = 0;
  106. int c = 0;
  107. FILE *in = rwpipe_reader( rw );
  108. do
  109. {
  110. c = fgetc( in );
  111. while( c != EOF && !isdigit( c ) && c != '#' )
  112. c = fgetc( in );
  113. if ( c == '#' )
  114. while( c != EOF && c != '\n' )
  115. c = fgetc( in );
  116. }
  117. while ( c != EOF && !isdigit( c ) );
  118. while( c != EOF && isdigit( c ) )
  119. {
  120. value = value * 10 + ( c - '0' );
  121. c = fgetc( in );
  122. }
  123. return value;
  124. }
  125. /** Read a PPM P6 header.
  126. */
  127. static int rwpipe_read_ppm_header( rwpipe *rw, int *width, int *height )
  128. {
  129. char line[ 3 ];
  130. FILE *in = rwpipe_reader( rw );
  131. int max;
  132. fgets( line, 3, in );
  133. if ( !strncmp( line, "P6", 2 ) )
  134. {
  135. *width = rwpipe_read_number( rw );
  136. *height = rwpipe_read_number( rw );
  137. max = rwpipe_read_number( rw );
  138. return max != 255 || *width <= 0 || *height <= 0;
  139. }
  140. return 1;
  141. }
  142. /** Close the pipe and process.
  143. */
  144. static void rwpipe_close( rwpipe *this )
  145. {
  146. if ( this != NULL )
  147. {
  148. fclose( this->reader );
  149. fclose( this->writer );
  150. waitpid( this->pid, NULL, 0 );
  151. av_free( this );
  152. }
  153. }
  154. /** Context info for this vhook - stores the pipe and image buffers.
  155. */
  156. typedef struct
  157. {
  158. rwpipe *rw;
  159. int size1;
  160. char *buf1;
  161. int size2;
  162. char *buf2;
  163. // This vhook first converts frame to RGB ...
  164. struct SwsContext *toRGB_convert_ctx;
  165. // ... then processes it via a PPM command pipe ...
  166. // ... and finally converts back frame from RGB to initial format
  167. struct SwsContext *fromRGB_convert_ctx;
  168. }
  169. ContextInfo;
  170. /** Initialise the context info for this vhook.
  171. */
  172. int Configure(void **ctxp, int argc, char *argv[])
  173. {
  174. if ( argc > 1 )
  175. {
  176. *ctxp = av_mallocz(sizeof(ContextInfo));
  177. if ( ctxp != NULL && argc > 1 )
  178. {
  179. ContextInfo *info = (ContextInfo *)*ctxp;
  180. info->rw = rwpipe_open( argc - 1, &argv[ 1 ] );
  181. return 0;
  182. }
  183. }
  184. return 1;
  185. }
  186. /** Process a frame.
  187. */
  188. void Process(void *ctx, AVPicture *picture, enum PixelFormat pix_fmt, int width, int height, int64_t pts)
  189. {
  190. int err = 0;
  191. ContextInfo *ci = (ContextInfo *) ctx;
  192. AVPicture picture1;
  193. AVPicture picture2;
  194. AVPicture *pict = picture;
  195. int out_width;
  196. int out_height;
  197. int i;
  198. uint8_t *ptr = NULL;
  199. FILE *in = rwpipe_reader( ci->rw );
  200. FILE *out = rwpipe_writer( ci->rw );
  201. /* Check that we have a pipe to talk to. */
  202. if ( in == NULL || out == NULL )
  203. err = 1;
  204. /* Convert to RGB24 if necessary */
  205. if ( !err && pix_fmt != PIX_FMT_RGB24 )
  206. {
  207. int size = avpicture_get_size(PIX_FMT_RGB24, width, height);
  208. if ( size != ci->size1 )
  209. {
  210. av_free( ci->buf1 );
  211. ci->buf1 = av_malloc(size);
  212. ci->size1 = size;
  213. err = ci->buf1 == NULL;
  214. }
  215. if ( !err )
  216. {
  217. avpicture_fill(&picture1, ci->buf1, PIX_FMT_RGB24, width, height);
  218. // if we already got a SWS context, let's realloc if is not re-useable
  219. ci->toRGB_convert_ctx = sws_getCachedContext(ci->toRGB_convert_ctx,
  220. width, height, pix_fmt,
  221. width, height, PIX_FMT_RGB24,
  222. sws_flags, NULL, NULL, NULL);
  223. if (ci->toRGB_convert_ctx == NULL) {
  224. av_log(NULL, AV_LOG_ERROR,
  225. "Cannot initialize the toRGB conversion context\n");
  226. return;
  227. }
  228. // img_convert parameters are 2 first destination, then 4 source
  229. // sws_scale parameters are context, 4 first source, then 2 destination
  230. sws_scale(ci->toRGB_convert_ctx,
  231. picture->data, picture->linesize, 0, height,
  232. picture1.data, picture1.linesize);
  233. pict = &picture1;
  234. }
  235. }
  236. /* Write out the PPM */
  237. if ( !err )
  238. {
  239. ptr = pict->data[ 0 ];
  240. fprintf( out, "P6\n%d %d\n255\n", width, height );
  241. for ( i = 0; !err && i < height; i ++ )
  242. {
  243. err = !fwrite( ptr, width * 3, 1, out );
  244. ptr += pict->linesize[ 0 ];
  245. }
  246. if ( !err )
  247. err = fflush( out );
  248. }
  249. /* Read the PPM returned. */
  250. if ( !err && !rwpipe_read_ppm_header( ci->rw, &out_width, &out_height ) )
  251. {
  252. int size = avpicture_get_size(PIX_FMT_RGB24, out_width, out_height);
  253. if ( size != ci->size2 )
  254. {
  255. av_free( ci->buf2 );
  256. ci->buf2 = av_malloc(size);
  257. ci->size2 = size;
  258. err = ci->buf2 == NULL;
  259. }
  260. if ( !err )
  261. {
  262. avpicture_fill(&picture2, ci->buf2, PIX_FMT_RGB24, out_width, out_height);
  263. ptr = picture2.data[ 0 ];
  264. for ( i = 0; !err && i < out_height; i ++ )
  265. {
  266. err = !fread( ptr, out_width * 3, 1, in );
  267. ptr += picture2.linesize[ 0 ];
  268. }
  269. }
  270. }
  271. /* Convert the returned PPM back to the input format */
  272. if ( !err )
  273. {
  274. /* The out_width/out_height returned from the PPM
  275. * filter won't necessarily be the same as width and height
  276. * but it will be scaled anyway to width/height.
  277. */
  278. av_log(NULL, AV_LOG_DEBUG,
  279. "PPM vhook: Input dimensions: %d x %d Output dimensions: %d x %d\n",
  280. width, height, out_width, out_height);
  281. ci->fromRGB_convert_ctx = sws_getCachedContext(ci->fromRGB_convert_ctx,
  282. out_width, out_height, PIX_FMT_RGB24,
  283. width, height, pix_fmt,
  284. sws_flags, NULL, NULL, NULL);
  285. if (ci->fromRGB_convert_ctx == NULL) {
  286. av_log(NULL, AV_LOG_ERROR,
  287. "Cannot initialize the fromRGB conversion context\n");
  288. return;
  289. }
  290. // img_convert parameters are 2 first destination, then 4 source
  291. // sws_scale parameters are context, 4 first source, then 2 destination
  292. sws_scale(ci->fromRGB_convert_ctx,
  293. picture2.data, picture2.linesize, 0, out_height,
  294. picture->data, picture->linesize);
  295. }
  296. }
  297. /** Clean up the effect.
  298. */
  299. void Release(void *ctx)
  300. {
  301. ContextInfo *ci;
  302. ci = (ContextInfo *) ctx;
  303. if (ctx)
  304. {
  305. rwpipe_close( ci->rw );
  306. av_free( ci->buf1 );
  307. av_free( ci->buf2 );
  308. sws_freeContext(ci->toRGB_convert_ctx);
  309. sws_freeContext(ci->fromRGB_convert_ctx);
  310. av_free(ctx);
  311. }
  312. }