[xiph-cvs] cvs commit: snatch INSTALL README-MJPEG esd.c libsnatch.c snatch2yuv.c snatchconvert.c x11.c

Monty xiphmont at xiph.org
Mon Feb 25 22:01:16 PST 2002



xiphmont    02/02/25 22:01:15

  Modified:    .        INSTALL README-MJPEG esd.c libsnatch.c snatch2yuv.c
                        snatchconvert.c x11.c
  Log:
  updates to readmes, build warning fixes

Revision  Changes    Path
1.2       +19 -13    snatch/INSTALL

Index: INSTALL
===================================================================
RCS file: /usr/local/cvsroot/snatch/INSTALL,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- INSTALL	2001/11/12 23:16:25	1.1
+++ INSTALL	2002/02/26 06:01:14	1.2
@@ -11,16 +11,18 @@
 
 *************************** COMPILATION ***************************
 
-libsnatch has to be compiled.  It isn't actually worthy of a Makefile
-at this point.
+libsnatch has to be compiled.  The conversion utilities that make
+.snatch files useful have to be compiled.  I supply a trivial,
+hand-written makefile to do both.  It assumes gcc, and that
+installation should go in /usr/local.
 
-gcc -O2 -shared libsnatch.c -o libsnatch.so
+As root...
 
-All the dynamic libs libnatch needs are sucked in from RealPlayer.
+make install
 
-The Snatch Robot need not be compiled as it's a Perl script.
+...will build and install Snatch.  It's now ready to run.
 
-*************************** INSTALLATION **************************
+************************ MANUAL INSTALLATION **********************
 
 The only two important bits to install are libsnatch.so and the Snatch
 Robot.  Installation consists of:
@@ -39,12 +41,17 @@
 The Snatch Robot will need to find RealPlayer too.  If it's not in the
 path, you can deal with that after starting Snatch.
 
