ExoPlayer 播放视频黑屏的解决方法

最近项目中在使用 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<Renderer> 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<Renderer> out) {
//          out.add(new FfmpegAudioRenderer());
//
//          super.buildAudioRenderers(context, extensionRendererMode, mediaCodecSelector, enableDecoderFallback, audioSink, eventHandler, eventListener, out);
//      }


}

接着在初始化的时候加入到构造函数中即可。

val player = ExoPlayer.Builder(this,FfmpegRenderersFactory(this)).build()
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
exoPlayer加载视频时出现黑屏是因为视频还没有加载完成,这是一个正常的现象。不过我们可以通过一些措施来减少黑屏时间,提高用户体验。 1. 设置预加载:使用exoPlayer的预加载功能可以在视频播放前就开始加载视频,这样可以减少黑屏时间。具体实现方式是使用ExoPlayer的prepare()方法,通过设置预加载的宽带和缓存大小来改善视频加载速度。可以参考以下代码: ``` DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter.Builder(context).build(); DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(context, Util.getUserAgent(context, "yourApp"), bandwidthMeter); Cache cache = new SimpleCache(context.getCacheDir(), new NoOpCacheEvictor()); CacheDataSourceFactory cacheDataSourceFactory = new CacheDataSourceFactory(cache, dataSourceFactory); ExtractorMediaSource mediaSource = new ExtractorMediaSource.Factory(cacheDataSourceFactory).createMediaSource(Uri.parse(videoUrl)); SimpleExoPlayer player = new SimpleExoPlayer.Builder(context).build(); player.prepare(mediaSource); ``` 在上面的代码中,我们使用了CacheDataSourceFactory来实现预加载。CacheDataSourceFactory是ExoPlayer的一个数据源工厂,它可以将视频数据加载到缓存中,从而提高视频播放速度。 2. 设置封面图:在视频加载期间,我们可以设置一个封面图来替代黑屏,这样可以提高用户体验。具体实现方式是使用ExoPlayer的PlayerView,通过设置PlayerView的默认封面图来实现。可以参考以下代码: ``` SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(context); playerView.setPlayer(player); // 设置默认封面图 playerView.setDefaultArtwork(BitmapFactory.decodeResource(getResources(), R.drawable.default_cover)); MediaSource mediaSource = new ExtractorMediaSource(Uri.parse(videoUrl), new DefaultDataSourceFactory(context, Util.getUserAgent(context, "yourApp")), new DefaultExtractorsFactory(), null, null); player.prepare(mediaSource); ``` 在上面的代码中,我们使用了PlayerView的setDefaultArtwork()方法来设置默认封面图。 3. 优化视频质量:如果视频的分辨率过高或码率过大,会导致视频加载时间过长,从而出现黑屏现象。因此,我们可以通过优化视频质量来减少黑屏时间。可以将视频的分辨率和码率适当调整,以提高视频加载速度。 这些措施可以帮助我们减少exoPlayer加载视频时出现黑屏的时间,提高用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值