【问题标题】:SurfaceTexture.OnFrameAvailableListener stops being calledSurfaceTexture.OnFrameAvailableListener 停止被调用
【发布时间】:2012-12-20 13:47:59
【问题描述】:

我正在我的应用程序中实现 SurfaceTexture.OnFrameAvailableListener 接口,因此我可以将视频帧用作 OpenGL 纹理。一切都按应有的方式设置,并且运行良好,但是 onFrameAvailable(SurfaceTexture surfaceTexture) 在几秒钟后停止被调用,实际上并且似乎冻结了 OpenGL 中的视频,因为没有通过 SurfaceTexture.updateTextImage 上传新的纹理数据。

我在 onFrameAvailable 中设置了一个标志,以便仅在需要时从 GL 线程调用 updateTextImage。目前,我在每次绘制调用时都将标志设置为 true,以便在跳过 onFrameAvailable 检查时每帧上传视频纹理数据。像这样,一切都按原样运行,但似乎效率低下,因为如果仍然相同(电影帧)就不需要上传新的纹理数据。

AFAIK 没有内存泄漏,并且 logcat 没有显示任何错误。此外,媒体播放器设置为循环播放,但问题发生在单次运行完成之前。

什么会导致 onFrameAvailable 在几秒钟后不再被调用?

【问题讨论】:

    标签: android opengl-es


    【解决方案1】:

    我在某些设备上遇到了完全相同的问题。找到了一个修复,并认为我会分享。基本上这是@user2254894 的建议,除了因为计数器可以由2个不同的线程更改,所以使用2个不同的变量是个好主意。下面是一些示例代码:

    private int             _updateTexImageCounter = 0;
    private int             _updateTexImageCompare = 0;
    

    而且 onFrameAvailable() 很简单。

    @Override
    public void onFrameAvailable(SurfaceTexture surfaceTexture) 
    {
        // increment every time a new frame is avail
        _updateTexImageCounter++;
    }
    

    然后在您的 GL 更新中,您将执行以下操作...

    public void update() 
    {
    
        .... create texture... etc.
        ..
        // compare _updateTexImageCompare and _updateTexImageCounter
        if( _surfaceTexture!=null && _updateTexImageCompare != _updateTexImageCounter ) 
        {
            // loop and call updateTexImage() for each time the onFrameAvailable() method was called below.
            while(_updateTexImageCompare != _updateTexImageCounter) {
                _surfaceTexture.updateTexImage();
                _surfaceTexture.getTransformMatrix(x);
    
                _updateTexImageCompare++;  // increment the compare value until it's the same as _updateTexImageCounter
            }
        }
    
    
    }
    

    这对我有用。让我知道是否有更好的方法。

    【讨论】:

    • 哇。这修复了一个甚至存在于原始 Android 代码中的错误。 (即:MediaCodec 的 CTS)
    • @LéonPelletier 很高兴有帮助。
    【解决方案2】:

    我刚刚看到了一个类似的问题,并对其进行了调试。我和你一样,有一个布尔标志,表明一个(或多个!)帧已准备好使用。

    当我在一对 OpenGL 帧之间收到两个相机帧时出现问题(可能是因为我的 OpenGL 重绘处理太慢了)。这意味着我设置了两次布尔标志。但是,我随后只读取了一次该帧数据,并且似乎 updateTexImage 实现了某种排队功能。

    用未决摄像机帧的整数计数器替换布尔标志为我解决了这个问题。也许这也适合你?

    (我怀疑这比每帧调用 updateTexImage 更有效。至少在我的代码中,很少有(1-2%)OpenGL 帧需要足够长的时间来跨越两个相机帧。)

    【讨论】:

    • 感谢您的调试工作。似乎为解码分配了有限数量的缓冲区,并且调用 onFrameAvailable() 会检出一个缓冲区,并且仅通过调用 updateTexImage() 将该缓冲区检入可用池中。文档中没有的关键事实!
    • @bleater - 您上面的评论是我最终需要了解我的特定问题的线索。我试图忽略一些框架以产生口吃效果,当我不画框架时,我会停止获取新框架。你的回答让我明白了为什么。
    • 感谢您的工作,它节省了我很多时间。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-13
    相关资源
    最近更新 更多