[mythtv] [PATCH] mono support, take two

Jim Radford mythtv-dev@snowman.net
Fri, 15 Nov 2002 03:52:44 -0800


Hi John,

On Mon, Nov 18, 2002 at 11:53:03PM -0500, John Coiner wrote:
> It would be great to parameterize all of the player/recorder code in 
> terms of 'channels' and 'bytes_per_sample' etc. The option to use mono 
> would be pretty sweet for people with mono tuners, especially if they 
> don't have the world's fastest CPU.

Ok here it is.  I actually have sound now for the first time.  And
it's in sync!

>   ( By the way -- if you're going to work on the player -- take a minute 
> to see if you can figure out how the audio buffer's read pointer could 
> "lap" the write pointer. This should never happen, though Isaac seems to 
> have observed just this. We were stymied, the code looked pretty solid, 
> to me anyway...)

Will do, now that I have a better grasp on the code.

-Jim

Index: libs/libNuppelVideo/NuppelVideoPlayer.cpp
===================================================================
RCS file: /var/lib/cvs/MC/libs/libNuppelVideo/NuppelVideoPlayer.cpp,v
retrieving revision 1.96
diff -u -r1.96 NuppelVideoPlayer.cpp
--- libs/libNuppelVideo/NuppelVideoPlayer.cpp	18 Nov 2002 01:59:38 -0000	1.96
+++ libs/libNuppelVideo/NuppelVideoPlayer.cpp	19 Nov 2002 10:37:59 -0000
@@ -41,6 +41,7 @@
 #define wsEnter         0x8d + 256
 #define wsReturn        0x0d + 256
 
