Remove cast, now tables are signed.
[ffmpeg.git] / vhook / ppm.c
index 8a5e188..0e37ac4 100644 (file)
@@ -1,20 +1,22 @@
 /*
- * PPM Video Hook 
+ * PPM Video Hook
  * Copyright (c) 2003 Charles Yates
  *
- * This library is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
  *
- * This library is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <ctype.h>
-#include "framehook.h"
+#include "libavutil/avstring.h"
+#include "libavformat/framehook.h"
+#include "libavformat/avformat.h"
+#include "libswscale/swscale.h"
+#undef fprintf
+
+static int sws_flags = SWS_BICUBIC;
 
 /** Bi-directional pipe structure.
 */
 
 typedef struct rwpipe
 {
-       int pid;
-       FILE *reader;
-       FILE *writer;
+    int pid;
+    FILE *reader;
+    FILE *writer;
 }
 rwpipe;
 
 /** Create a bidirectional pipe for the given command.
 */
 
-rwpipe *rwpipe_open( int argc, char *argv[] )
+static rwpipe *rwpipe_open( int argc, char *argv[] )
 {
-       rwpipe *this = av_mallocz( sizeof( rwpipe ) );
+    rwpipe *this = av_mallocz( sizeof( rwpipe ) );
 
-       if ( this != NULL )
-       {
+    if ( this != NULL )
+    {
         int input[ 2 ];
         int output[ 2 ];
 
@@ -55,15 +63,16 @@ rwpipe *rwpipe_open( int argc, char *argv[] )
 
         if ( this->pid == 0 )
         {
-                       char *command = av_mallocz( 10240 );
-                       int i;
+#define COMMAND_SIZE 10240
+            char *command = av_mallocz( COMMAND_SIZE );
+            int i;
 
-                       strcpy( command, "" );
-                       for ( i = 0; i < argc; i ++ )
-                       {
-                               strcat( command, argv[ i ] );
-                               strcat( command, " " );
-                       }
+            strcpy( command, "" );
+            for ( i = 0; i < argc; i ++ )
+            {
+                av_strlcat( command, argv[ i ], COMMAND_SIZE );
+                av_strlcat( command, " ", COMMAND_SIZE );
+            }
 
             dup2( output[ 0 ], STDIN_FILENO );
             dup2( input[ 1 ], STDOUT_FILENO );
@@ -73,8 +82,8 @@ rwpipe *rwpipe_open( int argc, char *argv[] )
             close( output[ 0 ] );
             close( output[ 1 ] );
 
-            execl("/bin/sh", "sh", "-c", command, NULL );
-                       exit( 255 );
+            execl("/bin/sh", "sh", "-c", command, (char*)NULL );
+            _exit( 255 );
         }
         else
         {
@@ -84,188 +93,277 @@ rwpipe *rwpipe_open( int argc, char *argv[] )
             this->reader = fdopen( input[ 0 ], "r" );
             this->writer = fdopen( output[ 1 ], "w" );
         }
-       }
+    }
 
-       return this;
+    return this;
 }
 
 /** Read data from the pipe.
 */
 
-FILE *rwpipe_reader( rwpipe *this )
+static FILE *rwpipe_reader( rwpipe *this )
 {
-       if ( this != NULL )
-               return this->reader;
-       else
-               return NULL;
+    if ( this != NULL )
+        return this->reader;
+    else
+        return NULL;
 }
 
 /** Write data to the pipe.
 */
 
-FILE *rwpipe_writer( rwpipe *this )
+static FILE *rwpipe_writer( rwpipe *this )
 {
-       if ( this != NULL )
-               return this->writer;
-       else
-               return NULL;
+    if ( this != NULL )
+        return this->writer;
+    else
+        return NULL;
 }
 
-/** Close the pipe and process.
+/* Read a number from the pipe - assumes PNM style headers.
 */
 
