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"
33 static int sws_flags
= SWS_BICUBIC
;
35 /** Bi-directional pipe structure.
46 /** Create a bidirectional pipe for the given command.
49 static rwpipe
*rwpipe_open( int argc
, char *argv
[] )
51 rwpipe
*this = av_mallocz( sizeof( rwpipe
) );
65 #define COMMAND_SIZE 10240
66 char *command
= av_mallocz( COMMAND_SIZE
);
69 strcpy( command
, "" );
70 for ( i
= 0; i
< argc
; i
++ )
72 av_strlcat( command
, argv
[ i
], COMMAND_SIZE
);
73 av_strlcat( command
, " ", COMMAND_SIZE
);
76 dup2( output
[ 0 ], STDIN_FILENO
);
77 dup2( input
[ 1 ], STDOUT_FILENO
);
84 execl("/bin/sh", "sh", "-c", command
, (char*)NULL
);
92 this->reader
= fdopen( input
[ 0 ], "r" );
93 this->writer
= fdopen( output
[ 1 ], "w" );
100 /** Read data from the pipe.
103 static FILE *rwpipe_reader( rwpipe
*this )
111 /** Write data to the pipe.
114 static FILE *rwpipe_writer( rwpipe
*this )
122 /* Read a number from the pipe - assumes PNM style headers.
125 static int rwpipe_read_number( rwpipe
*rw
)
129 FILE *in
= rwpipe_reader( rw
);
135 while( c
!= EOF
&& !isdigit( c
) && c
!= '#' )
139 while( c
!= EOF
&& c
!= '\n' )
142 while ( c
!= EOF
&& !isdigit( c
) );
144 while( c
!= EOF
&& isdigit( c
) )
146 value
= value
* 10 + ( c
- '0' );
153 /** Read a PPM P6 header.
156 static int rwpipe_read_ppm_header( rwpipe
*rw
, int *width
, int *height
)
159 FILE *in
= rwpipe_reader( rw
);
162 fgets( line
, 3, in
);
163 if ( !strncmp( line
, "P6", 2 ) )
165 *width
= rwpipe_read_number( rw
);
166 *height
= rwpipe_read_number( rw
);
167 max
= rwpipe_read_number( rw
);
168 return max
!= 255 || *width
<= 0 || *height
<= 0;
173 /** Close the pipe and process.
176 static void rwpipe_close( rwpipe
*this )
180 fclose( this->reader
);
181 fclose( this->writer
);
182 waitpid( this->pid
, NULL
, 0 );
187 /** Context info for this vhook - stores the pipe and image buffers.
198 // This vhook first converts frame to RGB ...
199 struct SwsContext
*toRGB_convert_ctx
;
200 // ... then processes it via a PPM command pipe ...
201 // ... and finally converts back frame from RGB to initial format
202 struct SwsContext
*fromRGB_convert_ctx
;
206 /** Initialise the context info for this vhook.
209 int Configure(void **ctxp
, int argc
, char *argv
[])
213 *ctxp
= av_mallocz(sizeof(ContextInfo
));
214 if ( ctxp
!= NULL
&& argc
> 1 )
216 ContextInfo
*info
= (ContextInfo
*)*ctxp
;
217 info
->rw
= rwpipe_open( argc
- 1, &argv
[ 1 ] );
227 void Process(void *ctx
, AVPicture
*picture
, enum PixelFormat pix_fmt
, int width
, int height
, int64_t pts
)
230 ContextInfo
*ci
= (ContextInfo
*) ctx
;
233 AVPicture
*pict
= picture
;
238 FILE *in
= rwpipe_reader( ci
->rw
);
239 FILE *out
= rwpipe_writer( ci
->rw
);
241 /* Check that we have a pipe to talk to. */
242 if ( in
== NULL
|| out
== NULL
)
245 /* Convert to RGB24 if necessary */
246 if ( !err
&& pix_fmt
!= PIX_FMT_RGB24
)
248 int size
= avpicture_get_size(PIX_FMT_RGB24
, width
, height
);
250 if ( size
!= ci
->size1
)
253 ci
->buf1
= av_malloc(size
);
255 err
= ci
->buf1
== NULL
;
260 avpicture_fill(&picture1
, ci
->buf1
, PIX_FMT_RGB24
, width
, height
);
262 // if we already got a SWS context, let's realloc if is not re-useable
263 ci
->toRGB_convert_ctx
= sws_getCachedContext(ci
->toRGB_convert_ctx
,
264 width
, height
, pix_fmt
,
265 width
, height
, PIX_FMT_RGB24
,
266 sws_flags
, NULL
, NULL
, NULL
);
267 if (ci
->toRGB_convert_ctx
== NULL
) {
268 av_log(NULL
, AV_LOG_ERROR
,
269 "Cannot initialize the toRGB conversion context\n");
273 // img_convert parameters are 2 first destination, then 4 source
274 // sws_scale parameters are context, 4 first source, then 2 destination
275 sws_scale(ci
->toRGB_convert_ctx
,
276 picture
->data
, picture
->linesize
, 0, height
,
277 picture1
.data
, picture1
.linesize
);
283 /* Write out the PPM */
286 ptr
= pict
->data
[ 0 ];
287 fprintf( out
, "P6\n%d %d\n255\n", width
, height
);
288 for ( i
= 0; !err
&& i
< height
; i
++ )
290 err
= !fwrite( ptr
, width
* 3, 1, out
);
291 ptr
+= pict
->linesize
[ 0 ];
297 /* Read the PPM returned. */
298 if ( !err
&& !rwpipe_read_ppm_header( ci
->rw
, &out_width
, &out_height
) )
300 int size
= avpicture_get_size(PIX_FMT_RGB24
, out_width
, out_height
);
302 if ( size
!= ci
->size2
)
305 ci
->buf2
= av_malloc(size
);
307 err
= ci
->buf2
== NULL
;
312 avpicture_fill(&picture2
, ci
->buf2
, PIX_FMT_RGB24
, out_width
, out_height
);
313 ptr
= picture2
.data
[ 0 ];
314 for ( i
= 0; !err
&& i
< out_height
; i
++ )
316 err
= !fread( ptr
, out_width
* 3, 1, in
);
317 ptr
+= picture2
.linesize
[ 0 ];
322 /* Convert the returned PPM back to the input format */
325 /* The out_width/out_height returned from the PPM
326 * filter won't necessarily be the same as width and height
327 * but it will be scaled anyway to width/height.
329 av_log(NULL
, AV_LOG_DEBUG
,
330 "PPM vhook: Input dimensions: %d x %d Output dimensions: %d x %d\n",
331 width
, height
, out_width
, out_height
);
332 ci
->fromRGB_convert_ctx
= sws_getCachedContext(ci
->fromRGB_convert_ctx
,
333 out_width
, out_height
, PIX_FMT_RGB24
,
334 width
, height
, pix_fmt
,
335 sws_flags
, NULL
, NULL
, NULL
);
336 if (ci
->fromRGB_convert_ctx
== NULL
) {
337 av_log(NULL
, AV_LOG_ERROR
,
338 "Cannot initialize the fromRGB conversion context\n");
342 // img_convert parameters are 2 first destination, then 4 source
343 // sws_scale parameters are context, 4 first source, then 2 destination
344 sws_scale(ci
->fromRGB_convert_ctx
,
345 picture2
.data
, picture2
.linesize
, 0, out_height
,
346 picture
->data
, picture
->linesize
);
350 /** Clean up the effect.
353 void Release(void *ctx
)
356 ci
= (ContextInfo
*) ctx
;
360 rwpipe_close( ci
->rw
);
363 sws_freeContext(ci
->toRGB_convert_ctx
);
364 sws_freeContext(ci
->fromRGB_convert_ctx
);