iOS / Objective C how to gracefully shutdown

David Walter d.walter at scewo.ch
Wed Jul 22 09:48:56 UTC 2020


Hello everyone

I have a simple use case where we just need a video feed which we
receive via udp. No scrubbing etc needed, just the video feed in real
time.
I can start the stream and it works as expected and I get the video
feed. But I can't get the code to stop when the app is entering the
background.
I have not found any solution to this problem in this list.

I suspect this has to do with my GStreamerBackend not cleaning up
properly. I have attached the source code that I use for starting and
stopping the stream.
It is heavily based on the iOS Tutorial 3, so the start and stop
functions are left like they are.

It streams like expected and I get a stable Videofeed that I can play
and pause. But when calling stop I get a BAD ACCESS. Namely in
'CA::Layer::retain_parent:'
For the layer I use the EaglUIView like in the Tutorial. The error
occurs when i stop the stream with

-(void) stop {
    if (main_loop) {
        g_main_loop_quit(main_loop);
    }
}

and the app enters the background. Any help would be much appreciated.

I'm using gstreamer 1.17.2 (because 1.16.4 had UI-manipulation from a
background thread that caused other issues)



My start_bus function below.


/* Main method for the bus monitoring code */

-(void) start_bus {
    GstBus *bus;
    GSource *bus_source;
    GError *error = NULL;
    GST_DEBUG ("Creating pipeline");

    /* Create our own GLib Main Context and make it the default one */
    context = g_main_context_new ();
    g_main_context_push_thread_default(context);

    /* Build pipeline */
    // ORIGINAL: "videotestsrc ! warptv ! videoconvert ! autovideosink"

    pipeline = gst_parse_launch("udpsrc multicast-group=224.1.1.1
auto-multicast=true port=1234 multicast-iface=wlp10s0 !
application/x-rtp,encoding-name=JPEG,payload=26 ! rtpjpegdepay !
jpegdec ! autovideosink", &error);

    if (error) {
        gchar *message = g_strdup_printf("Unable to build pipeline:
%s", error->message);
        g_clear_error (&error);
        [self gstreamerReceivedError:message];
        g_free (message);
        return;
    }


    /* Set the pipeline to READY, so it can already accept a window handle */
    gst_element_set_state(pipeline, GST_STATE_READY);
    video_sink = gst_bin_get_by_interface(GST_BIN(pipeline),
GST_TYPE_VIDEO_OVERLAY);

    if (!video_sink) {
        GST_ERROR ("Could not retrieve video sink");
        return;
    }
    gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink),
(guintptr) (id) ui_video_view);


    /* Instruct the bus to emit signals for each received message, and
connect to the interesting signals */
    bus = gst_element_get_bus (pipeline);
    bus_source = gst_bus_create_watch (bus);
    g_source_set_callback (bus_source, (GSourceFunc)
gst_bus_async_signal_func, NULL, NULL);
    g_source_attach (bus_source, context);
    g_source_unref (bus_source);
    g_signal_connect (G_OBJECT (bus), "message::error",
(GCallback)error_cb, (__bridge void *)self);
    g_signal_connect (G_OBJECT (bus), "message::state-changed",
(GCallback)state_changed_cb, (__bridge void *)self);
    gst_object_unref (bus);


    /* Create a GLib Main Loop and set it to run */
    GST_DEBUG ("Entering main loop...");
    main_loop = g_main_loop_new (context, FALSE);
    [self check_initialization_complete];
    g_main_loop_run (main_loop);
    GST_DEBUG ("Exited main loop");
    g_main_loop_unref (main_loop);
    main_loop = NULL;



    /* Free resources */
    g_main_context_pop_thread_default(context);
    g_main_context_unref (context);
    gst_element_set_state (pipeline, GST_STATE_NULL);
    gst_object_unref (pipeline);
    pipeline = NULL;
    gst_object_unref (video_sink);
    video_sink = NULL;

//  ##### I suspect I'm not cleaning up properly here. Ev some
callback cancelation is missing but I really can't figure out what
exactly. #####
//    g_signal_stop_emission_by_name(G_OBJECT (bus), "message::error");
//    g_signal_stop_emission_by_name(G_OBJECT (bus), "message::state-changed");
//    g_source_set_dummy_callback(bus_source);

    ui_delegate = NULL;
    ui_video_view = NULL;

    return;
}


More information about the gstreamer-devel mailing list