+int audio_ioctl_int(int fd, int arg, int *value, const char *decscription);
 
 NuppelVideoPlayer::NuppelVideoPlayer(void)
 {
@@ -75,7 +76,9 @@
     weMadeBuffer = false;
 
     osd = NULL;
+    audio_channels = 2;
     audio_samplerate = 44100;
+    audio_bits_per_sample = 16;
     editmode = false;
     advancevideo = resetvideo = advancedecoder = false;
 
@@ -171,13 +174,13 @@
  
 void NuppelVideoPlayer::InitSound(void)
 {
-    int bits = 16, stereo = 1, speed = audio_samplerate, caps;
+    int caps;
 
     if (usingextradata)
     {
-        bits = extradata.audio_bits_per_sample;
-        stereo = (extradata.audio_channels == 2);
-        speed = extradata.audio_sample_rate;
+        audio_bits_per_sample = extradata.audio_bits_per_sample;
+        audio_channels = extradata.audio_channels;
+        audio_samplerate = extradata.audio_sample_rate;
     }
 
     if (disableaudio)
@@ -194,25 +197,10 @@
 	return;
     }
 
-    if (ioctl(audiofd, SNDCTL_DSP_SAMPLESIZE, &bits) < 0)
-    {
-        cerr << "problem setting sample size, exiting\n";
-        close(audiofd);
-        audiofd = -1;
-        return;
-    }
-
-    if (ioctl(audiofd, SNDCTL_DSP_STEREO, &stereo) < 0) 
-    {
-        cerr << "problem setting to stereo, exiting\n";
-        close(audiofd);
-        audiofd = -1;
-        return;
-    }
-
-    if (ioctl(audiofd, SNDCTL_DSP_SPEED, &speed) < 0) 
+    if(audio_ioctl_int(audiofd, SNDCTL_DSP_CHANNELS, &audio_channels, "audio output channels") < 0 ||
+       audio_ioctl_int(audiofd, SNDCTL_DSP_SPEED, &audio_samplerate, "audio output samplerate") < 0 ||
+       audio_ioctl_int(audiofd, SNDCTL_DSP_SAMPLESIZE, &audio_bits_per_sample, "audio output bits per sample") < 0)
     {
-        cerr << "problem setting sample rate, exiting\n";
         close(audiofd);
         audiofd = -1;
         return;
@@ -480,7 +468,11 @@
     foundit = 0;
     effdsp = audio_samplerate;
     if (usingextradata)
+    {
         effdsp = extradata.audio_sample_rate;
+        audio_channels = extradata.audio_channels;
+        audio_bits_per_sample = extradata.audio_bits_per_sample;
+    }
 
     while (!foundit) 
     {
@@ -856,8 +848,8 @@
     ioctl(audiofd, SNDCTL_DSP_GETODELAY, &soundcard_buffer); // bytes
     totalbuffer = audiolen(false) + soundcard_buffer;
                
-    audiotime = audbuf_timecode - (int)((double)totalbuffer * 25000.0 /
-                                        (double)effdsp);
+    audiotime = audbuf_timecode - 
+      (int)(totalbuffer * 100000.0 / (audio_bits_per_sample/8 * audio_channels * effdsp));
  
     gettimeofday(&audiotime_updated, NULL);
 
@@ -993,17 +985,29 @@
 
                 do
                 {
-                    lameret = lame_decode(strm, packetlen, pcmlbuffer, 
-                                          pcmrbuffer);
+                    mp3data_struct header;
+                    lameret = lame_decode_headers(strm, packetlen, pcmlbuffer, 
+                                                  pcmrbuffer, &header);
 
                     if (lameret > 0)
                     {
                         int itemp = 0;
                         int afree = audiofree(false);
 
-                        if (lameret * 4 > afree)
+                        if(header.header_parsed && header.stereo != audio_channels &&
+                           audio_ioctl_int(audiofd, SNDCTL_DSP_CHANNELS, &(audio_channels=header.stereo), 
+                                           "audio mp3 output channels") < 0 ||
+                           header.header_parsed && header.samplerate != audio_samplerate &&
+                           audio_ioctl_int(audiofd, SNDCTL_DSP_SPEED, &(audio_samplerate=header.samplerate), 
+                                           "audio mp3 output samplerate") < 0)
+                        {
+                            close(audiofd);
+                            audiofd = -1;
+                        }
+
+                        if (lameret * audio_channels * audio_bits_per_sample/8 > afree)
                         {
-                            lameret = afree / 4;
+                            lameret = afree / audio_channels / (audio_bits_per_sample/8);
                             cout << "Audio buffer overflow, audio data lost!\n";
                         }
 
@@ -1011,11 +1015,17 @@
 
                         for (itemp = 0; itemp < lameret; itemp++)
                         {
-                            saudbuffer[waud / 2] = pcmlbuffer[itemp];
-                            saudbuffer[waud / 2 + 1] = pcmrbuffer[itemp];
-                           
-                            waud += 4;
-                            len += 4;
+                            if(audio_channels == 2)
+                            {
+                                saudbuffer[waud / 2] = pcmlbuffer[itemp];
+                                saudbuffer[waud / 2 + 1] = pcmrbuffer[itemp];
+                            }
+                            else
+                            {
+                                saudbuffer[waud] = pcmlbuffer[itemp];
+                            }
+                            waud += audio_channels * audio_bits_per_sample/8;
+                            len += audio_channels * audio_bits_per_sample/8;
                             if (waud >= AUDBUFSIZE)
                                 waud -= AUDBUFSIZE;
                         }
@@ -1388,8 +1398,8 @@
         /* do audio output */
 	
         /* approximate # of audio bytes for each frame. */
-        bytesperframe = 4 * (int)((1.0/video_frame_rate) *
-                                  ((double)effdsp/100.0) + 0.5);
+        bytesperframe = (audio_channels * audio_bits_per_sample/8) * 
+          (int)(effdsp / 100.0 / video_frame_rate + 0.5);
 	
         // wait for the buffer to fill with enough to play
         if (bytesperframe >= audiolen(true))
Index: libs/libNuppelVideo/NuppelVideoPlayer.h
===================================================================
RCS file: /var/lib/cvs/MC/libs/libNuppelVideo/NuppelVideoPlayer.h,v
retrieving revision 1.48
diff -u -r1.48 NuppelVideoPlayer.h
--- libs/libNuppelVideo/NuppelVideoPlayer.h	15 Nov 2002 00:12:07 -0000	1.48
+++ libs/libNuppelVideo/NuppelVideoPlayer.h	19 Nov 2002 10:37:59 -0000
@@ -183,6 +183,8 @@
     unsigned char *buf2;
     char lastct;
     int effdsp; // from the recorded stream
+    int audio_channels; // from the recorded stream
+    int audio_bits_per_sample; // per channel
     int audio_samplerate; // rate to tell the output device
     int filesize;
     int startpos;
Index: libs/libNuppelVideo/NuppelVideoRecorder.cpp
===================================================================
RCS file: /var/lib/cvs/MC/libs/libNuppelVideo/NuppelVideoRecorder.cpp,v
retrieving revision 1.62
diff -u -r1.62 NuppelVideoRecorder.cpp
--- libs/libNuppelVideo/NuppelVideoRecorder.cpp	18 Nov 2002 01:59:38 -0000	1.62
+++ libs/libNuppelVideo/NuppelVideoRecorder.cpp	19 Nov 2002 10:38:00 -0000
@@ -24,6 +24,21 @@
 
 pthread_mutex_t avcodeclock = PTHREAD_MUTEX_INITIALIZER;
 
+int audio_ioctl_int(int fd, int arg, int *value, const char *decscription)
+{
+    int ret, orig = *value;
+
+    cout << "setting " << decscription << " to " << *value << endl;
+
+    if ((ret=ioctl(fd, arg, value)) < 0)
+        cerr << "problem setting " << decscription << ", exiting\n";
+    else
+        if(orig != *value) 
+           cout << decscription << " forced to use " << *value
+                << " instead of " << orig << endl;
+    return ret;
+}
+
 NuppelVideoRecorder::NuppelVideoRecorder(void)
 {
     sfilename = "output.nuv";
@@ -71,6 +86,8 @@
     keyframedist = KEYFRAMEDIST;
 
     audiobytes = 0;
+    audio_channels = 2;
+    audio_bits_per_sample = 16;
     audio_samplerate = 44100;
 
     picture_format = PIX_FMT_YUV420P;
@@ -259,6 +276,8 @@
 	lame_set_bWriteVbrTag(gf, 0);
 	lame_set_quality(gf, mp3quality);
 	lame_set_compression_ratio(gf, 11);
+        lame_set_mode(gf, audio_channels == 2 ? STEREO : MONO);
+        lame_set_num_channels(gf, audio_channels);
         lame_set_out_samplerate(gf, audio_samplerate);
         lame_set_in_samplerate(gf, audio_samplerate);
 	lame_init_params(gf);
@@ -313,5 +332,5 @@
 int NuppelVideoRecorder::AudioInit(void)
 {
     int afmt, afd;
-    int frag, channels, rate, blocksize = 4096;
+    int frag, blocksize = 4096;
 
@@ -331,30 +351,18 @@
     if (afmt != AFMT_S16_LE) 
     {
         cerr << "Can't get 16 bit DSP, exiting\n";
-        return(1);
-    }
-
-    channels = 2;
-    ioctl(afd, SNDCTL_DSP_CHANNELS, &channels);
-
-    /* sample rate */
-    rate = audio_samplerate;
-    if (ioctl(afd, SNDCTL_DSP_SPEED, &rate) < 0)
-    {
-        cerr << "setting sample rate failed, exiting\n";
         return 1;
     }
 
-    if (rate != audio_samplerate)
-    {
-        cerr << "setting sample rate to " << audio_samplerate << " failed\n";
-        return 1;
-    }
+    if(audio_ioctl_int(afd, SNDCTL_DSP_CHANNELS, &audio_channels, "audio input channels") < 0 ||
+       audio_ioctl_int(afd, SNDCTL_DSP_SPEED, &audio_samplerate, "audio input samplerate") < 0 ||
+       audio_ioctl_int(afd, SNDCTL_DSP_SAMPLESIZE, &audio_bits_per_sample, "audio input bits per sample") < 0)
+      return 1;
 
     if (-1 == ioctl(afd, SNDCTL_DSP_GETBLKSIZE, &blocksize)) 
     {
         cerr << "Can't get DSP blocksize, exiting\n";
-        return(1);
+        return 1;
     }
     blocksize *= 4;
 
@@ -1107,8 +1115,8 @@
     }
 
     moredata.audio_sample_rate = audio_samplerate;
-    moredata.audio_channels = 2;
-    moredata.audio_bits_per_sample = 16;
+    moredata.audio_channels = audio_channels;
+    moredata.audio_bits_per_sample = audio_bits_per_sample;
 
     extendeddataOffset = ringBuffer->GetFileWritePosition();
 
@@ -1238,8 +1246,8 @@
 {
     int afmt = 0, trigger = 0;
     int afd = 0, act = 0, lastread = 0;
-    int frag = 0, channels = 0, rate = 0, blocksize = 0;
+    int frag = 0, blocksize = 0;
     unsigned char *buffer;
     audio_buf_info ispace;
     struct timeval anow;
 
@@ -1265,12 +1274,13 @@
         return;
     }
 
-    channels = 2;
-    ioctl(afd, SNDCTL_DSP_CHANNELS, &channels);
-
-    /* sample rate */
-    rate = audio_samplerate;
-    ioctl(afd, SNDCTL_DSP_SPEED, &rate);
+    if(audio_ioctl_int(afd, SNDCTL_DSP_CHANNELS, &audio_channels, "audio input channels") < 0 ||
+       audio_ioctl_int(afd, SNDCTL_DSP_SPEED, &audio_samplerate, "audio input samplerate") < 0 ||
+       audio_ioctl_int(afd, SNDCTL_DSP_SAMPLESIZE, &audio_bits_per_sample, "audio input bits per sample") < 0)
+    {
+        close(afd);
+        return;
+    }
 
     if (-1 == ioctl(afd, SNDCTL_DSP_GETBLKSIZE,  &blocksize)) 
     {
@@ -1339,8 +1349,8 @@
 	/* Back up the timecode. The more stuff is in the hw buffer,
 	   the earlier this audio was actually recorded. */
 	audiobuffer[act]->timecode -=
-	    (int) ( ( (double)ispace.fragments * (double)ispace.fragsize * 1000.0 ) /
-		    ( (double)audio_samplerate * 4.0 ) );
+	    (int)(ispace.fragments * ispace.fragsize * 1000.0 /
+                  (audio_samplerate * audio_bits_per_sample/8 * audio_channels));
 
         memcpy(audiobuffer[act]->buffer, buffer, audio_buffer_size);
 
@@ -1728,12 +1738,12 @@
                                      // wrong guess ;-)
         // need seconds instead of msec's
         //mt = (double)timecode/1000.0;
-        mt = (double)timecode;
+        mt = timecode;
         if (mt > 0.0) 
         {
             //eff = (abytes/4.0)/mt;
             //effectivedsp=(int)(100.0*eff);
-            eff = (abytes/mt)*((double)100000.0/(double)4.0);
+            eff = (abytes/mt)*(100000.0 / (audio_bits_per_sample/8) / audio_channels);
             effectivedsp=(int)eff;
         }
     }
@@ -1745,10 +1755,21 @@
         int gaplesssize = 0;
         int lameret = 0;
 
-        lameret = lame_encode_buffer_interleaved(gf, (short int *)buf,
-                                                 audio_buffer_size / 4,
-                                                 (unsigned char *)mp3buf,
-                                                 mp3buf_size);
+        if(audio_channels == 2)
+        {
+            lameret = lame_encode_buffer_interleaved(gf, (short int *)buf,
+                                                     audio_buffer_size / audio_channels / (audio_bits_per_sample/8),
+                                                     (unsigned char *)mp3buf,
+                                                     mp3buf_size);
+        }
+        else
+        {
+            lameret = lame_encode_buffer(gf, (short int *)buf, (short int *)buf,
+                                         audio_buffer_size / audio_channels / (audio_bits_per_sample/8),
+                                         (unsigned char *)mp3buf,
+                                         mp3buf_size);
+        }
+
         if (lameret < 0)
         {
             cerr << "lame error, exiting\n";
Index: libs/libNuppelVideo/NuppelVideoRecorder.h
===================================================================
RCS file: /var/lib/cvs/MC/libs/libNuppelVideo/NuppelVideoRecorder.h,v
retrieving revision 1.25
diff -u -r1.25 NuppelVideoRecorder.h
--- libs/libNuppelVideo/NuppelVideoRecorder.h	18 Nov 2002 01:59:38 -0000	1.25
+++ libs/libNuppelVideo/NuppelVideoRecorder.h	19 Nov 2002 10:38:00 -0000
@@ -126,6 +126,8 @@
     int compression;
     int compressaudio;
     unsigned long long audiobytes;
+    int audio_channels; // channels to request from sounddevice
+    int audio_bits_per_sample; // per channel
     int audio_samplerate; // rate we request from sounddevice
     int effectivedsp; // actual measured rate