Android 上的 gstreamer:取消引用管道时出现异常?

gstreamer on Android: exception when unrefing pipeline?

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

当我的 activity 终止时,它调用 release_pipeline(将管道状态设置为 GST_STATE_NULL,取消引用,将我的引用设置为 NULL)。取消引用导致此错误,我不知道是什么原因造成的:

 validate_display:211 error 3001 (EGL_NOT_INITIALIZED)

后跟一个段错误。该应用程序实际上在 Android 的 Choreographer 中崩溃了,但我不知道从那里去哪里。

SurfaceView 存在于 Fragment 中并有一个回调,它在 surfaceDestroyed 中调用 surface_release 并在 surfaceChanged 中调用 surface_updateonCreateView 中添加了回调。 我的对象保存在一个名为 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 的代码来自找到的示例 here。我应该补充一点,该管道未在其他地方引用,我也不会在不检查它是否为 NULL 的情况下在任何地方访问它。

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

无论如何,如果有人能提供帮助,我将不胜感激!如果您需要更多代码,请告诉我。

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

使用 GST_DEBUG_BIN_TO_DOT_FILE() 可视化管道有助于确定问题(参见 this link)。