You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用MediaCodec时崩溃:native_window_api_connect返回-19设备不存在错误

解决MediaCodec配置时的native_window_api_connect returned an error: No such device (-19)崩溃问题

这个-19错误(对应Linux系统的ENODEV错误码)我之前在高通设备上碰到过好几次,本质是MediaCodec无法正常连接到你传入的Surface对象,结合你的日志和代码,我整理了几个最可能的原因和对应的解决办法:

1. 传入的Surface已经失效或状态异常

从日志里看到D/SVPlayerView: onSurfaceTextureAvailable width 1080 h,但很可能在调用createVideoDecoder时,Surface已经因为页面生命周期变化(比如Activity暂停、SurfaceTexture被销毁)变得无效了。

解决思路:

  • 严格绑定解码器的生命周期和Surface:在onSurfaceTextureAvailable回调触发后再初始化解码器,在onSurfaceTextureDestroyed回调中立即停止并释放解码器资源,避免持有无效的Surface引用。
  • 在调用configure前先检查Surface有效性:添加((Surface) surface).isValid()判断,如果Surface无效就直接返回,不要继续执行配置逻辑。

2. SPS/PPS数据处理可能存在问题

你的代码手动给SPS/PPS添加了0,0,0,1的起始码,虽然这是H.264的标准起始码,但部分设备的硬件解码器可能期望原始的、不带起始码的NAL单元数据;或者传入的SPS/PPS本身就有截断、格式错误的问题。

解决思路:

  • 尝试去掉手动添加的起始码,直接将原始的sps/pps字节数组放入csd-0和csd-1中:
    // 替换原来的ByteBuffer处理逻辑
    mFormat.setByteBuffer("csd-0", ByteBuffer.wrap(sps));
    mFormat.setByteBuffer("csd-1", ByteBuffer.wrap(pps));
    
  • 验证SPS/PPS数据的正确性:可以打印它们的十六进制值,对比标准H.264的SPS结构,确保数据没有损坏。

3. 高通硬件解码器的兼容性坑

日志里显示用的是OMX.qcom.video.decoder.avc(高通硬件解码器),部分高通机型在处理特定分辨率(比如奇数分辨率)、特殊编码参数的视频时,会出现这种配置失败的问题。

解决思路:

  • 增加软件解码器作为降级方案:当硬件解码器配置失败时,自动切换到软件解码器。可以通过遍历MediaCodec列表找到软件解码器:
    private MediaCodec getSoftwareAvcDecoder() {
        MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
        for (MediaCodecInfo codecInfo : codecList.getCodecInfos()) {
            if (!codecInfo.isEncoder() && codecInfo.getName().contains("avc") && codecInfo.isSoftwareOnly()) {
                try {
                    return MediaCodec.createByCodecName(codecInfo.getName());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
    
  • 检查视频宽高是否符合设备支持范围:通过MediaCodecInfo.CodecCapabilities查询硬件解码器支持的最大分辨率,避免传入超出范围的参数。

4. 线程同步问题

从日志的线程信息来看,createVideoDecoder可能在后台线程调用,但Surface的初始化是在主线程的onSurfaceTextureAvailable回调中完成的,存在线程同步问题——可能Surface还没完全初始化好,就被传入解码器进行配置了。

解决思路:

  • 确保解码器的创建和配置操作在onSurfaceTextureAvailable的同一个线程中执行,或者用Handler.post将配置逻辑post到主线程执行,保证Surface已经完全就绪。
  • 避免在多个线程中同时操作MediaCodec或Surface对象,解码器的创建、配置、启动流程要在同一个线程中完成。

针对你的代码的具体修改建议

我给你的createVideoDecoder方法加了几个关键的防护和降级逻辑,你可以参考:

public boolean createVideoDecoder(Object surface, int width, int height, byte[] sps, byte[] pps) {
    Log.i(TAG,"createVideoDecoder");
    // 先检查Surface有效性
    if (!(surface instanceof Surface) || !((Surface) surface).isValid()) {
        Log.e(TAG, "Invalid or null Surface");
        return false;
    }

    mFormat = new MediaFormat();
    mFormat.setString(MediaFormat.KEY_MIME, "video/avc");
    mFormat.setInteger(MediaFormat.KEY_WIDTH, width);
    mFormat.setInteger(MediaFormat.KEY_HEIGHT, height);
    // 尝试直接使用原始SPS/PPS,不添加起始码
    mFormat.setByteBuffer("csd-0", ByteBuffer.wrap(sps));
    mFormat.setByteBuffer("csd-1", ByteBuffer.wrap(pps));
    mFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);

    try {
        mCodec = MediaCodec.createDecoderByType("video/avc");
        if (mCodec == null) {
            return false;
        }
        mCodec.configure(mFormat, (Surface) surface, null, 0);
        mCodec.start();
        info = new BufferInfo();
    } catch (IOException e) {
        e.printStackTrace();
        return cleanupAndReturnFalse();
    } catch (MediaCodec.CodecException e) {
        Log.e(TAG, "Hardware codec configure failed: " + e.getMessage());
        // 尝试切换到软件解码器
        mCodec = getSoftwareAvcDecoder();
        if (mCodec == null) {
            return cleanupAndReturnFalse();
        }
        try {
            mCodec.configure(mFormat, (Surface) surface, null, 0);
            mCodec.start();
            info = new BufferInfo();
            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
            return cleanupAndReturnFalse();
        }
    }
    return true;
}

private boolean cleanupAndReturnFalse() {
    if (mCodec != null) {
        mCodec.release();
        mCodec = null;
    }
    return false;
}

private MediaCodec getSoftwareAvcDecoder() {
    MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
    for (MediaCodecInfo codecInfo : codecList.getCodecInfos()) {
        if (!codecInfo.isEncoder() && codecInfo.getName().contains("avc") && codecInfo.isSoftwareOnly()) {
            try {
                return MediaCodec.createByCodecName(codecInfo.getName());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return null;
}

内容的提问来源于stack exchange,提问作者CHUANGXIN LEE

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:10:10