暂时未有相关云产品技术能力~
Android、音视频、AI相关领域从业者
自从 Android Studio 使用 CMake 进行编译就方便多了,不需要再写 Android.mk 了,也不需要用 javah 来生成头文件了,直接写好 native 方法,快捷方式就可以生成对应的 C++ 方法,只要专注写好 C++ 代码,CMake 就可以指定的 CPU 架构生成对应的 SO 库。
Apache Ant 是由 Java 语言开发的工具,由 Apache 软件基金会所提供。Ant 是一个将软件编译、测试、部署等步骤联系在一起加以自动化的一个工具,大多用于Java环境中的软件开发。Apache Ant 的配置文件写成 XML 容易维护和书写,而且结构很清晰。
习惯了IDE以及各种现成的编译工具为我们提供便捷的编译方式,我们很少会操心编译工具的编译过程和原理,但是工具越高级,隐藏的细节就越多,这样编译遇到问题时我们难以定位,遇到复杂的项目(尤其跨平台项目难以用ide)时不知如何下手。所以准备写两篇关于编译器和编译工具的文章。本文先来介绍编译工具。
最早之前不管是视频录制还是视频直播,都是从麦克风获取音频后,直接交编码器,封装复用到不同媒体格式。在后面在IM场景中做短语音消息、短语音消息转文本以及语音输入设计到语音识别,也仍然是直接从麦克风拿数据。在整个语音SDK设计开发完成后自己规划了音效、语音分离合成、重采样等技术需求。
在编程中我们经常遇到多线程相关的问题,记得刚工作的时候对线程没有太多概念,只知道new Thread()run函数中是新的线程,函数多调用几层,特别是一些别人的回调函数中,就忽略了线程引起的并发问题,产生了并发修改异常的崩溃。今天总结一些线程相关的知识。
语音合成又称文语转换(Text to Speech,TTS)技术,是语音处理领域的一个重要的研究方向,旨在让机器生成自然动听的人类语音。
接触过计算机的朋友们都知道CPU的含义,就是中央处理器,是负责计算机主要运算任务的组件。一般我们把CPU比喻为人的大脑。而了解略深的用户会听说CPU有x86、ARM等分类,前者主要用于PC而后者主要用于手机平板等设备。
市面上的UI自动化平台基本上都是大同小异,把查找元素的方法抽象到一个下拉列表,再通过输入框输入要查找元素ID,查到到元素对应做一些动作。今天以opendx为例介绍一下UI自动化平台能力(它的页面和架构相对更人性化)。
如果不做定制化操作,我们不需要自己编译TensorFlow Lite Android库。我们可以直接使用位于MavenCentral的TensorFlow Lite AAR。但是在某些情况下,我们需要本地编译TensorFlow Lite。例如,您可能正在构建一个包含operations selected from TensorFlow的自定义二进制文件,或者需要对TensorFlow Lite进行局部修改。
Bazel和Gradle强调构建体验的不同方面。在某种程度上,它们的侧重点是互斥的——Gradle对灵活性和非突出性的要求对它的构建结构进行了限制,而Bazel对可靠性和性能的要求产生了强制不可协商的限制。
Bazel只是编译工具,不是真正的编译器,所以还是需要Andorid开发的SD、NDK以及Android Studio,并配置开发环境。
Android开发我们主要用到的编译器是Java的Java编译器以及C/C++的gcc/clang编译器。对应Java层构建工具最初是Ant,后面Maven以及gradle;C/C++构建工具主要是make/cmake,做过系统开发或者chromeium,可能还用过ninjia、gclient、mm等。最近在编译Android平台的tensorflow lite库,发现官方使用的是Bazel构建工具,大概了解了下,它不仅可以构建Native层还可以构建Java层库。今天我们简单介绍下什么是Bazel,后续我们逐步深入了解Bazel构建工具,使用Bazel构建我们的Android项目。
在移动端应用开发场景下,不可避免的要与网络打交道。有时在网络请求失败时,我们想知道网络的质量;有时需要明确的告知用户当前网络质量(比如游戏场景实时显示延迟)。网络监控离不开最经典的TCP/IP模型,基于模型分层统计网络耗时有助于我们更清晰的了解当前网络质量。
通过语音和视频通话与他人在线联系正日益成为日常生活的一部分。实时通信框架,如WebRTC,使这成为可能,依赖于有效的压缩技术,编解码器,编码(或解码)信号传输或存储。几十年来,编解码器一直是媒体应用的重要组成部分,它使需要带宽的应用程序能够有效地传输数据,并使人们期望在任何时间、任何地点都能实现高质量的通信。
当时在做一款游戏SDK,SDK主要提供了游戏画面声音采集、音视频编解码、直播推流、直播拉流播放等,SDK为游戏提供直播功能,播放也是采用了现成的ijkplayer播放器。但是SDK推广的时候遇到了问题,游戏厂家嫌弃SDK体积大(其实总共也就3Mb左右),我们需要一款体积小,性能高的播放器,由于开发成本的原因一直没有时间做,后面换工作期间,花了一个月时间把这款播放器开发出来,并开源了出来。oarplayer 是基于MediaCodec与srs-librtmp,完全不依赖ffmpeg,纯C语言实现的播放器。本文主要介绍这款播放器的实现思路。
我们上面介绍的四个层面的音频API实现均在Framework层,其他各层音频相关有哪些功能?当我们调用某一API时最终是怎么驱动硬件工作的呢?下面我们先看看系统各层音频相关模块及功能。
MediaRecorder与MediaPlayer并不能算完整意义的音频API,它们只是系统音频API的封装,除了采集/播放,他们集成了编码/解码、复用/解复用等能力。它们在最底层还是调用了AudioRecorder、AudioTrack。下面主要介绍它们的几个主要的配置项。
TensorFlow Lite是为了解决TensorFlow在移动平台和嵌入式端过于臃肿而定制开发的轻量级解决方案,是与TensorFlow完全独立的两个项目,与TensorFlow基本没有代码共享。TensorFlow本身是为桌面和服务器端设计开发的,没有为ARM移动平台定制优化,因此如果直接用在移动平台或者嵌入式端会“水土不服”。
文本编辑器切换到VSCode上很久了,主要用来看看代码,文档,写写Markdown文档,后面慢慢的使用VSCode来写写简单的C/CPP代码,后面Flutter的,Python等都切换到VSCode上开发了,已经成了第一生产力工具了.需要花时间探索它的技巧,提高效率.今天总结了常用的一些技巧快捷键,帮助大家更高效的使用VSCode.
但是系统相机和系统控件VideoView的局限性都是可定制型太差,系统相机的图像分辨率,视频码率以及VideoView的进度条等.
接下来要实现connect,createStream,play,..,为了效率和篇幅,我们直接分析srs-librtmp的实现.srs-librtmp是从srs作者为srs服务实现的客户端库(The client library srs-librtmp of SRS),其实不止客户端,也实现了一个简单的server功能.
注意事项: 在实际工程应用中,一般是客户端先将C0, C1块同时发出,服务器在收到C1 之后同时将S0, S1, S2发给客户端。S2的内容就是收到的C1块的内容。之后客户端收到S1块,并原样返回给服务器,简单握手完成。按照RTMP协议个要求,客户端需要校验C1块的内容和S2块的内容是否相同,相同的话才彻底完成握手过程,实际编写程序用一般都不去做校验。
作为一个码农,搬砖搬到一定高度就需要"脚手架"来支撑我们"够得住".为了方面我们把rtmp推拉流sdk实现为一个PC上的命令行程序,当开发调试稳定后,我们可以快速的通过交叉编译工具编译到Android/iOS等移动端设备.
SRS(Simple Rtmp Server)定位是运营级的互联网直播服务器集群,追求更好的概念完整性和最简单实现的代码,这是该产品自己官方的介绍。值得一说的是,前面几个产品都是国外的,而这个作者是国内的,目前作者在阿里.
莫尔斯码就是大家熟悉的电报码,它的发明为人类做出了巨大的贡献.该码采用"."和"-"来表示26个英文字母,这实质上还是二进制码(点为"0",而杠为"1"),但是它没有采用固定字长的编码方式,而是采用了常用字母用短码表示(如E用"."表示,T用"-"表示),不常用字母用长码表示(如Z用"--.."表示,j用"-..-"表示)的变长编码方式.通过对英文单词进行大量统计,找出各字母的概率,最后确定有12个字母出现概率最低,用4bit数字表示,有8个字母出现概率较低,用3bit数字表示;有4个字母出现概率较高,用2bit数字表示;有两个字母出现概率最高,用1bit表示,共26个字母.
前面我们分析完Opus的编解码api使用,封装原理等,接下来我们准备分析Opus编码原理.Opus编码是一个复杂的工作,我们需要做一些基本铺垫,包括认识声音,压缩编码基础.认识音频有助于我们了解音频特征,不仅对语音有助于我们理解编码技术,同时在语音识别,TTS等场景提供帮助
针对上面的问题我们可以自定义一种封装格式,增加类似于WAV的Header,Header中存储元数据,每一帧音频数据前面增加可以标识帧边界的头,但是又会引出其他问题
Ogg编解码器将原始压缩数据放入数据包中。数据包是八位字节有效载荷,其中包含单个解压缩单元(例如一个视频帧)所需的数据。数据包没有最大大小,长度可能为零。它们通常没有任何框架信息。串在一起的未成帧的数据包形成没有内部界标的编解码器数据的逻辑比特流。
由于我们解码后的数据直接写入文件,无法通过vlc等播放器播放,我们通过lame将解码后的数据再编码成mp3,当然,你要乐意也可以直接价格wav头输出成wav. 通过采样率,声道数等创建lame编码器
PCM数据大小怎么计算呢?根据采样率采样格式,声道数计算.根据前面文章音视频之音频知识入门介绍:PCM文件大小 = 采样率 * 采样格式 * 声道数 * 录制时长采样率即一秒多少采样,采样格式指一个采用占多少字节,通常一个采用使用一个字节或者两个字节,所以采样率*采样格式计算出一秒钟一个声道PCM多少字节,乘以声道数,算出一秒钟PCM大小,再乘以时长就可以计算出PCM文件大小.
每个FRAME 都有一个帧头FRAMEHEADER,长度是4BYTE(32bit),帧头后面可能有两个字节的CRC 校验,这两个字节的是否存在决定于FRAMEHEADER 信息的第16bit, 为0 则帧头后面无校验,为1 则有校验,校验值长度为2 个字节,紧跟在FRAMEHEADER 后面,接着就是帧的实体数据了
ID3V2一共有四个版本,ID3V2.1/2.2/2.3/2.4,目前流行的播放软件一般只支持第三版即ID3V2.3,由于ID3V1记录在文件的末尾处,ID3V2就只能记录在文件的首部了,也是因为这个原因,对ID3V2的操作比ID3V1要慢,而且ID3V2的结构比ID3V1的结构复杂的多,但是ID3V2可以记录更多的信息,长度可变
Gradle插件分为脚本插件和对象插件,脚本插件就是在普通的gradle中写一系列task,然后在别的gradle构建脚本中通过 apply from: 'xx.gradle' 引用这个脚本插件,下面主要介绍一下对象插件对象插件是指实现了org.gradle.api.Plugin接口的类。并且需要实现void apply(T target)这个方法,该方法中的泛型指的是此Plugin可以应用到的对象,而我们通常是将其应用到Project对象上。 编写对象插件常见创建方式
MP4视频文件封装格式是基于QuickTime容器格式定义的,因此参考QuickTime的格式定义对理解MP4文件格式很有帮助。MP4文件格式是一个十分开放的容器,几乎可以用来描述所有的媒体结构,MP4文件中的媒体描述与媒体数据是分开的,并且媒体数据的组织也很自由,不一定要按照时间顺序排列,甚至媒体数据可以直接引用其他文件。同时,MP4也支持流媒体。MP4目前被广泛用于封装h.264视频和AAC音频,是高清视频的代表。MP4格式的官方文件后缀名是“.mp4”,还有其他的以mp4为基础进行的扩展或者是缩水版本的格式,包括:M4V, 3GP, F4V等。
opus_encoder_get_size()返回编码器状态要求的大小。注意,这段代码的未来版本可能改变大小,所以没有assuptions应该对它做出。编码器状态在内存中总是连续,复制它只要一个浅拷贝就足够了。使用opus_encoder_ctl()接口可以改变一些编码器的参数设置。所有这些参数都已有缺省值,所以只在必要的情况下改变它们。
Opus编解码器是专门设计用于互联网的交互式语音和音频传输。它是由IETF的编解码器工作组设计的,合并了Skype的SILK和Xiph. Org的CELT技术。
信息论的观点来看,描述信源的数据是信息和数据冗余之和,即:数据=信息+数据冗余。音频信号在时域和频域上具有相关性,也即存在数据冗余。将音频作为一个信源,音频编码的实质是减少音频中的冗余。自然界中的声音非常复杂,波形极其复杂,通常我们采用的是脉冲代码调制编码,即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。
评估音频编码指标,除码率、采样率、和算法延迟以外,还要参考MOS、VBR/CBR、和基础算法等。其中,MOS(Mean OpinionScore)是语音编解码器的主观评估指标。MOS是一个广为接受的有统计意义的主观听音指标。上面音视频编解码器的列表没有把它包含进去,是因为同一个编解码器,在不同码率下,表现出来的MOS值是会变化的。对一个音频编解码器给出一个固定的MOS值,反而会起误导的作用。另外,虽然MOS值已经是主观的听觉测试评估结果,但是音频工程师在选用音频编解码器的时候,还要以自己亲身的听感作为最终的依据。
FLV(Flash Video)是现在非常流行的流媒体格式,由于其视频文件体积轻巧、封装播放简单等特点,使其很适合在网络上进行应用,目前主流的视频网站无一例外地使用了FLV格式。另外由于当前浏览器与Flash Player紧密的结合,使得网页播放FLV视频轻而易举,也是FLV流行的原因之一。