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;
}