我想使用ExoPlayer实现节拍匹配Crossfade功能。基本上,我对它应该如何工作有一个概念,但是我发现很难使其适应ExoPlayer。
首先,请允许我写出我想如何执行此操作,以便您了解情况。如您所知,Beat Matching Crossfade让我们从一首歌曲无缝切换到另一首歌曲。另外,它在淡入淡出期间将第二首歌曲的速度调整为第一首歌曲的速度。
所以我的计划如下:1.加载歌曲A和B,以便它们都开始缓冲。2.歌曲A和B的解码样本存储在缓冲区BF1和BF2中。3.会有一个称为MUX的类,它是一个主缓冲区,同时包含歌曲缓冲区BF1和BF2。MUX向播放器提供音频样本。提供给播放器的样本是BF1样本,或者是存在淡入淡出的BF1和BF2的混合样本。4.当缓冲区达到淡入淡出点时,会将样本发送到Analyzer类,以便它可以分析两个缓冲区中的样本并修改它们以进行淡入淡出。分析器将修改后的样本发送到MUX,MUX会更新其主缓冲区。淡入淡出完成后,请从播放列表加载下一首歌曲。
我的主要问题是如何混合两首歌曲,以便实现MUX之类的类。到目前为止,我所知道的是我可以在MediaCodecRender.processOutputBuffer()方法中访问解码的样本,因此从那时起,我可以创建BF1和BF2缓冲区。
还有一个想法是创建两个ExoPlayer实例,然后在播放第一首歌曲时分析第二首歌曲,并修改其样本以进行进一步淡入淡出,但我认为可能很难同步两个播放器,因此拍子会匹配。
在此先感谢您的帮助!
回答@David 关于交叉淡入淡出实现的问题,它看起来或多或少像这样。当您想要开始交叉淡入淡出时,您必须监听活动播放器的播放并调用此方法。它采用 RxJava,但可以轻松迁移到 Couroutines Flow。
fun crossfadeObservable(
fadeOutPlayer: Player?,
fadeInPlayer: Player,
crossfadeDurationMs: Long,
crossfadeScheduler: Scheduler,
uiScheduler: Scheduler
): Observable<Unit> {
val fadeInMaxGain = fadeInPlayer.audioTrack?.volume ?: 1f
val fadeOutMaxGain = fadeOutPlayer?.audioTrack?.volume ?: 1f
fadeOutPlayer?.enableAudioFocus(false)
fadeInPlayer.enableAudioFocus(true)
fadeInPlayer.playerVolume = 0f
fadeInPlayer.play()
fadeOutPlayer?.playerVolume = fadeOutMaxGain
fadeOutPlayer?.play()
val iterations: Float = crossfadeDurationMs / CROSSFADE_STEP_MS.toFloat()
return Observable.interval(CROSSFADE_STEP_MS, TimeUnit.MILLISECONDS, crossfadeScheduler)
.take(iterations.toInt())
.map { iteration -> (iteration + 1) / iterations }
.filter { percentOfCrossfade -> percentOfCrossfade <= 1f }
.observeOn(uiScheduler)
.map { percentOfCrossfade ->
fadeInPlayer.playerVolume = percentOfCrossfade.coerceIn(0f, fadeInMaxGain)
fadeOutPlayer?.playerVolume = (fadeOutMaxGain - percentOfCrossfade).coerceIn(0f, fadeOutMaxGain)
}
.last()
.doOnTerminate { fadeOutPlayer?.pause() }
.doOnUnsubscribe { fadeOutPlayer?.pause() }
}
Run Code Online (Sandbox Code Playgroud)
常量值 CROSSFADE_STEP_MS = 100L
归档时间: |
|
查看次数: |
352 次 |
最近记录: |