Reputation: 51
I am new to GStreamer and trying to create a simple example where I am getting video from the webcam and saving it using filesink. I have added a watch on bus to get EOS event but it never gets executed. Could somebody tell me what am I doing wrong here and how can I stop pipeline and get EOS Event working?
import gi import time
gi.require_version('Gst', '1.0') gi.require_version('Gtk', '3.0')
from gi.repository import GObject, Gst, Gtk import signal
Gst.init(None)
class Main: def init(self): signal.signal(signal.SIGINT, self.keyboardInterruptHandler)
self._pipeline = Gst.parse_launch("avfvideosrc name=avfvideosrc ! x264enc ! queue ! mp4mux ! filesink name=filesink location=output.mp4")
bus = self._pipeline.get_bus()
bus.add_signal_watch()
bus.connect("message::eos", self._on_eos_from_sink_pipeline)
self._pipeline.set_state(Gst.State.PLAYING)
def _on_eos_from_sink_pipeline(self, _bus, _message):
print("Got EOS from sink pipeline")
def keyboardInterruptHandler(self,signal, frame):
print("KeyboardInterrupt (ID: {}) has been caught. Cleaning up...".format(signal))
self.stopFetching()
time.sleep(5)
exit()
def stopFetching(self):
print("AT THE START OF STOP FETCHING")
self._pipeline.set_state(Gst.State.NULL)
self._pipeline.send_event(Gst.Event.new_eos())
print("AT THE END OF STOP FETCHING")
start = Main() Gtk.main()
Upvotes: 2
Views: 1912
Reputation: 109
@ravi's answer above worked for me!
For C++ devs and also those who have the specific use case of using a muxer for combining audio and video onto a mp4 file, here is how I handled sending the EOS message:
std::string FlowyMedia::StopRecord()
{
if (m_record_pipeline == nullptr)
{
std::cerr << "MEDIA: record pipeline not initialized" << std::endl;
return std::string("");
}
std::cout << "Stopping record, sending eos" << std::endl;
GstElement *video_src = gst_bin_get_by_name(GST_BIN(m_record_pipeline), "videosrc");
g_assert(video_src);
GstElement *audio_src = gst_bin_get_by_name(GST_BIN(m_record_pipeline), "audiosrc");
g_assert(audio_src);
gst_element_send_event(video_src, gst_event_new_eos());
gst_element_send_event(audio_src, gst_event_new_eos());
// get full path to file
return std::string("./test.mp4");
}
I then have this as my bus watcher callback. The set_state for the EOS case is what properly stops my pipeline and finishes writing to a proper mp4 file.
gboolean FlowyMedia::HandleGstMessage(GstBus* bus, GstMessage* message, gpointer user_data)
{
switch (GST_MESSAGE_TYPE(message))
{
case GST_MESSAGE_EOS:
{
g_print("End of stream message received \n");
gst_element_set_state(GST_ELEMENT(user_data), GST_STATE_NULL);
break;
}
case GST_MESSAGE_WARNING:
{
gchar* debug;
GError* error;
gst_message_parse_warning(message, &error, &debug);
g_printerr(
"WARNING from element %s: %s\n", GST_OBJECT_NAME(message->src), error->message);
g_printerr("Warning details: %s\n", debug);
g_free(debug);
g_error_free(error);
break;
}
case GST_MESSAGE_ERROR:
{
gchar* debug;
GError* error;
gst_message_parse_error(message, &error, &debug);
g_printerr(
"ERROR from element %s: %s\n", GST_OBJECT_NAME(message->src), error->message);
g_printerr("Error details: %s\n", debug);
g_free(debug);
g_error_free(error);
break;
}
default:
break;
}
return GST_BUS_PASS;
}
Upvotes: 2
Reputation: 51
Answering my own question. the solution is to send the EOS event only to the src element, not to every element in the pipeline or to pipeline
Upvotes: 3