Media3 ExoPlayer解码器初始化失败分析

1.问题发现

从日志中看DecoderInitializationException: Decoder init failed: c2.qti.avc.decoder,解码器初始化失败

ijkPlayer同样的媒资可以正常播放

sh 复制代码
candidate codec: c2.qti.avc.decoder rank=100
candidate codec: OMX.qcom.video.decoder.avc rank=800
candidate codec: c2.qti.avc.decoder.low_latency rank=100
candidate codec: OMX.qcom.video.decoder.avc.low_latency rank=700
candidate codec: c2.android.avc.decoder rank=100
candidate codec: OMX.google.h264.decoder rank=200
selected codec: OMX.qcom.video.decoder.avc rank=800

ijkPlayer从这些候选的解码器中选择了OMX.qcom.video.decoder.avc ==> 高通芯片硬件解码器

2.问题分析

直接定位到报错的地方

Java 复制代码
public abstract class MediaCodecRenderer extends BaseRenderer {
    public DecoderInitializationException(
        Format format,
        @Nullable Throwable cause,
        boolean secureDecoderRequired,
        MediaCodecInfo mediaCodecInfo) {
      this(
          "Decoder init failed: " + mediaCodecInfo.name + ", " + format,
          cause,
          format.sampleMimeType,
          secureDecoderRequired,
          mediaCodecInfo,
          (cause instanceof CodecException) ? ((CodecException) cause).getDiagnosticInfo() : null,
          /* fallbackDecoderInitializationException= */ null);
    }
}

往上走到maybeInitCodecWithFallback

Java 复制代码
private void maybeInitCodecWithFallback(
    @Nullable MediaCrypto crypto, boolean mediaCryptoRequiresSecureDecoder)
    throws DecoderInitializationException, ExoPlaybackException {
  Format inputFormat = checkNotNull(this.inputFormat);
  if (availableCodecInfos == null) {
    try {
      //返回能够解码指定格式媒体的解码器列表,并按照优先级排序。  
      List<MediaCodecInfo> allAvailableCodecInfos =
          getAvailableCodecInfos(mediaCryptoRequiresSecureDecoder);
      availableCodecInfos = new ArrayDeque<>();
      //解码器初始化失败时启用回退到低优先级解码器的功能开关
      if (enableDecoderFallback) {
        availableCodecInfos.addAll(allAvailableCodecInfos);
      } else if (!allAvailableCodecInfos.isEmpty()) {
        availableCodecInfos.add(allAvailableCodecInfos.get(0));
      }
      preferredDecoderInitializationException = null;
    } catch (DecoderQueryException e) {
      throw new DecoderInitializationException(
          inputFormat,
          e,
          mediaCryptoRequiresSecureDecoder,
          DecoderInitializationException.DECODER_QUERY_ERROR);
    }
  }

  if (availableCodecInfos.isEmpty()) {
    throw new DecoderInitializationException(
        inputFormat,
        /* cause= */ null,
        mediaCryptoRequiresSecureDecoder,
        DecoderInitializationException.NO_SUITABLE_DECODER_ERROR);
  }

  ArrayDeque<MediaCodecInfo> availableCodecInfos = checkNotNull(this.availableCodecInfos);
  while (codec == null) {
    MediaCodecInfo codecInfo = checkNotNull(availableCodecInfos.peekFirst());
    if (!maybeInitializeProcessingPipeline(inputFormat)) {
      return;
    }
    if (!shouldInitCodec(codecInfo)) {
      return;
    }
    try {
      //初始化解码器  
      initCodec(codecInfo, crypto);
    } catch (Exception e) {
      Log.w(TAG, "Failed to initialize decoder: " + codecInfo, e);
      // This codec failed to initialize, so fall back to the next codec in the list (if any). We
      // won't try to use this codec again unless there's a format change or the renderer is
      // disabled and re-enabled.
      availableCodecInfos.removeFirst();
      DecoderInitializationException exception =
          new DecoderInitializationException(
              inputFormat, e, mediaCryptoRequiresSecureDecoder, codecInfo);
      onCodecError(exception);
      if (preferredDecoderInitializationException == null) {
        preferredDecoderInitializationException = exception;
      } else {
        preferredDecoderInitializationException =
            preferredDecoderInitializationException.copyWithFallbackException(exception);
      }
      if (availableCodecInfos.isEmpty()) {
        throw preferredDecoderInitializationException;
      }
    }
  }

  this.availableCodecInfos = null;
}

while (codec == null)会遍历availableCodecInfos获取解码器进行initCodec初始化,成功codec则不为空循环结束。

解码器初始化失败时启用回退到低优先级解码器的功能开关enableDecoderFallback默认false,availableCodecInfos只会取第一个。

3.问题处理

把上面的enableDecoderFallback设置为true,设置是否在解码器初始化失败时启用回退到低优先级解码器的功能。若启用,可能会使用性能较低的解码器。

Java 复制代码
DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(this);
//允许解码器回退,使用所有可用的解码器,以处理部分设备解码器初始化失败
renderersFactory.setEnableDecoderFallback(true);
 player = new ExoPlayer.Builder(this,renderersFactory)
          .build();
相关推荐
Tiny_React2 天前
使用 Claude Code Skills 模拟的视频生成流程
人工智能·音视频开发·vibecoding
hk112411 天前
【音视频/边缘计算】2025年度H.265/HEVC高并发解码与画质修复(Super-Resolution)基准测试报告(含沙丘/失控玩家核心样本)
ffmpeg·边缘计算·音视频开发·h.265·测试数据集
李小轰_Rex21 天前
把手机变成听诊器!摄像头 30 秒隔空测心率 - 开箱即用
android·音视频开发
李小轰_Rex22 天前
纯算法AEC:播录并行场景的回声消除实战笔记
android·音视频开发
否子戈23 天前
WebCut前端视频编辑UI框架一周开源进度
前端·音视频开发·ui kit
SHERlocked931 个月前
摄像头 RTSP 流视频多路实时监控解决方案实践
c++·后端·音视频开发
mortimer1 个月前
Python + FFmpeg 视频自动化处理指南:从硬件加速到精确剪辑
python·ffmpeg·音视频开发
否子戈1 个月前
做中国人自己的视频编辑UI框架,WebCut正式开源
前端框架·音视频开发·视频编码
音视频牛哥1 个月前
从低延迟到高可用:RTMP与 HTTP/HTTPS-FLV在App播放体系中的角色重构
人工智能·音视频·音视频开发·http-flv播放器·https-flv播放器·ws-flv播放器·wss-flv播放器
音视频牛哥2 个月前
轻量级RTSP服务的工程化设计与应用:从移动端到边缘设备的实时媒体架构
人工智能·计算机视觉·音视频·音视频开发·rtsp播放器·安卓rtsp服务器·安卓实现ipc功能