ExoPlayer 漫谈之Sonic调整音量

2024-09-05 21:48

本文主要是介绍ExoPlayer 漫谈之Sonic调整音量,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

提一个问题:如何在播放视频的时候调整声音的大小?

我们使用Android手机播放视频的时候,发现声音大了,我们手动调低音量;发现声音小了,我们手动调高音量。

这个过程中,都要依赖手动,如果你在不断地刷短视频的时候,如果需要用户不断地手动调整音量键,那这个体验是不能忍受的。

这对我们提了一个要求:我们能在解码音频流的时候通过矩阵运算调整音频原始数据的大小,达到调整音量的目的?

这个思路是可行的,接下来我们分析一下声音的特征,进而给出如何做的方式。

声音的三个特征:

  • 音调:声音频率的高低叫做音调(Pitch),是声音的三个主要的主观属性,即音量(响度)、音调、音色(也称音品) 之一。表示人的听觉分辨一个声音的调子高低的程度。音调主要由声音的频率决定,同时也与声音强度有关
  • 响度:人主观上感觉声音的大小(俗称音量),由“振幅”(amplitude)和人离声源的距离决定,振幅越大响度越大,人和声源的距离越小,响度越大。(单位:分贝dB)
  • 音色:又称音品,波形决定了声音的音色。声音因不同物体材料的特性而具有不同特性,音色本身是一种抽象的东西,但波形是把这个抽象直观的表现。音色不同,波形则不同。典型的音色波形有方波,锯齿波,正弦波,脉冲波等。不同的音色,通过波形,完全可以分辨的。

声波的振幅表示声音的音量大小:

波长长短是衡量声音音调的因素:

音色主要和声波的波纹有关:

这儿我们要调整的是响度,就是调整声音的振幅,学过矩阵运算的同学都知道,声音振幅的调整通过简单的矩阵运算就能实现。 这儿先推荐一下ijkplayer调整声音的做法: ijkplayer 开源项目分析(十二)filter改变声音音量 这是ffmpeg提供的做法,通过在filter中传入af : volume=3dB 来动态调整音量的目的。

借助ffmpeg的强大后盾,实现这个功能自然不难,但是一些使用MediaCodec的播放器,能实现这个功能吗? 我们要在ExoPlayer中实现动态调整声音振幅的功能。

DefaultAudioSink.java是ExoPlayer中播放音频的控制类。 其中提供了多种AudioProcessor来处理音频数据。 AudioProcessor中主要函数:

  AudioFormat configure(AudioFormat inputAudioFormat) throws UnhandledAudioFormatException;boolean isActive();void queueInput(ByteBuffer buffer);void queueEndOfStream();ByteBuffer getOutput();boolean isEnded();void flush();void reset();
复制代码
  • configure : 配置当前的AudioFormat
  • isActive : 当前的AudioProcessor是否可用
  • queueInput : 输入input buffer数据,这个ByteBuffer是原始数据
  • queueEndOfStream:当前队列中已经没有数据了
  • getOutput:处理完的ByteBuffer数据,送给DefaultAudioSink,开始AudioTrack播放
  • ChannelMappingAudioProcessor
  • FloatResamplingAudioProcessor:将24-bit和32-bit 的整型audio转化为32-bit的浮点型audio,整型和浮点型占用的位宽不一样,浮点型表现出现的声音更加细腻
  • ResamplingAudioProcessor:将其他位数的audio数据重采样位16-bit的audio数据
  • SilenceSkippingAudioProcessor:跳过静音部分
  • TeeAudioProcessor
  • TrimmingAudioProcessor

SonicAudioProcessor很重要了,倍速和调整声音振幅都依赖他。SonicAudioProcessor是根据Sonic算法来调整pitch、speed、volume变化时的声音处理。