+The conversion utils (snatch2yuv, snatch2yuv2, snatch2wav) are not
+needed to run Snatch, but are useful to convert the output to
+something useful.  These need simply be compiled (see Makefile) and
+placed wherever they're to be used.
+
 ***************************** EXAMPLES ****************************
 
 To install Snatch in your home directory (doesn't need root)
 
-tar -xvzf snatch-20011112.tgz
-cd snatch-20011112
+tar -xvzf snatch-20020225.tgz
+cd snatch-20020225
 gcc -O2 -shared libsnatch.c -o libsnatch.so
 mkdir ~/.snatch
 mv libsnatch.so ~/.snatch
@@ -54,8 +61,7 @@
 
 To install Snatch for the whole system (as root)
 
-tar -xvzf snatch-20011112.tgz
-cd snatch-20011112
-gcc -O2 -shared libsnatch.c -o libsnatch.so
-mv libsnatch.so /usr/lib/
-mv Snatch /usr/bin/
+tar -xvzf snatch-20020225.tgz
+cd snatch-20020225
+make install
+

<p><p>1.3       +120 -57   snatch/README-MJPEG

Index: README-MJPEG
===================================================================
RCS file: /usr/local/cvsroot/snatch/README-MJPEG,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- README-MJPEG	2002/02/22 21:34:00	1.2
+++ README-MJPEG	2002/02/26 06:01:14	1.3
@@ -1,37 +1,41 @@
-Snatch 20020222
+Snatch 20020225
 
-Converting Snatch capture files to MPEG audio/video with MJPEG-1.4.1
+Converting Snatch capture files to MPEG audio/video with mjpeg-tools
 
 ****************************** ABOUT ******************************
 
-mjpegtools-1.4.1 is a nice little collection of MPEG audio and video
-utilities that, for the most part, work out of the box.  The output
-quality is very nice, and the tool set is intelligently arranged.
-
-(I'll note that 1.6.0 of mjpeg-tools is now out; I find that 1.4.1
-gives slightly better quality performance and still prefer it over its
-newer cousing.  Also, 1.6.0 changes the YUV file format used together
-by the tools in an incompatable way with 1.4.1, so supporting both
-will take some hacking).
-
-The various tools in the mjpeg-tools trade video in YUV format and
-audio as WAV.  Snatch support for mjpegtools consists of two
-conversion utilities, snatch2wav and snatch2yuv (naturally, these
-utilities need not be used only with mjpegtools.
+mjpeg-tools is a nice little collection of MPEG audio and video
+utilities that work out of the box.  The output quality is very nice,
+and the tool set is intelligently arranged.
+
+The various tools in the mjpeg-tools trade video in YUV4MPEG[2] format
+and audio as WAV.  Snatch support for mjpeg-tools consists of three
+conversion utilities, snatch2wav, snatch2yuv and snatch2yuv2
+(Naturally, these utilities will work with any application accepting
+these formats).
+
+The conversion utilities are tested to work with
+mjpeg-tools-1.4 through 1.6.0-beta2.  Note that newer versions of
+mjpeg-tools use YUV4MPEG2 format (produced by snatch2yuv2) while 1.4
+uses the original YUV4MEG (produced by snatch2yuv).  1.6.0 compiled
+cleanly here for Debian/x86 and Debian/PPC.  1.4.1 requires some
+hacking to correct a few [very minor] problems.  If you don't have
+either yet, go for 1.6.0.
 
 Converting a snatch capture file to MPEG video using mjpeg is done in
 three steps: encode audio to MPEG-1 layer 2 audio using snatch2wav and
-mp2enc(.mp2), encode the video to MPEG-1/2 video using snatch2yuv and
-mpeg2enc and then multiplexing the audio/video into a complete MPEG
-video stream with mplex.  All of these tools are included in the package.
+mp2enc or toolame (.mp2), encode the video to MPEG-1/2 video using
+snatch2yuv[2] and mpeg2enc and then multiplexing the audio/video into
+a complete MPEG video stream with mplex.  All of these tools [except
+toolame] are included in the mjpeg-tools and Snatch packages.
 
 ***************************** INSTALL *****************************
 
-The official home of mjpegtools is http://mjpeg.sourceforge.net/ Note
-that the official mjpegtools-1.4.1 has a few annoying build and option
-parsing bugs.  I've patched the bugs I've found, as well as added the
-Snatch conversion utility source to my own distribution of the
-mjpegtools source:
+The official home of mjpeg-tools is http://mjpeg.sourceforge.net/ 
+Note that the older, official mjpegtools-1.4.1 has a few annoying
+build and option parsing bugs.  I've patched the bugs I've found, as
+well as added the Snatch conversion utility source to my own
+distribution of the mjpeg-tools source:
 
 A patch against stock mjpegtools-1.4.1 can be found at: 
 http://www.mit.edu/afs/athena/user/x/i/xiphmont/Public/Snatch/mjpegtools-1.4.1-snatchpatch.diff
@@ -39,12 +43,13 @@
 The complete source with patch already applied is at:
 http://www.mit.edu/afs/athena/user/x/i/xiphmont/Public/Snatch/mjpegtools-1.4.1-snatch.tgz
 
-If you just want the utilities, the source files 'snatchconvert.c',
-'snatch2yuv.c' and 'snatch2wav.c' are included in the main
-distribution.  They build/work fine without mjpegtools.
+Unless there's a reason to use the older 1.4 release, 1.6 is
+recommended.  1.6 requires no patch, and the Makefile included with
+Snatch builds and installs the Snatch conversion utilities (as they're
+not included with the official 1.6 source).
 
 When building mjpeg-tools, pay attention to the INSTALL document in
-the mjpegtools tarball.  Things will probably go wrong if you don't
+the mjpeg-tools tarball.  Things will probably go wrong if you don't
 read it.
 
 One trick wrt Debian and installing quicktime4linux through dpkg/apt;
@@ -56,9 +61,9 @@
 
 ****************************** USAGE ******************************
 
-Once installed, snatch2wav and snatch2yuv work just like the other
+Once installed, snatch2wav and snatch2yuv[2] work just like the other
 mjpeg 'xxxx2wav' and 'xxx2yuv' tools.  The command line options are
-different, but snatch2wav -h and snatch2yuv -h will give a clear
+different, but snatch2wav -h and snatch2yuv[2] -h will give a clear
 summary.
 
 The basic idea:
@@ -67,7 +72,7 @@
 snatch2wav < capture.snatch | mp2enc -o temp.mp2
 
 Encode an .m1v video file from the Snatch capture file using 
-snatch2yuv -f fpscode < capture.snatch | mpeg2enc -a 1 -f fpscode -o temp.mp2
+snatch2yuv < capture.snatch | mpeg2enc -o temp.m1v
 
 Multiplex them into one movie file:
 mplex temp.mp2 temp.m1v -o output.mpeg
@@ -82,23 +87,36 @@
    merely letterbox/crop.  That's OK, mpeg2enc will encode practically
    any frame size.
 
-2) snatch2yuv does not autosense frame rate.  Real frame rates are
-   going to be weird, non-MPEG ones for the most part, so choosing an
-   even multiple of the Real frame rate is the best bet.  Eg, if the
-   Real stream was 15fps, select '30fps' when using snatch2yuv; it
-   will do the pullup/pulldown automatically. see snatch2yuv -h for a 
-   list of frame rates/
-
-   snatch2yuv will stuff the capture data into any frame rate the user
-   selects; choosing the wrong one will work, it will just be jerky
-   and not smooth.
+   However, many MPEG _players_ require that video width be a multiple
+   of 8 and RealPlayer, for God Knows What Reason, often decodes, for
+   example, 240x180 video into a screen resolution of, say, 238x180
+   for no good reason.  You may need to use -s with snatch2yuv[2] to
+   force a multiple of eight size for maximum compatibility with
+   various MPEG players.
+
+2) snatch2yuv does not autosense frame rate.  RealVideo frame rates
+   are going to be weird, non-MPEG ones for the most part...  but the
+   oddest thing about RealPlayer8 is that it doesn't display at the
+   encoded frame rate!  RP8 seems to blast frames to the screen at
+   ~30fps regardless of what the encoded video actually wants.
+   snatch2yuv[2] defaults to 30fps, so you shouldn't need to frob frame
+   rate (but you can if you want to).
 
 3) audio/video sync is Just Not A Concern.  Snatch records timing data
    in the capture file; snatch2wav pays attention to the video timing
