iphone利用AudioQueue播放wav(PCM码)

续上一篇iphone利用AudioQueue播放音频文件(mp3,aac,caf,wav等)

绝对原创,转载请注明出处:http://www.cnblogs.com/xuanyuanchen/admin/EditPosts.aspx?postid=2450169

1、ffmpeg解码音频流并且保存成wav文件。

 这一步比较简单,只要熟悉ffmpeg解码音频的流程,将解码出的pcm码,保存到本地文件中,并实时统计解码的pcm的字节长度,最后解码完成之后再添加44字节的wav文件头。

save_audio.c

View Code
  1 #include <stdio.h>

  2 #include "libavformat/avformat.h"

  3 #include "libavcodec/avcodec.h"

  4 #include "libavutil/avutil.h"

  5 static void writeWavHeader(AVCodecContext *pCodecCtx,AVFormatContext *pFormatCtx,FILE *audioFile) {

  6     int8_t *data;

  7     int32_t long_temp;

  8     int16_t short_temp;

  9     int16_t BlockAlign;

 10     int bits=16;

 11     int32_t fileSize;

 12     int32_t audioDataSize;

 13     

 14     switch(pCodecCtx->sample_fmt) {

 15         case AV_SAMPLE_FMT_S16:

 16             bits=16;

 17             break;

 18         case AV_SAMPLE_FMT_S32:

 19             bits=32;

 20             break;

 21         case AV_SAMPLE_FMT_U8:

 22             bits=8;

 23             break;

 24         default:

 25             bits=16;

 26             break;

 27     }

 28     audioDataSize=(pFormatCtx->duration)*(bits/8)*(pCodecCtx->sample_rate)*(pCodecCtx->channels);

 29     fileSize=audioDataSize+36;

 30     data="RIFF";

 31     fwrite(data,sizeof(char),4,audioFile);

 32     fwrite(&fileSize,sizeof(int32_t),1,audioFile);

 33 

 34     //"WAVE"

 35     data="WAVE";

 36     fwrite(data,sizeof(char),4,audioFile);

 37     data="fmt ";

 38     fwrite(data,sizeof(char),4,audioFile);

 39     long_temp=16;

 40     fwrite(&long_temp,sizeof(int32_t),1,audioFile);

 41     short_temp=0x01;

 42     fwrite(&short_temp,sizeof(int16_t),1,audioFile);

 43     short_temp=(pCodecCtx->channels);

 44     fwrite(&short_temp,sizeof(int16_t),1,audioFile);

 45     long_temp=(pCodecCtx->sample_rate);

 46     fwrite(&long_temp,sizeof(int32_t),1,audioFile);

 47     long_temp=(bits/8)*(pCodecCtx->channels)*(pCodecCtx->sample_rate);

 48     fwrite(&long_temp,sizeof(int32_t),1,audioFile);

 49     BlockAlign=(bits/8)*(pCodecCtx->channels);

 50     fwrite(&BlockAlign,sizeof(int16_t),1,audioFile);

 51     short_temp=(bits);

 52     fwrite(&short_temp,sizeof(int16_t),1,audioFile);

 53     data="data";

 54     fwrite(data,sizeof(char),4,audioFile);

 55     fwrite(&audioDataSize,sizeof(int32_t),1,audioFile);

 56 

 57     fseek(audioFile,44,SEEK_SET);

 58 }

 59 

 60 int main(){

 61     char *filename="E:\\flv\\Love_You.mp4";

 62     AVFormatContext *pFormatCtx;

 63     int audioStream=-1;

 64     int i;

 65     int iFrame=0;

 66     AVCodecContext *pCodecCtx;

 67     AVCodec *pCodec=NULL;

 68     static AVPacket packet;

 69     uint8_t *pktData=NULL;

 70     int pktSize;

 71     int outSize=AVCODEC_MAX_AUDIO_FRAME_SIZE;

 72 //    FILE *wavfile=NULL;

 73     uint8_t *inbuf=(uint8_t *)av_malloc(outSize);

 74 

 75     FILE *wavFile=NULL;

 76     int32_t audioFileSize=0;

 77     av_register_all();

 78     if(av_open_input_file(&pFormatCtx,filename,NULL,0,NULL)!=0)

 79     {

 80         printf("Could not open input file %s\n",filename);

 81         return 0;

 82     }

 83     if(av_find_stream_info(pFormatCtx)<0)

 84     {

 85         printf("Could not find stream information\n");

 86     }

 87     av_dump_format(pFormatCtx,0,filename,0);

 88     for(i=0;i<pFormatCtx->nb_streams;i++) {

 89          if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO) {

 90             audioStream=i;

 91             break;

 92         }

 93     }

 94 

 95         pCodecCtx=pFormatCtx->streams[audioStream]->codec;

 96     pCodec=avcodec_find_decoder(pCodecCtx->codec_id);

 97             if(avcodec_open(pCodecCtx,pCodec)<0) {

 98         printf("Error avcodec_open failed.\n");

 99         return 1;

100     }