-void rwpipe_close( rwpipe *this )
+static int rwpipe_read_number( rwpipe *rw )
 {
-       if ( this != NULL )
-       {
-               fclose( this->reader );
-               fclose( this->writer );
-               waitpid( this->pid, NULL, 0 );
-               av_free( this );
-       }
+    int value = 0;
+    int c = 0;
+    FILE *in = rwpipe_reader( rw );
+
+    do
+    {
+        c = fgetc( in );
+
+        while( c != EOF && !isdigit( c ) && c != '#' )
+            c = fgetc( in );
+
+        if ( c == '#' )
+            while( c != EOF && c != '\n' )
+                c = fgetc( in );
+    }
+    while ( c != EOF && !isdigit( c ) );
+
+    while( c != EOF && isdigit( c ) )
+    {
+        value = value * 10 + ( c - '0' );
+        c = fgetc( in );
+    }
+
+    return value;
 }
 
-typedef struct 
+/** Read a PPM P6 header.
+*/
+
+static int rwpipe_read_ppm_header( rwpipe *rw, int *width, int *height )
 {
-       rwpipe *rw;
-} 
-ContextInfo;
+    char line[ 3 ];
+    FILE *in = rwpipe_reader( rw );
+    int max;
+
+    fgets( line, 3, in );
+    if ( !strncmp( line, "P6", 2 ) )
+    {
+        *width = rwpipe_read_number( rw );
+        *height = rwpipe_read_number( rw );
+        max = rwpipe_read_number( rw );
+        return max != 255 || *width <= 0 || *height <= 0;
+    }
+    return 1;
+}
 
-int Configure(void **ctxp, int argc, char *argv[])
+/** Close the pipe and process.
+*/
+
+static void rwpipe_close( rwpipe *this )
 {
-    *ctxp = av_mallocz(sizeof(ContextInfo));
-       if ( ctxp != NULL && argc > 1 )
-       {
-               ContextInfo *info = (ContextInfo *)*ctxp;
-               info->rw = rwpipe_open( argc - 1, &argv[ 1 ] );
-       }
-    return 0;
+    if ( this != NULL )
+    {
+        fclose( this->reader );
+        fclose( this->writer );
+        waitpid( this->pid, NULL, 0 );
+        av_free( this );
+    }
 }
 
-int rwpipe_read_number( rwpipe *rw )
+/** Context info for this vhook - stores the pipe and image buffers.
+*/
+
+typedef struct
 {
-       int value = 0;
-       int c = 0;
-       FILE *in = rwpipe_reader( rw );
-
-       do 
-       {
-               c = fgetc( in );
-
-               while( c != EOF && !isdigit( c ) && c != '#' )
-                       c = fgetc( in );
-
-               if ( c == '#' )
-                       while( c != EOF && c != '\n' )
-                               c = fgetc( in );
-       }
-       while ( c != EOF && !isdigit( c ) );
-
-       while( c != EOF && isdigit( c ) )
-       {
-               value = value * 10 + ( c - '0' );
-               c = fgetc( in );
-       }
-
-       return value;
+    rwpipe *rw;
+    int size1;
+    char *buf1;
+    int size2;
+    char *buf2;
+
+    // This vhook first converts frame to RGB ...
+    struct SwsContext *toRGB_convert_ctx;
+    // ... then processes it via a PPM command pipe ...
+    // ... and finally converts back frame from RGB to initial format
+    struct SwsContext *fromRGB_convert_ctx;
 }
+ContextInfo;
+
+/** Initialise the context info for this vhook.
+*/
 
-int rwpipe_read_ppm_header( rwpipe *rw, int *width, int *height )
+int Configure(void **ctxp, int argc, char *argv[])
 {
-       char line[ 3 ];
-       FILE *in = rwpipe_reader( rw );
-       int max;
-
-       fgets( line, 3, in );
-       if ( !strncmp( line, "P6", 2 ) )
-       {
-               *width = rwpipe_read_number( rw );
-               *height = rwpipe_read_number( rw );
-               max = rwpipe_read_number( rw );
-               return max != 255 || *width <= 0 || *height <= 0;
-       }
-       return 1;
+    if ( argc > 1 )
+    {
+        *ctxp = av_mallocz(sizeof(ContextInfo));
+        if ( *ctxp != NULL && argc > 1 )
+        {
+            ContextInfo *info = (ContextInfo *)*ctxp;
+            info->rw = rwpipe_open( argc - 1, &argv[ 1 ] );
+            return 0;
+        }
+    }
+    return 1;
 }
 
