On Sun, 7 Nov 2004, Ronald S. Bultje wrote: > Hi Steve, > > On Sun, 2004-11-07 at 06:27, Steve Tell wrote:
> > 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:##################-- > > Hahaha! Sorry to laugh at your pains, but it's amusing nonetheless. :). > So... Should this go in? Here is a better version of the patch. It attempts to do the right thing with 16-bit audio samples on a big-endian host. Although I have no way to test this case, the previous patch didn't even try. It would be great if you'd consider merging this. > This reminds me how badly we need graphical desktop-integrated > video/audio capture applications under Linux. ;). LVS' capture tab is a > good first step, but nowhere close to what's required... Agreed, although my wishlist for a graphical capture application includes only: - window showing the captured video - audio level meters - hour/minute/second/frame counter - video window and audio meters active even when not recording to files (i.e. the app is always capturing) - start/stop buttons/keystrokes When recording live, I'd rather have most of the setup and configuration options safely in a script, and not on menus or guis that can be bumped accidently. I may yet tackle an "xlavrec" hack like this for lavrec. 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-07 16:53:18.738968354 -0500 @@ -627,6 +627,53 @@ } /* + * 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; + * If 0, assume buf is already in native endian-ness + * 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; + uint8_t dat[2]; + 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: + if(swap) { + dat[0] = buf[1]; + dat[1] = buf[0]; + val = *(signed short *)dat; + } else { + 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.000000000 -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 16:52:28.046881183 -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,9 @@ stats->num_aerr++; stats->stats_changed = 1; } + stats->audio_handled = 1; + audio_compute_peaks((unsigned char*)settings->AUDIO_buff, x, + WORDS_BIGENDIAN, stats->audio_peaks); /* Adjust for difference at start */ if (settings->audio_offset >= x) @@ -1930,6 +1934,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 +2053,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.000000000 -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.000000000 -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