shithub: sox

Download patch

ref: e8893f3feff1f7b93f848f42a82a2d52fea10e0b
parent: 3ee5ec9286a35a3cfb726662d905067dbb8c8bad
author: cbagwell <cbagwell>
date: Sat Jun 5 15:08:28 EDT 2004

Support for ignoring garbage on mp3 files.

--- a/Changelog
+++ b/Changelog
@@ -15,6 +15,11 @@
     appears to confuse some conversion programs.  Updated sox.1
     man page for typo in reverb option.
   o Andrew Church fixed problem with header of stereo 8SVX files.
+  o Jimen Ching added support to scan over garbage data at the
+    beginning of MP3 files to find valid frames.  This is useful
+    to play WAV and AIFF files that have MP3 data in them until
+    those handlers support it directly.  To play those, force
+    sox to use the mp3 handler with the "-t mp3" option.
 
 sox-12.17.4
 -----------
--- a/src/mp3.c
+++ b/src/mp3.c
@@ -28,22 +28,22 @@
 #define MIN(s1,s2) ((s1)<(s2)?(s1):(s2))
 #endif
 
-#define INPUT_BUFFER_SIZE	(5*ST_BUFSIZ)
+#define INPUT_BUFFER_SIZE       (5*ST_BUFSIZ)
 
 /* Private data */
 struct mp3priv {
 #if defined(HAVE_LIBMAD)
-	struct mad_stream	*Stream;
-	struct mad_frame	*Frame;
-	struct mad_synth	*Synth;
-	mad_timer_t		*Timer;
-	unsigned char		*InputBuffer;
-	st_ssize_t		cursamp;
-	unsigned long		FrameCount;
-	int			eof;
+        struct mad_stream       *Stream;
+        struct mad_frame        *Frame;
+        struct mad_synth        *Synth;
+        mad_timer_t             *Timer;
+        unsigned char           *InputBuffer;
+        st_ssize_t              cursamp;
+        unsigned long           FrameCount;
+        int                     eof;
 #endif /*HAVE_LIBMAD*/
 #if defined(HAVE_LAME)
-	lame_global_flags	*gfp;
+        lame_global_flags       *gfp;
 #endif /*HAVE_LAME*/
 };
 
