After recording two and a half hours of video with one channel of the 
stereo audio missing, I decided that lavrec should display audio level 
meters while recording.
(I also decided that I hate 1/8" plugs even more than I used to).

The attached patch adds a "--vu-meter" option to lavrec from
mjpegtools-1.6.2. The option makes the status output output look somthing
like this when recording stereo audio:

0.00.10:00 int:033 lst:  0 ins:  0 del:  0 ae:  0 td1=0.050 td2=0.009 
L:###################- R:##################--

Although the option is called "vu-meter" the actual meter is linear, not
logarithmic, and responds to the peak sample values seen.  The
peak-metering code is inspired by that in arecord, from alsa-utils.


Steve
--- mjpegtools-1.6.2-orig/lavtools/audiolib.h   2002-03-23 17:47:57.000000000 
-0500
+++ mjpegtools-1.6.2/lavtools/audiolib.h        2004-11-04 22:04:37.000000000 
-0500
@@ -28,6 +28,7 @@
 int audio_read( uint8_t *buf, int size, int swap, 
                            struct timeval *tmstmp, int *status);
 int audio_write( uint8_t *buf, int size, int swap);
+void audio_compute_peaks(uint8_t *buf, int size, int swap, signed int *peaks);
 
 void audio_start(void);
 
--- mjpegtools-1.6.2-orig/lavtools/audiolib.c   2003-12-01 01:42:51.000000000 
-0500
+++ mjpegtools-1.6.2/lavtools/audiolib.c        2004-11-06 22:58:33.018970794 
-0500
@@ -627,6 +627,44 @@
 }
 
 /*
+ * audio_compute_peaks:  
+ *             scan buffer of audio samples, and determine
+ *             the peak levels found.
+ *
+ *    buf       Buffer with audio data
+ *    size      Size of the buffer
+ *    swap      Flag if to swap the endian-ness of 16 bit data
+ *    peaks    pointer to pair of integers holding running peak values
+ */
+
+void audio_compute_peaks(uint8_t *buf, int size, int swap, signed int *peaks)
+{
+       signed int val;
+       size_t step;
+       int ch = 0;
+
+       if(audio_size == 0)
+               return;
+
+        while (size > 0) {
+               switch(audio_size) {
+                case 8: val = *(unsigned char *)buf - 128;
+                       step = 1; break;
+                case 16: val = *(signed short *)buf;
+                               step = 2; break;
+                default: val = 0; step = 1; break;
+               }
+                buf += step;
+               size -= step;
+                val = abs(val);
+               if(peaks[ch] < val)
+                       peaks[ch] = val;
+               if(stereo)
+                       ch ^= 1;
+       }
+}
+
+/*
  * The audio task
  */
 
--- mjpegtools-1.6.2-orig/lavtools/liblavrec.h  2003-11-14 22:36:17.000000000 
-0500
+++ mjpegtools-1.6.2/lavtools/liblavrec.h       2004-11-06 23:08:00.554574371 
-0500
@@ -66,6 +66,8 @@
 
    struct timeval prev_sync;
    struct timeval cur_sync;
+   int audio_peaks[2];
+   int audio_handled;          /* any audio buffers handled ? */
 } video_capture_stats;
 
 
--- mjpegtools-1.6.2-orig/lavtools/liblavrec.c  2003-08-26 14:09:11.000000000 
-0400
+++ mjpegtools-1.6.2/lavtools/liblavrec.c       2004-11-07 00:04:22.077503105 
-0500
@@ -1865,6 +1865,7 @@
    int nerr = 0;
    video_capture_setup *settings = (video_capture_setup *)info->settings;
    video_capture_stats *stats = settings->stats;
+   stats->audio_handled = 0;
 
    while (info->audio_size)
    {
@@ -1896,6 +1897,8 @@
          stats->num_aerr++;
          stats->stats_changed = 1;
       }
+      stats->audio_handled = 1;
+      audio_compute_peaks((unsigned char*)settings->AUDIO_buff, x, 0, 
stats->audio_peaks);
 
       /* Adjust for difference at start */
       if (settings->audio_offset >= x)
@@ -1930,6 +1933,7 @@
    /* output_statistics */
    if (info->output_statistics) info->output_statistics(stats);
    stats->stats_changed = 0;
+   stats->audio_peaks[0] = stats->audio_peaks[1] = 0;
 
    stats->prev_sync = stats->cur_sync;
 
@@ -2048,6 +2052,9 @@
    stats.num_aerr = 0;
    stats.tdiff1 = 0.;
    stats.tdiff2 = 0.;
+   stats.audio_peaks[0] = 0;
+   stats.audio_peaks[1] = 0;
+   stats.audio_handled = 0;
    if (info->software_encoding);
       settings->bsync.frame = -1;
    gettimeofday( &(stats.prev_sync), NULL );
