* Add frame rate conversion when there is no audio channel. This makes
authorPhilip Gladstone <philipjsg@users.sourceforge.net>
Wed, 20 Nov 2002 03:06:12 +0000 (03:06 +0000)
committerPhilip Gladstone <philipjsg@users.sourceforge.net>
Wed, 20 Nov 2002 03:06:12 +0000 (03:06 +0000)
  ffmpeg/ffserver work again when just capturing video from a live
  source and you are streaming feeds of different frame rates.
* Fix a segfault in argument processing
* Add handling for -vhook argument
* Add logic to call video hooks if any have been specified.

Originally committed as revision 1247 to svn://svn.ffmpeg.org/ffmpeg/trunk

ffmpeg.c

index f6c7f70..25cfba6 100644 (file)
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -18,6 +18,7 @@
  */
 #define HAVE_AV_CONFIG_H
 #include "avformat.h"
+#include "framehook.h"
 
 #ifndef CONFIG_WIN32
 #include <unistd.h>
@@ -447,6 +448,46 @@ static void write_picture(AVFormatContext *s, int index, AVPicture *picture,
     av_free(buf);
 }
 
+static void pre_process_video_frame(AVInputStream *ist, AVPicture *picture, void **bufp)
+{
+    AVCodecContext *dec;
+    AVPicture *picture2;
+    AVPicture picture_tmp;
+    UINT8 *buf = 0;
+
+    dec = &ist->st->codec;
+
+    /* deinterlace : must be done before any resize */
+    if (do_deinterlace) {
+        int size;
+
+        /* create temporary picture */
+        size = avpicture_get_size(dec->pix_fmt, dec->width, dec->height);
+        buf = av_malloc(size);
+        if (!buf)
+            return;
+        
+        picture2 = &picture_tmp;
+        avpicture_fill(picture2, buf, dec->pix_fmt, dec->width, dec->height);
+
+        if (avpicture_deinterlace(picture2, picture, 
+                                  dec->pix_fmt, dec->width, dec->height) < 0) {
+            /* if error, do not deinterlace */
+            av_free(buf);
+            buf = NULL;
+            picture2 = picture;
+        }
+    } else {
+        picture2 = picture;
+    }
+
+    frame_hook_process(picture2, dec->pix_fmt, dec->width, dec->height);
+
+    if (picture != picture2)
+        *picture = *picture2;
+    *bufp = buf;
+}
+
 /* we begin to correct av delay at this threshold */
 #define AV_DELAY_MAX 0.100
 
@@ -457,8 +498,8 @@ static void do_video_out(AVFormatContext *s,
                          int *frame_size, AVOutputStream *audio_sync)
 {
     int nb_frames, i, ret;
-    AVPicture *picture, *picture2, *pict;
-    AVPicture picture_tmp1, picture_tmp2;
+    AVPicture *picture, *pict;
+    AVPicture picture_tmp1;
     static UINT8 *video_buffer;
     UINT8 *buf = NULL, *buf1 = NULL;
     AVCodecContext *enc, *dec;
@@ -496,8 +537,18 @@ static void do_video_out(AVFormatContext *s,
             else if (av_delay > AV_DELAY_MAX)
                 nb_frames = 0;
         }
+    } else {
+        double vdelta;
+
+        if (ost->sync_ipts != AV_NOPTS_VALUE) {
+            vdelta = (double)(ost->st->pts.val) * s->pts_num / s->pts_den - ost->sync_ipts;
+            if (vdelta < -AV_DELAY_MAX)
+                nb_frames = 2;
+            else if (vdelta > AV_DELAY_MAX)
+                nb_frames = 0;
+            //printf("vdelta=%f\n", vdelta); 
+        }
     }
-    /* XXX: also handle frame rate conversion */
     if (nb_frames <= 0) 
         return;
 
