• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            zyzx的小窩

            C/C++,GUI,個(gè)人移動(dòng)存儲(chǔ),zyzx_lsl@163.com

             

            簡單mp3播放器:音頻播放核心

            tag:C,mp3解碼,libMAD,PortAudio

            /* Create by zyzx
            * Created 2008-08-09
            * Modified 2008-08-09
            */

            一、準(zhǔn)備
            ?????? 1、依賴庫PortAudio(http://www.portaudio.com/
            ???????????? Win32平臺(tái)編譯見《Win32環(huán)境PortAudio庫編譯簡介:音頻播放

            ?????? 2、依賴庫libMAD (http://www.underbit.com/products/mad/)
            ???????????? 簡介:開源跨平臺(tái)的mpeg-1,mpeg-2,mpeg-2.5,MP3解碼C庫。
            ???????????? 編譯環(huán)境 Win32 + VS
            ???????????? 下載libMAD 打開 ..\msvc++\LibMad.sln 可以用VS直接編譯。

            二、編碼試驗(yàn)
            ??????? 如上一篇《簡單音頻播放:音頻播放核心實(shí)現(xiàn)》的代碼實(shí)現(xiàn),不同的是LibMad 提供給我們的解碼方式稍微有些區(qū)別。

            ??????? 如下源碼參照 PortAudio庫中示例patest_read_write_wire.c 和 LibMad庫中示例minimad.c文件進(jìn)行的修改,還有Audacity中的部分實(shí)現(xiàn)。。所以還有很多地方懶得去理會(huì),代碼難看點(diǎn)。。

            ??????? 需要注意的地方:
            ??????? 基本上同上一篇。
            ??????? 1)PCM格式,分左右聲道2個(gè)緩存區(qū)域
            ??????? 2)PortAudio接受一個(gè)緩存區(qū)域,左右聲道并列方式組織。

            ??????? 3)當(dāng)然如果要讓你的音頻播放模塊能夠支持更多種格式,可要做一番設(shè)計(jì)了。。要做到可以替換編解碼模塊,驅(qū)動(dòng)聲卡模塊,跨平臺(tái),移植ARM那些系統(tǒng),還是不容易的。。


            如下是全部的源碼:

            #include <stdio.h>
            #include <stdlib.h>
            #include <string.h>
            #include "portaudio.h"

            #include <sys/types.h>

            #include "mad.h"

            #include "windows.h"

            /* #define SAMPLE_RATE (17932) // Test failure to open with this value. */
            #define SAMPLE_RATE (44100)
            #define FRAMES_PER_BUFFER ( 64 * 1024 )
            #define NUM_CHANNELS??? (2)
            /* #define DITHER_FLAG???? (paDitherOff) */
            #define DITHER_FLAG???? (0) /**/

            /* Select sample format. */
            #if 1
            #define PA_SAMPLE_TYPE paFloat32
            #define SAMPLE_SIZE (4)
            #define SAMPLE_SILENCE (0.0f)
            #define CLEAR(a) bzero( (a), FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
            #define PRINTF_S_FORMAT "%.8f"
            #elif 0
            #define PA_SAMPLE_TYPE paInt16
            #define SAMPLE_SIZE (2)
            #define SAMPLE_SILENCE (0)
            #define CLEAR(a) bzero( (a), FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
            #define PRINTF_S_FORMAT "%d"
            #elif 0
            #define PA_SAMPLE_TYPE paInt24
            #define SAMPLE_SIZE (3)
            #define SAMPLE_SILENCE (0)
            #define CLEAR(a) bzero( (a), FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
            #define PRINTF_S_FORMAT "%d"
            #elif 0
            #define PA_SAMPLE_TYPE paInt8
            #define SAMPLE_SIZE (1)
            #define SAMPLE_SILENCE (0)
            #define CLEAR(a) bzero( (a), FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE )
            #define PRINTF_S_FORMAT "%d"
            #else
            #define PA_SAMPLE_TYPE paFloat32//paUInt8
            #define SAMPLE_SIZE ( sizeof(float) )
            #define SAMPLE_SILENCE (128)
            #define CLEAR( a ) { \
            ??? int i; \
            ??? for( i=0; i<FRAMES_PER_BUFFER*NUM_CHANNELS; i++ ) \
            ??? ((unsigned char *)a)[i] = (SAMPLE_SILENCE); \
            }
            #define PRINTF_S_FORMAT "%d"
            #endif

            #define WIN32_AUDIO_BUFF_LEN??? 32 * 1024 * 1024

            #define WIN32_BUFF_MAD_LEN??? ??? FRAMES_PER_BUFFER

            typedef struct
            {
            ??? float*??? ??? buffer;?????????????????????????????? //* - 解碼后的數(shù)據(jù)存儲(chǔ)區(qū)域
            ??? long??? ??? current, bufferlen ;

            ??? unsigned char*??? bufferMad;?????????? //* - 由于LibMad是一段一段讀寫,這里是緩沖區(qū)域
            ??? long??? bfMadLen;

            ??? unsigned int samplerate;??? ??? /* sampling frequency (Hz) */
            ??? unsigned short channels;??? ??? /* number of channels */

            ??? FILE* file;

            } Win32_Data ;

            struct MadBuffer {
            ??? unsigned char const *start;
            ??? unsigned long length;
            };

            static
            enum mad_flow input(void *data,
            struct mad_stream *stream)
            {
            ??? Win32_Data *buffer = (Win32_Data*)data;

            ??? //if (!buffer->length)
            ??? //??? return MAD_FLOW_STOP;

            ??? //mad_stream_buffer(stream, buffer->start, buffer->length);

            ??? //buffer->length = 0;

            ??? if( feof( buffer->file ) ) {
            ??? ??? return MAD_FLOW_STOP;
            ??? }

            ??? //* - 這段摘自Audacity(http://audacity.sourceforge.net/)
            ??? //* - 由于mp3編碼方式,可能某次讀取的數(shù)據(jù)并不是完整的,我們只取完整的 frame段,
            ??? //* - 將剩余的部分留給下段。

            ??? unsigned int unconsumedBytes;
            ??? if(stream->next_frame) {
            ??? ??? unconsumedBytes = buffer->bufferMad + WIN32_BUFF_MAD_LEN - stream->next_frame;
            ??? ??? memmove(buffer->bufferMad, stream->next_frame, unconsumedBytes);
            ??? }
            ??? else
            ??? ??? unconsumedBytes = 0;

            ??? off_t read = fread(buffer->bufferMad + unconsumedBytes, sizeof( unsigned char ), WIN32_BUFF_MAD_LEN - unconsumedBytes, buffer->file);

            ??? mad_stream_buffer(stream, buffer->bufferMad, read + unconsumedBytes);

            ??? return MAD_FLOW_CONTINUE;
            }

            /*
            * The following utility routine performs simple rounding, clipping, and
            * scaling of MAD's high-resolution samples down to 16 bits. It does not
            * perform any dithering or noise shaping, which would be recommended to
            * obtain any exceptional audio quality. It is therefore not recommended to
            * use this routine if high-quality output is desired.
            */

            static inline
            float scale(mad_fixed_t sample)
            {
            ??? /* round */
            ??? //sample += (1L << (MAD_F_FRACBITS - 16));

            ??? ///* clip */
            ??? //if (sample >= MAD_F_ONE)
            ??? //??? sample = MAD_F_ONE - 1;
            ??? //else if (sample < -MAD_F_ONE)
            ??? //??? sample = -MAD_F_ONE;

            ??? ///* quantize */
            ??? //return sample >> (MAD_F_FRACBITS + 1 - 16);

            ??? //* 將libMad庫內(nèi)置的采樣點(diǎn)格式轉(zhuǎn)換為 32位float類型
            ??? return (float) (sample / (float) (1L << MAD_F_FRACBITS));
            }

            /*
            * This is the output callback function. It is called after each frame of
            * MPEG audio data has been completely decoded. The purpose of this callback
            * is to output (or play) the decoded PCM audio.
            */

            static
            enum mad_flow output(void *data,
            struct mad_header const *header,
            struct mad_pcm *pcm)
            {
            ??? unsigned int nsamples;
            ??? mad_fixed_t const *left_ch, *right_ch;
            ??? Win32_Data* buffer = ( Win32_Data* ) data;

            ??? ///* pcm->samplerate contains the sampling frequency */

            ??? buffer->channels = pcm->channels;
            ??? buffer->samplerate = pcm->samplerate;
            ??? nsamples = pcm->length;
            ??? left_ch?? = pcm->samples[0];
            ??? right_ch = pcm->samples[1];

            ??? while (nsamples--) {
            ??? ??? float sample;

            ??? ??? /* output sample(s) in 16-bit signed little-endian PCM */
            ??????? //* - PCM格式 的數(shù)據(jù)是分布在2個(gè)緩存區(qū)域中分左右聲道,而PortAudio庫是只接受一個(gè)區(qū)域
            ??????? //* - 左右聲道數(shù)據(jù)相鄰,所以轉(zhuǎn)換下。
            ??? ??? if ( buffer->channels == 2) {
            ??? ??? ??? sample = scale(*left_ch++);
            ??? ??? ??? buffer->buffer[ buffer->current++ ] = sample;
            ??? ??? ??? sample = scale(*right_ch++);
            ??? ??? ??? buffer->buffer[ buffer->current++ ] = sample;
            ??? ??? }
            ??? }

            ??? return MAD_FLOW_CONTINUE;
            }

            /*
            * This is the error callback function. It is called whenever a decoding
            * error occurs. The error is indicated by stream->error; the list of
            * possible MAD_ERROR_* errors can be found in the mad.h (or stream.h)
            * header file.
            */

            static
            enum mad_flow error(void *data,
            struct mad_stream *stream,
            struct mad_frame *frame)
            {
            ??? //struct buffer *buffer = data;

            ??? //fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n",
            ??? //??? stream->error, mad_stream_errorstr(stream),
            ??? //??? stream->this_frame - buffer->start);

            ??? ///* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */

            ??? return MAD_FLOW_CONTINUE;
            }

            /*
            * This is the function called by main() above to perform all the decoding.
            * It instantiates a decoder object and configures it with the input,
            * output, and error callback functions above. A single call to
            * mad_decoder_run() continues until a callback function returns
            * MAD_FLOW_STOP (to stop decoding) or MAD_FLOW_BREAK (to stop decoding and
            * signal an error).
            */

            static
            int decode( Win32_Data * data )
            {
            ??? //struct buffer buffer;
            ??? struct mad_decoder decoder;
            ??? int result;

            ??? ///* initialize our private message structure */

            ??? //buffer.start = start;
            ??? //buffer.length = length;

            ??? ///* configure input, output, and error functions */

            ??? mad_decoder_init(&decoder, data,
            ??? ??? ??? ??? ??? input, 0 /* header */, 0 /* filter */, output,
            ??? ??? ??? ??? ??? error, 0 /* message */);

            ??? ///* start decoding */

            ??? //* - 此函數(shù)是同步函數(shù),在“input”函數(shù)返回MAD_FLOW_STOP后才完成。
            ??? //* - 出錯(cuò)在error函數(shù)中定義行為。
            ??? result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);

            ??? ///* release the decoder */

            ??? mad_decoder_finish(&decoder);

            ??? return result;
            }

            /*******************************************************************/
            int main(int argc, char *argv [] );
            int main(int argc, char *argv [] )
            {

            ??? Win32_Data audio_data;

            ??? audio_data.buffer = new float[ WIN32_AUDIO_BUFF_LEN ] ;
            ??? audio_data.bufferMad = new unsigned char[ WIN32_BUFF_MAD_LEN ];
            ??? audio_data.current = 0;

            ??? PaStreamParameters inputParameters, outputParameters;
            ??? PaStream *stream = NULL;
            ??? PaError err;
            ??? char *sampleBlock;
            ??? int i;
            ??? int numBytes;


            ??? printf("patest_read_write_wire.c\n"); fflush(stdout);

            ??? //numBytes = FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ;
            ??? //sampleBlock = (char *) malloc( numBytes );
            ??? //if( sampleBlock == NULL )
            ??? //{
            ??? //??? printf("Could not allocate record array.\n");
            ??? //??? exit(1);
            ??? //}

            ??? audio_data.file = fopen ( argv[1] , "rb" );

            ??? if (audio_data.file == NULL)
            ??? {
            ??? ??? fputs ("File error",stderr);
            ??? ??? exit (1);
            ??? }

            ??? printf( "-- Start Decode %s\n" , argv[1] );

            ??? decode( &audio_data );
            ??? audio_data.bufferlen = audio_data.current;
            ??? audio_data.current = 0;

            ??? fclose( audio_data.file );
            ??? printf( "-- End Decode\n" );

            ??? printf( "-------------------------------\n" );

            ??? printf( "Output samplerate %d\n", audio_data.samplerate );
            ??? printf( "Output channels %d\n", audio_data.channels );

            ??? err = Pa_Initialize();
            ??? if( err != paNoError ) goto error;

            ??? //printf( "-------------------------------\n" );

            ??? //printf( "Output samplerate %d\n", audio_data.sfinfo.samplerate );
            ??? //printf( "Output frames %d\n", audio_data.sfinfo.frames );
            ??? //printf( "Output channels %d\n", audio_data.sfinfo.channels );
            ??? //printf( "seekable %d\n ", audio_data.sfinfo.seekable );
            ??? //printf( "format is %d\n ", audio_data.sfinfo.format );
            ??? //printf( "Sections is %d\n ", audio_data.sfinfo.sections );

            ??? //printf( "Read buffer len %d\n" , audio_data.bufferlen );

            ??? //printf( "-------------------------------\n" );

            ??? //inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
            ??? //printf( "Input device # %d.\n", inputParameters.device );
            ??? //printf( "Input LL: %g s\n", Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency );
            ??? //printf( "Input HL: %g s\n", Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency );
            ??? //inputParameters.channelCount = audio_data.sfinfo.channels;//NUM_CHANNELS;
            ??? //inputParameters.sampleFormat = PA_SAMPLE_TYPE;
            ??? //inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ;
            ??? //inputParameters.hostApiSpecificStreamInfo = NULL;

            ??? outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
            ??? printf( "Output device # %d.\n", outputParameters.device );
            ??? printf( "Output LL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency );
            ??? printf( "Output HL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency );
            ??? outputParameters.channelCount = audio_data.channels;//NUM_CHANNELS;
            ??? outputParameters.sampleFormat = PA_SAMPLE_TYPE;
            ??? outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency;
            ??? outputParameters.hostApiSpecificStreamInfo = NULL;

            ??? /* -- setup -- */

            ??? err = Pa_OpenStream(
            ??? ??? &stream,
            ??? ??? NULL,//&inputParameters,
            ??? ??? &outputParameters,
            ??? ??? SAMPLE_RATE,
            ??? ??? FRAMES_PER_BUFFER,
            ??? ??? paClipOff,????? /* we won't output out of range samples so don't bother clipping them */
            ??? ??? NULL, /* no callback, use blocking API */
            ??? ??? NULL ); /* no callback, so no callback userData */
            ??? if( err != paNoError ) goto error;

            ??? //err = Pa_StartStream( stream );
            ??? //if( err != paNoError ) goto error;
            ??? //printf("Wire on. Will run one minute.\n"); fflush(stdout);

            ??? //for( i=0; i<(60*SAMPLE_RATE)/FRAMES_PER_BUFFER; ++i )
            ??? //{
            ??? //??? err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER );
            ??? //??? if( err ) goto xrun;
            ??? //??? err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER );
            ??? //??? if( err ) goto xrun;
            ??? //}
            ??? //err = Pa_StopStream( stream );
            ??? //if( err != paNoError ) goto error;

            ??? //CLEAR( sampleBlock );

            ??? err = Pa_StartStream( stream );
            ??? if( err != paNoError ) goto error;
            ??? printf("Wire on. Interrupt to stop.\n"); fflush(stdout);

            ??? while( 1 )
            ??? {

            ??? ??? err = Pa_WriteStream( stream, audio_data.buffer + audio_data.current/*sampleBlock*/, FRAMES_PER_BUFFER );
            ??? ??? audio_data.current = audio_data.current + FRAMES_PER_BUFFER * NUM_CHANNELS /* SAMPLE_SIZE */;

            ??? ??? //if( audio_data.current + FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE > audio_data.bufferlen ) break;

            ??? ??? printf( "%d\n", audio_data.current);

            ??? ??? if( err ) goto xrun;
            ??? ??? //err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER );
            ??? ??? //if( err ) goto xrun;
            ??? }
            ??? err = Pa_StopStream( stream );
            ??? if( err != paNoError ) goto error;

            ??? Pa_CloseStream( stream );

            ??? free( sampleBlock );

            ??? Pa_Terminate();
            ??? return 0;

            xrun:
            ??? if( stream ) {
            ??? ??? Pa_AbortStream( stream );
            ??? ??? Pa_CloseStream( stream );
            ??? }
            ??? free( sampleBlock );
            ??? Pa_Terminate();
            ??? if( err & paInputOverflow )
            ??? ??? fprintf( stderr, "Input Overflow.\n" );
            ??? if( err & paOutputUnderflow )
            ??? ??? fprintf( stderr, "Output Underflow.\n" );

            ??? delete [] audio_data.buffer;
            ??? delete [] audio_data.bufferMad;
            ??? return -2;

            error:
            ??? if( stream ) {
            ??? ??? Pa_AbortStream( stream );
            ??? ??? Pa_CloseStream( stream );
            ??? }
            ??? free( sampleBlock );
            ??? Pa_Terminate();
            ??? fprintf( stderr, "An error occured while using the portaudio stream\n" );
            ??? fprintf( stderr, "Error number: %d\n", err );
            ??? fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );

            ??? delete [] audio_data.buffer;
            ??? delete [] audio_data.bufferMad;
            ??? return -1;
            }

            三、某此播放mp3文件 截圖 -- 留念

            TestMadMp3.png

            posted on 2009-04-27 17:19 zyzx 閱讀(1912) 評論(0)  編輯 收藏 引用 所屬分類: OpenSource開源

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            留言簿(1)

            隨筆分類

            隨筆檔案

            常用鏈接

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            中文字幕无码免费久久| 久久国产精品久久精品国产| 久久久久国产一区二区| 少妇被又大又粗又爽毛片久久黑人| 国产视频久久| 久久人人爽人人爽AV片| 久久亚洲国产精品成人AV秋霞 | 手机看片久久高清国产日韩 | 国产精品亚洲综合专区片高清久久久 | 丰满少妇人妻久久久久久| 91久久香蕉国产熟女线看| 久久久久se色偷偷亚洲精品av| 久久久精品2019免费观看 | 久久久久久毛片免费看| 久久亚洲视频| 久久不射电影网| 亚洲色大成网站WWW久久九九| 国产成人综合久久精品尤物| 欧美亚洲日本久久精品| 99久久精品国产毛片| 欧美丰满熟妇BBB久久久| 午夜精品久久久久久影视777| 日韩一区二区久久久久久| 久久久这里只有精品加勒比| 精品久久久久久亚洲| 久久精品一本到99热免费| 久久婷婷五月综合97色直播| 久久91精品综合国产首页| 成人妇女免费播放久久久| 日产精品99久久久久久| 99精品国产综合久久久久五月天| 久久99国产精品久久99小说| 久久99精品国产99久久| 性欧美大战久久久久久久久| 思思久久好好热精品国产| 久久久精品日本一区二区三区 | 精品久久久久久综合日本| 中文字幕乱码人妻无码久久| 亚洲日韩欧美一区久久久久我 | 要久久爱在线免费观看| 久久青青国产|