envyen
2/22/2017 - 4:31 AM

rtsp-live.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>

#include <glib.h>
#define GST_USE_UNSTABLE_API
#include <gst/gst.h>

#include <gst/rtsp-server/rtsp-server.h>


static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data)
{
  GMainLoop *loop = (GMainLoop *) data;

  switch (GST_MESSAGE_TYPE (msg)) {

    case GST_MESSAGE_EOS:
      g_print ("End of stream\n");
      g_main_loop_quit (loop);
      break;

    case GST_MESSAGE_ERROR: {
      gchar  *debug;
      GError *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 (loop);
      break;
    }
    default:
      //g_print ("unknown message: %s\n",
      //         gst_message_type_get_name(GST_MESSAGE_TYPE (msg)));
      break;
  }

  return TRUE;
}


GstPipeline *
make_pipeline (int argc, char *argv[])
{
  /* make a parseable argvn array */
  gchar **argvn = g_new0 (char *, argc);
  memcpy (argvn, argv + 1, sizeof (char *) * (argc - 1));

  GError *error = NULL;

  GstElement *pipeline = gst_parse_launchv((const gchar **)argvn, &error);
  if (!pipeline || error) {
    g_printerr ("pipeline couldn't be created: %s\n", error->message);
    return NULL;
  }
  if (!GST_IS_PIPELINE(pipeline)) {
    g_printerr ("complete pipeline required\n");
    return NULL;
  }
  return GST_PIPELINE (pipeline);
}


GstElement *
get_element (GstRTSPMediaFactory *factory, const GstRTSPUrl *url)
{
  // hack, see set_rtsp_server()
  GstPipeline *pipeline = (GstPipeline *) factory->launch;

  GstElement *stream = gst_bin_get_by_name (GST_BIN (pipeline), "stream");
  GstPad *src = gst_element_get_static_pad (stream, "src");
  g_object_unref (stream);

  GstBin *streambin = GST_BIN (gst_pipeline_new ("streambin"));
  GstElement *queue = gst_element_factory_make ("queue", "pay0");
  if (FALSE == gst_bin_add (streambin, queue)) {
    printf ("couldn't add queue to streambin\n");
    return NULL;
  }

  GstPad *ghost_pad;
  GstPad *queue_sinkpad = gst_element_get_static_pad (queue, "sink");
  if (NULL == (ghost_pad = gst_ghost_pad_new (NULL, queue_sinkpad))) {
    printf ("couldn't create ghost pad\n");
    return NULL;
  }
  g_object_unref (queue_sinkpad);

  if (GST_PAD_LINK_OK != gst_pad_link (src, ghost_pad)) {
    g_printerr ("couldn't link src and ghost pad\n");
    return NULL;
  }

  return GST_ELEMENT (streambin);
}


int
set_rtsp_server (GstPipeline *pipeline, GMainLoop *loop)
{
  GstRTSPServer *server = gst_rtsp_server_new ();
  GstRTSPMediaMapping *mapping = gst_rtsp_server_get_media_mapping (server);
  GstRTSPMediaFactory *factory = gst_rtsp_media_factory_new ();

  // hack: save a pointer to pipeline object in factory->launch property
  factory->launch = (char *) pipeline;
  GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory)->get_element = get_element;

  gst_rtsp_media_factory_set_shared (factory, TRUE);
  gst_rtsp_media_mapping_add_factory (mapping, "/test", factory);
  g_object_unref (mapping);
  if (0 == gst_rtsp_server_attach (server, NULL)) {
    g_printerr ("couldn't attach rtsp server to the context\n");
    return -4;
  }
  return 0;
}


int
main(int argc, char *argv[])
{
  if (argc < 2) {
    g_printerr ("Usage: %s <source> ! <filter> ! <filter> ...  \n", argv[0]);
    return -1;
  }

  gst_init(&argc, &argv);

  GstPipeline *pipeline = make_pipeline (argc, argv);
  if (NULL == pipeline)
    return -1;

  GMainLoop *loop = g_main_loop_new (NULL, FALSE);
  GstBus *bus = gst_pipeline_get_bus (pipeline);
  gst_bus_add_watch (bus, bus_call, loop);
  gst_object_unref (bus);

  if (0 != set_rtsp_server (pipeline, loop))
    return -6;

  g_print ("Now playing\n");
  gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);

  g_main_loop_run (loop);

  g_print ("Returned, stopping playback\n");
  gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);

  g_print ("Deleting pipeline\n");
  gst_object_unref (GST_OBJECT (pipeline));

  return 0;
}