@@ -506,30 +557,6 @@ static void do_video_out(AVFormatContext *s,
     if (!video_buffer)
         return;
 
-    /* deinterlace : must be done before any resize */
-    if (do_deinterlace) {
-        int size;
-
-        /* create temporary picture */
-        size = avpicture_get_size(dec->pix_fmt, dec->width, dec->height);
-        buf1 = av_malloc(size);
-        if (!buf1)
-            return;
-        
-        picture2 = &picture_tmp2;
-        avpicture_fill(picture2, buf1, dec->pix_fmt, dec->width, dec->height);
-
-        if (avpicture_deinterlace(picture2, picture1, 
-                                  dec->pix_fmt, dec->width, dec->height) < 0) {
-            /* if error, do not deinterlace */
-            av_free(buf1);
-            buf1 = NULL;
-            picture2 = picture1;
-        }
-    } else {
-        picture2 = picture1;
-    }
-
     /* convert pixel format if needed */
     if (enc->pix_fmt != dec->pix_fmt) {
         int size;
@@ -543,13 +570,13 @@ static void do_video_out(AVFormatContext *s,
         avpicture_fill(pict, buf, enc->pix_fmt, dec->width, dec->height);
         
         if (img_convert(pict, enc->pix_fmt, 
-                        picture2, dec->pix_fmt, 
+                        picture1, dec->pix_fmt, 
                         dec->width, dec->height) < 0) {
             fprintf(stderr, "pixel format conversion not handled\n");
             goto the_end;
         }
     } else {
-        pict = picture2;
+        pict = picture1;
     }
 
     /* XXX: resampling could be done before raw format convertion in
@@ -690,6 +717,10 @@ void print_report(AVFormatContext **output_files,
         ost = ost_table[i];
         os = output_files[ost->file_index];
         enc = &ost->st->codec;
+        if (vid && enc->codec_type == CODEC_TYPE_VIDEO) {
+            sprintf(buf + strlen(buf), "q=%2d ",
+                    enc->quality);
+        }
         if (!vid && enc->codec_type == CODEC_TYPE_VIDEO) {
             frame_number = ost->frame_number;
             sprintf(buf + strlen(buf), "frame=%5d q=%2d ",
@@ -1019,8 +1050,8 @@ static int av_encode(AVFormatContext **output_files,
             AVCodec *codec;
             codec = avcodec_find_decoder(ist->st->codec.codec_id);
             if (!codec) {
-                fprintf(stderr, "Unsupported codec for input stream #%d.%d\n", 
-                        ist->file_index, ist->index);
+                fprintf(stderr, "Unsupported codec (id=%d) for input stream #%d.%d\n", 
+                        ist->st->codec.codec_id, ist->file_index, ist->index);
                 exit(1);
             }
             if (avcodec_open(&ist->st->codec, codec) < 0) {
@@ -1075,6 +1106,7 @@ static int av_encode(AVFormatContext **output_files,
         int data_size, got_picture;
         AVPicture picture;
         short samples[AVCODEC_MAX_AUDIO_FRAME_SIZE / 2];
+        void *buffer_to_free;
         double pts_min;
         
     redo:
@@ -1221,6 +1253,11 @@ static int av_encode(AVFormatContext **output_files,
             ptr += ret;
             len -= ret;
 
+            buffer_to_free = 0;
+            if (ist->st->codec.codec_type == CODEC_TYPE_VIDEO) {
+                pre_process_video_frame(ist, &picture, &buffer_to_free);
+            }
+
             ist->frame_decoded = 1;
 
 #if 0
@@ -1257,6 +1294,9 @@ static int av_encode(AVFormatContext **output_files,
                         /* XXX: take into account the various fifos,
                            in particular for audio */
                         ost->sync_opts = ost->st->pts.val;
+                        //printf("ipts=%lld sync_ipts=%f sync_opts=%lld pts.val=%lld pkt.pts=%lld\n", ipts, ost->sync_ipts, ost->sync_opts, ost->st->pts.val, pkt.pts); 
+                    } else {
+                        //printf("pts.val=%lld\n", ost->st->pts.val); 
                     }
 
                     if (ost->encoding_needed) {
@@ -1296,6 +1336,7 @@ static int av_encode(AVFormatContext **output_files,
                     }
                 }
             }
+            av_free(buffer_to_free);
             ipts = AV_NOPTS_VALUE;
         }
     discard_packet:
@@ -1719,6 +1760,25 @@ void opt_audio_codec(const char *arg)
     }
 }
 
+void add_frame_hooker(const char *arg)
+{
+    int argc = 0;
+    char *argv[64];
+    int i;
+    char *args = strdup(arg);
+
+    argv[0] = strtok(args, " ");
+    while (argc < 62 && (argv[++argc] = strtok(NULL, " "))) {
+    }
+
+    i = frame_hook_add(argc, argv);
+
+    if (i != 0) {
+        fprintf(stderr, "Failed to add video hook function: %s\n", arg);
+        exit(1);
+    }
+}
+
 const char *motion_str[] = {
     "zero",
     "full",
@@ -2489,6 +2549,7 @@ const OptionDef options[] = {
     { "psnr", OPT_BOOL | OPT_EXPERT, {(void*)&do_psnr}, "calculate PSNR of compressed frames" },
     { "vstats", OPT_BOOL | OPT_EXPERT, {(void*)&do_vstats}, "dump video coding statistics to file" }, 
     { "bitexact", OPT_EXPERT, {(void*)opt_bitexact}, "only use bit exact algorithms (for codec testing)" }, 
+    { "vhook", HAS_ARG | OPT_EXPERT, {(void*)add_frame_hooker}, "insert video processing module", "module name and parameters" },
     { NULL, },
 };
 
@@ -2526,8 +2587,13 @@ int main(int argc, char **argv)
                 exit(1);
             }
             arg = NULL;
-            if (po->flags & HAS_ARG)
+            if (po->flags & HAS_ARG) {
                 arg = argv[optindex++];
+                if (!arg) {
+                    fprintf(stderr, "%s: missing argument for option '%s'\n", argv[0], opt);
+                    exit(1);
+                }
+            }
             if (po->flags & OPT_STRING) {
                 char *str;
                 str = strdup(arg);