On Wed, 4 May 2016, Christophe Fergeau wrote:
> On Wed, May 04, 2016 at 12:03:57PM +0200, Christophe Fergeau wrote:
> > Ugh that's bad :( Using gst_message_new_request_state() might avoid
> > this, but while the GstAppSink element is blocked waiting for data, I
> > don't know if state changes are going to be handled (ie I'm not sure
> > about GStreamer threading model and which thread the state change is
> > going to come from). I can try asking on #gstreamer if needed.
>
> Looking at the code, GST_MESSAGE_REQUEST_STATE_CHANGE does not seem to
> be used within GStreamer. GstBin looks at EOS message though from the
> thread GstBus runs in (I think), and GstAppSink also handles this
> message, so maybe we could use EOS to recover from errors?
I tried sending an EOS from handle_pipeline_message() but it does
not work.
Sending the EOS seems to work but then I get the following messages and
pull_buffer/pull_sample() never returns:
(Xorg:19764): Spice-WARNING **: gstreamer-encoder.c:809:handle_pipeline_message: GStreamer error from element encoder: Can not initialize x264 encoder.
gstreamer-encoder.c:809:handle_pipeline_message: GStreamer error from element encoder: Can not initialize x264 encoder.
gstreamer-encoder.c:811:handle_pipeline_message: debug details: gstx264enc.c(1269): gst_x264_enc_init_encoder (): /GstPipeline:pipeline3/GstX264Enc:encoder
[...]
(Xorg:19764): Spice-WARNING **: gstreamer-encoder.c:809:handle_pipeline_message: GStreamer error from element src: Internal data flow error.
gstreamer-encoder.c:809:handle_pipeline_message: GStreamer error from element src: Internal data flow error.
gstreamer-encoder.c:811:handle_pipeline_message: debug details: gstbasesrc.c(2625): gst_base_src_loop (): /GstPipeline:pipeline3/GstAppSrc:src:
streaming task paused, reason not-negotiated (-4)
[...]
0:00:00.736257174 19764 0x7f64807fd540 DEBUG basesink gstbasesink.c:2277:gst_base_sink_wait_preroll:<sink> waiting in preroll for flush or PLAYING
(full log at http://fgouget.free.fr/tmp/Xspice-eos.log.xz)
My understanding is that x264enc did not like the first frame, so the
pipeline remained in preroll, a state in which an EOS cannot be sent.
I also tried variants like sending a gst_event_new_flush_stop() event
but the send operation failed altogether (and had no effect obviously).
See the attachment for reference.
--
Francois Gouget <fgouget@xxxxxxxxxxxxxxx>
diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c
index c61afea..ba83ead 100644
--- a/server/gstreamer-encoder.c
+++ b/server/gstreamer-encoder.c
@@ -215,6 +215,32 @@ static void set_appsrc_caps(SpiceGstEncoder *encoder)
gst_app_src_set_caps(encoder->appsrc, encoder->src_caps);
}
+static GstBusSyncReply handle_pipeline_message(GstBus *bus, GstMessage *msg, gpointer video_encoder)
+{
+ SpiceGstEncoder *encoder = video_encoder;
+
+ if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
+ GError *err = NULL;
+ gchar *debug_info;
+ gst_message_parse_error(msg, &err, &debug_info);
+ spice_warning("GStreamer error from element %s: %s",
+ GST_OBJECT_NAME(msg->src), err->message);
+ if (debug_info) {
+ spice_debug("debug details: %s", debug_info);
+ g_free(debug_info);
+ }
+ g_clear_error(&err);
+
+ /* Unblock the main thread which may be stuck calling gst_app_sink_pull_sample() */
+ spice_debug("sending event");
+ gboolean success = gst_element_send_event(GST_ELEMENT(encoder->pipeline), gst_event_new_eos());
+ //gboolean success = gst_element_send_event(GST_ELEMENT(encoder->pipeline), gst_event_new_flush_stop());
+ //gboolean success = gst_element_send_event(GST_ELEMENT(encoder->pipeline), gst_event_new_seek(1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_SET, 0));
+ spice_debug("event sent: %d", success);
+ }
+ return GST_BUS_PASS;
+}
+
static int physical_core_count = 0;
static int get_physical_core_count(void)
{
@@ -294,6 +320,15 @@ static gboolean create_pipeline(SpiceGstEncoder *encoder)
encoder->gstenc = gst_bin_get_by_name(GST_BIN(encoder->pipeline), "encoder");
encoder->appsink = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(encoder->pipeline), "sink"));
+ /* Hook into the bus so we can handle errors */
+ GstBus *bus = gst_element_get_bus(encoder->pipeline);
+#ifdef HAVE_GSTREAMER_0_10
+ gst_bus_set_sync_handler(bus, handle_pipeline_message, encoder);
+#else
+ gst_bus_set_sync_handler(bus, handle_pipeline_message, encoder, NULL);
+#endif
+ gst_object_unref(bus);
+
if (encoder->base.codec_type == SPICE_VIDEO_CODEC_TYPE_MJPEG) {
/* See https://bugzilla.gnome.org/show_bug.cgi?id=753257 */
spice_debug("removing the pipeline clock");
@@ -340,6 +375,7 @@ static gboolean configure_pipeline(SpiceGstEncoder *encoder)
return TRUE;
}
+ spice_debug("start...");
/* If the pipeline state does not need to be changed it's because it is
* already in the PLAYING state. So first set it to the NULL state so it
* can be (re)configured.
@@ -368,6 +404,7 @@ static gboolean configure_pipeline(SpiceGstEncoder *encoder)
return FALSE;
}
+ spice_debug("done");
encoder->set_pipeline = 0;
return TRUE;
}
@@ -562,7 +599,9 @@ static int spice_gst_encoder_encode_frame(VideoEncoder *video_encoder,
int rc = push_raw_frame(encoder, bitmap, src, top_down);
if (rc == VIDEO_ENCODER_FRAME_ENCODE_DONE) {
+ spice_debug("calling pull_compressed_buffer");
rc = pull_compressed_buffer(encoder, outbuf);
+ spice_debug("pull_compressed_buffer returned %d", rc);
if (rc != VIDEO_ENCODER_FRAME_ENCODE_DONE) {
/* The input buffer will be stuck in the pipeline, preventing
* later ones from being processed. Furthermore something went
_______________________________________________
Spice-devel mailing list
Spice-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/spice-devel