3 * Copyright (c) 2003 Charles Yates
5 * This file is part of FFmpeg.
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.
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.
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
25 #include <sys/types.h>
28 #include "libavutil/avstring.h"
29 #include "libavformat/framehook.h"
30 #include "libavformat/avformat.h"
31 #include "libswscale/swscale.h"
34 static int sws_flags
= SWS_BICUBIC
;
36 /** Bi-directional pipe structure.
47 /** Create a bidirectional pipe for the given command.
50 static rwpipe
*rwpipe_open( int argc
, char *argv
[] )
52 rwpipe
*this = av_mallocz( sizeof( rwpipe
) );
66 #define COMMAND_SIZE 10240
67 char *command
= av_mallocz( COMMAND_SIZE
);
70 strcpy( command
, "" );
71 for ( i
= 0; i
< argc
; i
++ )
73 av_strlcat( command
, argv
[ i
], COMMAND_SIZE
);
74 av_strlcat( command
, " ", COMMAND_SIZE
);
77 dup2( output
[ 0 ], STDIN_FILENO
);
78 dup2( input
[ 1 ], STDOUT_FILENO
);
85 execl("/bin/sh", "sh", "-c", command
, (char*)NULL
);
93 this->reader
= fdopen( input
[ 0 ], "r" );
94 this->writer
= fdopen( output
[ 1 ], "w" );
101 /** Read data from the pipe.
104 static FILE *rwpipe_reader( rwpipe
*this )
112 /** Write data to the pipe.
115 static FILE *rwpipe_writer( rwpipe
*this )
123 /* Read a number from the pipe - assumes PNM style headers.
126 static int rwpipe_read_number( rwpipe
*rw
)
130 FILE *in
= rwpipe_reader( rw
);
136 while( c
!= EOF
&& !isdigit( c
) && c
!= '#' )
140 while( c
!= EOF
&& c
!= '\n' )
143 while ( c
!= EOF
&& !isdigit( c
) );
145 while( c
!= EOF
&& isdigit( c
) )
147 value
= value
* 10 + ( c
- '0' );
154 /** Read a PPM P6 header.
157 static int rwpipe_read_ppm_header( rwpipe
*rw
, int *width
, int *height
)
160 FILE *in
= rwpipe_reader( rw
);
163 fgets( line
, 3, in
);
164 if ( !strncmp( line
, "P6", 2 ) )
166 *width
= rwpipe_read_number( rw
);
167 *height
= rwpipe_read_number( rw
);
168 max
= rwpipe_read_number( rw
);
169 return max
!= 255 || *width
<= 0 || *height
<= 0;
174 /** Close the pipe and process.
177 static void rwpipe_close( rwpipe
*this )
181 fclose( this->reader
);
182 fclose( this->writer
);
183 waitpid( this->pid
, NULL
, 0 );
188 /** Context info for this vhook - stores the pipe and image buffers.
199 // This vhook first converts frame to RGB ...
200 struct SwsContext
*toRGB_convert_ctx
;
201 // ... then processes it via a PPM command pipe ...
202 // ... and finally converts back frame from RGB to initial format
203 struct SwsContext
*fromRGB_convert_ctx
;
207 /** Initialise the context info for this vhook.
210 int Configure(void **ctxp
, int argc
, char *argv
[])
214 *ctxp
= av_mallocz(sizeof(ContextInfo
));
215 if ( *ctxp
!= NULL
&& argc
> 1 )
217 ContextInfo
*info
= (ContextInfo
*)*ctxp
;
218 info
->rw
= rwpipe_open( argc
- 1, &argv
[ 1 ] );
228 void Process(void *ctx
, AVPicture
*picture
, enum PixelFormat pix_fmt
, int width
, int height
, int64_t pts
)
231 ContextInfo
*ci
= (ContextInfo
*) ctx
;
234 AVPicture
*pict
= picture
;
239 FILE *in
= rwpipe_reader( ci
->rw
);
240 FILE *out
= rwpipe_writer( ci
->rw
);
242 /* Check that we have a pipe to talk to. */
243 if ( in
== NULL
|| out
== NULL
)
246 /* Convert to RGB24 if necessary */
247 if ( !err
&& pix_fmt
!= PIX_FMT_RGB24
)
249 int size
= avpicture_get_size(PIX_FMT_RGB24
, width
, height
);
251 if ( size
!= ci
->size1
)
254 ci
->buf1
= av_malloc(size
);
256 err
= ci
->buf1
== NULL
;
261 avpicture_fill(&picture1
, ci
->buf1
, PIX_FMT_RGB24
, width
, height
);
263 // if we already got a SWS context, let's realloc if is not re-useable
264 ci
->toRGB_convert_ctx
= sws_getCachedContext(ci
->toRGB_convert_ctx
,
265 width
, height
, pix_fmt
,
266 width
, height
, PIX_FMT_RGB24
,
267 sws_flags
, NULL
, NULL
, NULL
);
268 if (ci
->toRGB_convert_ctx
== NULL
) {
269 av_log(NULL
, AV_LOG_ERROR
,
270 "Cannot initialize the toRGB conversion context\n");
274 // img_convert parameters are 2 first destination, then 4 source
275 // sws_scale parameters are context, 4 first source, then 2 destination
276 sws_scale(ci
->toRGB_convert_ctx
,
277 picture
->data
, picture
->linesize
, 0, height
,
278 picture1
.data
, picture1
.linesize
);
284 /* Write out the PPM */
287 ptr
= pict
->data
[ 0 ];
288 fprintf( out
, "P6\n%d %d\n255\n", width
, height
);
289 for ( i
= 0; !err
&& i
< height
; i
++ )
291 err
= !fwrite( ptr
, width
* 3, 1, out
);
292 ptr
+= pict
->linesize
[ 0 ];
298 /* Read the PPM returned. */
299 if ( !err
&& !rwpipe_read_ppm_header( ci
->rw
, &out_width
, &out_height
) )
301 int size
= avpicture_get_size(PIX_FMT_RGB24
, out_width
, out_height
);
303 if ( size
!= ci
->size2
)
306 ci
->buf2
= av_malloc(size
);
308 err
= ci
->buf2
== NULL
;
313 avpicture_fill(&picture2
, ci
->buf2
, PIX_FMT_RGB24
, out_width
, out_height
);
314 ptr
= picture2
.data
[ 0 ];
315 for ( i
= 0; !err
&& i
< out_height
; i
++ )
317 err
= !fread( ptr
, out_width
* 3, 1, in
);
318 ptr
+= picture2
.linesize
[ 0 ];
323 /* Convert the returned PPM back to the input format */
326 /* The out_width/out_height returned from the PPM
327 * filter won't necessarily be the same as width and height
328 * but it will be scaled anyway to width/height.
330 av_log(NULL
, AV_LOG_DEBUG
,
331 "PPM vhook: Input dimensions: %d x %d Output dimensions: %d x %d\n",
332 width
, height
, out_width
, out_height
);
333 ci
->fromRGB_convert_ctx
= sws_getCachedContext(ci
->fromRGB_convert_ctx
,
334 out_width
, out_height
, PIX_FMT_RGB24
,
335 width
, height
, pix_fmt
,
336 sws_flags
, NULL
, NULL
, NULL
);
337 if (ci
->fromRGB_convert_ctx
== NULL
) {
338 av_log(NULL
, AV_LOG_ERROR
,
339 "Cannot initialize the fromRGB conversion context\n");
343 // img_convert parameters are 2 first destination, then 4 source
344 // sws_scale parameters are context, 4 first source, then 2 destination
345 sws_scale(ci
->fromRGB_convert_ctx
,
346 picture2
.data
, picture2
.linesize
, 0, out_height
,
347 picture
->data
, picture
->linesize
);
351 /** Clean up the effect.
354 void Release(void *ctx
)
357 ci
= (ContextInfo
*) ctx
;
361 rwpipe_close( ci
->rw
);
364 sws_freeContext(ci
->toRGB_convert_ctx
);
365 sws_freeContext(ci
->fromRGB_convert_ctx
);