Using appsrc in push mode

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Using appsrc in push mode

Nostalgia
Hi everyone,

I am interested in using appsrc for pushing data from an application to a
gstreamer pipeline, and this for my university final project. Till now, they
don't tell me what application I should use to produce multimedia data
(probably it is yuv video/file) to be pushed to the pipeline (to processing
the data and encode it ...). But I should, as first step, to understand the
concept of gstreamer's pipeline and to make an example using appsrc. But I
don't succeed to understand very well the concept of appsrc, so I found a
code (this one is used by many people, and I put it in the end of my
message) and I try it, but I didn't understand where is the data that we
should push to the pipeline ? From where the data will be pushed when
executing the code ? What is the meaning of "is-live" property of appsrc ?
When executing the code, from where data will be pushed to the appsrc ?

Thanks for helping me to understand the concept of using appsrc in general
and how we can test the following code :

#include <string.h>

#include <gst/gst.h>

#include <gst/app/gstappsrc.h>

/*
 * an example application of using appsrc in push mode to create a file.
 * from buffers we push into the pipeline.
 */

/* S16LE 10ms frame audio */
#define BUFFER_SIZE 160

/* 300 frames = 5 minutes */
#define TOTAL_FRAMES 30000

#define QUEUED_FRAMES 30

typedef struct
{
  GMainLoop *loop;
  GstElement *pipeline;
  GstElement *source;
  guint source_id;
  guint num_frame;
} AppData;

/* This method is called by the idle GSource in the mainloop. We feed 1
buffer
 * of BUFFER_SIZE bytes into appsrc.
 * The ide handler is added to the mainloop when appsrc requests us to start
 * sending data (need-data signal) and is removed when appsrc has enough
data
 * (enough-data signal).
 */
static gboolean
push_buffer (AppData * app)
{
  gpointer raw_buffer;
  GstBuffer *app_buffer;
  GstMemory *mem;
  GstFlowReturn ret;

  app->num_frame++;

  if (app->num_frame >= TOTAL_FRAMES) {
    /* we are EOS, send end-of-stream and remove the source */
    g_signal_emit_by_name (app->source, "end-of-stream", &ret);
    return FALSE;
  }

  app_buffer = gst_buffer_new();

  mem = gst_allocator_alloc (NULL, BUFFER_SIZE, NULL);

  gst_buffer_append_memory(app_buffer, mem);

  gst_buffer_set_size(app_buffer, BUFFER_SIZE);

  /* Setting the correct timestamp for the buffer is very important,
otherwise the
   * resulting file won't be created correctly */
  GST_BUFFER_TIMESTAMP(app_buffer) = (GstClockTime)((app->num_frame / 100.0)
* 1e9);

  /* push new buffer */
  g_signal_emit_by_name (app->source, "push-buffer", app_buffer, &ret);

  gst_buffer_unref(app_buffer);

  if (ret != GST_FLOW_OK) {
    /* some error, stop sending data */
    return FALSE;
  }

  return TRUE;
}

/* This signal callback is called when appsrc needs data, we add an idle
handler
 * to the mainloop to start pushing data into the appsrc */
static void
start_feed (GstElement * pipeline, guint size, AppData * app)
{
  if (app->source_id == 0) {
        g_print ("start feeding at frame %i\n", app->num_frame);
    app->source_id = g_idle_add ((GSourceFunc) push_buffer, app);
  }
}

/* This callback is called when appsrc has enough data and we can stop
sending.
 * We remove the idle handler from the mainloop */
static void
stop_feed (GstElement * pipeline, AppData * app)
{
  if (app->source_id != 0) {
        g_print ("stop feeding at frame %i\n", app->num_frame);
    g_source_remove (app->source_id);
    app->source_id = 0;
  }
}

/* called when we get a GstMessage from the pipeline when we get EOS, we
 * exit the mainloop and this testapp. */
static gboolean
on_pipeline_message (GstBus * bus, GstMessage * message, AppData * app)
{
  GstState state, pending;

  switch (GST_MESSAGE_TYPE (message)) {
    case GST_MESSAGE_EOS:
      g_print ("Received End of Stream message\n");
      g_main_loop_quit (app->loop);
      break;
    case GST_MESSAGE_ERROR:
      {
        g_print ("Received error\n");

        GError *err = NULL;
        gchar *dbg_info = NULL;

        gst_message_parse_error (message, &err, &dbg_info);
        g_printerr ("ERROR from element %s: %s\n",
            GST_OBJECT_NAME (message->src), err->message);
        g_printerr ("Debugging info: %s\n", (dbg_info) ? dbg_info : "none");
        g_error_free (err);
        g_free (dbg_info);
      }

      g_main_loop_quit (app->loop);
      break;
    case GST_MESSAGE_STATE_CHANGED:
          gst_element_get_state(app->source, &state, &pending,
GST_CLOCK_TIME_NONE);
      /* g_print ("State changed from %i to %i\n", state, pending); */
      break;
        default:
      break;
  }
  return TRUE;
}

