安卓系统上的gstreamer:取消刷新管道时出现异常



我的应用程序中出现了一个非常奇怪的问题。计划是使用gstreamer播放视频流并将其显示在SurfaceView上。管道使用glimagesink来显示视频。

当我的活动终止时,它会调用release_pipeline(将管道状态设置为GST_state_NULL,取消引用,将引用设置为NULL)。取消搜索导致了这个错误,我不知道是什么原因造成的:

 validate_display:211 error 3001 (EGL_NOT_INITIALIZED)

然后是segfault。该应用程序实际上在Android的Choreographer中崩溃了,但我不知道该怎么办。

SurfaceView位于Fragment内部,并具有回调,该回调在surfaceDestroyed中调用surface_release,在surfaceChanged中调用surface_update。回调添加在onCreateView中。我的对象保存在一个名为jnictx的extern结构中。这些功能定义为:

 void surface_release()
{
    if (jnictx->gst.pipeline != NULL)
    {
        GstElement* vsink = gst_bin_get_by_name(jnictx->gst.pipeline, "vr_sink");
        gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(vsink), (guintptr) NULL);
        gst_element_set_state(GST_ELEMENT(jnictx->gst.pipeline), GST_STATE_READY);
        gst_object_unref(vsink);
    }
    if (jnictx->gst.surface_win != NULL)
    {
        ANativeWindow_release(jnictx->gst.surface_win);
        jnictx->gst.surface_win = NULL;
    }
}
void surface_update(JNIEnv* env, jobject surface)
{
    ANativeWindow *new_window = ANativeWindow_fromSurface(env, surface);
    if (jnictx->gst.surface_win != NULL)
    {
        // Release the old reference
        ANativeWindow_release(jnictx->gst.surface_win);
        // The window did not change, just update the surface
        if (jnictx->gst.surface_win == new_window)
        {
            if (jnictx->gst.pipeline != NULL)
            {
                GstElement* vsink = gst_bin_get_by_name(jnictx->gst.pipeline, "vr_sink");
                // Supposedly we have to call this twice so the surface updates with the new values
                gst_video_overlay_expose(GST_VIDEO_OVERLAY(vsink));
                gst_video_overlay_expose(GST_VIDEO_OVERLAY(vsink));
                gst_object_unref(vsink);
            }
            // The window did not change, by unreffing it above we unreffed the
            // reference we acquired with ANativeWindow_fromSurface as well
            return;
        }
    }

    // If we reach this point the window changed and we have to set the new handle
    if (jnictx->gst.pipeline != NULL)
    {
        GstElement* vsink = gst_bin_get_by_name(jnictx->gst.pipeline, "vr_sink");
        jnictx->gst.surface_win = new_window;
        gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(vsink), (guintptr) new_window);
        gst_object_unref(vsink);
    }
}

设置glimagesink的代码来自这里的示例。我应该补充一点,该管道在其他地方没有被引用,在没有检查它是否为NULL的情况下,我也不会在任何地方访问它。

我不确定这是否相关,但gstreamer位于它自己的线程中,该线程使用GMainLoop。管道在该线程内创建,并在GMainLoop退出时释放。我认为Android上的GLES和线程。。。棘手,所以也许。。。?

不管怎样,如果有人能帮忙,我会非常感激的!如果你需要更多的代码,请告诉我。

我的管道在错误的位置使用了队列(leakak=下游),这以某种方式阻止了管道进入PAUSED状态(某些元素仍处于READY状态)。释放管道可能导致非法指针访问(可能在消息总线侦听器上),从而导致所述异常。

使用GST_DEBUG_BIN_TO_DOT_FILE()可视化管道有助于识别问题(请参阅此链接)。

最新更新