101 

102     printf("\tbit_rate=%d\n \

103     bytes_per_secondes=%d\n \

104     sample_rate=%d\n \

105     channels=%d\n \

106     codec_name=%s\n",pCodecCtx->bit_rate,(pCodecCtx->codec_id==CODEC_ID_PCM_U8)?8:16,

107     pCodecCtx->sample_rate,pCodecCtx->channels,pCodecCtx->codec->name);

108 

109     wavFile=fopen("E:\\flv\\myPlayerWav.wav","wb");

110     if (wavFile==NULL)

111     {

112         printf("open error\n");

113         return 1;

114     }

115 

116            writeWavHeader(pCodecCtx,pFormatCtx,wavFile);

117 

118         av_free_packet(&packet);

119     while(av_read_frame(pFormatCtx,&packet)>=0) {

120         if(packet.stream_index==audioStream) {

121             int len=0;

122             if((iFrame++)>=4000)

123                 break;

124             pktData=packet.data;

125             pktSize=packet.size;

126             while(pktSize>0) {

127                 outSize=AVCODEC_MAX_AUDIO_FRAME_SIZE;

128                 len=avcodec_decode_audio3(pCodecCtx,(short *)inbuf,&outSize,&packet);

129                 if(len<0){

130                     printf("Error while decoding\n");

131                     break;

132                 }

133                 if(outSize>0) {

134                     audioFileSize+=outSize;

135                     fwrite(inbuf,1,outSize,wavFile);

136                     fflush(wavFile);

137                 }

138                 pktSize-=len;

139                 pktData+=len;

140             }

141         }

142         av_free_packet(&packet);

143     }

144 

145         fseek(wavFile,40,SEEK_SET);

146     fwrite(&audioFileSize,1,sizeof(int32_t),wavFile);

147     audioFileSize+=36;

148     fseek(wavFile,4,SEEK_SET);

149     fwrite(&audioFileSize,1,sizeof(int32_t),wavFile);

150     fclose(wavFile);

151     av_free(inbuf);

152     if(pCodecCtx!=NULL){

153         avcodec_close(pCodecCtx);

154     }

155     av_close_input_file(pFormatCtx);

156     return 0;

157 }

注意:我用的ffmpeg的版本是ffmpeg-0.8.6。我已经成功地将ffmpeg在Windows、Linux(Ubuntu)、Ios平台上编译通过,这段代码没有什么平台依赖性,都是用的标准C的代码。

2、iphone读PCM码,并且送AudioQueue播放

playAudio.h

View Code
 1 #import <Foundation/Foundation.h>

 2 #import <AudioToolbox/AudioToolbox.h>

 3 #import <AudioToolbox/AudioFile.h>

 4 #define NUM_BUFFERS 3

 5 

 6 @interface playAudio : NSObject{

 7     //播放音频文件ID

 8     AudioFileID audioFile;

 9     //音频流描述对象

10     AudioStreamBasicDescription dataFormat;

11     //音频队列

12     AudioQueueRef queue;

13     SInt64 packetIndex;

14     UInt32 numPacketsToRead;

15     UInt32 bufferByteSize;

16     uint8_t *inbuf;

17     AudioStreamPacketDescription *packetDescs;

18     AudioQueueBufferRef buffers[NUM_BUFFERS];

19     FILE *wavFile;    

20 }

21 

22 //定义队列为实例属性

23 @property AudioQueueRef queue;

24 //播放方法定义

25 -(id)initWithAudio:(NSString *) path;

26 //定义缓存数据读取方法

27 -(void) audioQueueOutputWithQueue:(AudioQueueRef)audioQueue

28                       queueBuffer:(AudioQueueBufferRef)audioQueueBuffer;

29 -(UInt32)readPacketsIntoBuffer:(AudioQueueBufferRef)buffer;

30 //定义回调(Callback)函数

31 static void BufferCallack(void *inUserData,AudioQueueRef inAQ,

32                           AudioQueueBufferRef buffer);

33 

34 @end

playAudio.m

