最近项目中在使用 ExoPlayer 来进行视频的播放,开发过程中遇到了部分视频打开后黑屏的问题,报错日志如下。
E Audio codec error android.media.MediaCodec$CodecException: Error 0xe
E Playback error androidx.media3.exoplayer.ExoPlaybackException: MediaCodecAudioRenderer error, index=1, format=Format(2, null, null, audio/mp4a-latm, mp4a.40.1, -1, und, [-1, -1, -1.0, null], [2, 44100]), format_supported=YES Caused by: androidx.media3.exoplayer.mediacodec.MediaCodecDecoderException: Decoder failed: c2.android.aac.decoder at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.createDecoderException(MediaCodecRenderer.java:976)
经过在网上的一番查找,发现是需要自行编译 ffmpeg 作为音频解码来使用的,具体可以参考这篇文章。
https://juejin.cn/post/7115987944099282952
但是有一点需要注意,文章里面使用的 ExoPlayer 现在(2024.3.3)google 已经迁移了这个项目到 androidx.media3 这个项目里了,所以编译时需要注意看一下代码中使用的版本是什么。
下面是 ExoPlayer 官方的教程
https://github.com/google/ExoPlayer/tree/r2.18.0/extensions/ffmpeg
这个是 Media3 的官方教程
https://github.com/androidx/media/tree/release/libraries/decoder_ffmpeg
官方文档里面也都是推荐使用 media3 了,毕竟后续的更新维护都会在这个项目上进行。
https://developer.android.com/media/media3/exoplayer/hello-world?hl=zh-cn
编译完成后,通过 android studio 打包出对应的 aar 文件即可,然后在代码中配置使用。下面代码就是使用方法,注释掉的是 exoplayer 2 的使用方式,剩下的是 media3 的方式。
//import static com.google.android.exoplayer2.DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
//
//import com.google.android.exoplayer2.DefaultRenderersFactory;
//import com.google.android.exoplayer2.Renderer;
//import com.google.android.exoplayer2.audio.AudioRendererEventListener;
//import com.google.android.exoplayer2.audio.AudioSink;
//import com.google.android.exoplayer2.ext.ffmpeg.FfmpegAudioRenderer;
//import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
import androidx.media3.decoder.ffmpeg.FfmpegAudioRenderer;
import androidx.media3.exoplayer.DefaultRenderersFactory;
import androidx.media3.exoplayer.Renderer;
import androidx.media3.exoplayer.audio.AudioRendererEventListener;
import androidx.media3.exoplayer.audio.AudioSink;
import androidx.media3.exoplayer.mediacodec.MediaCodecSelector;
import java.util.ArrayList;
@SuppressLint("UnsafeOptInUsageError")
class FfmpegRenderersFactory extends DefaultRenderersFactory {
/**
* @param context A {@link Context}.
*/
public FfmpegRenderersFactory(Context context) {
super(context);
setExtensionRendererMode(EXTENSION_RENDERER_MODE_ON);
}
@Override
protected void buildAudioRenderers(Context context, int extensionRendererMode, MediaCodecSelector mediaCodecSelector, boolean enableDecoderFallback, AudioSink audioSink, Handler eventHandler, AudioRendererEventListener eventListener, ArrayList out) {
out.add(new FfmpegAudioRenderer());
super.buildAudioRenderers(context, extensionRendererMode, mediaCodecSelector, enableDecoderFallback, audioSink, eventHandler, eventListener, out);
}
// public FfmpegRenderersFactory(Context context) {
// super(context);
// setExtensionRendererMode(EXTENSION_RENDERER_MODE_PREFER);
// }
//
//
//
// @Override
// protected void buildAudioRenderers(Context context, int extensionRendererMode,
// MediaCodecSelector mediaCodecSelector,
// boolean enableDecoderFallback, AudioSink audioSink,
// Handler eventHandler, AudioRendererEventListener
// eventListener, ArrayList out) {
// out.add(new FfmpegAudioRenderer());
//
// super.buildAudioRenderers(context, extensionRendererMode, mediaCodecSelector, enableDecoderFallback, audioSink, eventHandler, eventListener, out);
// }
}
接着在初始化的时候加入到构造函数中即可。
val player = ExoPlayer.Builder(this,FfmpegRenderersFactory(this)).build()