热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

英语流利说Android音视频处理相关实践与优化

前言:移动互联网的火爆改变了人们一系列的生活方式,从社交、购物、教育等方方面面渗透进大众的生活,移动端的迅速崛起和高速发展离不开移动端背后的技术演进和迭代,产品更新迭代过


前言:

移动互联网的火爆改变了人们一系列的生活方式,从社交、购物、教育等方方面面渗透进大众的生活,移动端的迅速崛起和高速发展离不开移动端背后的技术演进和迭代,产品更新迭代过程中如何优化它的性能?实际实践中遇到的坑又该如何处理?本文是根据七牛架构师实践日上海站,英语流利说Android 端开发人员王聪武的演讲内容进行整理,介绍了英语流利说移动应用在Android音视频处理相关实践。



英语流利说 APP 有一个配音功能,功能简而言之就是将一系列录音片段和视频背景声做混合,最后合成输出视频。本次分享『音视频相关的实践与优化』主要讲得就是对功能实现与优化的一个过程,就此分享出来希望对大家有所帮助。


一、方案的考量指标

实现功能需要选择方案,选择方案需要确立对应的指标。就此归纳了如下四个指标。

内存占用:

Android App 的内存占用一般分两种 Java Heap 和 Native Heap,可以采用 Android Monitor 和 GT 来看,也可以自己动手通过 Android Api 周期性采集数据。

执行耗时: 

方法耗时的统计通用的做法就是打 log 记录耗时。倘若想要整体了解一系列耗时,其中 Java 层可以用 Device Monitor 提供的 method profiling,native 可以采用 valgrind。

代码大小:

一般自己实现的代码量有限,这里指特指方案依赖 Library 的大小。library 的种类也一般分两种. jar 与 .so。jar 的大小会影响 dex method count,method count 过大不仅 Apk 会变大,也会影响运行时性能。so 的问题则是,需要多种 cpu 架构会让 so 的大小成倍放大,最终导致 Apk 急剧膨胀。

复杂度:

包含两个考量点,一是开发语言,java 与 c/c++ 的选择,一般情况下后者会更加复杂。  二是实现的代码量,实现所需的代码量一般越短越易于理解与维护。


二、方案优化的方法

代码指令上面的优化:一般可以选取更合适的算法或者内存占用更少的数据结构,如果是 native 层可以试试 neon 指令有没有帮助。

预处理:把原先需要客户端及时处理生成的,交给服务单预先生成好,提前下发客户端避免客户端处理耗时,空间换时间。

后台处理:也是预处理一种,区别在于这个预处理是客户端将任务放在后台预处理,当需要用到相关数据的时候,可以 join 这个后台任务

不完美的替代方案:曲线优化选用一个性能更好的近似方案来替代。


三、案例分析

案例一

0?wx_fmt=jpeg


配音第一步,需要将多段人声与背景音做混合。

0?wx_fmt=jpeg


第一个方案需要引入 AacEncoder Mp3Decoder FlacDecode,虽然有现成的实现,但是三者 api 接口不一致,有一定使用成本,并且在 java 层来做 mix 效率也不行,所以不考虑。第二个方案采用 ffmpeg命令行的方式调用,会因为命令的不灵活无法一条命令完成,需要产生一些中间文件,导致产生很多多余步骤。第三个方案采用 Sox/libSox 来,Sox 被称为音频处理的瑞士军刀,专注于音频领域,整个项目代码量不大能够通读了解以便定制开发。针对这个功能参考 Sox 中 mix 的实现调用 libSox 来实现 mix 即可。

0?wx_fmt=jpeg


libSox 中定义支持编解码的支持很简单,只需要在 soxconfig.h 开启配置,并且将相对应的 编解码库挂载编译即可,而后 libSox 则会通过统一的封装自动处理编码解码。


0?wx_fmt=jpeg