@@ -58,7 +58,7 @@
 int tagtype(const unsigned char *data, int length)
 {
   if (length >= 3 && data[0] == 'T' && data[1] == 'A' && data[2] == 'G')
-	return 128; /* ID3V1 */
+        return 128; /* ID3V1 */
 
   if (length >= 10 &&
       (data[0] == 'I' && data[1] == 'D' && data[2] == '3') &&
@@ -65,13 +65,13 @@
       data[3] < 0xff && data[4] < 0xff &&
       data[6] < 0x80 && data[7] < 0x80 && data[8] < 0x80 && data[9] < 0x80)
   {     /* ID3V2 */
-	unsigned char flags;
-	unsigned int size;
-	flags = data[5];
-	size = (data[6]<<21) + (data[7]<<14) + (data[8]<<7) + data[9];
-	if (flags & ID3_TAG_FLAG_FOOTERPRESENT)
-		size += 10;
-	return 10 + size;
+        unsigned char flags;
+        unsigned int size;
+        flags = data[5];
+        size = (data[6]<<21) + (data[7]<<14) + (data[8]<<7) + data[9];
+        if (flags & ID3_TAG_FLAG_FOOTERPRESENT)
+                size += 10;
+        return 10 + size;
   }
 
   return 0;
@@ -79,107 +79,113 @@
 
 int st_mp3startread(ft_t ft) 
 {
-	struct mp3priv *p = (struct mp3priv *) ft->priv;
-	size_t ReadSize;
+        struct mp3priv *p = (struct mp3priv *) ft->priv;
+        size_t ReadSize;
 
-	p->Stream=malloc(sizeof(struct mad_stream));
-	if (p->Stream == NULL){
-	  st_fail_errno(ft, ST_ENOMEM, "Could not allocate memory");
-	  return ST_EOF;
-	}
-	
-	p->Frame=malloc(sizeof(struct mad_frame));
-	if (p->Frame == NULL){
-	  st_fail_errno(ft, ST_ENOMEM, "Could not allocate memory");
-	  free(p->Stream);
-	  return ST_EOF;
-	}
-	
-	p->Synth=malloc(sizeof(struct mad_synth));
-	if (p->Synth == NULL){
-	  st_fail_errno(ft, ST_ENOMEM, "Could not allocate memory");
-	  free(p->Stream);
-	  free(p->Frame);
-	  return ST_EOF;
-	}
-	
-	p->Timer=malloc(sizeof(mad_timer_t));
-	if (p->Timer == NULL){
-	  st_fail_errno(ft, ST_ENOMEM, "Could not allocate memory");
-	  free(p->Stream);
-	  free(p->Frame);
-	  free(p->Synth);
-	  return ST_EOF;
-	}
-	
-	p->InputBuffer=malloc(INPUT_BUFFER_SIZE);
-	if (p->InputBuffer == NULL){
-	  st_fail_errno(ft, ST_ENOMEM, "Could not allocate memory");
-	  free(p->Stream);
-	  free(p->Frame);
-	  free(p->Synth);
-	  free(p->Timer);
-	  return ST_EOF;
-	}
-	
-	mad_stream_init(p->Stream);
-	mad_frame_init(p->Frame);
-	mad_synth_init(p->Synth);
-	mad_timer_reset(p->Timer);
+        p->Stream=malloc(sizeof(struct mad_stream));
+        if (p->Stream == NULL){
+          st_fail_errno(ft, ST_ENOMEM, "Could not allocate memory");
+          return ST_EOF;
+        }
+        
+        p->Frame=malloc(sizeof(struct mad_frame));
+        if (p->Frame == NULL){
+          st_fail_errno(ft, ST_ENOMEM, "Could not allocate memory");
+          free(p->Stream);
+          return ST_EOF;
+        }
+        
+        p->Synth=malloc(sizeof(struct mad_synth));
+        if (p->Synth == NULL){
+          st_fail_errno(ft, ST_ENOMEM, "Could not allocate memory");
+          free(p->Stream);
+          free(p->Frame);
+          return ST_EOF;
+        }
+        
+        p->Timer=malloc(sizeof(mad_timer_t));
+        if (p->Timer == NULL){
+          st_fail_errno(ft, ST_ENOMEM, "Could not allocate memory");
+          free(p->Stream);
+          free(p->Frame);
+          free(p->Synth);
+          return ST_EOF;
+        }
+        
+        p->InputBuffer=malloc(INPUT_BUFFER_SIZE);
+        if (p->InputBuffer == NULL){
+          st_fail_errno(ft, ST_ENOMEM, "Could not allocate memory");
+          free(p->Stream);
+          free(p->Frame);
+          free(p->Synth);
+          free(p->Timer);
+          return ST_EOF;
+        }
+        
+        mad_stream_init(p->Stream);
+        mad_frame_init(p->Frame);
+        mad_synth_init(p->Synth);
+        mad_timer_reset(p->Timer);
 
-	ft->info.encoding = ST_ENCODING_MP3;
-	ft->info.size = ST_SIZE_DWORD;
+        ft->info.encoding = ST_ENCODING_MP3;
+        ft->info.size = ST_SIZE_DWORD;
 
-	/* We need to decode the first frame,
-	 * so we know the output format */
+        /* We need to decode the first frame,
+         * so we know the output format */
 
-	ReadSize=fread(p->InputBuffer,1,INPUT_BUFFER_SIZE,ft->fp);
-	if(ReadSize<=0)
-	{
-		if(ferror(ft->fp))
-			st_fail_errno(ft,ST_EOF,"read error on bitstream");
-		if(feof(ft->fp))
-			st_fail_errno(ft,ST_EOF,"end of input stream");
-		return(ST_EOF);
-	}
-	
-	mad_stream_buffer(p->Stream,p->InputBuffer,ReadSize);
-	p->Stream->error = 0;
+        ReadSize=fread(p->InputBuffer,1,INPUT_BUFFER_SIZE,ft->fp);
+        if(ReadSize<=0)
+        {
+                if(ferror(ft->fp))
+                        st_fail_errno(ft,ST_EOF,"read error on bitstream");
+                if(feof(ft->fp))
+                        st_fail_errno(ft,ST_EOF,"end of input stream");
+                return(ST_EOF);
+        }
+        
+        mad_stream_buffer(p->Stream,p->InputBuffer,ReadSize);
+        p->Stream->error = 0;
 
-	while(mad_frame_decode(p->Frame,p->Stream)) {
-	    int tagsize;
-	    if ( (tagsize=tagtype(p->Stream->this_frame, p->Stream->bufend - p->Stream->this_frame)) == 0){
+        while(mad_frame_decode(p->Frame,p->Stream)) {
+            int tagsize;
+            if ((p->Stream->bufend - p->Stream->this_frame) < (INPUT_BUFFER_SIZE - ST_BUFSIZ)){
 
-	      /* we assume that, if the first frame fails, the file is not an MP3 file */
-	      
-	      st_fail_errno(ft,ST_EOF,"The file is not an MP3 file or it is corrupted");
-	      return ST_EOF;
-	    }
-	    mad_stream_skip(p->Stream, tagsize);
-	}
+              /* we assume that, if the first frame fails, the file is not an MP3 file */
+              
+              st_fail_errno(ft,ST_EOF,"The file is not an MP3 file or it is corrupted");
+              return ST_EOF;
+            }
+            /* Walk threw the stream one byte at a time (tagsize=1)
+             * until we find a valid frame.  Previous if() will
+             * abort once we got a certain distance.
+             */
+            if ((tagsize=tagtype(p->Stream->this_frame, p->Stream->bufend - p->Stream->this_frame)) == 0)
+                tagsize = 1; /* Walk through the stream. */
+            mad_stream_skip(p->Stream, tagsize);
+        }
 
-	switch(p->Frame->header.mode)
-	{
-		case MAD_MODE_SINGLE_CHANNEL:
-		case MAD_MODE_DUAL_CHANNEL:
-		case MAD_MODE_JOINT_STEREO:
-		case MAD_MODE_STEREO:
-		  ft->info.channels = MAD_NCHANNELS(&p->Frame->header);
-		  break;
-		default:
-		  st_fail_errno(ft,ST_EFMT,"Cannot determine number of channels");
-		  return ST_EOF;
-	}
+        switch(p->Frame->header.mode)
+        {
+                case MAD_MODE_SINGLE_CHANNEL:
+                case MAD_MODE_DUAL_CHANNEL:
+                case MAD_MODE_JOINT_STEREO:
+                case MAD_MODE_STEREO:
+                  ft->info.channels = MAD_NCHANNELS(&p->Frame->header);
+                  break;
+                default:
+                  st_fail_errno(ft,ST_EFMT,"Cannot determine number of channels");
+                  return ST_EOF;
+        }
 
-	p->FrameCount=1;
-	ft->info.rate=p->Frame->header.samplerate;
+        p->FrameCount=1;
+        ft->info.rate=p->Frame->header.samplerate;
 
-	mad_timer_add(p->Timer,p->Frame->header.duration);
-	mad_synth_frame(p->Synth,p->Frame);
-	p->cursamp = 0;
-	p->eof     = 0;
+        mad_timer_add(p->Timer,p->Frame->header.duration);
+        mad_synth_frame(p->Synth,p->Frame);
+        p->cursamp = 0;
+        p->eof     = 0;
 
-	return ST_SUCCESS;
+        return ST_SUCCESS;
 }
 
 /*
@@ -201,13 +207,13 @@
     i=0;
     while(i<donow){
       for(chan=0;chan<ft->info.channels;chan++){
-	sample=p->Synth->pcm.samples[chan][p->cursamp];
-	if (sample < -MAD_F_ONE)
-	  sample=-MAD_F_ONE;
-	else if (sample >= MAD_F_ONE)
-	  sample=MAD_F_ONE-1;
-	*buf++=(st_sample_t)(sample<<(32-1-MAD_F_FRACBITS));
-	i++;
+        sample=p->Synth->pcm.samples[chan][p->cursamp];
+        if (sample < -MAD_F_ONE)
+          sample=-MAD_F_ONE;
+        else if (sample >= MAD_F_ONE)
+          sample=MAD_F_ONE-1;
+        *buf++=(st_sample_t)(sample<<(32-1-MAD_F_FRACBITS));
+        i++;
       }
       p->cursamp++;
     };
@@ -221,56 +227,56 @@
 
     if(p->Stream->error==MAD_ERROR_BUFLEN)
       {
-	size_t		ReadSize, Remaining;
-	
-			/* libmad does not consume all the buffer it's given. Some
-			 * datas, part of a truncated frame, is left unused at the
-			 * end of the buffer. Those datas must be put back at the
-			 * beginning of the buffer and taken in account for
-			 * refilling the buffer. This means that the input buffer
-			 * must be large enough to hold a complete frame at the
-			 * highest observable bit-rate (currently 448 kb/s). XXX=XXX
-			 * Is 2016 bytes the size of the largest frame?
-			 * (448000*(1152/32000))/8
-			 */
-	
-	Remaining=p->Stream->bufend - p->Stream->next_frame;
-	memmove(p->InputBuffer,p->Stream->next_frame,Remaining);
+        size_t          ReadSize, Remaining;
+        
+                        /* libmad does not consume all the buffer it's given. Some
+                         * datas, part of a truncated frame, is left unused at the
+                         * end of the buffer. Those datas must be put back at the
+                         * beginning of the buffer and taken in account for
+                         * refilling the buffer. This means that the input buffer
+                         * must be large enough to hold a complete frame at the
+                         * highest observable bit-rate (currently 448 kb/s). XXX=XXX
+                         * Is 2016 bytes the size of the largest frame?
+                         * (448000*(1152/32000))/8
+                         */
+        
+        Remaining=p->Stream->bufend - p->Stream->next_frame;
+        memmove(p->InputBuffer,p->Stream->next_frame,Remaining);
 
-	ReadSize=fread(p->InputBuffer+Remaining,1,INPUT_BUFFER_SIZE-Remaining,ft->fp);
-	if(ReadSize == 0){
-	  p->eof=1;
-	  memset(p->InputBuffer+Remaining,0,MAD_BUFFER_GUARD);
-	  ReadSize=MAD_BUFFER_GUARD;
-	}
+        ReadSize=fread(p->InputBuffer+Remaining,1,INPUT_BUFFER_SIZE-Remaining,ft->fp);
+        if(ReadSize == 0){
+          p->eof=1;
+          memset(p->InputBuffer+Remaining,0,MAD_BUFFER_GUARD);
+          ReadSize=MAD_BUFFER_GUARD;
+        }
 
-	mad_stream_buffer(p->Stream,p->InputBuffer,ReadSize+Remaining);
-	p->Stream->error=0;
+        mad_stream_buffer(p->Stream,p->InputBuffer,ReadSize+Remaining);
+        p->Stream->error=0;
       }
 
     if(mad_frame_decode(p->Frame,p->Stream)){
       if(MAD_RECOVERABLE(p->Stream->error))
-	{
-	  int tagsize;
-	  if ( (tagsize=tagtype(p->Stream->this_frame, p->Stream->bufend - p->Stream->this_frame)) == 0){
-	    if (!p->eof)
-	      st_warn("recoverable frame level error (%s).\n",
-		      mad_stream_errorstr(p->Stream));
-	  }
-	  else mad_stream_skip(p->Stream,tagsize);
-	  continue;
-      	}
+        {
+          int tagsize;
+          if ( (tagsize=tagtype(p->Stream->this_frame, p->Stream->bufend - p->Stream->this_frame)) == 0){
+            if (!p->eof)
+              st_warn("recoverable frame level error (%s).\n",
+                      mad_stream_errorstr(p->Stream));
+          }
+          else mad_stream_skip(p->Stream,tagsize);
+          continue;
+        }
       else
-	{
-	  if(p->Stream->error==MAD_ERROR_BUFLEN)
-	    continue;
-	  else
-	    {
-	      st_warn("unrecoverable frame level error (%s).\n",
-		      mad_stream_errorstr(p->Stream));
-	      return done;
-	    }
-	}
+        {
+          if(p->Stream->error==MAD_ERROR_BUFLEN)
+            continue;
+          else
+            {
+              st_warn("unrecoverable frame level error (%s).\n",
+                      mad_stream_errorstr(p->Stream));
+              return done;
+            }
+        }
     }
     p->FrameCount++;
     mad_timer_add(p->Timer,p->Frame->header.duration);