-   when extracting audio and snatch2yuv watches the audio when
+   when extracting audio and snatch2yuv[2] watches the audio when
    extracting video.  The separated audio and video will always be in
    sync unless explicitly requested otherwise.
 
+   However, A/V sync can be a problem in the resulting MPEG file if
+   you use VBR encoding and an Easily Confused Player.  For example,
+   the only *NIX player I've seen that pays any attention to sync with
+   VBR MPEG video is MPlayer (and MPlayer does an excellent job).
+   Others (like the ubiquitous Xine) have serious trouble even playing
+   VBR, let alone keeping sync solid.  This, obviously, is not a bug
+   in Snatch.  The sync is perfect in the .snatch file, and
+   snatch2yuv/snatch2wav will produce synchronized output.
+
 4) It's possible a capture file will contain different sampling rates
    or mixed frame sizes/rates; this can happen if the window is
    resized, congestion causes a change in stream rate, etc.
@@ -112,32 +130,77 @@
    snatch2yuv, similarly, forces all output to the same frame rate and
    frame size.
 
-Now for a real example:
+5) If a capture is momentarily interrupted (congestion, or an old
+   Linux machine using a 2.2 kernel that only allows 2GB files)
+   resulting in the capture going into multiple .snatch files, the
+   files can be strung back together in sequence with cat and piped
+   into the conversion utilities.  Catting and processing in one batch
+   eliminates any additional audio/video dropout or padding at the
+   boundaries that would be caused by the conversion utilities having
+   to invent or discard frames to keep the beginning and ending output
+   in sync (an odd but necessary thing about players... although the
+   audio and video are _played_ in sync, they're not produced that
+   way.  Audio usually runs several seconds ahead of video because of
+   hardware buffering.  This would show up if you independently
+   processed multiple .snatch files comprising one program.  The output
+   would sill be in sync, but the beginning of each file would begin
+   with video for several seconds before audio started and end with
+   audio for several seconds after video stopped).
+
+   If a gap within or between two files is greater than two
+   seconds, the conversion utils will snip most of the gap out
+   (intentionally leaving a bit), else the splice will be seamless.
+
+   Note that the conversion utilities are counting absolute seconds
+   when using the -b and -n options; gaps and interruptions are
+   counted time.  That is, if splicing back together, say, a one hour
+   segment of a live program that lost five minutes in the middle due
+   to a momentary network outage, "snatch2yuv2 -n 3600" will produce
+   video for the one hour program, without the five minute gap in the
+   middle, for a total of 55 minutes of actual video.  Naturally,
+   snatch2wav will still produce audio exactly matching the video.
+
+Now for a real example.  I've captured a 240x180 (which RP8 actually
+displays at 238x180), mono 22050Hz file using Snatch.  Because
+RealPlayer actually displays at 30fps, the .snatch file is already at
+30fps, which is both the default rate assumed by snatch2yuv and a
+legal MPEG1/2 video frame rate (even had it been captured at 10 or
+15fps, which is a more likely native RealVideo frame rate, it would
+need to be upsampled to 30fps for MPEG encoding).  I, personally,
+would use (assuming mjpeg-tools-1.6.0):
 