--- mjpegtools-1.6.2-orig/lavtools/lavrec.c     2004-01-09 22:23:53.000000000 
-0500
+++ mjpegtools-1.6.2/lavtools/lavrec.c  2004-11-06 23:59:30.737300638 -0500
@@ -215,6 +215,7 @@
 static int batch_mode = 0;
 static char input_source;
 static pthread_t signal_thread;
+static int vumeter = 0;
 
 static void Usage(char *progname)
 {
@@ -250,6 +251,7 @@
        fprintf(stderr, "  -C/--channel LIST:CHAN      When using a TV tuner, 
channel list/number\n");
        fprintf(stderr, "  -F/--frequency KHz          When using a TV tuner, 
frequency in KHz\n");
        fprintf(stderr, "  -U/--use-read               Use read instead of mmap 
for recording\n");
+       fprintf(stderr, "  --vu-meter                  show audio level 
meter\n");
        fprintf(stderr, "  --software-encoding         Use software 
JPEG-encoding (for BTTV-capture)\n");
        fprintf(stderr, "  --num-procs num             Number of encoding 
processes (default: 1)\n");
        fprintf(stderr, "  --max-file-size num         Maximum size per file 
(in MB)\n");
@@ -538,6 +540,25 @@
 }
 #endif
 
+static void draw_vumeter(char label, int level)
+{
+       int max, i, percent;
+       if(info->audio_size == 16) {
+               max = 32767;
+               percent = level / (max/100);
+       } else {
+               max = 127;
+               percent = level * 100 / max;
+       }
+       printf(" %c:", label);
+       for(i = 0; i < 20; i++) {
+               if(percent && (i <= percent/5))
+                       putc('#', stdout);
+               else
+                       putc('-', stdout);
+       }
+}
+
 static void output_stats(video_capture_stats *stats)
 {
   num_frames = stats->num_frames;
@@ -546,6 +567,8 @@
   num_del = stats->num_del;
   num_aerr = stats->num_aerr;
 
+  static int peaks[2];
+
   if (show_stats > 0 && !batch_mode)
   {
     MPEG_timecode_t tc;
@@ -559,12 +582,28 @@
     else {
       printf(
         "%d.%2.2d.%2.2d:%2.2d int:%03ld lst:%3d ins:%3d del:%3d "
-        "ae:%3d td1=%.3f td2=%.3f\r",
+        "ae:%3d td1=%.3f td2=%.3f",
         tc.h, tc.m, tc.s, tc.f,
         (stats->cur_sync.tv_usec - stats->prev_sync.tv_usec)/1000, 
stats->num_lost,
         stats->num_ins, stats->num_del, stats->num_aerr, stats->tdiff1, 
stats->tdiff2);
-      if(verbose) printf("\n"); // Keep lines from overlapping
-    }
+       if(vumeter) {
+               if(stats->audio_handled) {
+               // if no audio samples handled this frame
+               // (due to low audio bit rate) draw meter using peak
+               //  level from previous frame.
+                       peaks[0] = stats->audio_peaks[0];
+                       peaks[1] = stats->audio_peaks[1];
+               }
+               if(info->stereo) {
+                       draw_vumeter('L', peaks[0]);
+                       draw_vumeter('R', peaks[1]);
+               } else {
+                       draw_vumeter('V', peaks[0]); 
+               }
+       }
+       putchar('\r');
+       if(verbose) printf("\n"); // Keep lines from overlapping
+       }
      fflush(stdout);
   }
 }
@@ -739,6 +778,10 @@
                        nerr++;
                }
        }
+       else if (strcmp(name, "vu-meter")==0)
+       {
+               vumeter = 1;
+       }
        else if (strcmp(name, "mjpeg-buffers")==0 || strcmp(name, "n")==0)
        {
                info->MJPG_numbufs = atoi(value);
@@ -879,6 +922,7 @@
                {"max-file-frames"  ,1,0,0},   /* --max-file-frames      */
                {"file-flush"       ,1,0,0},   /* --file-flush           */
                {"frequency"        ,1,0,0},   /* --frequency/-F         */
+               {"vu-meter"         ,0,0,0},   /* --vu-meter             */
                {0,0,0,0}
        };
 #endif
@@ -947,6 +991,9 @@
        if(optind>=argc) nerr++;
        if(nerr) Usage(argv[0]);
 
+       if(info->audio_size == 0)
+               vumeter = 0;
+
        mjpeg_default_handler_verbosity(verbose);
 
        /* disable audio for jpeg */
--- mjpegtools-1.6.2-orig/docs/lavrec.1 2003-11-14 22:36:17.000000000 -0500
+++ mjpegtools-1.6.2/docs/lavrec.1      2004-11-07 00:20:39.465737975 -0500
@@ -138,6 +138,10 @@
 at all.
 
 .TP 8
+.B \-\-vu\-meter
+If this option is given, lavrec will display audio level meters.
+
+.TP 8
 .B \-m/\-\-mute
 Mute sound output while recording. This can be useful when recording
 sound from the microphone to disable echos. This option is disabled by

Reply via email to