View Code
  1 #import "playAudio.h"

  2 

  3 #define AVCODEC_MAX_AUDIO_FRAME_SIZE  4096*2// (0x10000)/4

  4 //static UInt32 gBufferSizeBytes=0x10000;//65536

  5 static UInt32 gBufferSizeBytes=0x10000;//It must be pow(2,x)

  6 

  7 @implementation playAudio

  8 

  9 @synthesize queue;

 10 

 11 //回调函数(Callback)的实现

 12 static void BufferCallback(void *inUserData,AudioQueueRef inAQ,

 13                            AudioQueueBufferRef buffer){

 14     playAudio* player=(__bridge playAudio*)inUserData;

 15     [player audioQueueOutputWithQueue:inAQ queueBuffer:buffer];

 16 }

 17 

 18 

 19 //缓存数据读取方法的实现

 20 -(void) audioQueueOutputWithQueue:(AudioQueueRef)audioQueue queueBuffer:(AudioQueueBufferRef)audioQueueBuffer{

 21     //读取包数据

 22     UInt32 numBytes;

 23 //    UInt32 numPackets=numPacketsToRead;

 24     UInt32 numPackets=numPacketsToRead;

 25     

 26     //成功读取时

 27     numBytes=fread(inbuf, 1, numPackets*4,wavFile);

 28     AudioQueueBufferRef outBufferRef=audioQueueBuffer;      

 29     NSData *aData=[[NSData alloc]initWithBytes:inbuf length:numBytes];

 30     

 31     if(numBytes>0){

 32         memcpy(outBufferRef->mAudioData, aData.bytes, aData.length);

 33    

 34         outBufferRef->mAudioDataByteSize=numBytes;

 35         AudioQueueEnqueueBuffer(audioQueue, outBufferRef, 0, nil);

 36         packetIndex += numPackets;

 37     }

 38     else{

 39     }

 40 }

 41 

 42 //音频播放方法的实现

 43 -(id) initWithAudio:(NSString *)path{

 44     if (!(self=[super init])) return nil;

 45     int i;

 46     

 47     wavFile=fopen([path cStringUsingEncoding:NSASCIIStringEncoding], "rb");

 48     if (wavFile==NULL) {

 49         printf("open wavFile error in current file %s,in line %d",__FILE__,__LINE__);

 50         return nil;

 51     }

 52     //跳过wav文件的44字节的文件头

 53     fseek(wavFile, 44, SEEK_SET);

 54     

 55     for (int i=0; i<NUM_BUFFERS; i++) {

 56         AudioQueueEnqueueBuffer(queue, buffers[i], 0, nil);

 57     }

 58     

 59     //取得音频数据格式

 60     {

 61         dataFormat.mSampleRate=44100;//采样频率

 62         dataFormat.mFormatID=kAudioFormatLinearPCM;

 63         dataFormat.mFormatFlags=kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;

 64         dataFormat.mBytesPerFrame=4;

 65         dataFormat.mBytesPerPacket=4;

 66         dataFormat.mFramesPerPacket=1;//wav 通常为1

 67         dataFormat.mChannelsPerFrame=2;//通道数

 68         dataFormat.mBitsPerChannel=16;//采样的位数

 69         dataFormat.mReserved=0;

 70     }

 71     

 72     //创建播放用的音频队列

 73     AudioQueueNewOutput(&dataFormat, BufferCallback, self,

 74                         nil, nil, 0, &queue);

 75     //计算单位时间包含的包数

 76  

 77 //    numPacketsToRead= gBufferSizeBytes/dataFormat.mBytesPerPacket;

 78 //    numPacketsToRead=AVCODEC_MAX_AUDIO_FRAME_SIZE    

 79     numPacketsToRead=AVCODEC_MAX_AUDIO_FRAME_SIZE;      

 80     packetDescs=nil;

 81     

 82     //设置Magic Cookie,参见第二十七章的相关介绍

 83     

 84     //创建并分配缓冲控件

 85     packetIndex=0;

 86     for (i=0; i<NUM_BUFFERS; i++) {

 87         AudioQueueAllocateBuffer(queue, gBufferSizeBytes, &buffers[i]);

 88         //读取包数据

 89         if ([self readPacketsIntoBuffer:buffers[i]]==1) {

 90             break;

 91         }

 92     }

 93     

 94     Float32 gain=1.0;

 95     //设置音量

 96     AudioQueueSetParameter(queue, kAudioQueueParam_Volume, gain);

 97     //队列处理开始,此后系统开始自动调用回调(Callback)函数

 98     AudioQueueStart(queue, nil);

 99     return self;

100 }

101 

102 -(UInt32)readPacketsIntoBuffer:(AudioQueueBufferRef)buffer {

103     UInt32 numBytes,numPackets;

104     //从文件中接受数据并保存到缓存(buffer)中

105 //AVCODEC_MAX_AUDIO_FRAME_SIZE*100    

106     numPackets = numPacketsToRead;

107     inbuf=(uint8_t *)malloc(numPackets);

108     AudioQueueBufferRef outBufferRef=buffer;  

109     numBytes=fread(inbuf, 1, numPackets*4,wavFile);

110     NSData *aData=[[NSData alloc]initWithBytes:inbuf length:numBytes];

111 

112     

113     if(numBytes>0){

114         memcpy(outBufferRef->mAudioData, aData.bytes, aData.length);      

115         outBufferRef->mAudioDataByteSize=numBytes;

116         AudioQueueEnqueueBuffer(queue, outBufferRef, 0, nil);

117         packetIndex += numPackets;

118     }

119     else{

120         return 1;//意味着我们没有读到任何的包

121     }

122     return 0;//0代表正常的退出

123 }

124 @end

可以参考:http://developer.apple.com/library/mac/#documentation/MusicAudio/Reference/AudioQueueReference/Reference/reference.html#//apple_ref/doc/c_ref/AudioQueueOutputCallback

你可能感兴趣的:(iPhone)