gimp-gap r831 - in trunk: . vid_enc_avi



Author: wolfgangh
Date: Mon Apr 13 12:57:43 2009
New Revision: 831
URL: http://svn.gnome.org/viewvc/gimp-gap?rev=831&view=rev

Log:
fixed AVI1 encoder and avilib audio handling

Modified:
   trunk/ChangeLog
   trunk/README
   trunk/vid_enc_avi/avilib.c
   trunk/vid_enc_avi/avilib.h
   trunk/vid_enc_avi/gap_enc_avi_main.c

Modified: trunk/README
==============================================================================
--- trunk/README	(original)
+++ trunk/README	Mon Apr 13 12:57:43 2009
@@ -1,4 +1,4 @@
-This is an unstable developers version 2.3.0 of the GIMP Video menu.
+This is an unstable developers version 2.5.0 of the GIMP Video menu.
 
 The GIMP-GAP (GIMP Animation Package) is a collection of Plug-Ins
 to extend the GIMP with capabilities to edit and create
@@ -7,12 +7,12 @@
 
 Requires:
 =========
- - gimp 2.2 or higher.
-     This release was tested with gimp-2.2.11
+ - gimp 2.6.0 or higher.
+     This release was tested with gimp-2.6.6
      
      Note: GIMP-GAP provides some features that are able to call many of the
            GIMP standard filters. (plug-in programs that are shiped with 
-           gimp-2.2.11) Those features depend on the tested PDB interface
+           gimp-2.6.6) Those features depend on the tested PDB interface
            versions and may fail if newer version are used.
 
  - glib 2.8 or higher.
@@ -23,8 +23,7 @@
    ffmpeg and libmpeg3 are included as sourcecode tarball in this
    GIMP-GAP distribution.
    
-   - nasm  and the old gcc 3.3 version 
-           are required only in case when compiling of the
+   - nasm  is required only in case when compiling of the
            (optional) libmpeg3 is desired.
            (nasm for the .asm sources)
    
@@ -34,15 +33,8 @@
 
  Optional libs for decode/encode videofiles:
 
- - liba52     0.7.4
-                   recent ffmpeg libraries do no longer include
-                   this library that is required to encode/decode
-                   DVD audio, but ffmpeg supports dynamic linking of the liba52
-                   library if it is installed and the GPL licence 
-                   configure option is set ( --enable-gpl --enable-liba52 )
-                   installation of liba52 is Recommanded.
 