-snatch2wav < 20011115_22:00:10_mono22050Hz_320x240_AV.snatch | \
-	   mp2enc -m -b 128 -o temp.mp2
+snatch2wav < 20011115_22:00:10_mono22050Hz_238x180_AV.snatch | \
+	   mp2enc -m -b 64 -o temp.mp2
 
-snatch2yuv -f 5 < 20011115_22:00:10_mono22050Hz_320x240_AV.snatch | \
-	   mpeg2enc -a 1 -f 5 -b 576 -o temp.m1v
+snatch2yuv2 -s 240x180 < 20011115_22:00:10_mono22050Hz_238x180_AV.snatch | \
+	   mpeg2enc -q 8 -b 576 -f 3 -B 64 -o temp.m1v
 
-mplex temp.mp2 temp.m1v -o out.mpeg
+mplex temp.mp2 temp.m1v -r 640 -f 3 -V -o out.mpeg
 
 The first line instructs snatch2wav to convert the audio from the
 .snatch file into standard RIFF WAV (but without the length tag set.
-That won't be an issue here).  mp2enc then turns that WAV into a 128
-kbps mono mpeg2 file.  These options can vary (and are not actually
-necessary at all).
+That won't be an issue here).  mp2enc then turns that WAV into a 64
+kbps mono mpeg layer 2 file.  These options can vary (and are not
+actually necessary at all).  I'll note that toolame produces
+considerably higher quality output than mp2enc.  It's worth getting.
 
 The second line instructs snatch2yuv to convert the video from the
 capture file into YUV 4:2:0 (also called YV12), the format preferred
-by mpeg2enc.  The frame rate here is 'MPEG frame rate # 5', which
-equals 30fps.  In this case, the input was 15fps, so snatch2yuv is
-doing an automatic pullup.  mpeg2enc then produces an output video in
-MPEG format consisting of square pixels (-a 1) 30fps (-f 5 , the
-number given to -f should match the one given to snatch2yuv unless
-you're doing something deliberately odd), 576kbps (-b 576).
+by mpeg2enc.  The -s argument to snatch2yuv2 forces an output frame
+width that's a multiple of eight for maximum MPEG player
+compatibility.  mpeg2enc then produces an output video in MPEG format
+consisting of square pixels (no option necessary, this is forced by
+snatch2yuv2) 30fps (also set in the YUV4MPEG2 header produced by
+snatch2yuv2), at a variable bitrate quality level 8 (-q 8) not to
+exceed 576kbps for the video (-b 576).  -f 3 requests a generic MPEG 2
+output file, and -B 64 lets the encoder know ahead of time that a
+64kbps audio stream will also be multiplexed in later on.  The -B is
+not strictly necessary.
 
 The third line mixes the audio and video files into the final stream.
+-r sets the peak output bitrate of the output stream (add the peak -b
+bitrates for audio and video), -f 3 selects MPEG 2, and -V is
+required when muxing VBR streams.
 
 ****************************** MORE *******************************
 

<p><p>1.3       +3 -2      snatch/esd.c

Index: esd.c
===================================================================
RCS file: /usr/local/cvsroot/snatch/esd.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- esd.c	2001/11/12 23:16:25	1.2
+++ esd.c	2002/02/26 06:01:14	1.3
@@ -58,7 +58,8 @@
 /* RealPlayer opens two EsounD connections.  One for daemon control
    requests, the other for streaming audio */
 
-static esd_connection esdconn[2]={{-1},{-1}};
+static esd_connection esdconn[2]={{-1,-1,-1,{0},-1,-1},
+				  {-1,-1,-1,{0},-1,-1}};
 static int esdconmax=2;
 
 static esd_connection *getcon(int fd){
@@ -145,7 +146,7 @@
     struct sockaddr_in *addr=(struct sockaddr_in *)serv_addr;
     unsigned int port=ntohs(addr->sin_port);
     char *colonpos=strchr(esdsocket,':');
-    if(colonpos && port==atoi(colonpos+1))return(1);
+    if(colonpos && (int)port==atoi(colonpos+1))return(1);
   }
   return(0);
 }

<p><p>1.34      +3 -3      snatch/libsnatch.c

Index: libsnatch.c
===================================================================
RCS file: /usr/local/cvsroot/snatch/libsnatch.c,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -r1.33 -r1.34
--- libsnatch.c	2001/11/26 05:45:02	1.33
+++ libsnatch.c	2002/02/26 06:01:14	1.34
@@ -231,7 +231,7 @@
       if(ret==1){
         if(length)buf=calloc(length+1,1);
         if(length)ret=fread(buf,1,length,backchannel_fd);
-	if(length && ret==length)
+	if(length && (int)ret==length)
           switch(rq){
           case 'U':
             if(username)free(username);
@@ -589,7 +589,7 @@
     if(ret<0 && count==0)return(ret);
     if(ret<0)return(count);
     count+=ret;
-    if(ret<v[i].iov_len)return(count);
+    if(ret<(int)(v[i].iov_len))return(count);
   }
   return(count);
 }
@@ -601,7 +601,7 @@
     if(ret<0 && count==0)return(ret);
     if(ret<0)return(count);
     count+=ret;
-    if(ret<v[i].iov_len)return(count);
+    if(ret<(int)(v[i].iov_len))return(count);
   }
   return(count);
 }