+/** Process a frame.
+*/
+
 void Process(void *ctx, AVPicture *picture, enum PixelFormat pix_fmt, int width, int height, int64_t pts)
 {
-       int err = 0;
+    int err = 0;
     ContextInfo *ci = (ContextInfo *) ctx;
-    char *buf1 = 0;
-    char *buf2 = 0;
     AVPicture picture1;
     AVPicture picture2;
     AVPicture *pict = picture;
-       int out_width;
-       int out_height;
-       int i;
-       uint8_t *ptr = NULL;
-       FILE *in = rwpipe_reader( ci->rw );
-       FILE *out = rwpipe_writer( ci->rw );
-
-       /* Convert to RGB24 if necessary */
-    if (pix_fmt != PIX_FMT_RGB24) {
-        int size;
-
-        size = avpicture_get_size(PIX_FMT_RGB24, width, height);
-        buf1 = av_malloc(size);
-
-        avpicture_fill(&picture1, buf1, PIX_FMT_RGB24, width, height);
-        if (img_convert(&picture1, PIX_FMT_RGB24, 
-                        picture, pix_fmt, width, height) < 0) {
-                       err = 1;
+    int out_width;
+    int out_height;
+    int i;
+    uint8_t *ptr = NULL;
+    FILE *in = rwpipe_reader( ci->rw );
+    FILE *out = rwpipe_writer( ci->rw );
+
+    /* Check that we have a pipe to talk to. */
+    if ( in == NULL || out == NULL )
+        err = 1;
+
+    /* Convert to RGB24 if necessary */
+    if ( !err && pix_fmt != PIX_FMT_RGB24 )
+    {
+        int size = avpicture_get_size(PIX_FMT_RGB24, width, height);
+
+        if ( size != ci->size1 )
+        {
+            av_free( ci->buf1 );
+            ci->buf1 = av_malloc(size);
+            ci->size1 = size;
+            err = ci->buf1 == NULL;
+        }
+
+        if ( !err )
+        {
+            avpicture_fill(&picture1, ci->buf1, PIX_FMT_RGB24, width, height);
+
+            // if we already got a SWS context, let's realloc if is not re-useable
+            ci->toRGB_convert_ctx = sws_getCachedContext(ci->toRGB_convert_ctx,
+                                        width, height, pix_fmt,
+                                        width, height, PIX_FMT_RGB24,
+                                        sws_flags, NULL, NULL, NULL);
+            if (ci->toRGB_convert_ctx == NULL) {
+                av_log(NULL, AV_LOG_ERROR,
+                       "Cannot initialize the toRGB conversion context\n");
+                return;
+            }
+
+// img_convert parameters are          2 first destination, then 4 source
+// sws_scale   parameters are context, 4 first source,      then 2 destination
+            sws_scale(ci->toRGB_convert_ctx,
+                     picture->data, picture->linesize, 0, height,
+                     picture1.data, picture1.linesize);
+
+            pict = &picture1;
+        }
+    }
+
+    /* Write out the PPM */
+    if ( !err )
+    {
+        ptr = pict->data[ 0 ];
+        fprintf( out, "P6\n%d %d\n255\n", width, height );
+        for ( i = 0; !err && i < height; i ++ )
+        {
+            err = !fwrite( ptr, width * 3, 1, out );
+            ptr += pict->linesize[ 0 ];
         }
-        pict = &picture1;
+        if ( !err )
+            err = fflush( out );
     }
 
-       /* Write out the PPM */
-       if ( !err )
-       {
-               ptr = pict->data[ 0 ];
-               fprintf( out, "P6\n%d %d\n255\n", width, height );
-               for ( i = 0; !err && i < height; i ++ )
-               {
-                       err = !fwrite( ptr, width * 3, 1, out );
-                       ptr += pict->linesize[ 0 ];
-               }
-               if ( !err )
-                       err = fflush( out );
-       }
-
-       /* Read the PPM returned. */
-       if ( !err && !rwpipe_read_ppm_header( ci->rw, &out_width, &out_height ) )
-       {
+    /* Read the PPM returned. */
+    if ( !err && !rwpipe_read_ppm_header( ci->rw, &out_width, &out_height ) )
+    {
         int size = avpicture_get_size(PIX_FMT_RGB24, out_width, out_height);
-        buf2 = av_malloc(size);
-        avpicture_fill(&picture2, buf2, PIX_FMT_RGB24, out_width, out_height);
-               ptr = picture2.data[ 0 ];
-               for ( i = 0; !err && i < out_height; i ++ )
-               {
-                       err = !fread( ptr, out_width * 3, 1, in );
-                       ptr += picture2.linesize[ 0 ];
-               }
-       }
-
-       /* Convert the returned PPM back to the input format */
-       if ( !err )
-       {
-        if (img_convert(picture, pix_fmt, &picture2, PIX_FMT_RGB24, width, height) < 0) {
+
+        if ( size != ci->size2 )
+        {
+            av_free( ci->buf2 );
+            ci->buf2 = av_malloc(size);
+            ci->size2 = size;
+            err = ci->buf2 == NULL;
         }
-       }
 
-    av_free(buf1);
-    av_free(buf2);
+        if ( !err )
+        {
+            avpicture_fill(&picture2, ci->buf2, PIX_FMT_RGB24, out_width, out_height);
+            ptr = picture2.data[ 0 ];
+            for ( i = 0; !err && i < out_height; i ++ )
+            {
+                err = !fread( ptr, out_width * 3, 1, in );
+                ptr += picture2.linesize[ 0 ];
+            }
+        }
+    }
+
+    /* Convert the returned PPM back to the input format */
+    if ( !err )
+    {
+        /* The out_width/out_height returned from the PPM
+         * filter won't necessarily be the same as width and height
+         * but it will be scaled anyway to width/height.
+         */
+        av_log(NULL, AV_LOG_DEBUG,
+                  "PPM vhook: Input dimensions: %d x %d Output dimensions: %d x %d\n",
+                  width, height, out_width, out_height);
+        ci->fromRGB_convert_ctx = sws_getCachedContext(ci->fromRGB_convert_ctx,
+                                        out_width, out_height, PIX_FMT_RGB24,
+                                        width,     height,     pix_fmt,
+                                        sws_flags, NULL, NULL, NULL);
+        if (ci->fromRGB_convert_ctx == NULL) {
+            av_log(NULL, AV_LOG_ERROR,
+                   "Cannot initialize the fromRGB conversion context\n");
+            return;
+        }
+
+// img_convert parameters are          2 first destination, then 4 source
+// sws_scale   parameters are context, 4 first source,      then 2 destination
+        sws_scale(ci->fromRGB_convert_ctx,
+                 picture2.data, picture2.linesize, 0, out_height,
+                 picture->data, picture->linesize);
+    }
 }
 
+/** Clean up the effect.
+*/
+
 void Release(void *ctx)
 {
     ContextInfo *ci;
     ci = (ContextInfo *) ctx;
 
     if (ctx)
-       {
-               rwpipe_close( ci->rw );
+    {
+        rwpipe_close( ci->rw );
+        av_free( ci->buf1 );
+        av_free( ci->buf2 );
+        sws_freeContext(ci->toRGB_convert_ctx);
+        sws_freeContext(ci->fromRGB_convert_ctx);
         av_free(ctx);
-       }
+    }
 }