libSox 将音频处理抽象成添加 effect,将多个 effect 添加到 chain 上处理即可。其中 input_combiner_effect_fn 会提供读取输入文件进行 mix的 effect,而 output_aac_effect_fn 则会提供输出到 aac 文件的 effect。( aac 在 libSox 里面的实现是依赖 ffmpeg 的,所以需要手工引入编码器,自定义 effect 来做输出处理)


0?wx_fmt=jpeg


effect_hanlder 将音频处理抽象出 start drain stop 这几个阶段,libSox 会将数据流依次流经这几个 callback 进行处理。


0?wx_fmt=jpeg


这里 mix 操作是将音频 sample 进行加和进行处理。在 combinder_drain 中将 ibuf 中的音频进行加和后输出到 obuf 即可。


0?wx_fmt=jpeg


针对于 mix 这个场景主要耗时分布在 IO 读写文件、编解码文件、mix 操作。先针对 mix 操作进行优化,会发现 在 combinder_drain 中我们对音频进行加和,将 sample 转成 double 后进行处理的方式是有优化空间的。可以采用 Neon 指令中 VQADDS32 指令,该指令会自动对溢出进行处理,避免原先需要转换成浮点型进行计算,并且在计算后还需要比较是否有溢出。用 neon 实现替换后,会发现对应的汇编指令少了不少,并且整体 mix 的操作耗时减少了 10%-20%左右。

案例二

0?wx_fmt=jpeg


配音第二步骤,需要将处理完的音频 mux 到视频上。mux 也有两个方案,一是 Java 的 Mp4parser 二是 ffmpeg。


0?wx_fmt=jpeg


首先比较一下Mp4Parser和FFmpeg的代码库大小,前者大小会小很多。当然此处 ffmpeg 这个尺寸大小是因为没有经过细致裁剪导致的,如果支持 mux 可能只需要 几百kb,但是因为 so 的大小和支持的 cpu 架构有关,所以整体上的大小肯定是 ffmpeg 大的。


0?wx_fmt=jpeg


然后再对比一下性能。发现首次调用的时候两者耗时差距比较大,在多次调用后差距逐渐缩小。就此倘若解决这个首次调用的耗时问题,选用 mp4parse 也未尝不可。


0?wx_fmt=jpeg


使用 Method Profiling 对 mp4parse 的调用进行分析,会发现首次运行主要耗时在 getResourceAsStream 这个方法,而 getResourceAsStream 这个方法在 Android 上的实现非常慢。所以解决这个问题也很简单,参照 jodatime-android 的实现,用 android get resource 的方式即可。


案例三

0?wx_fmt=jpeg


Mix+Mux 的耗时是受到视频长度,音频长度影响的,所以总耗时无法控制,需要用进度动画来提示用户,但是这在一定程度上是打断用户操作。


0?wx_fmt=jpeg


就此曲线优化,在预览的时候并不合成,而是定制播放器来实现实时的预览。通过定制 exoPlayer 支持播放时指定外部音轨和 注入 MixAudioProcessor 来实现实时混合。


案例四


0?wx_fmt=gif


配音作品中加上了添加版权信息。


0?wx_fmt=jpeg


采用 ffmpeg 的实现,取视频最后一帧作为背景,并且动态生成版权消息绘制到图片上,最后将图片生成1.5s的视频,将这视频拼接到作品上即可。其中最后一帧图片的获取转为服务端生成下发,可以避免30%的耗时。


0?wx_fmt=jpeg


虽然以上优化减少了一定耗时,但是视频编码操作仍然非常耗时,所以采用 rxJava 提供的 BehaviorSubject 将生成操作提交交给后台进行预处理,而后将依赖于他的合成操作用 flatMap 串联即可。





