📄 madlld.c
字号:
ReadSize+=MAD_BUFFER_GUARD;
}
/* Pipe the new buffer content to libmad's stream decoder
* facility.
*/
mad_stream_buffer(&Stream,InputBuffer,ReadSize+Remaining);
Stream.error=0;
}
/* Decode the next MPEG frame. The streams is read from the
* buffer, its constituents are break down and stored the the
* Frame structure, ready for examination/alteration or PCM
* synthesis. Decoding options are carried in the Frame
* structure from the Stream structure.
*
* Error handling: mad_frame_decode() returns a non zero value
* when an error occurs. The error condition can be checked in
* the error member of the Stream structure. A mad error is
* recoverable or fatal, the error status is checked with the
* MAD_RECOVERABLE macro.
*
* {4} When a fatal error is encountered all decoding
* activities shall be stopped, except when a MAD_ERROR_BUFLEN
* is signaled. This condition means that the
* mad_frame_decode() function needs more input to complete
* its work. One shall refill the buffer and repeat the
* mad_frame_decode() call. Some bytes may be left unused at
* the end of the buffer if those bytes forms an incomplete
* frame. Before refilling, the remaining bytes must be moved
* to the beginning of the buffer and used for input for the
* next mad_frame_decode() invocation. (See the comments
* marked {2} earlier for more details.)
*
* Recoverable errors are caused by malformed bit-streams, in
* this case one can call again mad_frame_decode() in order to
* skip the faulty part and re-sync to the next frame.
*/
if(mad_frame_decode(&Frame,&Stream))
{
if(MAD_RECOVERABLE(Stream.error))
{
/* Do not print a message if the error is a loss of
* synchronization and this loss is due to the end of
* stream guard bytes. (See the comments marked {3}
* supra for more informations about guard bytes.)
*/
if(Stream.error!=MAD_ERROR_LOSTSYNC ||
Stream.this_frame!=GuardPtr)
{
fprintf(stderr,"%s: recoverable frame level error (%s)\n",
ProgName,MadErrorString(&Stream));
fflush(stderr);
}
continue;
}
else
if(Stream.error==MAD_ERROR_BUFLEN)
continue;
else
{
fprintf(stderr,"%s: unrecoverable frame level error (%s).\n",
ProgName,MadErrorString(&Stream));
Status=1;
break;
}
}
/* The characteristics of the stream's first frame is printed
* on stderr. The first frame is representative of the entire
* stream.
*/
if(FrameCount==0)
if(PrintFrameInfo(stderr,&Frame.header))
{
Status=1;
break;
}
/* Accounting. The computed frame duration is in the frame
* header structure. It is expressed as a fixed point number
* whole data type is mad_timer_t. It is different from the
* samples fixed point format and unlike it, it can't directly
* be added or subtracted. The timer module provides several
* functions to operate on such numbers. Be careful there, as
* some functions of libmad's timer module receive some of
* their mad_timer_t arguments by value!
*/
FrameCount++;
mad_timer_add(&Timer,Frame.header.duration);
/* Between the frame decoding and samples synthesis we can
* perform some operations on the audio data. We do this only
* if some processing was required. Detailed explanations are
* given in the ApplyFilter() function.
*/
if(DoFilter)
ApplyFilter(&Frame);
/* Once decoded the frame is synthesized to PCM samples. No errors
* are reported by mad_synth_frame();
*/
mad_synth_frame(&Synth,&Frame);
/* Synthesized samples must be converted from libmad's fixed
* point number to the consumer format. Here we use unsigned
* 16 bit big endian integers on two channels. Integer samples
* are temporarily stored in a buffer that is flushed when
* full.
*/
for(i=0;i<Synth.pcm.length;i++)
{
signed short Sample;
/* Left channel */
Sample=MadFixedToSshort(Synth.pcm.samples[0][i]);
*(OutputPtr++)=Sample>>8;
*(OutputPtr++)=Sample&0xff;
/* Right channel. If the decoded stream is monophonic then
* the right output channel is the same as the left one.
*/
if(MAD_NCHANNELS(&Frame.header)==2)
Sample=MadFixedToSshort(Synth.pcm.samples[1][i]);
*(OutputPtr++)=Sample>>8;
*(OutputPtr++)=Sample&0xff;
/* Flush the output buffer if it is full. */
if(OutputPtr==OutputBufferEnd)
{
if(fwrite(OutputBuffer,1,OUTPUT_BUFFER_SIZE,OutputFp)!=OUTPUT_BUFFER_SIZE)
{
fprintf(stderr,"%s: PCM write error (%s).\n",
ProgName,strerror(errno));
Status=2;
break;
}
OutputPtr=OutputBuffer;
}
}
}while(1);
/* The input file was completely read; the memory allocated by our
* reading module must be reclaimed.
*/
BstdFileDestroy(BstdFile);
/* Mad is no longer used, the structures that were initialized must
* now be cleared.
*/
mad_synth_finish(&Synth);
mad_frame_finish(&Frame);
mad_stream_finish(&Stream);
/* If the output buffer is not empty and no error occurred during
* the last write, then flush it.
*/
if(OutputPtr!=OutputBuffer && Status!=2)
{
size_t BufferSize=OutputPtr-OutputBuffer;
if(fwrite(OutputBuffer,1,BufferSize,OutputFp)!=BufferSize)
{
fprintf(stderr,"%s: PCM write error (%s).\n",
ProgName,strerror(errno));
Status=2;
}
}
/* Accounting report if no error occurred. */
if(!Status)
{
char Buffer[80];
/* The duration timer is converted to a human readable string
* with the versatile, but still constrained mad_timer_string()
* function, in a fashion not unlike strftime(). The main
* difference is that the timer is broken into several
* values according some of it's arguments. The units and
* fracunits arguments specify the intended conversion to be
* executed.
*
* The conversion unit (MAD_UNIT_MINUTES in our example) also
* specify the order and kind of conversion specifications
* that can be used in the format string.
*
* It is best to examine libmad's timer.c source-code for details
* of the available units, fraction of units, their meanings,
* the format arguments, etc.
*/
mad_timer_string(Timer,Buffer,"%lu:%02lu.%03u",
MAD_UNITS_MINUTES,MAD_UNITS_MILLISECONDS,0);
fprintf(stderr,"%s: %lu frames decoded (%s).\n",
ProgName,FrameCount,Buffer);
}
/* That's the end of the world (in the H. G. Wells way). */
return(Status);
}
/****************************************************************************
* Prints a message on stderr explaining the usage of the program. Two *
* versions of this function are provided, depending on the system type. *
****************************************************************************/
static void PrintUsage(void)
{
#ifdef HAVE_GETOPT /* This version is for Unix systems. */
fprintf(stderr,"usage: %s [-p] [-a <amp/atten>]\n"
"\t-a\tSets an amplification or attenuation factor expressed\n"
"\t\tin dB. The factor bounds are [-Inf,%f].\n"
"\t-p\tRequests that the output samples be filtered as if\n"
"\t\ttransmitted through a telephone switch.\n",
ProgName,
20.*log10(mad_f_todouble(MAD_F_MAX)));
#else /* HAVE_GETOPT */ /* This other version is for non-Unix systems. */
fprintf(stderr,"usage: %s [<number>] [phone]\n"
"\t<number> is a floating point number expressing an "
"amplification\n"
"\t\tor attenuation factor expressed in dB. The factor bounds\n"
"\t\tare [-Inf,%f].\n"
"\tThe \"phone\" argument requests that the output samples be "
"filtered\n"
"\t\tas if transmitted through a telephone switch.\n",
ProgName,
20.*log10(mad_f_todouble(MAD_F_MAX)));
#endif /* HAVE_GETOPT */
}
/****************************************************************************
* Command-line arguments parsing. We use two methods and two command-line *
* formats depending on the system type. On unix system we apply the good *
* old getopt() method, other system are offered a really primitive options *
* interface. *
****************************************************************************/
static int ParseArgs(int argc, char * const argv[])
{
int DoPhoneFilter=0,
i;
double AmpFactor;
mad_fixed_t Amp=MAD_F_ONE;
#ifdef HAVE_GETOPT /* This version is for Unix systems. */
int Option;
/* Parse the command line. */
while((Option=getopt(argc,argv,"a:p"))!=-1)
switch(Option)
{
/* {5} Set the amplification/attenuation factor, expressed
* in dB.
*/
case 'a':
/* If the current linear amplification factor is not
* one (MAD_F_ONE) then is was already set. Setting it
* again is not permitted.
*/
if(Amp!=MAD_F_ONE)
{
fprintf(stderr,"%s: the amplification/attenuation factor "
"was set several times.\n",ProgName);
return(1);
}
/* The decibel value is converted to a linear factor.
* That factor is checked against the maximum value
* that can be stored in a mad_fixed_t. The upper
* bound is MAD_F_MAX, it is converted to a double
* value with mad_f_todouble() for comparison.
*/
AmpFactor=pow(10.,atof(optarg)/20);
if(AmpFactor>mad_f_todouble(MAD_F_MAX))
{
fprintf(stderr,"%s: amplification out of range.\n",
ProgName);
return(1);
}
/* Eventually the amplification factor is converted
* from double to fixed point with mad_f_tofixed().
*/
Amp=mad_f_tofixed(AmpFactor);
break;
/* {6} The output is filtered through a telephone wire. */
case 'p':
/* Only one occurrence of the option is permitted. */
if(DoPhoneFilter)
{
fprintf(stderr,"%s: the phone-line simulation option "
"was already set.\n",ProgName);
return(1);
}
/* The output will be filtered through a band-pass
* filter simulating a phone line transmission.
*/
DoPhoneFilter=1;
break;
/* Print usage guide for invalid options. */
case '?':
default:
PrintUsage();
return(1);
}
#else /* HAVE_GETOPT */ /* This other version is for non-Unix systems. */
/* Scan all command-line arguments. */
for(i=1;i<argc;i++)
{
/* Set the amplification factor if the current argument looks
* like a number. Look at the comment of the case marked {5}
* in the Unix section for details.
*/
if(*argv[i]=='+' || *argv[i]=='-' || isdigit(*argv[i]))
{
if(Amp!=MAD_F_ONE)
{
fprintf(stderr,"%s: the amplification/attenuation factor "
"was set several times.\n",ProgName);
return(1);
}
AmpFactor=pow(10.,atof(argv[i])/20);
if(AmpFactor>mad_f_todouble(MAD_F_MAX))
{
fprintf(stderr,"%s: amplification out of range.\n",
ProgName);
return(1);
}
Amp=mad_f_tofixed(AmpFactor);
}
else
/* Use the phone-like filter if the argument is the *
* 'phone' string. Look at the comment of the case marked
* {6} in the Unix section for details.
*/
if(strcmp(argv[i],"phone")==0)
{
if(DoPhoneFilter)
{
fprintf(stderr,"%s: the phone-line simulation option "
"was already set.\n",ProgName);
return(1);
}
DoPhoneFilter=1;
}
else
{
/* The argument is not a recognized one. Print the
* usage guidelines and stop there.
*/
PrintUsage();
return(1);
}
}
#endif /* HAVE_GETOPT */
/* Initialize the subband-domain filter coefficients to one if
* filtering is requested.
*/
if(Amp!=MAD_F_ONE || DoPhoneFilter)
for(i=0;i<32;i++)
Filter[i]=MAD_F_ONE;
/* The amplification/attenuation is applied to the subband-domain
* filter definition.
*/
if(Amp!=MAD_F_ONE)
{
DoFilter=1;
for(i=0;i<32;i++)
Filter[i]=Amp;
}
/* The telephone-like filter is applied to the subband-domain
* filter definition. All subbands are set to zero except bands 2
* to 6. This programs author has no access to the MPEG audio
* specification, he does not know the frequencies bands covered
* by the MPEG subbands.
*/
if(DoPhoneFilter)
{
DoFilter=1;
Filter[0]=MAD_F(0);
for(i=5;i<32;i++)
Filter[i]=MAD_F(0);
}
/* Command-line arguments are okay. */
return(0);
}
/****************************************************************************
* Program entry point. *
****************************************************************************/
int main(int argc, char *argv[])
{
char *cptr;
int Status;
/* Keep this for error messages. */
cptr=strrchr(argv[0],'/');
if(cptr==NULL)
ProgName=argv[0];
else
ProgName=cptr+1;
/* The command-line arguments are analyzed. */
if(ParseArgs(argc,argv))
return(1);
/* Decode stdin to stdout. */
Status=MpegAudioDecoder(stdin,stdout);
if(Status)
fprintf(stderr,"%s: an error occurred during decoding.\n",ProgName);
/* All done. */
return(Status);
}
/* LocalWords: BUFLEN HTAB madlld libmad bstdfile getopt subband ParseArgs JS
*/
/* LocalWords: DoFilter subbands errorstr bitrate scalefactor libmad's lu kb
*/
/* LocalWords: SWWWFFFFFFFFFFFFFFFFFFFFFFFFFFFF FRACBITS madplay fread synth
*/
/* LocalWords: ApplyFilter strftime fracunits atten tSets tRequest tThe tas
*/
/* LocalWords: ttransmitted unix todouble tofixed
*/
/*
* Local Variables:
* tab-width: 4
* End:
*/
/****************************************************************************
* End of file madlld.c *
****************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -