Hi, NVrec has a great feature where it slightly resamples the audio to make sure that exactly the right number of audio bytes are written to the output file to maintain sync even if the sound card clock is off. But there is a unpleasant interaction between that code and the btaudio drivers' fixed 8k fragment size. The big fragments mean a lot of jitter in the sampled number of bytes written. Resulting in NVrec making rather large adjustments to the resampling. The result is 4 or 5% "wow" added to the audio. (remember old tape recorders with a flat pinch wheel?) This patch changes NVrec to change the resampling rate much more slowly - so the jitter is proportionatly smaller. This eliminates the wow. This patch also makes a little change in v4l2_core.c to allow NVrec to work with Gerd's v4l2 implementation in bttv 0.8. To use NVrec and bttv 0.8 together you'll need these changes in NVrec as well as the VIDIOC_G_PARM implementation for bttv 0.8 that I posted a day or two ago as bttv-0.8.31-sld.patch. I'd appreciate confirmation from any brave person who'll give this a try - I believe Justin's away till the 20th. Regards, Steve
diff -r -U3 NVrec-20011203/nvrec_core.c NVrec-20011203-sld/nvrec_core.c --- NVrec-20011203/nvrec_core.c Mon Dec 3 09:31:04 2001 +++ NVrec-20011203-sld/nvrec_core.c Sat Dec 29 15:39:00 2001 @@ -162,7 +162,7 @@ atime = audt->aud_core_tailtime(audt); } } - fprintf(stderr, "NVrec: initial sync - audio: %lli video %lli (delta %f)\n", atime, vtime, (atime-vtime)/1e9); + fprintf(stderr, "NVrec: initial sync - audio: %lli video %lli (delta %f secs)\n", atime, vtime, (atime-vtime)/1e9); /* Now loop until we're done! */ while((!nvcore_fin) && (fcount)) { @@ -197,19 +197,27 @@ atime = audt->aud_core_tailtime(audt); - if ((cseq % 30) == 0) { - ftemp = (fatime * 1000000000LL) / audt->aud_core_bps(audt); - ftemp -= (double)fvtime; - drate = (int)(- ftemp / 1e6); - drate -= (int)(lastoff / 1e8); + // SLD: Add explanation of how this works before you forget! + // Also - the 300 should perhaps be adjusted to be an actual 10 second period + // if thats done, perhaps review the <<15 used in oss_core? + if ( (cseq = (cseq+1) % 300) == 0) { + ftemp = (fatime * 1000000000LL) / audt->aud_core_bps(audt); // in nsecs + ftemp -= (double)fvtime; // nsec, slip between video and audio, since start + // Why 1e7? 1e6 to convert from nanosec to millisecs. another 10 because + // our measurement interval is 300 frames - of the order of 10 seconds + // old code had this code running every 30 frames, and 1e6 and 1e8 below. + drate = (int)(- ftemp / 1e7); // millisecs per second(-ish) to be recovered + // don't know what this is for. Some sort of damping attempt I presume + drate -= (int)(lastoff / 1e9); lastoff = lastoff + ftemp; if(drate >= 1000) drate = 999; if(drate <= -1000) drate = -999; } - fprintf(stderr, "VQ:% 8.03f Offset: % 8.03f Slipage: % 8.03f Warp: %d Drop: %lld \r", capstat, (atime-vtime)/1e9, ftemp / 1e9, drate, fdrop); + fprintf(stderr, "VQ:% 8.03f Offset: % 8.03f Slippage: % 8.03f Warp: %d Drop: %lld \r", + capstat, (atime-vtime)/1e9, ftemp / 1e9, drate, fdrop); if(fcount > 0) fcount--; - cseq ++; } + fprintf(stderr, "\nTotal audio bytes: %lli\n", fatime); nvcore_die = 1; sigaction(SIGINT, &oldaction, NULL); return 0; diff -r -U3 NVrec-20011203/oss_core.c NVrec-20011203-sld/oss_core.c --- NVrec-20011203/oss_core.c Mon Dec 3 09:31:04 2001 +++ NVrec-20011203-sld/oss_core.c Fri Dec 28 22:40:36 2001 @@ -169,11 +169,11 @@ osst->tail = i; } +//FIXME: will work for little-endian only... (SLD) struct s2 { unsigned short lo; unsigned short hi; }; - typedef union { unsigned int ui; struct s2 us; @@ -202,6 +202,7 @@ } else { dt = 65536; } + j.ui = 0; while(1) { i = osst->tail; if((osst->frag + i)->full == 0) { @@ -220,14 +221,18 @@ unsigned int * in = (unsigned int *) ((osst->frag + i)->buf); unsigned int * out = (unsigned int *) (buf + c); k = 0; - for(j.ui = 0; j.us.hi < (osst->fragsize >> 2); j.ui += dt) + //SLD: Slight tweak here: retain fractional part of j between + //fragments. Should help even out resampling and get closer + //to the desired number of output samples + for(j.us.hi = 0; j.us.hi < (osst->fragsize >> 2); j.ui += dt) out[k++] = in[j.us.hi]; c += k << 2; } else { unsigned short * in = (unsigned short *) ((osst->frag + i)->buf); unsigned short * out = (unsigned short *) (buf + c); k = 0; - for(j.ui = 0; j.us.hi < (osst->fragsize >> 1); j.ui += dt) + //SLD: Comment as above + for(j.us.hi = 0; j.us.hi < (osst->fragsize >> 1); j.ui += dt) out[k++] = in[j.us.hi]; c += k << 1; } @@ -365,12 +370,12 @@ act = malloc(sizeof(struct aud_core_t)); if(!act) { - perror("oss core init - could no malloc new audio core"); + perror("oss core init - could not malloc new audio core"); return NULL; } osst = malloc(sizeof(struct oss_core_t)); if(!osst) { - perror("oss core init - could no malloc new oss core"); + perror("oss core init - could not malloc new oss core"); free(act); return NULL; } @@ -460,6 +465,7 @@ } osst->bps = osst->rate * osst->chans * ((osst->bits==16)?2:1); osst->realbps = j * osst->chans * ((osst->bits==16)?2:1); + fprintf(stderr, "oss core init - bps=%d, realbps=%d\n", osst->bps, osst->realbps); if (ioctl(osst->fd, SNDCTL_DSP_GETBLKSIZE, &j) < 0) { perror("oss core init - WARNING could not get block size"); diff -r -U3 NVrec-20011203/v4l2_core.c NVrec-20011203-sld/v4l2_core.c --- NVrec-20011203/v4l2_core.c Mon Dec 3 09:31:04 2001 +++ NVrec-20011203-sld/v4l2_core.c Wed Dec 26 12:39:21 2001 @@ -273,7 +273,7 @@ } fprintf(stderr, "v4l2 core init - Size: %dx%d from %s\n", vct->width, vct->height, fdev); - vct->fd = open(fdev, O_RDONLY); + vct->fd = open(fdev, O_RDWR); if(vct->fd<=0) { perror("v4l2 core init - open capture device"); goto error0; @@ -413,7 +413,7 @@ perror("v4l2 core init - querybuf failed"); goto error2; } - vct->bufs[i * vct->planes] = (unsigned char *)mmap(NULL, vct->cbuf.length, PROT_READ, MAP_SHARED, vct->fd, vct->cbuf.offset); + vct->bufs[i * vct->planes] = (unsigned char *)mmap(NULL, vct->cbuf.length, PROT_READ|PROT_WRITE, MAP_SHARED, vct->fd, vct->cbuf.offset); if((int)(vct->bufs[i * vct->planes])==-1) { perror("v4l2 core init - mmap failed"); goto error2;;