推荐阅读
  • 在处理大图片时,PHP 常常会遇到内存溢出的问题。为了避免这种情况,建议避免使用 `setImageBitmap`、`setImageResource` 或 `BitmapFactory.decodeResource` 等方法直接加载大图。这些函数在处理大图片时会消耗大量内存,导致应用崩溃。推荐采用分块处理、图像压缩和缓存机制等策略,以优化内存使用并提高处理效率。此外,可以考虑使用第三方库如 ImageMagick 或 GD 库来处理大图片,这些库提供了更高效的内存管理和图像处理功能。 ... [详细]
  • javax.mail.search.BodyTerm.matchPart()方法的使用及代码示例 ... [详细]
  • 解决Only fullscreen opaque activities can request orientation错误的方法
    本文介绍了在使用PictureSelectorLight第三方框架时遇到的Only fullscreen opaque activities can request orientation错误,并提供了一种有效的解决方案。 ... [详细]
  • 零拷贝技术是提高I/O性能的重要手段,常用于Java NIO、Netty、Kafka等框架中。本文将详细解析零拷贝技术的原理及其应用。 ... [详细]
  • 基址获取与驱动开发:内核中提取ntoskrnl模块的基地址方法解析
    基址获取与驱动开发:内核中提取ntoskrnl模块的基地址方法解析 ... [详细]
  • JVM参数设置与命令行工具详解
    JVM参数配置与命令行工具的深入解析旨在优化系统性能,通过合理设置JVM参数,确保在高吞吐量的前提下,有效减少垃圾回收(GC)的频率,进而降低系统停顿时间,提升服务的稳定性和响应速度。此外,本文还将详细介绍常用的JVM命令行工具,帮助开发者更好地监控和调优JVM运行状态。 ... [详细]
  • 深入解析零拷贝技术(Zerocopy)及其应用优势
    零拷贝技术(Zero-copy)是Netty框架中的一个关键特性,其核心在于减少数据在操作系统内核与用户空间之间的传输次数。通过避免不必要的内存复制操作,零拷贝显著提高了数据传输的效率和性能。本文将深入探讨零拷贝的工作原理及其在实际应用中的优势,包括降低CPU负载、减少内存带宽消耗以及提高系统吞吐量等方面。 ... [详细]
  • 在Android平台上利用FFmpeg的Swscale组件实现YUV与RGB格式互转
    本文探讨了在Android平台上利用FFmpeg的Swscale组件实现YUV与RGB格式互转的技术细节。通过详细分析Swscale的工作原理和实际应用,展示了如何在Android环境中高效地进行图像格式转换。此外,还介绍了FFmpeg的全平台编译过程,包括x264和fdk-aac的集成,并在Ubuntu系统中配置Nginx和Nginx-RTMP-Module以支持直播推流服务。这些技术的结合为音视频处理提供了强大的支持。 ... [详细]
  • 如果应用程序经常播放密集、急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了。因为MediaPlayer存在如下缺点:1)延时时间较长,且资源占用率高 ... [详细]
  • 本文将带你快速了解 SpringMVC 框架的基本使用方法,通过实现一个简单的 Controller 并在浏览器中访问,展示 SpringMVC 的强大与简便。 ... [详细]
  • DAO(Data Access Object)模式是一种用于抽象和封装所有对数据库或其他持久化机制访问的方法,它通过提供一个统一的接口来隐藏底层数据访问的复杂性。 ... [详细]
  • 大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式
    大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式 ... [详细]
  • 在PHP中如何正确调用JavaScript变量及定义PHP变量的方法详解 ... [详细]
  • 本文详细解析了客户端与服务器之间的交互过程,重点介绍了Socket通信机制。IP地址由32位的4个8位二进制数组成,分为网络地址和主机地址两部分。通过使用 `ipconfig /all` 命令,用户可以查看详细的IP配置信息。此外,文章还介绍了如何使用 `ping` 命令测试网络连通性,例如 `ping 127.0.0.1` 可以检测本机网络是否正常。这些技术细节对于理解网络通信的基本原理具有重要意义。 ... [详细]
  • 深入解析十大经典排序算法:动画演示、原理分析与代码实现
    本文深入探讨了十种经典的排序算法,不仅通过动画直观展示了每种算法的运行过程,还详细解析了其背后的原理与机制,并提供了相应的代码实现,帮助读者全面理解和掌握这些算法的核心要点。 ... [详细]
author-avatar
爱你116564
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有