int
main (int argc, char *argv[])
{
  AppData *app = NULL;
  GstBus *bus = NULL;
  GstElement *appsrc = NULL;

  gst_init (&argc, &argv);

  app = g_new0 (AppData, 1);

  app->loop = g_main_loop_new (NULL, FALSE);

  /* setting up pipeline, we push media data into this pipeline that will
   * then be recorded to a file, encoded with a codec*/
  app->pipeline = gst_parse_launch ("appsrc is-live=true name=source
caps=audio/x-raw,format=S16LE,rate=8000,channels=1,layout=interleaved !
flacenc ! oggmux ! filesink location=flac-audio.ogg", NULL);

  if (app->pipeline == NULL) {
    g_print ("Bad pipeline\n");
    return -1;
  }

  appsrc = gst_bin_get_by_name (GST_BIN (app->pipeline), "source");

  /* setting maximum of bytes queued */
  gst_app_src_set_max_bytes((GstAppSrc *)appsrc, QUEUED_FRAMES *
BUFFER_SIZE);

  /* uncomment the next line to block when appsrc has buffered enough */
  /* g_object_set (appsrc, "block", TRUE, NULL); */
  app->source = appsrc;

  /* add watch for messages */
  bus = gst_element_get_bus (app->pipeline);
  gst_bus_add_watch (bus, (GstBusFunc) on_pipeline_message, app);
  gst_object_unref (bus);

  /* configure the appsrc, we will push data into the appsrc from the
   * mainloop */
  g_signal_connect (app->source, "need-data", G_CALLBACK (start_feed), app);
  g_signal_connect (app->source, "enough-data", G_CALLBACK (stop_feed),
app);

  /* go to playing and wait in a mainloop */
  gst_element_set_state (app->pipeline, GST_STATE_PLAYING);

  /* this mainloop is stopped when we receive an error or EOS */
  g_print ("Creating movie...\n");
  g_main_loop_run (app->loop);
  g_print ("Done.\n");

  gst_app_src_end_of_stream (GST_APP_SRC (app->source));

  gst_element_set_state (app->pipeline, GST_STATE_NULL);

  /* Cleaning up */
  gst_object_unref (app->source);
  gst_object_unref (app->pipeline);
  g_main_loop_unref (app->loop);
  g_free (app);

  return 0;
}


Regards,




--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Using appsrc in push mode

Antonio Ospite-2
On Thu, 1 Mar 2018 22:07:35 -0700 (MST)
Nostalgia <[hidden email]> wrote:

> Hi everyone,
>
> I am interested in using appsrc for pushing data from an application to a
> gstreamer pipeline, and this for my university final project. Till now, they
> don't tell me what application I should use to produce multimedia data
> (probably it is yuv video/file) to be pushed to the pipeline (to processing
> the data and encode it ...). But I should, as first step, to understand the
> concept of gstreamer's pipeline and to make an example using appsrc. But I
> don't succeed to understand very well the concept of appsrc, so I found a
> code (this one is used by many people, and I put it in the end of my
> message) and I try it, but I didn't understand where is the data that we
> should push to the pipeline ?

Hi

appsrc is used BY/IN the program which produces the data, to push
the data TO a GStreamer pipeline.

Conversely appsink is used to get data FROM a GStreamer pipeline.

These are mechanisms to integrate GStreamer *inside* the code of a
program.

If you are interfacing with *external* applications on which you have
no control, there could be other mechanisms you could use to pass data
to GStreamer, depending on how the external application "exposes" the
produced data: does it write it to a file? Does it stream it via some
network protocol?

> From where the data will be pushed when executing the code ?

In the example you posted the data is *created* and pushed in
push_buffer() its' just that it's some dummy uninitialized data
because this is a trivial test application.

> What is the meaning of "is-live" property of appsrc ?

It affects how the synchronization with the other GStreamer elements in
the pipeline is performed, in this case it shouldn't really matter
if it's true or false because the sink is a file.

However others may provide better info on this point.

More details on live sources are here:
https://gstreamer.freedesktop.org/documentation/design/live-source.html

> When executing the code, from where data will be pushed to the appsrc ?

In this case the application is using some trivial data obtained
directly in push_buffer(), but in a real case you would have the data
provided by some other mechanism and then you'd have to wrap it into a
GstBuffer before pushing it.

> Thanks for helping me to understand the concept of using appsrc in general
> and how we can test the following code :
>

You just compile it and run it, and it will create an audio file with
unspecified content. It may be silence, it may be clicks, depending on
the memory content at the time of allocation.

You can compile it with this command line:

gcc $(pkg-config --cflags gstreamer-1.0 gstreamer-app-1.0) appsrc-test.c -o appsrc-test $(pkg-config --libs gstreamer-1.0 gstreamer-app-1.0)

Ciao,
   Antonio

--
Antonio Ospite
https://ao2.it
https://twitter.com/ao2it

A: Because it messes up the order in which people normally read text.
   See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Using appsrc in push mode

Nostalgia
Thank u Antonio for ur answer,



--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
Reply | Threaded
Open this post in threaded view
|

Re: Using appsrc in push mode

Nostalgia
In reply to this post by Antonio Ospite-2
Hi  Antonio Ospite-2,

>If you are interfacing with *external* applications on which you have
>no control, there could be other mechanisms you could use to pass data
>to GStreamer, depending on how the external application "exposes" the
>produced data: does it write it to a file? Does it stream it via some
>network protocol?

The external application produces data and send them buffer by buffer to the
coder pipeline. So what I need is create the pipeline and push buffers
produced by the application (the buffers will be in some regions of the
memory) to the pipeline and then retrieve the resulted buffers and send them
to another application. How can I do this without using the g_main_loop in
gstreamer ?

Regards.



--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/
_______________________________________________
gstreamer-devel mailing list
[hidden email]
https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel