续上一篇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