- - xvid       1.0.2
+ - libxvid       1.0.2
                    The free XVID Codec is used for MPEG4 encoding
 		   with the gimp-gap AVI fileformat encoding plug-in.
 		   (the FFMPEG libs have built in MPEG4 support
@@ -50,6 +42,15 @@
 		 
 		   You can get the xvid codec at:
 		       http://www.xvid.org/downloads.html
+ 
+ Optional libs for decode/encode videofiles based on ffmpeg
+ 
+ - libbz2
+ - libfaac 
+ - libfaad
+ - libmp3lame
+ - libx264
+
 
 
 For general information about GIMP-GAP concepts
@@ -69,7 +70,7 @@
 - ffmpeg
 - libmpeg3
 
-Those libs are built automatically.
+Those libs are built automatically in case their requirements are available.
 Configuration options for those libs can be set by editing the
 files:
 
@@ -79,20 +80,20 @@
 Those configure_option files are read by the master .configure script
 
 
-Installation:
 
-  ./autogen.sh   # includes the ./configure call
+Installation from SVN source tree:
+==================================
+
+  ./autogen.sh   # includes generation of the configure script ant the ./configure call
   make
   make install
 
 
 
 
-
-
 A correct installation adds the follwing menu trees to the GIMP:
   <Image>/Video
-  <Xtns>/Split Video to Frames
+  <Filters>/Split Video to Frames
   
 An overview of all menus can be found at
 docs/reference/txt/INTRODUCTION.txt    
@@ -102,18 +103,15 @@
 
 Additional notes:
   This version of GIMP-GAP is a separated Package since GIMP-1.3.x
-  and does not compile/run with GIMP-1.2.x or older GIMP versions than 2.2.
+  and does not compile/run with GIMP-1.2.x or older GIMP versions than 2.4.
 
 
 Notes:
 ======
-   
-   - GIMP 1.1.4 upto GIMP-1.2.x have included older versions of GIMP-GAP 
-     as standard plug-in (named gap) with no need of extra installation.
-
-
    - GIMP-GAP provides frontend dialogs for:
       - mplayer 1.0
+      
+      OLD frontends:
       - xanim 2.80.1 exporting edition (with the extensions from loki
         entertainment)
       - mpeg_encode (V1.5R2)
@@ -124,17 +122,19 @@
      The programs mpeg2encode, mpeg_encode, and xanim
      are old and you may not need them at all since GIMP-GAP-2.2
      provides improved alternatives for all of them.
+     Note that the old frontends are not bulit by default.
      
-     But it is higly recommanded to install the program mplayer.
-     MPlayer does support very much videofileformats.
-     
-     
-     If you like to use that stuff, you should install
-       mplayer
+     If you want to use that old stuff, you should install
        xanim 2.80.1 (loki)
        mpeg_encode and mpeg_play
        mpeg2encode and mpeg2decode
-     on your system.
+     on your system and configure gimp-gap with the option --enable-unix-frontends
+     
+     
+     
+     It is recommanded to install the program mplayer.
+     MPlayer does support very much videofileformats.
+     
 
    - The GIMP-GAP playback module provides audiosupport for audiofiles
      in RIFF WAV format.  The audiosupport is based on wavplay (tested
@@ -157,6 +157,11 @@
    - There is no need to install all those external programs to
      compile GIMP-GAP.
 
+   
+   - GIMP 1.1.4 upto GIMP-1.2.x have included older versions of GIMP-GAP 
+     as standard plug-in (named gap) with no need of extra installation.
+
+
 
 Bugs
 ====

Modified: trunk/vid_enc_avi/avilib.c
==============================================================================
--- trunk/vid_enc_avi/avilib.c	(original)
+++ trunk/vid_enc_avi/avilib.c	Mon Apr 13 12:57:43 2009
@@ -25,6 +25,20 @@
  *
  */
 
+/* hof: 2009.04.12
+ * use "00dc" for compressed video chunks  and use "00db"
+ * uncompressed video (where AVI->compressor is 0)
+ *
+ * idx1 offsets are written realtive to data start adress in the movi chunk
+ +
+ * fixes at write/update of the AVI audio stream header related to pcm audiodata
+ * (samplesize, blockAlign and averageBytesPerSec.
+ *  incorrect values resultes in video playback that is NOT synchron to the audio).
+ *
+ * avi_sampsize  allow samplesize < 4 (that is required for mono samples 8 and 16 bit)
+ */
+ 
+
 #include "avilib.h"
 #include "../config.h"
 
@@ -152,7 +166,8 @@
    int s;
    s = ((AVI->track[j].a_bits+7)/8)*AVI->track[j].a_chans;
    //   if(s==0) s=1; /* avoid possible zero divisions */
-   if(s<4) s=4; /* avoid possible zero divisions */
+   //if(s<4) s=4; /* avoid possible zero divisions */
+   if(s<1) s=1; /* avoid possible zero divisions */
    return s;
 }
 
@@ -510,7 +525,8 @@
        OUTLONG(-1);            /* Quality */
 
        // ThOe /4
-       OUTLONG(sampsize/4);    /* SampleSize */
+       ///OUTLONG(sampsize/4);    /* SampleSize */
+       OUTLONG(sampsize);    /* SampleSize hof: full samplesize */
 
        OUTLONG(0);             /* Frame */
        OUTLONG(0);             /* Frame */
@@ -525,10 +541,17 @@
        OUTSHRT(AVI->track[j].a_chans);         /* Number of channels */
        OUTLONG(AVI->track[j].a_rate);          /* SamplesPerSec */
        // ThOe
-       OUTLONG(1000*AVI->track[j].mp3rate/8);
+
+       if(AVI->track[j].a_fmt == 1) {
+           // hof: calculate average bytes per sec for simple PCM encoded data
+           OUTLONG(AVI->track[j].a_rate * sampsize);
+       } else {
+           OUTLONG(1000*AVI->track[j].mp3rate/8);
+       }
        //ThOe (/4)
 
-       OUTSHRT(sampsize/4);           /* BlockAlign */
+       ///OUTSHRT(sampsize/4);           /* BlockAlign */
+       OUTSHRT(sampsize);           /* BlockAlign hof: align to full sample size */
 
 
        OUTSHRT(AVI->track[j].a_bits);          /* BitsPerSample */
@@ -784,7 +807,8 @@
          OUTLONG(-1);            /* Quality */
 
          // ThOe /4
-         OUTLONG(sampsize/4);    /* SampleSize */
+         ///OUTLONG(sampsize/4);    /* SampleSize */
+         OUTLONG(sampsize);    /* SampleSize hof: full samplesize */
 
          OUTLONG(0);             /* Frame */
          OUTLONG(0);             /* Frame */
@@ -799,10 +823,17 @@
          OUTSHRT(AVI->track[j].a_chans);         /* Number of channels */
          OUTLONG(AVI->track[j].a_rate);          /* SamplesPerSec */
          // ThOe
-         OUTLONG(1000*AVI->track[j].mp3rate/8);
+         
+         if(AVI->track[j].a_fmt == 1) {
+           // hof: calculate average bytes per sec for simple PCM encoded data
+           OUTLONG(AVI->track[j].a_rate * sampsize);
+         } else {
+           OUTLONG(1000*AVI->track[j].mp3rate/8);
+         }
          //ThOe (/4)
 
-         OUTSHRT(sampsize/4);           /* BlockAlign */
+         ///OUTSHRT(sampsize/4);           /* BlockAlign */
+         OUTSHRT(sampsize);           /* BlockAlign hof: align to full sample size */
 
 
          OUTSHRT(AVI->track[j].a_bits);          /* BitsPerSample */
@@ -913,6 +944,7 @@
    int n;
 
    unsigned char astr[5];
+   unsigned long idx_pos;        /* index position relative to the movi chunk in file */
 
    /* Check for maximum file length */
 
@@ -921,15 +953,24 @@
      return -1;
    }
 
