How to change the filesink location on runtime.
Danny
churli at empal.com
Tue Aug 30 23:43:39 PDT 2011
Hi all.
In advance I want to say that sorry for my poor English.
I'm a newbie to Gstreamer.
I tried to make recording app like this(v4l2 -> omx_h264enc ->
queue->mpegtsmux -> filesink).
I got some tip that is about dynamic filesink location change from this site
and I made recording app as I learned.
I want my app to make new recoding file every 1 min without loosing data.
Below is my code. I doesn't work.
I think that there are some problem when gst_pad_set_blocked_async() is
called.
Callback function seems not to be called.
please give me a good way.
have a nice day!
#include <gst/gst.h>
#include <glib.h>
#define true 1
#define false 0
GstElement *pipeline, *vsource, *asource, *conv, *acodec, *h264enc, *mux,
*sink, *q1;
GstPad *q1_srcpad;
char name_buf[128];
GStaticRecMutex mutex;
int cnt;
static void create_filesink_tail()
{
GstPad *srcpad;
GstPad *sinkpad;
sink = NULL;
sink = gst_element_factory_make ("filesink", NULL);
if(!sink)
{
g_print("faile to create new sink element! \n");
return;
}
gst_bin_add(GST_BIN (pipeline), sink);
gst_element_link(mux, sink);
srcpad = gst_element_get_static_pad( mux, "src" );
sinkpad = gst_element_get_static_pad( sink, "sink" );
gst_pad_link(srcpad,sinkpad);
sprintf(name_buf, "test%d.mp4", cnt++);
g_object_set( G_OBJECT( sink ), "location", name_buf, NULL );
}
static gboolean destroy_bin_cb (gpointer user_data)
{
GstElement *oldbin = user_data;
g_print("Destroying old bin.\n");
if (pipeline)
{
gst_element_set_state (oldbin, GST_STATE_NULL);
gst_bin_remove (GST_BIN(pipeline), oldbin);
}
return FALSE;
}
static void replace_filesink_blocked_cb (GstPad *pad, gboolean blocked,
gpointer user_data)
{
int ret;
if (blocked)
{
GstElement *oldbin;
GstPad *sinkpad;
g_print("Blocked filesink queue.\n");
// g_static_rec_mutex_lock(&mutex);
g_print("Locked.\n");
oldbin = sink;
sinkpad = gst_element_get_static_pad(oldbin, "sink");
if (!sinkpad)
{
g_print("replace_filesink_blocked_cb: oldbin doesn't have sink
pad.\n");
goto fail;
}
gst_pad_unlink(q1_srcpad, sinkpad);
g_print("Unlinked.\n");
gst_pad_send_event(sinkpad, gst_event_new_eos());
g_print("Sent event.\n");
g_print("Checked sinks.\n");
g_idle_add(destroy_bin_cb, oldbin);
create_filesink_tail();
g_print("Created filesink.\n");
//g_static_rec_mutex_unlock(&mutex);
g_print("Unlocked mutex.\n");
/* And unblock again. */
ret = gst_pad_set_blocked_async(q1_srcpad, false,
replace_filesink_blocked_cb, NULL);
g_print("gst_pad_set_unblocked_async ret : %d \n", ret );
g_print("Done replacing filesink.\n");
}
else
{
g_print("Unblocked filesink queue.\n");
}
return;
fail:
return;
}
static void replace_filesink()
{
int ret;
if (q1_srcpad == NULL)
g_print("replace_filesink while no queuesrcpad yet, waiting for it
to appear.\n");
else
{
ret = gst_pad_set_blocked_async(q1_srcpad, true,
replace_filesink_blocked_cb, NULL);
g_print("gst_pad_set_blocked_async ret : %d \n", ret );
}
}
static gboolean link_video_elements_with_filter (GstElement *element1,
GstElement *element2)
{
gboolean link_ok;
GstCaps *caps;
caps = gst_caps_new_simple ("video/x-raw-yuv",
//"format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I','4','2','0'),
"width", G_TYPE_INT, 1280,
"height", G_TYPE_INT, 720,
//"framerate", GST_TYPE_FRACTION, 25, 1,
NULL);
link_ok = gst_element_link_filtered (element1, element2, caps);
gst_caps_unref (caps);
if (!link_ok) {
g_warning ("Failed to link element1 and element2!(v4l2src)");
}
return link_ok;
}
static gboolean link_audio_elements_with_filter (GstElement *element1,
GstElement *element2)
{
gboolean link_ok;
GstCaps *caps;
caps = gst_caps_new_simple ("audio/x-raw-int",
"channels", G_TYPE_INT, 2,
"rate", G_TYPE_INT, 44100,
"width", G_TYPE_INT, 16,
"signed", G_TYPE_BOOLEAN, 1,
"depth", G_TYPE_INT, 16,
NULL);
link_ok = gst_element_link_filtered (element1, element2, caps);
gst_caps_unref (caps);
if (!link_ok) {
g_warning ("Failed to link element1 and element2!(alsasrc)");
}
return link_ok;
}
static void on_pad_added (GstElement *element, GstPad *pad, gpointer data)
{
GstPad *sinkpad;
GstElement *decoder = (GstElement *) data;
/* We can now link this pad with the vorbis-decoder sink pad */
g_print ("Dynamic pad created, linking demuxer/decoder\n");
sinkpad = gst_element_get_static_pad (decoder, "sink");
gst_pad_link (pad, sinkpad);
gst_object_unref (sinkpad);
}
int cnt;
static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data)
{
GMainLoop *loop = (GMainLoop *) data;
int rc;
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_EOS:
g_print("get EOS ... \n");
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:
break;
}
return TRUE;
}
gpointer rec_loop(gpointer data)
{
int rc;
g_print("start recording loop ... \n ");
while(1)
{
sleep(60);
replace_filesink( );
g_print("replacing file sink complte .. \n");
}
}
int main (int argc, char *argv[])
{
int ret = 0;
GMainLoop *loop;
GstBus *bus;
pthread_t *thread;
GError *err = NULL;
GStaticRecMutex mut = G_STATIC_REC_MUTEX_INIT;
mutex = mut;
/* Initialisation */
gst_init (&argc, &argv);
loop = g_main_loop_new (NULL, FALSE);
/* Create gstreamer elements */
pipeline = gst_pipeline_new ("cl-blackboxr");
vsource = gst_element_factory_make ("v4l2src", "v4l-source");
h264enc = gst_element_factory_make ("omx_h264enc", "h264enc");
//asource = gst_element_factory_make ("alsasrc", "alsa-source");
//conv = gst_element_factory_make ("audioconvert", "audio-converter");
//acodec = gst_element_factory_make ("faac", "audio-codec");
mux = gst_element_factory_make ("avimux", "muxer");
sink = gst_element_factory_make ("filesink", "fsink");
q1 = gst_element_factory_make ("queue", "q1");
if (!pipeline || !vsource || !h264enc || !mux ) {
g_print ("One element could not be created. Exiting.\n");
return -1;
}
/* Set up the pipeline */
/* we set the input filename to the source element */
g_object_set (G_OBJECT (h264enc), "bitrate",400000, NULL);
g_object_set (G_OBJECT (sink), "location","test.mp4", NULL);
/* we add a message handler */
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
gst_bus_add_watch (bus, bus_call, loop);
gst_object_unref (bus);
gst_bin_add_many (GST_BIN (pipeline), vsource, h264enc, q1, mux, sink,
NULL);
/* we link the elements together */
/* file-source -> ogg-demuxer ~> vorbis-decoder -> converter ->
alsa-output */
link_video_elements_with_filter(vsource, h264enc);
gst_element_link_many (h264enc, q1, mux, sink, NULL);
//g_signal_connect (h264enc, "pad-added", G_CALLBACK (on_pad_added),
mux);
g_signal_connect (q1, "pad-added", G_CALLBACK (on_pad_added), mux);
/* Set the pipeline to "playing" state*/
g_print ("Now playing: %s\n", argv[1]);
ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
g_print("set state : %d \n", ret);
/* Iterate */
q1_srcpad = gst_element_get_static_pad( q1, "src" );
g_print ("Running...\n");
g_thread_create((void *)rec_loop, NULL, FALSE, &err);
g_main_loop_run (loop);
/* Out of the main loop, clean up nicely */
g_print ("Returned, stopping playback\n");
gst_element_set_state (pipeline, GST_STATE_NULL);
g_print ("Deleting pipeline\n");
gst_object_unref (GST_OBJECT (pipeline));
return 0;
}
--
View this message in context: http://gstreamer-devel.966125.n4.nabble.com/How-to-change-the-filesink-location-on-runtime-tp3780325p3780325.html
Sent from the GStreamer-devel mailing list archive at Nabble.com.
More information about the gstreamer-devel
mailing list