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();