📄 madlld.c
字号:
/* HTAB = 4 */
/****************************************************************************
* madlld.c -- A simple program decoding an MPEG audio stream to 16-bit *
* PCM from stdin to stdout. This program is just a simple sample *
* demonstrating how the low-level libmad API can be used. *
*--------------------------------------------------------------------------*
* (c) 2001--2004 Bertrand Petit *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* *
* 1. Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* *
* 2. Redistributions in binary form must reproduce the above *
* copyright notice, this list of conditions and the following *
* disclaimer in the documentation and/or other materials provided *
* with the distribution. *
* *
* 3. Neither the name of the author nor the names of its contributors *
* may be used to endorse or promote products derived from this *
* software without specific prior written permission. *
* *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' *
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR *
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF *
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND *
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, *
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT *
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF *
* SUCH DAMAGE. *
* *
****************************************************************************/
/*
* $Name: $
* $Date: 2004/05/02 20:39:17 $
* $Revision: 1.1 $
*/
/****************************************************************************
* Includes *
****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <math.h> /* for pow() and log10() */
#include <mad.h>
#include "bstdfile.h"
/* Should we use getopt() for command-line arguments parsing? */
#if (defined(unix) || defined (__unix__) || defined(__unix) || \
defined(HAVE_GETOPT)) \
&& !defined(WITHOUT_GETOPT)
#include <unistd.h>
#define HAVE_GETOPT
#else
#include <ctype.h>
#undef HAVE_GETOPT
#endif
/****************************************************************************
* Global variables. *
****************************************************************************/
/* Keeps a pointer to the program invocation name for the error
* messages.
*/
const char *ProgName;
/* This table represents the subband-domain filter characteristics. It
* is initialized by the ParseArgs() function and is used as
* coefficients against each subband samples when DoFilter is non-nul.
*/
mad_fixed_t Filter[32];
/* DoFilter is non-nul when the Filter table defines a filter bank to
* be applied to the decoded audio subbands.
*/
int DoFilter=0;
/****************************************************************************
* Return an error string associated with a mad error code. *
****************************************************************************/
/* Mad version 0.14.2b introduced the mad_stream_errorstr() function.
* For previous library versions a replacement is provided below.
*/
#if (MAD_VERSION_MAJOR>=1) || \
((MAD_VERSION_MAJOR==0) && \
(((MAD_VERSION_MINOR==14) && \
(MAD_VERSION_PATCH>=2)) || \
(MAD_VERSION_MINOR>14)))
#define MadErrorString(x) mad_stream_errorstr(x)
#else
static const char *MadErrorString(const struct mad_stream *Stream)
{
switch(Stream->error)
{
/* Generic unrecoverable errors. */
case MAD_ERROR_BUFLEN:
return("input buffer too small (or EOF)");
case MAD_ERROR_BUFPTR:
return("invalid (null) buffer pointer");
case MAD_ERROR_NOMEM:
return("not enough memory");
/* Frame header related unrecoverable errors. */
case MAD_ERROR_LOSTSYNC:
return("lost synchronization");
case MAD_ERROR_BADLAYER:
return("reserved header layer value");
case MAD_ERROR_BADBITRATE:
return("forbidden bitrate value");
case MAD_ERROR_BADSAMPLERATE:
return("reserved sample frequency value");
case MAD_ERROR_BADEMPHASIS:
return("reserved emphasis value");
/* Recoverable errors */
case MAD_ERROR_BADCRC:
return("CRC check failed");
case MAD_ERROR_BADBITALLOC:
return("forbidden bit allocation value");
case MAD_ERROR_BADSCALEFACTOR:
return("bad scalefactor index");
case MAD_ERROR_BADFRAMELEN:
return("bad frame length");
case MAD_ERROR_BADBIGVALUES:
return("bad big_values count");
case MAD_ERROR_BADBLOCKTYPE:
return("reserved block_type");
case MAD_ERROR_BADSCFSI:
return("bad scalefactor selection info");
case MAD_ERROR_BADDATAPTR:
return("bad main_data_begin pointer");
case MAD_ERROR_BADPART3LEN:
return("bad audio data length");
case MAD_ERROR_BADHUFFTABLE:
return("bad Huffman table select");
case MAD_ERROR_BADHUFFDATA:
return("Huffman data overrun");
case MAD_ERROR_BADSTEREO:
return("incompatible block_type for JS");
/* Unknown error. This switch may be out of sync with libmad's
* defined error codes.
*/
default:
return("Unknown error code");
}
}
#endif
/****************************************************************************
* Converts a sample from libmad's fixed point number format to a signed *
* short (16 bits). *
****************************************************************************/
static signed short MadFixedToSshort(mad_fixed_t Fixed)
{
/* A fixed point number is formed of the following bit pattern:
*
* SWWWFFFFFFFFFFFFFFFFFFFFFFFFFFFF
* MSB LSB
* S ==> Sign (0 is positive, 1 is negative)
* W ==> Whole part bits
* F ==> Fractional part bits
*
* This pattern contains MAD_F_FRACBITS fractional bits, one
* should alway use this macro when working on the bits of a fixed
* point number. It is not guaranteed to be constant over the
* different platforms supported by libmad.
*
* The signed short value is formed, after clipping, by the least
* significant whole part bit, followed by the 15 most significant
* fractional part bits. Warning: this is a quick and dirty way to
* compute the 16-bit number, madplay includes much better
* algorithms.
*/
/* Clipping */
if(Fixed>=MAD_F_ONE)
return(SHRT_MAX);
if(Fixed<=-MAD_F_ONE)
return(-SHRT_MAX);
/* Conversion. */
Fixed=Fixed>>(MAD_F_FRACBITS-15);
return((signed short)Fixed);
}
/****************************************************************************
* Print human readable informations about an audio MPEG frame. *
****************************************************************************/
static int PrintFrameInfo(FILE *fp, struct mad_header *Header)
{
const char *Layer,
*Mode,
*Emphasis;
/* Convert the layer number to it's printed representation. */
switch(Header->layer)
{
case MAD_LAYER_I:
Layer="I";
break;
case MAD_LAYER_II:
Layer="II";
break;
case MAD_LAYER_III:
Layer="III";
break;
default:
Layer="(unexpected layer value)";
break;
}
/* Convert the audio mode to it's printed representation. */
switch(Header->mode)
{
case MAD_MODE_SINGLE_CHANNEL:
Mode="single channel";
break;
case MAD_MODE_DUAL_CHANNEL:
Mode="dual channel";
break;
case MAD_MODE_JOINT_STEREO:
Mode="joint (MS/intensity) stereo";
break;
case MAD_MODE_STEREO:
Mode="normal LR stereo";
break;
default:
Mode="(unexpected mode value)";
break;
}
/* Convert the emphasis to it's printed representation. Note that
* the MAD_EMPHASIS_RESERVED enumeration value appeared in libmad
* version 0.15.0b.
*/
switch(Header->emphasis)
{
case MAD_EMPHASIS_NONE:
Emphasis="no";
break;
case MAD_EMPHASIS_50_15_US:
Emphasis="50/15 us";
break;
case MAD_EMPHASIS_CCITT_J_17:
Emphasis="CCITT J.17";
break;
#if (MAD_VERSION_MAJOR>=1) || \
((MAD_VERSION_MAJOR==0) && (MAD_VERSION_MINOR>=15))
case MAD_EMPHASIS_RESERVED:
Emphasis="reserved(!)";
break;
#endif
default:
Emphasis="(unexpected emphasis value)";
break;
}
fprintf(fp,"%s: %lu kb/s audio MPEG layer %s stream %s CRC, "
"%s with %s emphasis at %d Hz sample rate\n",
ProgName,Header->bitrate,Layer,
Header->flags&MAD_FLAG_PROTECTION?"with":"without",
Mode,Emphasis,Header->samplerate);
return(ferror(fp));
}
/****************************************************************************
* Applies a frequency-domain filter to audio data in the subband-domain. *
****************************************************************************/
static void ApplyFilter(struct mad_frame *Frame)
{
int Channel,
Sample,
Samples,
SubBand;
/* There is two application loops, each optimized for the number
* of audio channels to process. The first alternative is for
* two-channel frames, the second is for mono-audio.
*/
Samples=MAD_NSBSAMPLES(&Frame->header);
if(Frame->header.mode!=MAD_MODE_SINGLE_CHANNEL)
for(Channel=0;Channel<2;Channel++)
for(Sample=0;Sample<Samples;Sample++)
for(SubBand=0;SubBand<32;SubBand++)
Frame->sbsample[Channel][Sample][SubBand]=
mad_f_mul(Frame->sbsample[Channel][Sample][SubBand],
Filter[SubBand]);
else
for(Sample=0;Sample<Samples;Sample++)
for(SubBand=0;SubBand<32;SubBand++)
Frame->sbsample[0][Sample][SubBand]=
mad_f_mul(Frame->sbsample[0][Sample][SubBand],
Filter[SubBand]);
}
/****************************************************************************
* Main decoding loop. This is where mad is used. *
****************************************************************************/
#define INPUT_BUFFER_SIZE (5*8192)
#define OUTPUT_BUFFER_SIZE 8192 /* Must be an integer multiple of 4. */
static int MpegAudioDecoder(FILE *InputFp, FILE *OutputFp)
{
struct mad_stream Stream;
struct mad_frame Frame;
struct mad_synth Synth;
mad_timer_t Timer;
unsigned char InputBuffer[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD],
OutputBuffer[OUTPUT_BUFFER_SIZE],
*OutputPtr=OutputBuffer,
*GuardPtr=NULL;
const unsigned char *OutputBufferEnd=OutputBuffer+OUTPUT_BUFFER_SIZE;
int Status=0,
i;
unsigned long FrameCount=0;
bstdfile_t *BstdFile;
/* First the structures used by libmad must be initialized. */
mad_stream_init(&Stream);
mad_frame_init(&Frame);
mad_synth_init(&Synth);
mad_timer_reset(&Timer);
/* Decoding options can here be set in the options field of the
* Stream structure.
*/
/* {1} When decoding from a file we need to know when the end of
* the file is reached at the same time as the last bytes are read
* (see also the comment marked {3} bellow). Neither the standard
* C fread() function nor the POSIX read() system call provides
* this feature. We thus need to perform our reads through an
* interface having this feature, this is implemented here by the
* bstdfile.c module.
*/
BstdFile=NewBstdFile(InputFp);
if(BstdFile==NULL)
{
fprintf(stderr,"%s: can't create a new bstdfile_t (%s).\n",
ProgName,strerror(errno));
return(1);
}
/* This is the decoding loop. */
do
{
/* The input bucket must be filled if it becomes empty or if
* it's the first execution of the loop.
*/
if(Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN)
{
size_t ReadSize,
Remaining;
unsigned char *ReadStart;
/* {2} libmad may not consume all bytes of the input
* buffer. If the last frame in the buffer is not wholly
* contained by it, then that frame's start is pointed by
* the next_frame member of the Stream structure. This
* common situation occurs when mad_frame_decode() fails,
* sets the stream error code to MAD_ERROR_BUFLEN, and
* sets the next_frame pointer to a non NULL value. (See
* also the comment marked {4} bellow.)
*
* When this occurs, the remaining unused bytes must be
* put back at the beginning of the buffer and taken in
* account before refilling the buffer. This means that
* the input buffer must be large enough to hold a whole
* 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
*/
if(Stream.next_frame!=NULL)
{
Remaining=Stream.bufend-Stream.next_frame;
memmove(InputBuffer,Stream.next_frame,Remaining);
ReadStart=InputBuffer+Remaining;
ReadSize=INPUT_BUFFER_SIZE-Remaining;
}
else
ReadSize=INPUT_BUFFER_SIZE,
ReadStart=InputBuffer,
Remaining=0;
/* Fill-in the buffer. If an error occurs print a message
* and leave the decoding loop. If the end of stream is
* reached we also leave the loop but the return status is
* left untouched.
*/
ReadSize=BstdRead(ReadStart,1,ReadSize,BstdFile);
if(ReadSize<=0)
{
if(ferror(InputFp))
{
fprintf(stderr,"%s: read error on bit-stream (%s)\n",
ProgName,strerror(errno));
Status=1;
}
if(feof(InputFp))
fprintf(stderr,"%s: end of input stream\n",ProgName);
break;
}
/* {3} When decoding the last frame of a file, it must be
* followed by MAD_BUFFER_GUARD zero bytes if one wants to
* decode that last frame. When the end of file is
* detected we append that quantity of bytes at the end of
* the available data. Note that the buffer can't overflow
* as the guard size was allocated but not used the the
* buffer management code. (See also the comment marked
* {1}.)
*
* In a message to the mad-dev mailing list on May 29th,
* 2001, Rob Leslie explains the guard zone as follows:
*
* "The reason for MAD_BUFFER_GUARD has to do with the
* way decoding is performed. In Layer III, Huffman
* decoding may inadvertently read a few bytes beyond
* the end of the buffer in the case of certain invalid
* input. This is not detected until after the fact. To
* prevent this from causing problems, and also to
* ensure the next frame's main_data_begin pointer is
* always accessible, MAD requires MAD_BUFFER_GUARD
* (currently 8) bytes to be present in the buffer past
* the end of the current frame in order to decode the
* frame."
*/
if(BstdFileEofP(BstdFile))
{
GuardPtr=ReadStart+ReadSize;
memset(GuardPtr,0,MAD_BUFFER_GUARD);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -