Continuously streaming a video file code review

Russell Willis codinguy at gmail.com
Fri Mar 27 07:18:27 PDT 2015


Hi All,

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.
I've mainly used bits and pieces from the example files found within the
gstreamer and gstrtspserver source and documentation.
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.

#include <gst/gst.h>
#include <gst/app/gstappsink.h>
#include <gst/app/gstappsrc.h>
#include <rtsp-server.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct _App App;
struct _App
{
    GstElement *videosink;
};
App s_app;

typedef struct {
    App *glblapp;
    GstClockTime timestamp;
} Context;

const gchar *videocaps =
    "video/x-raw, format=(string)I420, width=(int)720, height=(int)480,
     pixel-aspect-ratio=(fraction)10/11,
interlace-mode=(string)progressive,
     colorimetry=(string)bt601, framerate=(fraction)5000/167";

// RTSP server signal and event handler
static void
need_data (GstElement *appsrc, guint unused, Context *ctx)
{
    GstFlowReturn ret;
    GstSample *sample = gst_app_sink_pull_sample
(GST_APP_SINK(ctx->glblapp->videosink));
    if (sample != NULL) {
        GstBuffer *buffer = gst_sample_get_buffer(sample);
        gst_sample_unref (sample);
        GST_BUFFER_PTS(buffer) = ctx->timestamp;
        GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale_int (1,
GST_SECOND, 25);
        ctx->timestamp += GST_BUFFER_DURATION (buffer);
        g_signal_emit_by_name(appsrc, "push-buffer", buffer, &ret);
    }
}

static void
media_configure (GstRTSPMediaFactory *factory, GstRTSPMedia *media, App
*app)
{
    Context *ctx;
    GstElement *pipeline;
    GstElement *appsrc;
    pipeline = gst_rtsp_media_get_element(media);
    appsrc = gst_bin_get_by_name_recurse_up (GST_BIN (pipeline), "mysrc");
    gst_rtsp_media_set_reusable(media, TRUE);
    gst_util_set_object_arg (G_OBJECT (appsrc), "format", "time");
    g_object_set (G_OBJECT (appsrc), "caps",
gst_caps_from_string(videocaps), NULL);
    g_object_set(G_OBJECT(appsrc), "max-bytes",
        gst_app_src_get_max_bytes(GST_APP_SRC(appsrc)), NULL);
    ctx = g_new0 (Context, 1);
    ctx->glblapp = app;
    ctx->timestamp = 0;
    g_signal_connect (appsrc, "need-data", (GCallback) need_data, ctx);
}

// Bus message handler
gboolean
bus_callback(GstBus *bus, GstMessage *msg, gpointer data)
{
    GstElement *pipeline = GST_ELEMENT(data);
    switch (GST_MESSAGE_TYPE(msg)) {
    case GST_MESSAGE_EOS:
        if (!gst_element_seek(pipeline,
            1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
            GST_SEEK_TYPE_SET, 1000000000,
            GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) {
            g_message("Seek failed!");
        }
        break;
    default:
        break;
    }
    return TRUE;
}

gint
main (gint argc, gchar *argv[])
{
    App *app = &s_app;
    GstBus *bus;
    GstRTSPServer *server;
    GstRTSPMediaFactory *factory;
    GstRTSPMountPoints *mountpoints;

    gst_init (&argc, &argv);
    GMainLoop *loop = g_main_loop_new (NULL, FALSE);

    // Playbin, setup and configuration
    GstElement *playbin = gst_element_factory_make ("playbin", "play");
    app->videosink = gst_element_factory_make ("appsink", "video_sink");
    g_object_set (G_OBJECT (app->videosink), "emit-signals", FALSE, "sync",
TRUE, NULL);
    g_object_set (G_OBJECT (playbin), "video-sink", app->videosink, NULL);
    gst_app_sink_set_drop(GST_APP_SINK (app->videosink), TRUE);
    gst_app_sink_set_max_buffers(GST_APP_SINK (app->videosink), 1);
    bus = gst_pipeline_get_bus (GST_PIPELINE (playbin));
    gst_bus_add_watch (bus, bus_callback, playbin);
    g_object_set (G_OBJECT (playbin), "uri", "
file:///home/user/Videos/TestVideo.mp4", NULL);
    gst_element_set_state (playbin, GST_STATE_PLAYING);

    // RTSP server, setup and configuration
    server = gst_rtsp_server_new();
    mountpoints = gst_rtsp_server_get_mount_points(server);
    factory = gst_rtsp_media_factory_new();
    gst_rtsp_media_factory_set_shared(factory, TRUE);
    gst_rtsp_media_factory_set_launch (factory,
        "( appsrc name=mysrc ! videoconvert ! jpegenc ! rtpjpegpay
name=pay0 pt=96 )");
    g_signal_connect (factory, "media-configure", (GCallback)
media_configure, app);
    gst_rtsp_mount_points_add_factory (mountpoints, "/test", factory);
    g_object_unref(mountpoints);
    gst_rtsp_server_attach (server, NULL);
    g_print("RTSP Server started...");
    g_main_loop_run (loop);

    // Clean up
    gst_element_set_state (playbin, GST_STATE_NULL);
    gst_object_unref (bus);
    return 0;
}


Many thanks for your help.

-RW
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/gstreamer-devel/attachments/20150327/4643f27c/attachment-0001.html>


More information about the gstreamer-devel mailing list