iOS音频播放
豆瓣开源播放器代码DOUAudioStreamer
starRTC,免费IM(含单聊,群聊,聊天室),免费一对一视频聊天(回音消除),语音聊天,直播连麦,白板,小班课,多人会议,局域网无服务器直连,兼容webRTC, 支持webRTC加速,P2P高清传输,安卓、iOS、web互通,支持门禁可视对讲,电视盒子,树莓派,海思,全志,OTT设备,C语言自研方案
AudioUnit框架详细解析
iOS 混音的一种实现方法
iOS8系统H264视频硬件编解码说明
使用AudioToolbox编码AAC
H.264是由视讯编码层(Video Coding Layer,VCL)与网络提取层(Network Abstraction Layer,NAL)组成
VideoToolBox硬编码H.264:
a.创建编码session:VTCompressionSessionCreate
b.编码的视频帧:VTCompressionSessionEncodeFrame
c.编码完成后会调用didCompressH264
如果是关键帧,调用CMSampleBufferGetFormatDescription获取CMFormatDescriptionRef
CMVideoFormatDescriptionGetH264ParameterSetAtIndex取得PPS和SPS
最后把每一帧的所有NALU数据前四个字节变成0x00 00 00 01之后再写入文件
d.VTCompressionSessionCompleteFrames完成编码,销毁session.
VideoToolBox硬解码H.264:
a.NSInputStream读入原始H.264码流
b.用CADisplayLink控制显示速率
c.用NALU的前四个字节识别SPS和PPS并存储,当读入IDR帧的时候初始化VideoToolbox,始同步解码
d.解码得到的CVPixelBufferRef会传入OpenGL ES类进行解析渲染
利用FFMpeg框架,底层使用的是CPU做视频的编码和解码,称为软编码软解码.
缺点:占用CPU资源,编解码效率不高
(1) VideoToolBox
苹果在iOS8.0之前,没开放硬件编解码功能.之后提供了Video ToolBox框架来实现硬件的编解码.
VideoToolBox在实际应用:VOIP视频通话,视频流播放
优点:可以通过它得到编码后的帧结构,也得到解码后的原始图像
(2) AVFoundation
AVFoundation框架也可以使用硬件对视频进行硬编解码,
缺点是:编码后写入文件,解码后直接显示.
VideoToolbox基本数据结构
CVPixelBuffer:编码前和解码后的图像数据结构
CMTime、CMClock和CMTimebase:时间戳相关。时间以64-bit/32-bit的形式出现。
CMBlockBuffer:编码后,结果图像的数据结构
CMVideoFormatDescription:图像存储方式,编解码器等格式描述
CMSampleBuffer:存放编解码前后的视频图像的容器数据结构
解码后:CMSampleBuffer包含:CMTime,CMViedoFormatDesc,CVPixelBuffer
编码后:CMSampleBuffer包含:CMTime,CMVideoFormatDesc,CMBlockBuffer
将H.264码流解码成CMSampleBuffer
因为网络中传输的是编码后的CMSampleBuffer = CMTime + FormatDesc + CMBlockBuffer,
提取以上三个信息,组成CMSampleBuffer,然后硬解码
H.264码流由NALU单元组成,NALU单元包含视频图像数据(CMBlockBuffer)和H.264参数(SPS,PPS)
码流结构:
NALU NALU NALU NALU NALU NALU
SPS PPS I Frame P Frame B Frame
(1)提取sps和pps城市format Description
a,每个NALU的开始码是0x000001,按照开始码定位NALU
(2)提取视频图像数据生成CMBlockBuffer
系统API来做混音 这三种方式可以实现混音: AudioUnit、AudioToolBox、AVFoundation
AudioToolbox编码AAC
PCM通过抽样、量化、编码将模拟信号变成数字信号.
采样数据大小=采样率值×采样大小值×声道数 bps
(1)PCM编码AAC
a.设置编码器,开始录制
b.收集pcm,传给编码器
c.编码完成回调,写入文件.
具体代码:
1.创建AVCaptureSession, AVCaptureDevice(初始化类型为AVMediaTypeAudio), AVCaptureDeviceInput(初始化传入设备), AVCaptureAudioDataOutput(音频数据输出)
2.AVCaptureSession添加音频输入capture,音频数据输出capture
3.session running.
4.创建转换器.
概念描述:
AudioStreamBasicDescriptions(ASBD)是音频输出流结构体描述.
AudioClassDescription是编码器.
AudioConverterNewSpecific创建转换器.
AudioBufferList:音频的缓存数据结构
a.设置编码参数:编码格式,每帧的大小,每个packet的音频数据大小,声道数,字节对齐
b.获取编码器(编码器通常用于视频会议和流媒体),实际要获取AudioClassDescription
编码器:一个对信号或者数据流进行变换的设备.
OSStatus st = AudioFormatGetPropertyInfo
c.获取PCM数据并传入编码器
从 CMSampleBufferGetDataBuffer 获取 CMBlockBufferRef
从CMBlockBufferGetDataPointer 获取 _pcmBufferSize 和 _pcmBuffer
AudioConverterFillComplexBuffer传入数据,填充buffer.
d.得到rawAAC码流,添加ADTS头,并写入文件
iOS提供的音频处理插件支持混合,均衡,格式转换以及录制,回放,离线渲染和实时对话
kAudioFormatMPEG4AAC(aac)
AudioUnit播放、录制声音
用AudioConvert转格式
AudioFileStream:转换音频流,可以用来读取音频流信息和分离音频帧,可以播放在线音频流
PCM:原始的音频数据完全无损
无损压缩:ALAC、APE、FLAC
有损压缩:MP3、AAC、OGG、WMA
MP3格式中的码率:128kbit/s、160kbit/s、320kbit/s
MP3编码方式:固定码率(Constant bitrate,CBR)和可变码率(Variable bitrate,VBR)。
iOS音频播放步骤
1.读取MP3文件
2.解析采样率、码率、时长等信息,分离MP3中的音频帧
3.对分离出来的音频帧解码得到PCM数据
4.对PCM数据进行音效处理(均衡器、混响器等,非必须)
5.把PCM数据解码成音频信号
6.把音频信号交给硬件播放
7.重复1-6步直到播放完成
专业的音乐播放软件:
需要进行音效处理(均衡器、混响器)
需要用到AudioConverter 音频数据转换成PCM
AudioUnit+AUGraph进行音效处理和播放,
PCM数据通过音效处理可以使用AudioUnit播放
当然AudioQueue也支持PCM数据播放
苹果官方使用AudioFile+AudioConverter+AudioUnit进行音频播放
AudioFileStreamer介绍
1.用来读取采样率、码率、时长等基本信息以及分离音频帧
2.既可以用于流媒体播放,也可以用于本地文件读取信息和分离音频帧
支持的文件格式:
(1)MPEG-1 Audio Layer 3, used for .mp3 files
(2)MPEG-2 ADTS, used for the .aac audio data format
(3)AIFC
(4)AIFF
(5)CAF
(6)MPEG-4, used for .m4a, .mp4, and .3gp file
(7)NeXT
(8)WAVE
extern OSStatus AudioFileStreamOpen (void * inClientData,
AudioFileStream_PropertyListenerProc inPropertyListenerProc,
AudioFileStream_PacketsProc inPacketsProc,
AudioFileTypeID inFileTypeHint,
AudioFileStreamID * outAudioFileStream);
AudioFileStream_PropertyListenerProc:歌曲信息解析的回调,每解析出一个歌曲信息都会进行一次回调
AudioFileStream_PacketsProc:是分离帧的回调,每解析出一部分帧就会进行一次回调
步骤:
(1) AudioFileStreamOpen()
(2) AudioFileStreamParseBytes()解析数据
(3)通过码率计算音频的总时长,对于CBR计算时长比较准确.
double duration = (audioDataByteCount * 8) / bitRate
audioDataByteCount通过kAudioFileStreamProperty_AudioDataByteCount获取
bitRate通过kAudioFileStreamProperty_BitRate获取
从指定字节位置开始读取音频数据
1.计算seek到那个字节
2.计算seekToTime对应的第几个帧(Packet)
3.使用AudioFileStreamSeek计算精确的字节偏移和时间
读取音频格式信息和进行帧分离
AudioFileOpenURL:读取本地文件
AudioFileOpenWithCallbacks的使用场景比前者要广泛,使用时需要注意AudioFile_ReadProc,这个回调方法在Open方法本身和Read方法被调用时会被同步调用
读取音频数据:
有两种方式:
a.直接读取音频数据
extern OSStatus AudioFileReadBytes (AudioFileID inAudioFile,
Boolean inUseCache,
SInt64 inStartingByte,
UInt32 * ioNumBytes,
void * outBuffer);
参数1:fileId;参数2:是否需要cache,一般来说传false;参数3:从第几个byte开始读取数据.
参数4:这个参数在调用时作为输入参数表示需要读取读取多少数据,调用完成后作为输出参数表示实际读取了多少数据(即Read回调中的requestCount和actualCount);参数5:buffer指针,需要事先分配好足够大的内存
缺点:数据没有进行帧分离,如果想播放或者解码必须通过AudioFileStream进行帧分离
b.按帧(Packet)读取音频数据: AudioFileReadPacketData 或 AudioFileReadPackets
区别:当需要读取固定长音频或者非压缩音频用AudioFileReadPackets
其他时候,用AudioFileReadPacketData会更高效并且更省内存
优点:这两个方法读取后的数据为帧分离后的数据,可以直接用来播放或者解码
拔掉耳机就把歌曲暂停
AudioQueue播放音频数据(音频格式自行解码成PCM数据后再给AudioQueue播放)
内部有一套缓冲队列(Buffer Queue)
AudioQueue播放的过程其实就是一个典型的生产者消费者问题
步骤:
(1)创建AudioQueue
(2) AudioQueueAllocateBuffer创建AudioQueueBufferRef(2-3个左右),放到BufferArray.
(3) BufferArray取出一个buffer, memcpy数据, AudioQueueEnqueueBuffer把buffer插入AudioQueue中
(4) AudioQueue中存在Buffer后,调用AudioQueueStart播放
(5) AudioQueue播放音乐后消耗了某个buffer,在另一个线程回调并送出该buffer,把buffer放回BufferArray供下一次使用
代码相关:
AudioQueueNewOutput(…)
AudioStreamBasicDescription:音频数据格式类型,AudioFileStream或者AudioFile解析出来的数据格式信息;
AudioQueueOutputCallback:某块Buffer被使用之后的回调
AudioQueueAllocateBuffer(…)
AudioUnit
audioUnit开启后,系统播放一段音频数据,一个audioBuffer,播完了,通过回调来跟APP索要下一段数据,这样循环,直到关闭这个audioUnit。重点就是:1. 是系统主动来索要 2.通过回调函数。
AudioUnitSetProperty 设置音频录制与放播的回调函数
在线音频流播放:
a.底层socket连接,bind绑定接口,fopen打开音频文件,fread读取音频数据,send发送音频流
b.AudioQueue播放音频:audioBuffer填充数据,加入AudioQueue
AVAudioSession作用:
1.设置自己的APP是否和其他APP音频同时存在,还是中断其他APP声音
2.在手机调到静音模式下,自己的APP音频是否可以播放出声音
3.电话或者其他APP中断自己APP的音频的事件处理
4.指定音频输入和输出的设备(比如是听筒输出声音,还是扬声器输出声音)
5.是否支持录音,录音同时是否支持音频播放
AVAssetReader:从原始数据获取音视频数据
AVAssetReaderTrackOutput:读取每帧的CMSampleBufferRef
AVAssetTrack:视频轨迹,视频来源
AVAsset:获取多媒体信息,抽象类不能直接使用
录制格式是.caf,导出时配置参数为aac编码,
voip:基于IP的语音传输