<p><p>1.6       +13 -4     snatch/snatch2yuv.c

Index: snatch2yuv.c
===================================================================
RCS file: /usr/local/cvsroot/snatch/snatch2yuv.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- snatch2yuv.c	2002/02/22 17:21:34	1.5
+++ snatch2yuv.c	2002/02/26 06:01:14	1.6
@@ -55,12 +55,18 @@
 extern double end_time;
 
 static double framerates[]={
-  0., 23.976 ,24., 25., 29.970, 30., 50., 59.940, 60. };
+  0., 23.976, 24., 25., 29.970, 30., 50., 59.940, 60. };
 
 static void usage(FILE *f){
   fprintf(f,
-	  "snatch2yuv 20011115\n\n"
-	  "USAGE: snatch2yuv [options] < infile { > outfile, | nextutil }\n\n"
+	  "snatch2yuv 20020225\n"
+	  "snatch2yuv2 20020225\n\n"
+	  "snatch2yuv produces YUV4MPEG format files (used by, for example,\n"
+	  "mjpeg-tools 1.4). snatch2yuv2 produces YUV4MPEG2 format files (used\n"
+	  "by, eg, mjpeg-tools 1.6)\n\n"
+
+	  "USAGE: snatch2yuv  [options] < infile { > outfile, | nextutil }\n"
+	  "       snatch2yuv2 [options] < infile { > outfile, | nextutil }\n\n"
           "OPTIONS:\n"
           "  -b <N>    : skip first <N> seconds of input file\n"
           "  -f <N>    : output video in specific MPEG legal\n"
@@ -99,6 +105,9 @@
   int c;
   int graph=0;
 
+  int yuvtype=1;
+  if(!strcmp(argv[0],"snatch2yuv2"))yuvtype=2;
+
   ratecode=5;
   vidin_fps=30;
   vidout_fps=30;
@@ -155,7 +164,7 @@
 
 
   while(!done){
-    done=snatch_iterator(stdin,stdout,0,1);
+    done=snatch_iterator(stdin,stdout,0,yuvtype);
 
     if(noisy){
       long seconds=framesout/vidout_fps;

<p><p>1.14      +13 -1     snatch/snatchconvert.c

Index: snatchconvert.c
===================================================================
RCS file: /usr/local/cvsroot/snatch/snatchconvert.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- snatchconvert.c	2002/02/23 23:19:43	1.13
+++ snatchconvert.c	2002/02/26 06:01:14	1.14
@@ -1053,6 +1053,16 @@
   fprintf(f,"YUV4MPEG %d %d %d\n",w,h,fpscode);
 }
 
+static int frameratesn[]={
+  0,   24000,  24,  25,  30000,  30,  50,  60000,  60 };
+static int frameratesd[]={
+  0.,   1001,   1,   1,   1001,   1,   1,   1001,   1 };
+
+void WriteYuv2(FILE *f,int w,int h,int fpscode){
+  fprintf(f,"YUV4MPEG2 W%d H%d F%d:%d Ip A1:1\n",w,h,
+	  frameratesn[fpscode],frameratesd[fpscode]);
+}
+
 /* YV12 aka 4:2:0 planar */
 void YUVout(unsigned char *buf,FILE *f){
   fprintf(f,"FRAME\n");
@@ -1103,7 +1113,9 @@
         if(!begun){
           if(process_audio)
             WriteWav(out,audbuf_channels,audbuf_rate,16);
-	  if(process_video)
+	  if(process_video==2)
+	    WriteYuv2(out,vidbuf_width,vidbuf_height,ratecode);
+	  if(process_video==1)
             WriteYuv(out,vidbuf_width,vidbuf_height,ratecode);
           begun=1;
         }

<p><p>1.27      +14 -13    snatch/x11.c

Index: x11.c
===================================================================
RCS file: /usr/local/cvsroot/snatch/x11.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -r1.26 -r1.27
--- x11.c	2001/11/16 06:30:23	1.26
+++ x11.c	2002/02/26 06:01:14	1.27
@@ -14,16 +14,16 @@
 static unsigned long rpmain_window=0;
 static unsigned long rpmenu_window=0;
 static unsigned long rpplay_window=0;
-static unsigned long rpplay_width=0;
-static unsigned long rpplay_height=0;
+static long rpplay_width=0;
+static long rpplay_height=0;
 
-static unsigned long logo_y=-1;
-static unsigned long logo_prev=-1;
+static long logo_y=-1;
+static long logo_prev=-1;
 
-static unsigned long play_blackleft=-1;
-static unsigned long play_blackright=-1;
-static unsigned long play_blackupper=-1;
-static unsigned long play_blacklower=-1;
+static long play_blackleft=-1;
+static long play_blackright=-1;
+static long play_blackupper=-1;
+static long play_blacklower=-1;
 
 static unsigned long rpvideo_window=0;
 static int video_width=-1;
@@ -108,7 +108,7 @@
 static void FakeKeySym(int keysym, int modmask, unsigned long window){
   KeyCode c=XKeysymToKeycode(Xdisplay,keysym);
 
-  if(XKeycodeToKeysym(Xdisplay,c,0)==keysym){
+  if((int)XKeycodeToKeysym(Xdisplay,c,0)==keysym){
     FakeKeycode(c,modmask,window);
   }else{
     FakeKeycode(c,1|modmask,window);
@@ -724,7 +724,8 @@
       }
       
       /* blank background */
-      if(x==0 && y==0 && d_width==rpplay_width && d_height==rpplay_height){
+      if(x==0 && y==0 && (int)d_width==rpplay_width && 
+	 (int)d_height==rpplay_height){
         unsigned char *bptr;
 
         if(snatch_active==1)
@@ -753,9 +754,9 @@
         
         /* paint logo */
         if(logo_y!=-1){
-	  unsigned char *logo;
-	  int logowidth;
-	  int logoheight;
+	  unsigned char *logo=NULL;
+	  int logowidth=-1;
+	  int logoheight=-1;
           
           switch(snatch_active){
           case 0:

<p><p><p>--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list