+
+   if(AVI->movi_pos == 0)
+      AVI->movi_pos = AVI->pos;
+      
+   idx_pos = 4 + (AVI->pos - AVI->movi_pos);
+
    /* Add index entry */
 
    //set tag for current audio track
    sprintf((char *)astr, "0%1dwb", AVI->aptr+1);
 
    if(audio)
-     n = avi_add_index_entry(AVI,astr,0x00,AVI->pos,length);
+     n = avi_add_index_entry(AVI,astr,0x00,idx_pos,length);
    else
-     n = avi_add_index_entry(AVI,(unsigned char *) "00db",((keyframe)?0x10:0x0),AVI->pos,length);
+     if (AVI->compressor[0] == 0)
+       n = avi_add_index_entry(AVI,(unsigned char *) "00db",((keyframe)?0x10:0x0),idx_pos,length);
+     else
+       n = avi_add_index_entry(AVI,(unsigned char *) "00dc",((keyframe)?0x10:0x0),idx_pos,length);
 
    if(n) return -1;
 
@@ -938,7 +979,10 @@
    if(audio)
      n = avi_add_chunk(AVI,(unsigned char *) astr,data,length);
    else
-     n = avi_add_chunk(AVI,(unsigned char *) "00db",data,length);
+     if (AVI->compressor[0] == 0)
+       n = avi_add_chunk(AVI,(unsigned char *) "00db",data,length);
+     else
+       n = avi_add_chunk(AVI,(unsigned char *) "00dc",data,length);
 
    if (n) return -1;
 
