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_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 的代码来自找到的示例 here。我应该补充一点,该管道未在其他地方引用,我也不会在不检查它是否为 NULL 的情况下在任何地方访问它。
我不确定这是否相关,但 gstreamer 存在于它自己的使用 GMainLoop
的线程中。管道在此线程内创建,并在 GMainLoop
退出时释放。我认为 Android 上的 GLES 和线程是......棘手的,所以也许......?
无论如何,如果有人能提供帮助,我将不胜感激!如果您需要更多代码,请告诉我。
我的管道在错误的地方使用了队列(leaky=downstream),这以某种方式阻止了管道进入 PAUSED 状态(一些元素仍然处于 READY)。释放管道可能导致非法指针访问(可能在消息总线侦听器上),从而导致上述异常。
使用 GST_DEBUG_BIN_TO_DOT_FILE()
可视化管道有助于确定问题(参见 this link)。
我的应用程序有一个很奇怪的问题。计划是使用 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_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 的代码来自找到的示例 here。我应该补充一点,该管道未在其他地方引用,我也不会在不检查它是否为 NULL 的情况下在任何地方访问它。
我不确定这是否相关,但 gstreamer 存在于它自己的使用 GMainLoop
的线程中。管道在此线程内创建,并在 GMainLoop
退出时释放。我认为 Android 上的 GLES 和线程是......棘手的,所以也许......?
无论如何,如果有人能提供帮助,我将不胜感激!如果您需要更多代码,请告诉我。
我的管道在错误的地方使用了队列(leaky=downstream),这以某种方式阻止了管道进入 PAUSED 状态(一些元素仍然处于 READY)。释放管道可能导致非法指针访问(可能在消息总线侦听器上),从而导致上述异常。
使用 GST_DEBUG_BIN_TO_DOT_FILE()
可视化管道有助于确定问题(参见 this link)。