About loop/segment play
Hi all. I'm experimenting with gstreamer segment seek to play a short file section in loop seamlessly, but it seems to work only when using a pipeline with a single 'playbin' element. This is the sequence of steps I do in the code to loop a file from 20s to 24s: 1. setup pipeline 2. set to playing state 3. in the first ASYNC_DONE callaback do a segment seek from 20s to 24s 4. on every consequent SEGMENT_DONE signal repeat the seek till EOF This seems to work fine for the simple pipeline with only 'playbin' element. (0 branch of the #ifdef macro) When building a little more complex pipeline with a 'filesrc' a 'decodebin' and a couple o queues elements the GST_SEGMENT* signals are never fired. (1 branch of the #ifdef macro). The seek to the 20s mark is correctly performed, but when play time reaches the 24s mark I get an EOF instead of a SEGMENT_DONE signal. Am I I missing something obvious ? I've read a lot of documentation and emails but I can't find a clear response. Moreover, on the few examples that I found and in the gstreamer documentation about segments, it seems that I should only set the GST_SEEK_FLAG_FLUSH on the first seek and not in the following SEGMENT_DONE callbacks... but doing that way after the first SEGMENT_DONE, the same callback is called rapidly multiple times and leads to app crash, which will overflow the sink and the program crashes. Can anyone shed some light on what I'm doing wrong or point me to some working example or documentation ? Any help will be really appreciated. Thanks :-) Code: // Compile with: // gcc -Wall test_seek.c -o test_seek $(pkg-config --cflags --libs gstreamer-1.0) #include <gst/gst.h> #include <glib.h> // Loop markers #define START_SEC 20 #define END_SEC 24 typedef struct { GMainLoop *loop; GstElement *seek_element; gboolean first_seek; } bus_data_t; static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data) { bus_data_t *bus_data = (bus_data_t *)data; gchar *debug; gboolean ret; GError *error; switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_EOS: g_print("EOS\n"); g_main_loop_quit(bus_data->loop); break; case GST_MESSAGE_ASYNC_DONE: if (bus_data->first_seek) { g_print("First seek\n"); bus_data->first_seek = FALSE; ret = gst_element_seek(bus_data->seek_element, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, START_SEC*GST_SECOND, GST_SEEK_TYPE_SET, END_SEC*GST_SECOND); if (!ret) g_print("First seek error\n"); } break; case GST_MESSAGE_SEGMENT_DONE: g_print("Segment done\n"); g_print("Loop seek\n"); ret = gst_element_seek(bus_data->seek_element, 1.0, GST_FORMAT_TIME, /* According to documentation, the flag FLUSH should not be set here, but without it the SEGMENT_DONE callback is called rapidly multiple times and leads to app crash */ GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET, START_SEC*GST_SECOND, GST_SEEK_TYPE_SET, END_SEC*GST_SECOND); if (!ret) g_print("Loop seek error\n"); break; case GST_MESSAGE_ERROR: gst_message_parse_error (msg, &error, &debug); g_free (debug); g_printerr ("Error: %s\n", error->message); g_error_free (error); g_main_loop_quit(bus_data->loop); break; default: break; } return TRUE; } int main(int argc, char *argv[]) { GMainLoop *loop; GstElement *pipeline; gchar *file; GstBus *bus; guint bus_watch_id; // Init gst_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE); // Get args if (argc != 2) { g_printerr ("Usage: %s <audio file>\n", argv[0]); return -1; } #if 0 // Not working, getting EOS insetad of GST_MESSAGE_SEGMENT_DONE GstElement *source; file = g_strdup (argv[1]); g_print("File: %s\n", file); pipeline = gst_parse_launch("filesrc name=src ! queue ! decodebin name=dec " "! queue ! pulsesink", NULL); source = gst_bin_get_by_name(GST_BIN(pipeline), "src"); g_object_set(source, "location", file, NULL); gst_object_unref(source); #else // Working (almost) file = gst_filename_to_uri(argv[1], NULL); g_print("File: %s\n", file); pipeline = gst_parse_launch("playbin", NULL); g_object_set(pipeline, "uri", file, NULL); #endif bus_data_t bus_data = { .loop = loop, .seek_element = pipeline, .first_seek = TRUE }; // Bus handler bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline)); bus_watch_id = gst_bus_add_watch(bus, bus_call, &bus_data); gst_object_unref (bus); g_print("Play start\n"); gst_element_set_state(pipeline, GST_STATE_PLAYING); // Loop g_print("Loop...\n"); g_main_loop_run(loop); // End g_print("Loop ended\n"); gst_element_set_state(pipeline, GST_STATE_NULL); // Cleanup g_print("Cleanup\n"); gst_object_unref(GST_OBJECT(pipeline)); g_source_remove(bus_watch_id); g_main_loop_unref(loop); return 0; } _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
Hi Gabriele,
It will depend a bit on the file type and the demuxer/parser elements involved whether segment seeks work well or not. But they should work fine with common elements. One thing you might want to remove is the queue element between filesrc and decodebin (or just use uridecodebin/uridecodebin3 directly and set a file:// uri like you did with playbin). The queue element after filesrc will force the demuxer/parser into a suboptimal code path for seeking. Also, the initial set_state() should probably be to PAUSED state, so you can then do a flushing segment seek to the start position without outputting anything yet. Cheers Tim _______________________________________________ gstreamer-devel mailing list [hidden email] https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel |
Free forum by Nabble | Edit this page |