7

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

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

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

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

4

2 回答 2

17

我在某些设备上遇到了完全相同的问题。找到了一个修复,并认为我会分享。基本上这是@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
        }
    }


}

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

于 2013-12-17T23:50:48.633 回答
14

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

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

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

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

于 2013-04-07T16:01:24.167 回答