Hi All ,
Could Team members please provide some pointer for below mentioned problem in Gstreamer-0.10 ( TI SDK )
1) With Gstreamer-0.10 the MUX element hangs when asked to change the state to NULL
( from PLAYING state to NULL state )
i.e
gst_element_set_state (mux, GST_STATE_NULL) , instruction hangs.
2) Same logic we tested on Gstreamer-1.0 on UBUNTU-14.04 logic where we are able to get
multiple files being created as the AVI MUX changes the state to NULL using the
same instruction ( this was done as proof of concept )
3) Attached is the stripped down sample to demonstrate the problem.
#define MACRO of VERSION can be used to compile same code effectively to
Gstreamer-0.10 ( VERSION = 0 ) & Gstreamer-1.0 ( VERSION = 1 )
Since we have the logic working on Gstreamer-1.0 , if group could please help us
to solve the above mentioned problem of " MUX getting hanged when asked to do an change of state"
we feel we could build up our solution quickly.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <gst/gst.h>
#define TIMER_DURATION 10
#define VERSION 0
GstElement *pipeline,
*src,
*timeoverlay,
*clockoverlay,
*q1,
*q2,
*filesink,
*mux,
*audiosrc,
*capsfilter,
*tempfilesink;
GstCaps *acaps;
GMainLoop *loop,
*mainloop;
GstPad *muxvideosinkpad,
*muxaudiosinkpad,
*muxsrcpad,
*filesinkpad,
*q1sinkpad,
*q2sinkpad;
static gulong probe_id; // probe ID
GstBus *bus;
GError *err = NULL;
gchar *sinkname;
char buffer[128];
volatile unsigned int attempt=0;
unsigned int timer_count=0;
unsigned int dynamic_filesink= 1;
gboolean return_bool = FALSE,
chunk = TRUE;
unsigned long return_gulong =0;
typedef enum {
NO_NEW_FILE, // Keep current file destination
NEW_FILE, // Switch file destination
} NewFileStatus;
static NewFileStatus newfile = NO_NEW_FILE; // Switch File Flag
#if ( VERSION == 1)
static GstPadProbeReturn eos_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
g_print("\t [ APP-BLOCK ]: EOS_PROBE [ START ] ===================\n");
if (GST_EVENT_TYPE (GST_PAD_PROBE_INFO_DATA (info)) != GST_EVENT_EOS)
return GST_PAD_PROBE_DROP;
gst_pad_remove_probe (pad, GST_PAD_PROBE_INFO_ID (info));
#else
static gboolean eos_cb (GstPad * pad, GstEvent * event, gpointer user_data)
{
g_print("\t [ APP-BLOCK ]: EOS_PROBE [ START ] ===================\n");
if (GST_EVENT_TYPE (event) != GST_EVENT_EOS){
return TRUE;
}
//Remove the probe first
gst_pad_remove_event_probe (pad, probe_id);
#endif
gst_element_release_request_pad(mux, muxvideosinkpad);
g_print("\t [ APP-BLOCK ]: About to set ELEMENTS as NULL \n");
gst_element_set_state (mux, GST_STATE_NULL); // Gst-0.10 hangs at this instruction
gst_element_set_state (filesink, GST_STATE_NULL);
// Remove unlinks automatically
gst_bin_remove (GST_BIN (pipeline), mux);
gst_bin_remove (GST_BIN (pipeline), filesink);
GstElement *mux0 = gst_element_factory_make ("avimux",NULL);
GstElement *fsink0 = gst_element_factory_make("filesink", NULL);
mux = mux0;
filesink = fsink0;
if(!mux0 || !fsink0) {
g_print("[ERROR]: Missing elements\n");
}
gst_bin_add (GST_BIN (pipeline), mux);
gst_bin_add (GST_BIN (pipeline), filesink);
#if (VERSION == 1)
sprintf( buffer, "test_%u.avi" , attempt);
#else
sprintf( buffer, "test_%d.avi" , attempt);
#endif
g_object_set(G_OBJECT (filesink),"location", buffer, NULL);
muxsrcpad = gst_element_get_static_pad (mux,"src");
#if (VERSION == 1)
muxvideosinkpad = gst_element_get_request_pad (mux, "video_%u");
#else
muxvideosinkpad = gst_element_get_request_pad (mux, "video_%d");
#endif
if (!gst_element_link_many (q1, mux,NULL )) {
g_print ("[APP]: Failed to link DYNAMIC Pad's of elements");
return -3;
}
filesinkpad = gst_element_get_static_pad (filesink,"sink");
if (!gst_element_link_many (mux,filesink, NULL)) {
g_print ("[APP]: Failed to link STATIC_2 Pad's of elements");
return -3;
}
g_print ("Moving to PLAYING\n");
gst_element_set_state (mux, GST_STATE_PLAYING);
gst_element_set_state (filesink, GST_STATE_PLAYING);
newfile = NO_NEW_FILE;
chunk = TRUE;
g_print("\t [ APP-BLOCK ]: EOS_PROBE [ STOP ] ===================\n");
#if ( VERSION == 1)
return GST_PAD_PROBE_OK;
#else
return TRUE;
#endif
}
#if ( VERSION == 1 )
static GstPadProbeReturn pad_probe_cb (GstPad * pad, GstPadProbeInfo * info,gpointer user_data)
#else
static gboolean pad_probe_cb (GstPad * pad, GstBuffer * buffer, gpointer user_data)
#endif
{
unsigned int sleep_count =0;
g_print("\t [ APP-BLOCK ]: VIDEO_PAD_BROBE [ START ] ===================\n");
#if ( VERSION == 1)
gst_pad_remove_probe (pad, GST_PAD_PROBE_INFO_ID (info));
#else
gst_pad_remove_buffer_probe (pad, probe_id);
#endif
g_object_set (G_OBJECT(src), "pattern",attempt, NULL);
#if ( VERSION == 1 )
gst_pad_add_probe (filesinkpad,GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, eos_cb, user_data, NULL);
#else
probe_id = gst_pad_add_event_probe (filesinkpad, G_CALLBACK(eos_cb), user_data);
#endif
gst_pad_send_event (muxvideosinkpad, gst_event_new_eos ());
// Wait til the EOS have been processed
while(newfile != NO_NEW_FILE){
g_print("In sleep %d \n",sleep_count);
sleep_count=sleep_count+1;
sleep(1);
}
g_print("\t [ APP-BLOCK ]: VIDEO_PAD_BROBE [ STOP ] ===================\n");
#if ( VERSION == 1)
return GST_PAD_PROBE_OK;
#else
return TRUE;
#endif
} // End brace of video_pad_probe_cb
static gboolean timeout_cb (gpointer user_data)
{
attempt = attempt+1;
timer_count=timer_count+1;
if ( chunk == TRUE ) {
chunk = FALSE;
g_print("\t [ APP-TIMER ]: IN-TIMER %d [ BEFORE-BLOCKING ] =========\n",timer_count);
newfile = NEW_FILE;
#if ( VERSION == 1 )
gst_pad_add_probe (q1sinkpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,pad_probe_cb, user_data, NULL);
#else
probe_id = gst_pad_add_buffer_probe (q1sinkpad, pad_probe_cb, user_data);
#endif
}
g_print("\t [ APP-TIMER ]: IN-TIMER %d =========\n",timer_count);
if ( timer_count == 12 ){
return FALSE;
}
return TRUE;
} // End brace of "timeout_cb"
static gboolean bus_cb (GstBus * bus, GstMessage * msg, gpointer user_data)
{
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_ERROR:{
GError *err = NULL;
gchar *dbg;
gst_message_parse_error (msg, &err, &dbg);
gst_object_default_error (msg->src, err, dbg);
g_error_free (err);
g_free (dbg);
g_main_loop_quit(mainloop);
break;
}
case GST_MESSAGE_STATE_CHANGED: {
GstState old_state, new_state;
gst_message_parse_state_changed (msg, &old_state, &new_state, NULL);
g_print ("[ APP - MESSAGE ]: Element %s changed state from %s to %s.\n",
GST_OBJECT_NAME (msg->src),
gst_element_state_get_name (old_state),
gst_element_state_get_name (new_state));
break;
}
case GST_MESSAGE_WARNING:{
GError *err = NULL;
gchar *name, *debug = NULL;
name = gst_object_get_path_string (msg->src);
gst_message_parse_warning (msg, &err, &debug);
g_print ("\n[ APP - MESSAGE ]: ERROR: from element %s: %s\n", name,
err->message);
if (debug != NULL)
g_print ("%s \n\n",debug);
g_error_free (err);
g_free (debug);
g_free (name);
break;
}
case GST_MESSAGE_EOS:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_EOS\n");
break;
}
case GST_MESSAGE_INFO:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_INFO\n");
break;
}
case GST_MESSAGE_TAG:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_TAG\n");
break;
}
case GST_MESSAGE_BUFFERING:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_BUFFERING\n");
break;
}
case GST_MESSAGE_STEP_DONE:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_STEP_DONE\n");
break;
}
case GST_MESSAGE_CLOCK_PROVIDE:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_CLOCK_PROVIDE\n");
break;
}
case GST_MESSAGE_CLOCK_LOST:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_CLOCK_LOST\n");
break;
}
case GST_MESSAGE_NEW_CLOCK:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_NEW_CLOCK\n");
break;
}
case GST_MESSAGE_APPLICATION:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_APPLICATION\n");
break;
}
case GST_MESSAGE_ELEMENT:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_ELEMENT\n");
break;
}
case GST_MESSAGE_SEGMENT_START:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_SEGMENT_START\n");
break;
}
case GST_MESSAGE_SEGMENT_DONE:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_SEGMENT_DONE\n");
break;
}
case GST_MESSAGE_LATENCY:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_LATENCY\n");
break;
}
case GST_MESSAGE_ASYNC_START:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_ASYNC_START\n");
break;
}
case GST_MESSAGE_ASYNC_DONE:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_ASYNC_DONE\n");
break;
}
case GST_MESSAGE_REQUEST_STATE:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_REQUEST_STATE\n");
break;
}
case GST_MESSAGE_STEP_START:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_STEP_START\n");
break;
}
case GST_MESSAGE_QOS:{
g_print ("[ APP - MESSAGE ]: GST_MESSAGE_QOS\n");
break;
}
default:
break;
}
return TRUE;
}//End brace of SWITCH condition
int main (int argc, char **argv)
{
gst_init (&argc, &argv);
// 0 - Creating the PIPELINE
pipeline = gst_pipeline_new ("pipeline");
// 1 - Creating the SRC & TIMEOVERLAY
src = gst_element_factory_make ("videotestsrc", NULL);
g_object_set (G_OBJECT(src), "pattern",attempt, NULL);
g_object_set (G_OBJECT(src), "do-timestamp",attempt, NULL);
g_object_set (G_OBJECT(src), "is-live", TRUE, NULL);
clockoverlay = gst_element_factory_make ("clockoverlay", NULL ) ;
g_object_set (G_OBJECT (clockoverlay), "time-format","%d-%b-%Y / %H:%M:%S",NULL);
timeoverlay = gst_element_factory_make ("timeoverlay", NULL ) ;
// 2 - Creating the QUEUE
q1 = gst_element_factory_make ("queue", NULL);
q2 = gst_element_factory_make ("queue", NULL);
// 3 - Creating the MUX
mux = gst_element_factory_make("avimux",NULL);
// 4 - Creating the FILESINK
filesink = gst_element_factory_make ("filesink", NULL);
sprintf( buffer, "test_%d.avi" , attempt);
g_print("\n\t [APP]: Created new file of %s \n",buffer);
g_object_set(G_OBJECT(filesink),"location", buffer, NULL);
// 7 - Adding all the elements in to BIN
gst_bin_add_many (GST_BIN (pipeline),mux,filesink, NULL);
gst_bin_add_many (GST_BIN (pipeline), src, clockoverlay ,timeoverlay, q1,NULL);
// 8 - Linking all static pad
if (!gst_element_link_many (src, clockoverlay,timeoverlay , q1, NULL )) {
g_print ("[APP]: Failed to link src, clockoverlay,timeoverlay \n");
return -3;
}
if (!gst_element_link_many (mux,filesink, NULL)) {
g_print ("[APP]: Failed to link mux,filesink ");
return -3;
}
// 9 - Linking DYNAMIC PAD
#if ( VERSION == 1 )
muxvideosinkpad = gst_element_get_request_pad (mux, "video_%u");
#else
muxvideosinkpad = gst_element_get_request_pad (mux, "video_%d");
#endif
sinkname = gst_pad_get_name (muxvideosinkpad);
g_print ("\t [APP]: A new pad %s was created\n\n", sinkname);
if (!gst_element_link_many (q1, mux,NULL )) {
g_print ("[APP]: Failed to link DYNAMIC Pad's of q1, mux");
return -3;
}
g_free (sinkname);
// 10 - Getting the blocking PAD
muxsrcpad = gst_element_get_static_pad (mux,"src");
filesinkpad = gst_element_get_static_pad (filesink,"sink");
q1sinkpad = gst_element_get_static_pad (q1,"sink");
if (q1sinkpad == NULL){
g_print("Q1SINK pad is NULL \n");
return -4;
}
// 11 - Starting the PIPELINE
if (gst_element_set_state (pipeline,GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
g_error ("[APP]: Failed to go into PLAYING state");
return -6;
}
mainloop = g_main_loop_new (NULL, FALSE);
gst_bus_add_watch (GST_ELEMENT_BUS (pipeline), bus_cb, mainloop);
g_timeout_add_seconds (TIMER_DURATION, timeout_cb, mainloop);
g_main_loop_run (mainloop);
// 10 - Stopping the PIPELINE
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
return 0;
}