@@ -963,10 +1007,19 @@
 
 int AVI_dup_frame(avi_t *AVI)
 {
+   unsigned long idx_pos;        /* index position relative to the movi chunk in file */
+
    if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
 
    if(AVI->last_pos==0) return 0; /* No previous real frame */
-   if(avi_add_index_entry(AVI,(unsigned char *)"00db",0x10,AVI->last_pos,AVI->last_len)) return -1;
+
+   idx_pos = 4 + (AVI->last_pos - AVI->movi_pos);
+
+   if (AVI->compressor[0] == 0)
+     if(avi_add_index_entry(AVI,(unsigned char *)"00db",0x10,idx_pos,AVI->last_len)) return -1;
+   else
+     if(avi_add_index_entry(AVI,(unsigned char *)"00dc",0x10,idx_pos,AVI->last_len)) return -1;
+   
    AVI->video_frames++;
    AVI->must_use_index = 1;
    return 0;

Modified: trunk/vid_enc_avi/avilib.h
==============================================================================
--- trunk/vid_enc_avi/avilib.h	(original)
+++ trunk/vid_enc_avi/avilib.h	Mon Apr 13 12:57:43 2009
@@ -117,6 +117,8 @@
   
   int anum;            // total number of audio tracks 
   int aptr;            // current audio working track 
+
+  unsigned long movi_pos;        /* position of the movi chunk in file */
   
 } avi_t;
 

Modified: trunk/vid_enc_avi/gap_enc_avi_main.c
==============================================================================
--- trunk/vid_enc_avi/gap_enc_avi_main.c	(original)
+++ trunk/vid_enc_avi/gap_enc_avi_main.c	Mon Apr 13 12:57:43 2009
@@ -599,6 +599,7 @@
 static gint
 p_avi_encode(GapGveAviGlobalParams *gpp)
 {
+#define AUDIO_CHUNK_ADVANCE_FRAMES 16
   GapGveAviValues   *epp;
   avi_t               *l_avifile;
   static GapGveStoryVidHandle *l_vidhand = NULL;
@@ -612,7 +613,6 @@
 
   FILE *l_fp_inwav = NULL;
   gint32 l_FRAME_size;
-  gint32 datasize;
   gint32 audio_size = 0;
   gint32 audio_stereo = 0;
   long  l_sample_rate = 22050;
@@ -629,13 +629,17 @@
   gint32         l_cnt_reused_frames;
   gint32         l_check_flags;
   gint32         l_out_frame_nr;
+  
+  gdouble        audio_samples_per_frame;
+  gint32         audio_samples_per_frame_gint32;
+  gint32         audio_bytes_per_frame_gint32;
+  gint32         audio_bytes_done_in_advance = 0;
+  gint32         l_frames_to_go;
 
   gint32 wavsize = 0; /* Data size of the wav file */
   long audio_margin = 8192; /* The audio chunk size */
-  long audio_filled_100 = 0;
-  long audio_per_frame_x100 = -1;
-  long frames_per_second_x100 = 2500;
-  gdouble frames_per_second_x100f = 2500;
+
+
   char databuffer[300000]; /* For transferring audio data */
   gint32   l_video_frame_chunk_size;
   gint32   l_video_frame_chunk_hdr_size;
@@ -735,21 +739,33 @@
 
     /* open WAVE file and set position to the 1.st audio databyte */
     l_fp_inwav = gap_audio_wav_open_seek_data(gpp->val.audioname1);
+    
+    if(gap_debug)
+    {
+      printf("Audiocheck results for file:%s\n", gpp->val.audioname1);
+      printf("  wavsize:%d\n", (int)wavsize);
+      printf("  l_samples:%d\n", (int)l_samples);
+      printf("  l_bytes_per_sample:%d\n", (int)l_bytes_per_sample);
+      printf("  l_channels:%d\n", (int)l_channels);
+      printf("  l_sample_rate:%d\n", (int)l_sample_rate);
+      printf("  audio_size (in bits):%d\n", (int)audio_size);
+      printf("  audio_stereo:%d\n", (int)audio_stereo);
+    }
   }
 
 
   /* Calculations for encoding the sound into the avi
    */
+  audio_samples_per_frame = l_sample_rate / MAX(1.0, gpp->val.framerate);
+  audio_samples_per_frame_gint32 = (audio_samples_per_frame + 0.5);
+  audio_bytes_per_frame_gint32 = audio_samples_per_frame_gint32 * l_bytes_per_sample;
 