我们这里只谈如何调整声音振幅: https://github.com/JeffMony/PlayerSDK/commit/ed9c12f169bb2bdd62978e7fecbfcb0972ece234

  private void processStreamInput() {// Resample as many pitch periods as we have buffered on the input.int originalOutputFrameCount = outputFrameCount;float s = speed / pitch;float r = rate * pitch;if (s > 1.00001 || s < 0.99999) {changeSpeed(s);} else {copyToOutput(inputBuffer, 0, inputFrameCount);inputFrameCount = 0;}if (r != 1.0f) {adjustRate(r, originalOutputFrameCount);}if(volume != 1.0f) {// Adjust output volume.scaleSamples(outputBuffer, originalOutputFrameCount, outputFrameCount - originalOutputFrameCount,volume);}}private void scaleSamples(short samples[],int position,int numSamples,float volume) {int fixedPointVolume = (int)(volume * 4096.0f);int start = position * channelCount;int stop = start + numSamples * channelCount;for(int xSample = start; xSample < stop; xSample++) {int value = (samples[xSample] * fixedPointVolume) >> 12;if(value > 32767) {value = 32767;} else if(value < -32767) {value = -32767;}samples[xSample] = (short)value;}}
复制代码

这里的volume是更新振幅的倍数。例如volume=1.2f,将振幅从原来的值调整为1.2倍。

声音的分贝如何计算? result = 20 * log(Cur/Max) Cur表示当前振幅 Max表示最大振幅 所以声音的分贝总是负的(Android平台下是的)。 volume(dB) = 20 * log(Cur / Max)

  • volume 表示计算出来的分贝值
  • Max表示最大振幅
  • Cur表示当前振幅

输入的参数有两个: MeanVolume , BaseVolume

  • MeanVolume: 平均分贝
  • BaseVolume: 基准分贝
BaseVolume - MeanVolume = result
20*log(CurBase/Max) - 20*log(Cur/Max) = result
20*log(CurBase/Cur)=result
CurBase/Cur = 10^(result/20)
CurBase = Cur * 10^(result/20)
复制代码

我们最终关注的是 (10^(result/20))

如果要设置到ExoPlayer中的数也是 (10^(result/20))

本文所讲源码均来自项目:https://github.com/JeffMony/PlayerSDK


作者:码上就说
链接:https://juejin.cn/post/6917227403207000078
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

这篇关于ExoPlayer 漫谈之Sonic调整音量的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1140154

相关文章

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

漫谈设计模式 [12]:模板方法模式

引导性开场 菜鸟:老大,我最近在做一个项目,遇到了点麻烦。我们有很多相似的操作流程,但每个流程的细节又有些不同。我写了很多重复的代码,感觉很乱。你有啥好办法吗? 老鸟:嗯,听起来你遇到了典型的代码复用和维护问题。你有没有听说过“模板方法模式”? 菜鸟:模板方法模式?没听过。这是什么? 老鸟:简单来说,模板方法模式让你在一个方法中定义一个算法的骨架,而将一些步骤的实现延迟到子类中。这样,你可

漫谈设计模式 [9]:外观模式

引导性开场 菜鸟:老鸟,我最近在做一个项目,感觉代码越来越复杂,我都快看不懂了。尤其是有好几个子系统,它们之间的调用关系让我头疼。 老鸟:复杂的代码确实让人头疼。你有没有考虑过使用设计模式来简化你的代码结构? 菜鸟:设计模式?我听说过一些,但不太了解。你觉得我应该用哪个模式呢? 老鸟:听起来你的问题可能适合用**外观模式(Facade Pattern)**来解决。我们可以一起探讨一下。

漫谈设计模式 [6]:适配器模式

引导性开场 菜鸟:老鸟,我最近在项目中遇到一个问题,我们的系统需要集成一个新的第三方库,但这个库的接口和我们现有的代码完全不兼容。我该怎么办? 老鸟:这是个常见的问题,很多开发者都会遇到这种情况。你有没有听说过适配器模式? 菜鸟:适配器模式?没有,能详细说说吗? 老鸟:当然可以!这就是我们今天要讨论的主题。适配器模式是一个设计模式,可以帮助我们解决你现在遇到的问题。 渐进式介绍概念 老

安卓实现弹出软键盘屏幕自适应调整

今天,我通过尝试诸多方法,最终实现了软键盘弹出屏幕的自适应。      其实,一开始我想通过EditText的事件来实现,后来发现,安卓自带的函数十分强大,只需几行代码,便可实现。实现如下:     在Manifest中设置activity的属性:android:windowSoftInputMode="adjustUnspecified|stateHidden|adjustResi

手机扬声器音量总是不够大?试试“扬声器助推器”吧

手机的扬声器音量总是不够大,尤其是在嘈杂的环境中,音乐和视频的声音总是不太清晰。直到我发现了这款“扬声器助推器”,我的手机音质瞬间提升了好几个档次。 软件简介: “扬声器助推器”利用先进的音频处理技术,能够提高手机扬声器的音量,让声音更加清晰响亮。此外,还可以设置最大允许增强量,避免音量过大损坏扬声器。 版本特点: 提升音量效果显著,音质清晰。可以自定义最大增强量,保护扬声器。 使用体

如何调整c盘分区大小,怎样把c盘空间调整小些

新买的笔记本电脑回来后发现电脑只分了C盘和D盘两个区,C盘就占了很大的空间,如何调整c盘分区大小,这样可以多腾些空间出来利用呢?虽然Win7有磁盘管理器可以压缩分区实现把C盘调小些,但是它的功能有限,压缩后也是很大一部分空间在C盘浪费,那怎样把c盘空间调整小些呢,下载我们介绍一个工具来完成这些复杂的动作:   1、下载安装分区助手DiskTool中文版。   在主界面上你可以看到C盘有60

java调整日期时间显示格式

SimpleDateFormat是一个以语言环境敏感的方式来格式化和分析日期的类。SimpleDateFormat允许你选择任何用户自定义日期时间格式来运行。 import java.util.*;import java.text.*;public class DateDemo {public static void main(String args[]) {Date dNow =

漫谈数仓五重奏

第一篇:漫谈数仓 什么是数据仓库?以下是百度百科的定义: 数据仓库,英文名称为Data Warehouse,可简写为DW或DWH。数据仓库,是为企业所有级别的决策制定过程,提供所有类型数据支持的战略集合。它是单个数据存储,出于分析性报告和决策支持目的而创建。为需要业务智能的企业,提供指导业务流程改进、监视时间、成本、质量以及控制。数据仓库的特征在于面向主题、集成性、稳定性和时变性。 从传统

Android12——Launcher3文件夹布局修改调整

文章声明:本文是笔者参考良心大佬作品后结合实际需求进行相应的定制,本篇主要是笔者记录一次解析bug笔记,文中可能会引用大佬文章中的部分图片在此声明,并非盈利目的,如涉嫌侵权请私信,谢谢! 大佬原文:安卓开发- 安卓13 Launcher3文件夹预览图、文件夹展开后布局修改-CSDN博客文章浏览阅读305次,点赞5次,收藏8次。Android 13 Launcher3 文件夹预览图标溢出、文件夹展