<div dir="ltr"><div class=""><div class=""><code class="">Hi All,<br><br></code></div><div class=""><code class="">I'm hoping someone can help me.  I've been asked to write a small program to continuously stream a video file, or loop the file, over rtsp.  I'm using the gstrtspserver, but having never used gstreamer before I've no idea if I have approached this correctly.  The solution I have works, but I would be grateful if someone could give me an indication if I've taken the right design decisions or not.<br></code></div><div class=""><code class="">I've mainly used bits and pieces from the example files found within the gstreamer and gstrtspserver source and documentation.<br></code></div><div class=""><code class="">Basically the first pipeline, using filesrc, reads in a file and uses the EOS bus message to loop to the beginning of the file.  The rtspserver pulls a sample from the videosink of the first pipeline and pushes it out across the network.  All code I use is below, there is no error checking and its not efficient, I want to make sure I'm on the right track before investing any more time.<br></code></div><div class=""><code class=""><br>#include <gst/gst.h></code></div><div class=""><code class="">#include <gst/app/gstappsink.h></code></div><div class=""><code class="">#include <gst/app/gstappsrc.h></code></div><div class=""><code class="">#include <rtsp-server.h></code></div><div class=""> </div><div class=""><code class="">#include <stdio.h></code></div><div class=""><code class="">#include <string.h></code></div><div class=""><code class="">#include <stdlib.h></code></div><div class=""> </div><div class=""><code class="">typedef</code> <code class="">struct</code> <code class="">_App App;</code></div><div class=""><code class="">struct</code> <code class="">_App</code></div><div class=""><code class="">{</code></div><div class=""><code class="">    </code><code class="">GstElement *videosink;</code></div><div class=""><code class="">};</code></div><div class=""><code class="">App s_app;</code></div><div class=""> </div><div class=""><code class="">typedef</code> <code class="">struct</code> <code class="">{</code></div><div class=""><code class="">    </code><code class="">App *glblapp;</code></div><div class=""><code class="">    </code><code class="">GstClockTime timestamp;</code></div><div class=""><code class="">} Context;</code></div><div class=""> </div><div class=""><code class="">const</code> <code class="">gchar *videocaps = </code></div><div class=""><code class="">    </code><code class="">"video/x-raw, format=(string)I420, width=(</code><code class="">int</code><code class="">)720, height=(</code><code class="">int</code><code class="">)480, </code></div><div class=""><code class="">     </code><code class="">pixel-aspect-ratio=(fraction)10/11, interlace-mode=(string)progressive, </code></div><div class=""><code class="">     </code><code class="">colorimetry=(string)bt601, framerate=(fraction)5000/167";</code></div><div class=""> </div><div class=""><code class="">// RTSP server signal and event handler</code></div><div class=""><code class="">static</code> <code class="">void</code></div><div class=""><code class="">need_data (GstElement *appsrc, guint unused, Context *ctx)</code></div><div class=""><code class="">{</code></div><div class=""><code class="">    </code><code class="">GstFlowReturn ret;</code></div><div class=""><code class="">    </code><code class="">GstSample *sample = gst_app_sink_pull_sample (GST_APP_SINK(ctx->glblapp->videosink));</code></div><div class=""><code class="">    </code><code class="">if</code> <code class="">(sample != NULL) {</code></div><div class=""><code class="">        </code><code class="">GstBuffer *buffer = gst_sample_get_buffer(sample);</code></div><div class=""><code class="">        </code><code class="">gst_sample_unref (sample);</code></div><div class=""><code class="">        </code><code class="">GST_BUFFER_PTS(buffer) = ctx->timestamp;</code></div><div class=""><code class="">        </code><code class="">GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale_int (1, GST_SECOND, 25);</code></div><div class=""><code class="">        </code><code class="">ctx->timestamp += GST_BUFFER_DURATION (buffer);</code></div><div class=""><code class="">        </code><code class="">g_signal_emit_by_name(appsrc, </code><code class="">"push-buffer"</code><code class="">, buffer, &ret); </code></div><div class=""><code class="">    </code><code class="">} </code></div><div class=""><code class="">}</code></div><div class=""> </div><div class=""><code class="">static</code> <code class="">void</code></div><div class=""><code class="">media_configure (GstRTSPMediaFactory *factory, GstRTSPMedia *media, App *app)</code></div><div class=""><code class="">{</code></div><div class=""><code class="">    </code><code class="">Context *ctx;</code></div><div class=""><code class="">    </code><code class="">GstElement *pipeline;</code></div><div class=""><code class="">    </code><code class="">GstElement *appsrc;</code></div><div class=""><code class="">    </code><code class="">pipeline = gst_rtsp_media_get_element(media);</code></div><div class=""><code class="">    </code><code class="">appsrc = gst_bin_get_by_name_recurse_up (GST_BIN (pipeline), </code><code class="">"mysrc"</code><code class="">);</code></div><div class=""><code class="">    </code><code class="">gst_rtsp_media_set_reusable(media, TRUE);</code></div><div class=""><code class="">    </code><code class="">gst_util_set_object_arg (G_OBJECT (appsrc), </code><code class="">"format"</code><code class="">, </code><code class="">"time"</code><code class="">);</code></div><div class=""><code class="">    </code><code class="">g_object_set (G_OBJECT (appsrc), </code><code class="">"caps"</code><code class="">, gst_caps_from_string(videocaps), NULL);</code></div><div class=""><code class="">    </code><code class="">g_object_set(G_OBJECT(appsrc), </code><code class="">"max-bytes"</code><code class="">, </code></div><div class=""><code class="">        </code><code class="">gst_app_src_get_max_bytes(GST_APP_SRC(appsrc)), NULL);</code></div><div class=""><code class="">    </code><code class="">ctx = g_new0 (Context, 1);</code></div><div class=""><code class="">    </code><code class="">ctx->glblapp = app;</code></div><div class=""><code class="">    </code><code class="">ctx->timestamp = 0;</code></div><div class=""><code class="">    </code><code class="">g_signal_connect (appsrc, </code><code class="">"need-data"</code><code class="">, (GCallback) need_data, ctx);</code></div><div class=""><code class="">}</code></div><div class=""> </div><div class=""><code class="">// Bus message handler</code></div><div class=""><code class="">gboolean </code></div><div class=""><code class="">bus_callback(GstBus *bus, GstMessage *msg, gpointer data)</code></div><div class=""><code class="">{</code></div><div class=""><code class="">    </code><code class="">GstElement *pipeline = GST_ELEMENT(data);</code></div><div class=""><code class="">    </code><code class="">switch</code> <code class="">(GST_MESSAGE_TYPE(msg)) {</code></div><div class=""><code class="">    </code><code class="">case</code> <code class="">GST_MESSAGE_EOS:</code></div><div class=""><code class="">        </code><code class="">if</code> <code class="">(!gst_element_seek(pipeline, </code></div><div class=""><code class="">            </code><code class="">1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,</code></div><div class=""><code class="">            </code><code class="">GST_SEEK_TYPE_SET, 1000000000, </code></div><div class=""><code class="">            </code><code class="">GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {</code></div><div class=""><code class="">            </code><code class="">g_message(</code><code class="">"Seek failed!"</code><code class="">);</code></div><div class=""><code class="">        </code><code class="">}</code></div><div class=""><code class="">        </code><code class="">break</code><code class="">;</code></div><div class=""><code class="">    </code><code class="">default</code><code class="">:</code></div><div class=""><code class="">        </code><code class="">break</code><code class="">;</code></div><div class=""><code class="">    </code><code class="">}</code></div><div class=""><code class="">    </code><code class="">return</code> <code class="">TRUE;</code></div><div class=""><code class="">}</code></div><div class=""> </div><div class=""><code class="">gint</code></div><div class=""><code class="">main (gint argc, gchar *argv[])</code></div><div class=""><code class="">{</code></div><div class=""><code class="">    </code><code class="">App *app = &s_app;</code></div><div class=""><code class="">    </code><code class="">GstBus *bus;</code></div><div class=""><code class="">    </code><code class="">GstRTSPServer *server;</code></div><div class=""><code class="">    </code><code class="">GstRTSPMediaFactory *factory;</code></div><div class=""><code class="">    </code><code class="">GstRTSPMountPoints *mountpoints;</code></div><div class=""> </div><div class=""><code class="">    </code><code class="">gst_init (&argc, &argv);</code></div><div class=""><code class="">    </code><code class="">GMainLoop *loop = g_main_loop_new (NULL, FALSE);</code></div><div class=""> </div><div class=""><code class="">    </code><code class="">// Playbin, setup and configuration</code></div><div class=""><code class="">    </code><code class="">GstElement *playbin = gst_element_factory_make (</code><code class="">"playbin"</code><code class="">, </code><code class="">"play"</code><code class="">);</code></div><div class=""><code class="">    </code><code class="">app->videosink = gst_element_factory_make (</code><code class="">"appsink"</code><code class="">, </code><code class="">"video_sink"</code><code class="">);</code></div><div class=""><code class="">    </code><code class="">g_object_set (G_OBJECT (app->videosink), </code><code class="">"emit-signals"</code><code class="">, FALSE, </code><code class="">"sync"</code><code class="">, TRUE, NULL);</code></div><div class=""><code class="">    </code><code class="">g_object_set (G_OBJECT (playbin), </code><code class="">"video-sink"</code><code class="">, app->videosink, NULL);</code></div><div class=""><code class="">    </code><code class="">gst_app_sink_set_drop(GST_APP_SINK (app->videosink), TRUE);</code></div><div class=""><code class="">    </code><code class="">gst_app_sink_set_max_buffers(GST_APP_SINK (app->videosink), 1);    </code></div><div class=""><code class="">    </code><code class="">bus = gst_pipeline_get_bus (GST_PIPELINE (playbin));</code></div><div class=""><code class="">    </code><code class="">gst_bus_add_watch (bus, bus_callback, playbin);</code></div><div class=""><code class="">    </code><code class="">g_object_set (G_OBJECT (playbin), </code><code class="">"uri"</code><code class="">, </code><code class="">"<a>file:///home/user/Videos/TestVideo.mp4</a>"</code><code class="">, NULL);</code></div><div class=""><code class="">    </code><code class="">gst_element_set_state (playbin, GST_STATE_PLAYING);</code></div><div class=""> </div><div class=""><code class="">    </code><code class="">// RTSP server, setup and configuration</code></div><div class=""><code class="">    </code><code class="">server = gst_rtsp_server_new();</code></div><div class=""><code class="">    </code><code class="">mountpoints = gst_rtsp_server_get_mount_points(server);</code></div><div class=""><code class="">    </code><code class="">factory = gst_rtsp_media_factory_new();</code></div><div class=""><code class="">    </code><code class="">gst_rtsp_media_factory_set_shared(factory, TRUE);</code></div><div class=""><code class="">    </code><code class="">gst_rtsp_media_factory_set_launch (factory, </code></div><div class=""><code class="">        </code><code class="">"( appsrc name=mysrc ! videoconvert ! jpegenc ! rtpjpegpay name=pay0 pt=96 )"</code><code class="">);</code></div><div class=""><code class="">    </code><code class="">g_signal_connect (factory, </code><code class="">"media-configure"</code><code class="">, (GCallback) media_configure, app);</code></div><div class=""><code class="">    </code><code class="">gst_rtsp_mount_points_add_factory (mountpoints, </code><code class="">"/test"</code><code class="">, factory);</code></div><div class=""><code class="">    </code><code class="">g_object_unref(mountpoints);</code></div><div class=""><code class="">    </code><code class="">gst_rtsp_server_attach (server, NULL);</code></div><div class=""><code class="">    </code><code class="">g_print(</code><code class="">"RTSP Server started..."</code><code class="">);</code></div><div class=""><code class="">    </code><code class="">g_main_loop_run (loop);</code></div><div class=""> </div><div class=""><code class="">    </code><code class="">// Clean up</code></div><div class=""><code class="">    </code><code class="">gst_element_set_state (playbin, GST_STATE_NULL);</code></div><div class=""><code class="">    </code><code class="">gst_object_unref (bus);</code></div><div class=""><code class="">    </code><code class="">return</code> <code class="">0;</code></div><div class=""><code class="">}<br><br><br></code></div><div class=""><code class="">Many thanks for your help.<br><br></code></div><div class=""><code class="">-RW<br></code></div></div></div>