青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

zyzx的小窩

C/C++,GUI,個人移動存儲,zyzx_lsl@163.com

 

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

tag:C,mp3解碼,libMAD,PortAudio

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

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

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

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

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

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

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


如下是全部的源碼:

#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;?????????????????????????????? //* - 解碼后的數據存儲區域
??? long??? ??? current, bufferlen ;

??? unsigned char*??? bufferMad;?????????? //* - 由于LibMad是一段一段讀寫,這里是緩沖區域
??? 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編碼方式,可能某次讀取的數據并不是完整的,我們只取完整的 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庫內置的采樣點格式轉換為 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格式 的數據是分布在2個緩存區域中分左右聲道,而PortAudio庫是只接受一個區域
??????? //* - 左右聲道數據相鄰,所以轉換下。
??? ??? 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 */

??? //* - 此函數是同步函數,在“input”函數返回MAD_FLOW_STOP后才完成。
??? //* - 出錯在error函數中定義行為。
??? 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 閱讀(1940) 評論(0)  編輯 收藏 引用 所屬分類: OpenSource開源

導航

統計

常用鏈接

留言簿(1)

隨筆分類

隨筆檔案

常用鏈接

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            国产一区av在线| 久久9热精品视频| 亚洲视频一区| 国产精品视频精品视频| 午夜精品成人在线| 久久久免费精品| 91久久精品美女高潮| 欧美美女bb生活片| 亚洲欧美国产视频| 免费在线欧美视频| 9色porny自拍视频一区二区| 欧美午夜视频| 激情丁香综合| 国语自产精品视频在线看8查询8| 国内精品一区二区三区| 欧美性久久久| 国产女人精品视频| 亚洲国产黄色片| 亚洲色图制服丝袜| 久久久免费av| 夜夜精品视频一区二区| 久久久午夜精品| 久久久久www| 国产精品高精视频免费| 欧美一级片一区| 亚洲精品在线观| 久久在线免费观看视频| 99国产精品久久久久久久久久 | 91久久精品国产91性色tv| 欧美日韩免费| 久久精品视频在线看| 99riav久久精品riav| 久久视频在线视频| 亚洲欧美一区二区三区极速播放 | 伊人男人综合视频网| 欧美视频中文字幕在线| 久久久噜噜噜久久人人看| 一区二区不卡在线视频 午夜欧美不卡在| 久久久久.com| 午夜精品国产| 亚洲美女视频在线免费观看| 狠狠色噜噜狠狠狠狠色吗综合| 欧美日韩一卡| 欧美阿v一级看视频| 欧美在线视频导航| 一区二区三区高清在线| 亚洲国产成人av| 美女日韩欧美| 久久久久久久综合| 欧美一区二区高清在线观看| 中文av一区二区| 夜夜嗨一区二区| 亚洲欧洲一区二区在线观看| 激情久久久久| 国产欧美视频一区二区三区| 国产精品分类| 欧美日韩免费| 欧美日韩亚洲一区二区三区在线观看 | 国产精品美女久久久| 欧美日本精品| 欧美国产精品久久| 欧美阿v一级看视频| 久久综合久久美利坚合众国| 久久精品2019中文字幕| 香蕉久久国产| 亚洲一区二区视频在线观看| 一个色综合av| 亚洲视频电影图片偷拍一区| 最新国产成人在线观看| 欧美国产日韩视频| 欧美不卡高清| 欧美成人中文字幕在线| 女主播福利一区| 另类激情亚洲| 欧美成人免费在线视频| 欧美成人tv| 亚洲电影一级黄| 亚洲精品国产无天堂网2021| 亚洲激情视频在线播放| 亚洲第一成人在线| 日韩视频―中文字幕| 99国产一区| 亚洲中字黄色| 久久久国产精彩视频美女艺术照福利| 久久精品盗摄| 欧美 日韩 国产一区二区在线视频| 老**午夜毛片一区二区三区| 欧美国产极速在线| 国产精品草莓在线免费观看| 国产精品私人影院| 国产一区二区在线观看免费| 在线看片日韩| 一本色道久久| 欧美一区不卡| 欧美丰满高潮xxxx喷水动漫| 亚洲精品欧美在线| 亚洲欧美网站| 蜜臀久久久99精品久久久久久 | 亚洲国产精品成人精品| 亚洲麻豆av| 午夜精品久久久久久久| 久久久精品日韩| 欧美日本精品| 国产亚洲视频在线| 亚洲日韩第九十九页| 小黄鸭精品aⅴ导航网站入口| 久久综合网hezyo| 亚洲免费观看在线观看| 欧美一区二区视频97| 欧美大片在线影院| 国产精品一区久久久| 亚洲精品国产精品久久清纯直播 | 欧美韩日亚洲| 国产偷国产偷亚洲高清97cao| 亚洲高清视频的网址| 亚洲制服丝袜在线| 欧美14一18处毛片| 亚洲一区二区三区在线播放| 另类专区欧美制服同性| 国产精品久久久91| 亚洲激情自拍| 欧美在线看片a免费观看| 亚洲大胆在线| 久久精品人人| 国产精品毛片a∨一区二区三区|国 | 欧美激情一区二区在线 | 在线观看欧美日本| 亚洲欧美成人一区二区在线电影| 免费久久久一本精品久久区| 亚洲午夜日本在线观看| 欧美 日韩 国产一区二区在线视频 | 亚洲欧美激情一区| 欧美另类综合| 在线免费观看日本欧美| 欧美一区二区三区男人的天堂| 亚洲黄色性网站| 毛片精品免费在线观看| 国产一区二区中文| 午夜一区二区三视频在线观看 | 久久综合狠狠综合久久激情| 亚洲先锋成人| 国产精品多人| 在线亚洲+欧美+日本专区| 欧美激情精品久久久六区热门| 欧美在线三区| 国产亚洲精品久久久久婷婷瑜伽| 亚洲一区二区在线免费观看| 亚洲人在线视频| 欧美大色视频| 亚洲精选一区二区| 欧美国产丝袜视频| 久久久久久网| 在线观看免费视频综合| 久久综合一区二区三区| 欧美自拍偷拍午夜视频| 国产日韩欧美日韩大片| 午夜精品福利一区二区三区av| 中国av一区| 国产精品久久久久久久久久尿| 亚洲一区不卡| 亚洲视频福利| 国产精品乱码人人做人人爱| 亚洲欧美日韩直播| 亚洲女女女同性video| 国产伦精品一区二区三区| 先锋影音国产精品| 欧美一区二区久久久| 国产一区香蕉久久| 久久精品午夜| 理论片一区二区在线| 亚洲日本激情| 一级日韩一区在线观看| 国产精品国产三级国产普通话蜜臀| 亚洲欧美国产日韩中文字幕| 亚洲欧美在线x视频| 国产一区二区三区四区五区美女 | 亚洲一区二区三区午夜| 亚洲天堂网在线观看| 国产女优一区| 久久只有精品| 欧美激情国产日韩精品一区18| 一区二区三欧美| 亚洲一区精品电影| 激情成人av在线| 亚洲国产欧美在线人成| 欧美三级欧美一级| 欧美在线观看视频| 美女黄毛**国产精品啪啪| 亚洲精品一区二区三区99| 一区二区高清在线| 国内一区二区三区在线视频| 欧美高清在线播放| 国产精品yjizz| 狂野欧美一区| 欧美日韩三级视频| 久久久精品999| 欧美精品一区二区在线观看| 亚洲女人天堂成人av在线| 欧美在线视频免费观看| 日韩一区二区福利|