-  /* ORIGINAL CODE:
-   *  frames_per_second_x100 = (norm == 0) ? 2500 : 2997;
-   *  audio_per_frame_x100 = (100 * 100 * l_sample_rate * audio_size / 8 *
-   *                        ((audio_stereo == TRUE) ? 2 : 1)) / frames_per_second_x100;
-   */
-
-  frames_per_second_x100f = (100.0 * gpp->val.framerate) + 0.5;
-  frames_per_second_x100 = frames_per_second_x100f;
-  audio_per_frame_x100 = (100 * 100 * l_sample_rate * l_bytes_per_sample) / MAX(1,frames_per_second_x100);
+  if(gap_debug)
+  {
+    printf("  audio_samples_per_frame:%f\n", (float)audio_samples_per_frame);
+    printf("  audio_samples_per_frame_gint32:%d\n", (int)audio_samples_per_frame_gint32);
+    printf("  audio_bytes_per_frame_gint32:%d\n", (int)audio_bytes_per_frame_gint32);
+  }
 
 
   /* build AVI 4 byte codec name
@@ -786,11 +802,20 @@
                , l_sample_rate
                , (int)l_bits
                , (int)WAVE_FORMAT_PCM    /* format 1 == pcm */
-               , (long)0                 /* mp3rate (WHAT else shall i use if NO MP3 is supplied ???) */
+               , (long)((l_sample_rate * 8) / 1000)    /* mp3rate,
+                                          * as seen seen in some AVI files)
+                                          * note that some mplayer versions freezes on attempt
+                                          * to playback AVI files with mp3rate 0
+                                          */
                );
+
+    //l_avifile->must_use_index = 1;
   }
 
-  if(gap_debug) printf("next is INIT Encoder Instance ?\n");
+  if(gap_debug)
+  {
+    printf("next is INIT Encoder Instance ?\n");
+  }
 
 #ifdef ENABLE_LIBXVIDCORE
   if ((strcmp(epp->codec_name, GAP_AVI_CODEC_RGB) != 0)
@@ -810,7 +835,10 @@
       printf("ERROR creation of XVID encoder instance FAILED\n");
       l_rc = -1;
     }
-    if(gap_debug)  printf("creation of XVID encoder instance DONE OK\n");
+    if(gap_debug)
+    {
+      printf("creation of XVID encoder instance DONE OK\n");
+    }
   }
 #endif
 
@@ -831,6 +859,10 @@
   l_begin = gpp->val.range_from;
   l_end   = gpp->val.range_to;
   l_max_master_frame_nr = abs(l_end - l_begin) + 1;
+  l_frames_to_go = l_max_master_frame_nr;
+
+
+  l_frames_to_go = l_max_master_frame_nr;
 
   l_cur_frame_nr = l_begin;
   while(l_rc >= 0)
@@ -864,7 +896,8 @@
     }     /* end setup of 1.st frame (l_cur_frame_nr == l_begin) */
 
 
-    /* calling the frame fetcher */
+
+    /* encode VIDEO PART, call the frame fetcher */
     {
       gboolean l_fetch_ok;
       gboolean l_force_keyframe;
@@ -1005,8 +1038,14 @@
         if(buffer)
         {
           /* store the compressed video frame */
-          if (gap_debug) printf("GAP_AVI: Writing frame nr. %d, size %d\n",
-                                (int)l_cur_frame_nr, (int)l_FRAME_size);
+          if (gap_debug)
+          {
+            printf("GAP_AVI: Writing frame nr. %d, size %d  l_keyframe:%d\n"
+                 , (int)l_cur_frame_nr
+                 , (int)l_FRAME_size
+                 , (int)l_keyframe
+                 );
+          }
           AVI_write_frame(l_avifile, buffer, l_FRAME_size, l_keyframe);
           /* free the (un)compressed Frame data buffer */
           g_free(buffer);
@@ -1027,48 +1066,90 @@
         /* destroy the tmp image */
         gimp_image_delete(l_tmp_image_id);
       }
+      
+      
+    }     /* end if l_rc == 0 */
+
+
+
+
+
 
       /* encode AUDIO PART */