@@ -340,8 +346,8 @@
 
   if (ft->info.channels != -1){
     if ( (lame_set_num_channels(p->gfp,ft->info.channels)) < 0) {
-	st_fail_errno(ft,ST_EOF,"Unsupported number of channels");
-	return(ST_EOF);
+        st_fail_errno(ft,ST_EOF,"Unsupported number of channels");
+        return(ST_EOF);
     }
   }
   else
@@ -355,8 +361,8 @@
      since SoX's command line options do not allow to set them */
 
   if (lame_init_params(p->gfp) < 0){
-	st_fail_errno(ft,ST_EOF,"LAME initialization failed");
-	return(ST_EOF);
+        st_fail_errno(ft,ST_EOF,"LAME initialization failed");
+        return(ST_EOF);
   }
   lame_set_errorf(p->gfp,null_error_func);
   lame_set_debugf(p->gfp,null_error_func);
@@ -404,11 +410,11 @@
   }
  
   if ( (written = lame_encode_buffer_long2(p->gfp,
-					   buffer_l,
-					   buffer_r,
-					   nsamples,
-					   mp3buffer,
-					   mp3buffer_size)) < 0){
+                                           buffer_l,
+                                           buffer_r,
+                                           nsamples,
+                                           mp3buffer,
+                                           mp3buffer_size)) < 0){
     st_fail_errno(ft,ST_EOF,"Encoding failed");
     goto end;
   }