内容原创,转载请注明出处算法
1、引言
移动App发展到今时今日,几乎全部应用程序里都有音视频相关功能,总结起来大概有音视频录制,音视频播放,音视频特效处理,音视频传输这几方面内容。
比较热门的短视频应用抖音与快手,K歌应用唱吧与全民K歌,以及网易云新出的音街,还有听歌的网易云音乐和qq音乐等。虽然每种应用的运营模式不同,可是从技术实现上大同小异。短视频类软件的视频处理更丰富,有很是炫酷的滤镜,贴纸,K歌类软件对音乐的细节处理的较多,诸如音量,音效,音调。
笔者是唱吧较早的用户,发展至今,唱吧涵盖的音视频技术相对比较全面,原唱吧音视频技术负责人展晓凯老师在《音视频进阶指南》一书中对移动端音视频最佳实践给出了具体实现,因此就以唱吧为参考,探索移动端的音视频相关技术。(代码实现上基于安卓,不过对于音视频这种偏底层的操做,各平台实现思路大体同样。另外,笔者不曾在唱吧工做过,如有侵权或其余行为,请留言沟通。若想与笔者共同探讨移动音视频技术,欢迎留言或微信smzh_james探讨)。
json
涉及技术目录一览
1、音频录制(录音,音频解码,音频重采样,音频混合)
2、音频播放与效果处理 (音量,音调,音效)
3、视频录制 (Camera相关,视频编码)
4、视频特效处理(美颜,滤镜,贴纸)
5、视频播放(视频解码,视频渲染, 音视频同步)
6、音视频混合
(内容连接会陆续更新)
2、效果对比与技术实现浅析
参考唱吧App的界面,作了一款简易的K歌软件,黑白风格,可是涵盖了大多数功能,如下称为SuperKtv。效果对好比下图。微信
(一)K歌列表页
图1是SuperKtv,图2是唱吧。
网络
SuperKtv实现比较简单,直接获取手机上现有音频文件以列表展现,为后续功能提供一个入口。实现上没啥难度,作开发的都懂,就再也不赘述。异步
(二)音频录制页
前两幅图是SuperKtv的音频录制页,第三幅图是唱吧音频录制页。
布局
-
歌词
对于K歌软件来讲歌词是很重要的一部,像唱吧这种专业K歌软件,曲库很庞大,为了与演唱同步,歌词通常都带有时间戳,以便演唱过程当中歌词动态滚动,还有打分功能。从技术方面分析,歌词和打分功能每首歌应该都不相同,这方面本质不涉及音视频技术,笔者也没有太多精力为歌曲自定义歌词和打分功能。
为了让SuperKtv与唱吧有较高的锲合度,笔者仍是想办法作了这方面的工做。要快速解决SuperKtv的歌词问题,只能从网络入手,利用 歌词网https://www.90lrc.cn 强大的搜索功能,使用其搜索接口先搜索歌名,返回带搜索结果列表的Html,而后解析Html获取合适的列表项,通常取第一项最为合适,并取出其中的歌词连接,再经过歌词连接获取带歌词的Html,过滤后便可获取获取歌词文本,显示效果如上图1。打分功能的一中实现方法是在演唱过程当中匹配动态识别的音高与预约义文件中的内容。
性能 -
录音
K歌软件的核心功能之一,对于录音的低延时性能要求较高,这一点上IOS比Android作的要好的多,并且功能很完善,用AudioUnit能够解决大部分问题;Android8.0如下推荐使用OpenSL ES,是OpengSL在嵌入式设备上的精简实现;Android8.0及以上推荐使用AAudio,一个轻量级录音接口,为低延时音频处理而生,据官网文档描述低延时性能较好,并且给出了Pixel几款机型的测试数据。可是由于安卓的机型是在太多,硬件实现上付出的努力不尽相同,因此这二者在兼容性上均不如AudioRecorder好。Google Android团队对OpenSL ES和AAudio进行了封装,命名为Oboe,看起来大有追赶AudioUnit的理想,提供了统一的调用接口,使用极为方便,在GitHub上直接能搜到Oboe https://GitHub/Oboe,提供的Demo参考价值很大,但根据GitHub上的反馈来看,使用起来问题很多,主要在杂音和延迟上。期待后续的更新能完全解决这个安卓从问世以来就一直被诟病的问题。
低延迟录音的另外一个解决方案是计算录音延迟,设想若是能获取到录音延迟,那么在编辑页混合的时候能够人为的将录到的声音提早一段时间,获得的结果几乎接近于没有延迟。但要是能这么容易解决的话就不是Android了,录音的延迟计算并不容易,粗略的计算 录音延迟 = 硬件延迟 + 缓冲延迟,若是在录音回调中有较多计算的话还须要加上计算延迟。截止目前只有AAudio中提供了计算延迟的方法,尴尬的是经实测延迟为0。即使是8.0以上的设备已经占据主流市场,但对于商用软件来讲支持到8.0确定是远远不够的,硬件的延迟或许只有厂商可以拿到比较准确的数据,因此和厂商合做也是其中一种解决办法。对于华为手机来讲,华为的Sdk里面提供了相应的Api,使用AudioKit能直接获取录音延迟,并且具有耳返功能和七个音效,这应该是迄今听到的最好的消息了。
学习 -
音频解码和重采样
在K歌软件录音的时候通常会播放伴奏或者原唱为演唱者提供参考,底层的Api通常都不提供解码功能,因此在将数据“填充”到设备缓冲区以前要将伴奏或原唱解码成原始数据,就是大名鼎鼎的Pcm。歌曲文件通常是Mp3或者AAC格式,Mp3的编解码推荐使用Lame,AAC的编解码推荐使用Fdk-aac,这二者在速度上迄今为止作到了最好,对于有实时性要求的最合适不过了,能够直接使用或者将这两个库编译到FFmpeg里面,调用FFmpeg的Api操做,再退一步,直接使用FFmpeg自带的解码算法也能完成相应功能,固然性能上是有所区别。在解码上广泛的作法是编译带有Lame或Fdk-aac的FFmpeg,调用FFmpeg的Api去作编解码,由于其Api的统一性上颇有优点。
在Android平台下还可使用MediaCodec进行解码,系统自带Api,使用方便,文档较多,并且使用硬件解码,速度上也比软件解码快不少,遗憾的是直到Android6.0之后才提供了MediaCodec的C++接口,考虑到和IOS的统一性,推荐使用前者。
重采样关键点是音乐文件的采样率、声道数和采样深度(也称量化精度)。某一个音乐文件的采样率、声道数、量化精度能够认为是不肯定的,但播放平台硬件支持的采样率、声道、采样深度是有限的、肯定的,因此在“填充”数据给音响设备的缓冲区以前的另外一项工做是重采样,直接使用FFmpeg就行了,FFmpeg提供的重采样功能比较强大,包括采样率、声道数和采样深度均可以改变。参考文档或在网上搜索均可以 。须要注意的是网上的FFmpeg重采样教程大多忽略了一个问题,从单声道重采样成双声道的时候,为了保证听觉上音量不变,实际的分贝(响度)会有轻微的变化,这点还须要特别注意。
测试 -
音频内容保存
考虑到K歌软件录到的音频内容在后面的要进行编辑,在磁盘空间不受限制的状况下建议直接保存原始数据,方便后续操做,一首歌的空间通常在100Mb之内。若是考虑磁盘空间的话,能够将录到的数据编码保存,编辑的时候再进行解码。关于音频编码部分在保存的时候再详细分析,要注意的是在保存数据的时候要频繁读写文件,考虑到性能问题,能够选用异步操做来完成,异步操做的线程同步问题可使用Boost库中提供的无锁队列来完成。
编码
(三)音频编辑页
前两幅图是SuperKtv,后两幅图是唱吧。在写这边文章的时候唱吧的编辑页进行的改版,页面布局发生了巨大变化,风格上跟音街比较像。但在笔者模仿唱吧界面的时候,老用户应该比较清楚,长相跟SuperKtv很是接近,此处比较许遗憾,没能以最高类似度复原唱吧App。
-
音频播放
K歌软件的在编辑页须要音频播放功能,对低延时性能要求也比较高,目的是将前面录好的内容和伴奏同时播放,听起来像是在听歌星的专辑同样。在Android平台上使用OpenSL ES和AAudio是较好的选择。为达到较好的同步效果,选用低延时Api是必要的,此外,还须要精确控制两个轨道播放的时间同样。比较简陋的作法是打开两个播放器,一个播放人声,另外一个播放伴奏,以达到同步播放的效果,更具使用价值的是选择一个播放器,将人声和伴奏的Pcm数据混合以后播放,后者的同步性要好于前者,效率是也更高。在SuperKtv中使用的是第二种方案,效果还不错。在播放以前要关注Pcm数据的声道、采样率、采样深度,必要时进行重采样。 -
音量控制
在音频处理中,对编码好的音频处理很难,通常是对原始数据进行处理。在后续的音量、音效、音调处理都是对Pcm处理。
众所周知声音是波,音量能够理解为波的振幅,也叫响度,改变音量即改变波的振幅,从数学的角度要增大一个正弦波的振幅只要乘以增益就能够,一样,音量也是对Pcm数据乘以增益就能够,固然能够直接使用FFmpeg来解决。要注意的是增大振幅以后不能超过每一帧数据的最大值和最小值,以16位整形精度为例,若是最终的数值大于32767或小于-32768,那么音质就会受损,听起来像杂音同样。 -
音调控制
音调主要由声音的频率决定,同时也与声音强度有关。对必定强度的纯音,音调随频率的升降而升降;对必定频率的纯音、低频纯音的音调随声强增长而降低,高频纯音的音调却随强度增长而上升。音调调节推荐使用SoundTouch https://sourceforge.net/projects/soundtouch/),用法比较简单,并且还具备变速等功能。
音调主要是由声波的频率决定的,联想到数学或物理学中波相关的知识点,能够本身手动实现,简单理解为将音频数据重采样成另外一个频率,但数据内容没有减小。由傅里叶变换的定义能够知道,任何周期性的波均可以分解成若干个正弦波的叠加。在这里广泛的作法是将Pcm数据经傅里叶变换获得频域的结果,改变基波的频率,由于频率的变化可能致使数据减小或增多,须要再进行插值计算,最后作反向傅里叶变换将数据变换到时域,就能够获得改变频率的Pcm数据,也就是改变了音调。 -
音效控制
由于声音是波,因此音效也是根据波的一些特性进行处理的,好比回声效果就是根据波的反射性实现的。展晓凯老师在《音视频进阶指南》一书中给出了用Sox实现音频效果的具体实现,FFmpeg也能够对音频进行效果处理,SuperKtv中用二者均实现了音频效果处理。Sox在音频效果处理上功能稍微更全面一些,推荐使用Sox http://sox.sourceforge.net/,被誉为音频处理方面的瑞士军刀,遗憾的是这个库在早些时候已经中止更新了,其功能逐渐被桌面版客户端AudioCity取代。
音频效果处理分为混响,均衡,压缩。混响能够理解为在一个房子里面唱歌有回声,影响的因素通常有房间的大小、墙壁的反射率(装修材料等),演唱者所处的位置等,因此经过改变房间大小等参数,就能够模仿专业演播大厅的效果,像维也纳演播大厅的混响参数都是已知的,参考这些参数就能模拟出在维也纳演播大厅开演唱会的效果。均衡器能够分别调节各类频率成分信号放大量,通常调音台上的均衡器仅能对高频、中频、低频三段频率电信号分别进行调节,均衡器还具有高通滤波和低通滤波的功能,好比唱吧中的留声机效果就是使用了均衡器,一方面过滤掉某些频率的谐波,另外一方变改变某些频率信号份量的增益就能够获得留声机的效果。压缩器在百度百科上的定义以下:“压缩器是一种随着输入信号电平增大而自己增益减小的放大器,实质上改变的就是输入与输出信号的比例。压缩器是两种最多见的用于处理音频信号动态范围的设备之一”,这个定义应该很明了了,在Sox的实现上主要以调节参数为主。经过这三种效果的叠加,就能够调节出Ktv、录音机、流行,说唱等不一样风格的效果。上图中的自定义音效是对混响、均衡、压缩三种效果中一些重要参数提供了可调节入口,其余音效能够理解为一些固定参数根据经验的组合。以上三种算法原理能够参考Sox源码中reverb.c,bequed.c,compand.c这三个文件。
(四)视频录制页
前三幅图的SuperKtv的视频录制界面,后三幅图是唱吧的视频录制界面。
从功能上对比,SuperKtv美颜面板少了锐化,瘦脸,大眼功能,另外道具功能也没有实现,稍后具体分析。
音频部分跟前面同样,重点分析视频的录制。视频的录制须要保存带美颜效果的视频,固然也能够保存原始视频画面在编辑页进行处理,唱吧中采用了前者,因此SuperKtv中也采用了第一种方案。
-
相机操做及美颜、滤镜
这一部份内容须要有必定的OpenGL ES基础,能够理解为对每一帧画面中的每个像素进行处理,而后渲染到屏幕上。详细原理能够参考博主OpenGL ES系列文章
Android OpenGL ES从入门到进阶(一)—— 五分钟开发一款美颜相机
Android OpenGL ES从入门到进阶(六)—— OpenGL ES人像美白与磨皮初探
Android OpenGL ES从入门到进阶(八)—— 万能的Lookup滤镜
上述内容都属于OpenGL ES基础部分,本文再也不描述,有疑问的能够留言交流。 -
贴纸(道具)
在美颜相机类产品中,贴纸功能应该算一个重头戏,唱吧中称为道具,目前抖音中的贴纸类功能算比较强大的。这类功能的实现依赖于人脸面部特征点识别,并且对实时性要求比较高,国内商用人脸识别Sdk里面作得比较好的商汤科技和旷视科技,中小型公司的美颜类产品都从这两家购买Sdk,抖音和FaceU激萌据笔者所知用的是字节跳动自研的人脸识别Sdk。因为对实时性要求较高,通常都是采用深度学习算法,训练好模型以后根据模型识别。若是对实时性要求不高的话可使用Dlib http://dlib.net/,基于OpenCV的使用比较简单,这个也是基于深度学习的,官方文档中给的模型大概有100Mb,毕竟是开源免费的,性能上较商用Sdk有不小差距。经实测,Dlib识别一幅1080 x 720的图片大概须要400 - 500ms,在某些性能低的手机上甚至须要1000ms,而商用Sdk能够在20ms内完成,这也是为何有开源免费的,商用的还能卖那么贵的缘由,同时启示咱们要尊重知识产权。因为这些限制,SuperKtv中暂时没有动态贴纸功能。
关于贴纸的使用,能够参考另外一篇博客 Android OpenGL ES从入门到进阶(七)—— OpenGL ES 2D贴纸与Blend混合 这是一篇关于静态贴纸的文章,动态贴纸稍微麻烦一些,须要根据面部特征点时时改变贴纸的位置和角度,有的还须要作平移和缩放,贴纸的变化规则须要提早定义好,以商汤Sdk为例,贴纸的运动规则定义在一个json文件中,使用贴纸先解析json内容,而后随时间作周期运动,这就是动态贴纸的大体原理。
- 视频编码
不一样于音频,原始视频占用磁盘空间很是大,若是录到的视频保存成原始数据的话那不可想象,因此在录制视频以后要编码以后进行保存,视频编码格式不少,移动端流行H264和H265,SuperKtv中采用的事H264编码,因此文中也以H264为例分析。
若是保存了带美颜效果的视频后不须要对画面进行二次编辑(好比唱吧),在Android平台首选MediaCodec配合Surface,一方面使用硬件编码速度要优于软件编码,另外一方面系统自带Api使用上会更方便,Mediacodec能够将Surface上的数据直接编码,只须要将编码后的数据写文件便可,这很是契合SuperKtv的需求。但硬件编码的兼容性不是很好,尤为是安卓的机型成千上万种,总有几款手机使用起来有这样那样的问题,考虑到这样的状况有时候也会采用软件编码,软件编码H264推荐使用X264,算法性能上要优于FFmpeg自带的H264编码算法,可是广泛的用法是将X264编译到FFmpeg里面,用统一的接口调用,这种方法稍微麻烦一些,先要将相机的回调数据作美颜、滤镜等处理,而后再根据需求看是否须要进行数据格式转换,由于Android的Camera API有两套,Camera1推荐使用NV21,Camera2推荐使用Yuv420p,用FFmpeg编码的时候,因为颜色空间的特殊性,为方便使用,建议将数据统一转换为Yuv420p格式再进行编码,转换算法网上有,这里推荐使用LibYuv,功能很强大,这一部份内容要求要对图像的几种颜色空间有所了解,特别是RGBA系列和YUV系列。
若是在编辑页面要对原始视频进行二次编辑,那么只能保存原始画面,这时候可使用MediaCodec,也可使用FFmpeg,在这种需求下两者的却别不是很大了,硬件编码速度快,但兼容性稍差,软件编码兼容性好,但速度稍慢,可适当取舍而定。固然FFmpeg也是支持硬件编码的,只是编译的时候须要作一些额外的处理,但若是是硬件编码,为什么不直接使用系统API呢。
(五)音视频编辑页
前两幅图是SuperKtv的实现,后两幅图是唱吧的实现。
一样的,唱吧在音视频编辑页面也进行了较大改版。唱吧在演唱功能下没有实现对视频的编辑,因此也跟随了唱吧的风格,主要是对音频的编辑,功能实现上跟前面提到的音频编辑同样,比较重要的一点是视频播放,涉及到视频解码和音视频同步。若是说要实现视频的编辑功能,有两种思路,一中是用OpenGL ES处理后后台保存,另外一种是使用FFmpeg或OpenCV对数据处理后保存,推荐使用OpenGL ES进行视频编辑。
-
视频解码
Android平台推荐使用MediaCodec解码,能够直接解码到Surface上进行显示,这省去了不少额外的操做(数据格式转换和渲染)。
固然也可使用X264或FFmpeg进行解码,将解码以后的数据拷贝到ANative_Window提供的缓冲区用以显示,这比起FFmpeg编码已经方便不少了,若须要使用OpenGL ES对视频进行编辑,须要将数据转换成纹理,并上传到OpenGL ES提供的缓冲区用来显示。唱吧导入外部视频能够编辑,能够用上述思路都可实现。 -
音视频同步
音视频同步是视频播放很重要的一个环节,直接影响到前面全部工做的结果。音视频同步通常使用时间戳同步,这要求在编码的时候加上正确的时间戳。Camera的回调里面有当前帧的时间戳,以微秒为单位,跟MediaCodec所需单位一致,编码时使用较方便。FFmpeg的时间戳跟MediaCodec不一样,使用的是根据时间基计算出来的,编码时只须要加上当前帧的索引就能够。同步的缘由是由于音频在单位时间内的播放数据量是固定的,只需给播放Api回调填充数据就能够,但视频没有相应的机制,在画面上显示的内容以及何时显示都是由外界控制,假如用解码速度控制的话,若是解码速度太快,在很短的时间内就能播放完一个较长视频,若是解码速度太慢,就会致使画面卡顿。同步的过程大体能够描述以下:若是当前帧播放快了,那下一阵继续播放当前帧,至关于等待,若是当前帧播放太慢,那就丢弃,播放下一帧或下下一帧,这样就能控制视频播放的速度了。同步的方法通常有音频向视频同步,视频向音频同步,两者向基准时间同步,普片选用视频向音频同步,由于音频在单位时间内播放的数据固定的。
(六)保存和做品列表页
第一幅图是保存的界面,第二幅图是保存后的做品列表页面。界面简单,没有与唱吧进行对比。
保存的目的是为了让保存的结果和编辑页面调节后的效果同样,至关于重复一遍编辑页面的操做,只不过要变成后台操做,前台惟一须要显示的是保存进度,后台处理过的数据直接进行编码便可。
-
音频编码
前面提到,为方便编辑,录到声音后保存成了原始数据,但音频的结果必然是成品(编码后的)的,因此在保存以前先要编码。移动端音频编码通常使用Mp3合适或者AAC格式。Mp3编码推荐使用Lame,AAC编码推荐使用Fdk-aac,也可使用MediaCodec 或者FFmpeg自带编码算法。对于SuperKtv的保存需求来讲,编码速度影响不是很大,因此选哪种均可以,在了解MP3格式和AAC格式的区别以后,任选一种使用哪一种方法均可以达到很好的效果。有一个不一样点是MediaCodec编码的AAC是不带ADTS的裸流,若是此处是最终音频文件,须要手动添加ADTS,而使用Fdk-aac编码以后会自动加上ADTS。 -
音视频合并
截止这一步骤,前面生成的音视频文件都是单独的,对于音频录制来讲到这一步就已经完成了,对于视频来讲还须要将音频和视频合并成一个文件,音视频合并能够理解为将两个文件合并成一个文件,经过某种规则将两个类型的数据区分,使用的时候可以单独拿到音频和视频数据,有点相似于编辑页面音视频的同步的感受。使用Android提供API MediaMuxer或者使用FFmpeg都可以。使用MediaMuxer合并音视频的时候,若音频是AAC格式,须要提供AAC裸流,使用FFmpeg的话就不用,甚至能够直接用命令来完成,合并完以后就是广泛意义上的视频,是能够直接发布的做品。
(七)本地做品播放页
第一幅推是音频播放界面,第二幅图是视频播放界面。界面简单,没有与唱吧进行对比。
前面作了好多工做,最后的结果只是一个文件,一种是音频文件,相似于.mp3,经常使用的还有.m4a等;另外一种是视频文件,相似于.mp4,经常使用格式还有.flv等。对于这样的文件每一个人应该都很熟悉,手机自带功能就可以播放,因此在SuperKtv中欣赏或者分享我的做品的时候不必本身再写一套播放器,使用现成的就能够,甚至直接调用系统API MediaPlayer就能够。关于播放器的使用,安卓平台下推荐使用EXOPlayer,这是谷歌基于MediaCodec的一款开源播放器,支持音、视频及其经常使用格式,使用硬件解码,还带有一些基础控件,定制性较高。SuperKtv就是基于ExoPlayer作的本地做品播放功能,效果展现如上图,使用体验也很不错。
3、总结
本文是以“唱吧App”为参考,基于Android平台,总结了移动端音视频技术的实现策略,适合有必定音视频基础的开发人员,能够做为技术方案参考,因为时间精力有限,实现细节随后以文章形式发布,如有疑问欢迎你们留言交流。
转载请注明出处。
友情连接:
一、FFmpeg http://ffmpeg.org/ (音视频必备神器)
二、Sox http://sox.sourceforge.net/ (音频界瑞士军刀)
三、SoundTouch https://sourceforge.net/projects/soundtouch/ (音调、变速)
四、Dlib http://dlib.net/ (人脸特征点识别开源库)
五、Oboe https://GitHub/Oboe (Android平台低延时音频接口)