IOS 音频开发文件大小计算
- 音频基础知识
- 音频文件计算大小
- 音频转码
标签(空格分隔): 调查 IOS音频
https://developer.apple.com/library/ios/documentation/MusicAudio/Conceptual/CoreAudioOverview/SupportedAudioFormatsMacOSX/SupportedAudioFormatsMacOSX.html
音频基础知识
组成
音频文件的组成:文件格式(或者音频容器) + 数据格式(或者音频编码)。
文件格式(或音频容器)是用于形容文件本身的格式。
我们可以通过多种不同的方法为真正的音频数据编码。例如CAF文件便是一种文件格式,它能够包含MP3格式,线性PCM以及其它数据格式的音频。
数据格式(或音频编码)
我们将从音频编码开始阐述(而不是文件格式),因为编码是最重要的环节。
线性PCM:
这是表示线性脉冲编码调制,主要是描写用于将模拟声音数据转换成数字格式的技术。简单地说也就是未压缩的数据。因为数据是未压缩的,所以我们便可以最快速地播放出音频,而如果空间不是问题的话这便是iPhone音频的优先代码选择。
音频文件计算大小
声卡对声音的处理质量可以用三个基本参数来衡量,即采样频率、采样位数和声道数。
采样频率:
是指单位时间内的采样次数。采样频率越大,采样点之间的间隔就越小,数字化后得到的声音就越逼真,但相应的数据量就越大。声卡一般提供11.025kHz、22.05kHz和44.1kHz等不同的采样频率。
采样位数:
是记录每次采样值数值大小的位数。采样位数通常有8bits或16bits两种,采样位数越大,所能记录声音的变化度就越细腻,相应的数据量就越大。
声道数
是指处理的声音是单声道还是立体声。单声道在声音处理过程中只有单数据流,而立体声则需要左、右声道的两个数据流。显然,立体声的效果要好,但相应的数据量要比单声道的数据量加倍。
声音数据量的计算公式为:
数据量(字节/秒)= (采样频率(Hz)× 采样位数(bit) × 声道数)/ 8
单声道的声道数为1,立体声的声道数为2。
【例1】请计算对于5分钟双声道、16位采样位数、44.1kHz采样频率声音的不压缩数据量是多少?
根据公式:数据量=(采样频率×采样位数×声道数×时间)/8
得,数据量(MB)=[44.1×1000×16×2×(5×60)] /(8×1024×1024)=50.47MB
计算时要注意几个单位的换算细节:
时间单位换算:1分=60秒
采样频率单位换算:1kHz=1000Hz
数据量单位换算:1MB=1024×1024=1048576B
【例2】请计算对于双声道立体声、采样频率为44.1kHz、采样位数为16位的激光唱盘(CD-A),用一个650MB的CD-ROM可存放多长时间的音乐?
已知音频文件大小的计算公式如下:
文件的字节数/每秒=采样频率(Hz)X采样位数(位)X声道数/8
根据上面的公式计算一秒钟时间内的不压缩数据量:(44.1×1000×16×2)/8=0.168MB/s
那么,一个650MB的CD-ROM可存放的时间为:(650/0.168)/(60×60)=1.07小时。
IOS 音频转码
音频转码使用的框架为:AudioToolBox
内存转码:
使用函数: AudioConverterFillComplexBuffer
- (void)handleAudioPackets:(const void *)inputData
numberOfBytes:(UInt32)numberOfBytes
numberOfPackets:(UInt32)numberOfPackets
packetDescriptions:(AudioStreamPacketDescription *)packetDescriptions
{
if (!_audioFileStream || !_parseAudioHeader || !_decodeConverterRef) return;
AudioConvertInfo convertInfo = (AudioConvertInfo){
.done = NO,
.numberOfPackets = numberOfPackets,
.packetDescriptions = packetDescriptions,
.audioBuffer = (AudioBuffer){
.mData = (void *)inputData,
.mDataByteSize = numberOfBytes,
.mNumberChannels = _sourceAsbd.mChannelsPerFrame
}
};
AudioBufferList decodedData;
decodedData.mNumberBuffers = 1;
decodedData.mBuffers[0].mNumberChannels = _canonicalAsbd.mChannelsPerFrame;
decodedData.mBuffers[0].mDataByteSize = _decodeBufferSize;
decodedData.mBuffers[0].mData = _decodeBuffer;
UInt32 ioOutputDataPackets1, ioOutputDataPackets2;
OSStatus decodingStatus, encodingStatus;
while (1)
{
ioOutputDataPackets1 = numberOfPackets;
decodingStatus = AudioConverterFillComplexBuffer(_decodeConverterRef, AudioConverterCallback, (void*)&convertInfo, &ioOutputDataPackets1, &decodedData, NULL);
if (decodingStatus == OS_STATUS_DONE || decodingStatus == 0)
{
if (ioOutputDataPackets1 > 0)
{
// Start encoding
AudioConvertInfo encodeConvertInfo = (AudioConvertInfo){
.done = NO,
.numberOfPackets = ioOutputDataPackets1,
.packetDescriptions = NULL,
.audioBuffer = (AudioBuffer){
.mData = decodedData.mBuffers[0].mData,
.mDataByteSize = decodedData.mBuffers[0].mDataByteSize,
.mNumberChannels = _canonicalAsbd.mChannelsPerFrame
}
};
AudioBufferList encodedData;
encodedData.mNumberBuffers = 1;
encodedData.mBuffers[0].mNumberChannels = _destinationAsbd.mChannelsPerFrame;
encodedData.mBuffers[0].mDataByteSize = _encodeBufferSize;
encodedData.mBuffers[0].mData = _encodeBuffer;
while (1)
{
ioOutputDataPackets2 = _encodePacketsPerBuffer;
encodingStatus = AudioConverterFillComplexBuffer(_encodeConverterRef, AudioConverterCallback, (void*)&encodeConvertInfo, &ioOutputDataPackets2, &encodedData, _encodePacketDescriptions);
if (encodingStatus == OS_STATUS_DONE || encodingStatus == 0)
{
//一个buffer 转码成功
}
else
{
[self failureOccurred];
return;
}
if (encodingStatus == OS_STATUS_DONE)
{
break;
}
}
// End encoding
}
}
else
{
[self failureOccurred];
return;
}
if (decodingStatus == OS_STATUS_DONE)
{
break;
}
}
}
文件转码:
使用函数 ExtAudioFileRead
void startConvert(ExtAudioConverterSettings* settings){
//Determine the proper buffer size and calculate number of packets per buffer
//for CBR and VBR format
UInt32 sizePerBuffer = 32*1024;//32KB is a good starting point
UInt32 framesPerBuffer = sizePerBuffer/sizeof(SInt16);
// allocate destination buffer
SInt16 *outputBuffer = (SInt16 *)malloc(sizeof(SInt16) * sizePerBuffer);
while (1) {
AudioBufferList outputBufferList;
outputBufferList.mNumberBuffers = 1;
outputBufferList.mBuffers[0].mNumberChannels = settings->outputFormat.mChannelsPerFrame;
outputBufferList.mBuffers[0].mDataByteSize = sizePerBuffer;
outputBufferList.mBuffers[0].mData = outputBuffer;
UInt32 framesCount = framesPerBuffer;
CheckError(ExtAudioFileRead(settings->inputFile,
&framesCount,
&outputBufferList),
"ExtAudioFileRead failed");
if (framesCount==0) {
printf("Done reading from input file\n");
return;
}
CheckError(ExtAudioFileWrite(settings->outputFile,
framesCount,
&outputBufferList),
"ExtAudioFileWrite failed");
}
}
代码下载 http://download.csdn.net/download/qihongru1227/9326777
原文链接:http://www.jianshu.com/p/5e5428471f48
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
IOS 音频开发文件大小计算的更多相关文章
- iOS 音频开发
音频基础知识 组成 音频文件的组成:文件格式(或者音频容器) + 数据格式(或者音频编码). 文件格式(或音频容器)是用于形容文件本身的格式. 我们可以通过多种不同的方法为真正的音频数据编码.例如 ...
- iOS音频开发系列-概述篇
概述 iOS中对于音频的处理,苹果提供了两个库. AVFoundation AudioToolbox 在iOS系统中apple对上述的流程进行了封装并提供了不同层次的接口
- iOS 音频开发之CoreAudio
转自:http://www.cnblogs.com/javawebsoa/archive/2013/05/20/3089511.html 接 触过IOS音频开发的同学都知道,Core Audio 是I ...
- 一篇对iOS音频比较完善的文章
转自:http://www.cnblogs.com/iOS-mt/p/4268532.html 感谢作者:梦想通 前言 从事音乐相关的app开发也已经有一段时日了,在这过程中app的播放器几经修改我也 ...
- IOS 音频播放
iOS音频播放 (一):概述 前言 从事音乐相关的app开发也已经有一段时日了,在这过程中app的播放器几经修改我也因此对于iOS下的音频播放实现有了一定的研究.写这个系列的博客目的一方面希望能够抛砖 ...
- iOS多线程开发
概览 大家都知道,在开发过程中应该尽可能减少用户等待时间,让程序尽可能快的完成运算.可是无论是哪种语言开发的程序最终往往转换成汇编语言进而解释成机器码来执行.但是机器码是按顺序执行的,一个复杂的多步操 ...
- iOS音频播放(一):概述
(本文转自码农人生) 前言 从事音乐相关的app开发也已经有一段时日了,在这过程中app的播放器几经修改,我也因此对于iOS下的音频播放实现有了一定的研究.写这个 系列的博客目的一方面希望能够抛砖引玉 ...
- ios新手开发——toast提示和旋转图片加载框
不知不觉自学ios已经四个月了,从OC语法到app开发,过程虽然枯燥无味,但是结果还是挺有成就感的,在此分享我的ios开发之路中的小小心得~废话不多说,先上我们今天要实现的效果图: 有过一点做APP经 ...
- iOS企业级开发初级课程-表视图(13集)
首先了解了表视图的组成.表视图类的构成.表视图的分类以及表视图的两个重要协议(委托协议和数据源协议),对表视图有了一个整体上的认识.接下来我们掌握了如何实现简单表视图和分节表视图,以及表视图中索引.搜 ...
随机推荐
- SSH项目整合教学Eclipse搭建SSH(Struts2+Spring3+Hibernate3)
这篇博文的目的 尝试搭建一个完整的SSH框架项目. 给以后的自己,也给别人一个参考. 读博文前应该注意: 本文提纲:本文通过一个用户注册的实例讲解SSH的整合.创建Struts项目,整合Hiberna ...
- 在windows下使用cmd命令行对java文件进行编译和执行
windows下利用cmd命令行可以调用jdk里的javac.exe和java.exe对java文件进行编译和执行,前提是jdk已成功安装并正确配置相关环境变量 相关配置链接:java基础学习总结—— ...
- MongoDB ObjectId
概述 > db.col.find() { , } { , } { , } { , } 每个文档中都有一个“_id”,她是一个12字节的BSON类型数据,格式如下 56c56dd4ca446fab ...
- Struts2上传图片时报404错误
可能是struts配置文件中定义的拦截器导致的,后缀拦截导致,将该拦截器去掉,在action类里判断后缀 public String upload()throws Exception{ ActionC ...
- Java基础之线程——派生自Thread类的子类(TryThread)
控制台程序. 程序总是至少有一个线程,程序开始执行时就会创建这个线程.在普通的Java应用程序中,这个线程从mian()方法的开头启动. 要开始执行线程,可以调用Thread对象的start()方法. ...
- zabbix监控企业esxi虚拟机
zabbix监控企业esxi虚拟机 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我来公司有一段时间了,最近也发现模型部有测试和开发反应某台机器登陆不上去了,结果登陆esxi服务器 ...
- SQL 简单查询语句 select
select *from emp;//查询emp表内容
- sdutoj 2607 Mountain Subsequences
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2607 Mountain Subsequence ...
- .NET: C#: Datetime
比较简单的类,一般用到它的属性.经常会用到的是DateTime.Now和DateTime.Now.TimeOfDay; using System; using System.Collections.G ...
- C语言 单引号 双引号问题
C语言中的单引号和双引号含义迥异,用单引号引起的一个字符实际上代表一个整数,整数值对应于该字符在编译器采用的字符集中的序列值,因此,采用ASCII字符集的编译器而言,‘a’的含义与0141或97严格一 ...