-      /* As long as there is a video frame, "fill" the fake audio buffer */
-      if (l_fp_inwav)
+      /* As long as there is a video frame, write audio chunks.
+       * set AUDIO_CHUNK_ADVANCE_FRAMES = 1 triggers writing of an audio chunk for each handled frame.
+       * values > 1 do write one longer audio chunk in advance for duration of the defined number of frames,
+       * in this case the next audio chunk is written after the number of video frames reached.
+       * in case the audio input is shorter than video playtime write the rest
+       * and stop writing audio for all further frame.
+       * in case the audio input is longer than video playtime it is truncated.
+       * (e.g. the remaining audio is not written to the resulting video file).
+       */
+      if ((l_fp_inwav) && (wavsize > 0))
       {
-        audio_filled_100 += audio_per_frame_x100;
-      }
+        gint32 datasize;
+        gint32 l_frames_advance;
+        
+        
+        l_frames_advance = MIN(AUDIO_CHUNK_ADVANCE_FRAMES, l_frames_to_go);
+        audio_margin = MIN((audio_bytes_per_frame_gint32 * l_frames_advance), sizeof(databuffer) -1);
+        
+        if(gap_debug)
+        {
+          printf("audio_bytes_per_frame:%d  audio_margin: %d (to_go:%d advance:%d)\n"
+             , (int)audio_bytes_per_frame_gint32
+             , (int)audio_margin
+             , (int)l_frames_to_go
+             , (int)l_frames_advance
+             );
+        }
 
-      /* Now "empty" the fake audio buffer, until it goes under the margin again */
-      while ((audio_filled_100 >= (audio_margin * 100)) && (wavsize > 0))
-      {
-        if (gap_debug) printf("Audio processing: Audio buffer at %ld bytes.\n", audio_filled_100);
-        if (wavsize >= audio_margin)
+        datasize = 0;
+        if (audio_bytes_done_in_advance <= 0)
         {
-            datasize = fread(databuffer, 1, audio_margin, l_fp_inwav);
-            if (datasize != audio_margin)
-            {
-              printf("Warning: Read from wav file failed. (non-critical)\n");
-            }
-            wavsize -= audio_margin;
+          if (wavsize >= audio_margin)
+          {
+              datasize = fread(databuffer, 1, audio_margin, l_fp_inwav);
+              if (datasize != audio_margin)
+              {
+                printf("Warning: Read %d bytes from wav file failed. (got %d bytes)\n"
+                      ,(int)audio_margin
+                      ,(int)datasize
+                      );
+              }
+              wavsize -= audio_margin;
+          }
+          else
+          {
+              datasize = fread(databuffer, 1, wavsize, l_fp_inwav);
+              if (datasize != wavsize)
+              {
+                printf("Warning: Read rest of %d bytes from wav file failed. (got %d bytes)\n"
+                      ,(int)wavsize
+                      ,(int)datasize
+                      );
+              }
+              wavsize = 0;
+          }
         }
-        else
+        if (datasize > 0)
         {
-            datasize = fread(databuffer, 1, wavsize, l_fp_inwav);
-            if (datasize != wavsize)
-            {
-              printf("Warning: Read from wav file failed. (non-critical)\n");
-            }
-            wavsize = 0;
-        }
-
-        if (gap_debug) printf("Now saving audio frame datasize:%d\n", (int)datasize);
+          if(gap_debug)
+          {
+            printf("Now saving audio frame datasize:%d\n", (int)datasize);
+          }
+          AVI_write_audio(l_avifile, databuffer, datasize);
 
-        /*XXX ?? - TODO check if write in portions or all at once */
-        /* XX     - check if we should use write or append Procedure ? */
+          if(gap_debug)
+          {
+            printf("audio chunk written\n");
+          }
+          audio_bytes_done_in_advance = datasize;
+        }
+        audio_bytes_done_in_advance -= audio_bytes_per_frame_gint32;
+      }
 
-        AVI_write_audio(l_avifile, databuffer, datasize);
-        /*AVI_append_audio(l_avifile, databuffer, datasize);*/
 
-        audio_filled_100 -= audio_margin * 100;
-      }
-    }     /* end if l_rc == 0 */
 
 
     l_percentage += l_percentage_step;
@@ -1097,9 +1178,12 @@
        break;
     }
     l_cur_frame_nr += l_step;
+    l_frames_to_go--;
 
   }  /* end loop foreach frame */
 
+
+
   if(l_avifile != NULL)
   {
     AVI_close(l_avifile);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]