static void
type_instance_init (GTypeInstance *instance,
                    gpointer g_class)
{
    GstOmxBaseFilter21 *self;
    GstElementClass *element_class;
    GstOmxBaseFilter21Class *bclass;
	int i;
	char srcname[10];

    element_class = GST_ELEMENT_CLASS (g_class);
    bclass = GST_OMX_BASE_FILTER21_CLASS (g_class);

    self = GST_OMX_BASE_FILTER21 (instance);

    GST_LOG_OBJECT (self, "begin");


    self->gomx = g_omx_core_new (self, g_class);
    for (i = 0; i < NUM_INPUTS; i++) {
		sprintf(srcname, "in_%02x", i);
		self->input_port_index[i] = OMX_VSWMOSAIC_INPUT_PORT_START_INDEX + i;
		self->in_port[i] = g_omx_core_get_port (self->gomx, srcname, self->input_port_index[i]);
		self->in_port[i]->omx_allocate = TRUE;
		self->in_port[i]->share_buffer = FALSE;
		self->in_port[i]->port_index = self->input_port_index[i];
	}
	self->output_port_index = OMX_VSWMOSAIC_OUTPUT_PORT_START_INDEX;
	self->out_port = g_omx_core_get_port (self->gomx, "out", self->output_port_index);
	self->out_port->buffer_alloc = buffer_alloc;
	self->out_port->omx_allocate = TRUE;
	self->out_port->share_buffer = FALSE;
	self->out_port->port_index = self->output_port_index;
	self->number_eos = 2;
    self->ready_lock = g_mutex_new ();
    self->collectpads = gst_collect_pads_new();
    gst_collect_pads_set_function(self->collectpads, &collected_pads, self);
	for (i = 0; i < NUM_INPUTS; i++) {
		sprintf(srcname, "sink_%02x", i);
		self->sinkpad[i] =	gst_pad_new_from_template (gst_element_class_get_pad_template (element_class, srcname), srcname);

		gst_pad_set_chain_function (self->sinkpad[i], bclass->pad_chain);
		gst_pad_set_event_function (self->sinkpad[i], bclass->pad_event);
		gst_pad_set_setcaps_function (self->sinkpad[i], GST_DEBUG_FUNCPTR (sink_setcaps));
		gst_element_add_pad (GST_ELEMENT (self), self->sinkpad[i]);
		gst_collect_pads_add_pad(self->collectpads, self->sinkpad[i], sizeof(GstCollectData));
	}
	self->srcpad=
		gst_pad_new_from_template (gst_element_class_get_pad_template (element_class, "src"), "src");
	gst_pad_set_activatepush_function (self->srcpad, activate_push);
	gst_pad_set_setcaps_function (self->srcpad, GST_DEBUG_FUNCPTR (src_setcaps));
	gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
    self->duration = GST_CLOCK_TIME_NONE;
    self->sink_camera_timestamp = GST_CLOCK_TIME_NONE;
    self->out_framerate = NULL;

    GST_LOG_OBJECT (self, "end");
}
static void
get_property (GObject *obj,
              guint prop_id,
              GValue *value,
              GParamSpec *pspec)
{
    GstOmxBaseFilter21 *self;

    self = GST_OMX_BASE_FILTER21 (obj);

    switch (prop_id)
    {
        case ARG_COMPONENT_ROLE:
            g_value_set_string (value, self->omx_role);
            break;
        case ARG_COMPONENT_NAME:
            g_value_set_string (value, self->omx_component);
            break;
        case ARG_LIBRARY_NAME:
            g_value_set_string (value, self->omx_library);
            break;
        case ARG_USE_TIMESTAMPS:
            g_value_set_boolean (value, self->gomx->use_timestamps);
            break;
        case ARG_GEN_TIMESTAMPS:
            g_value_set_boolean (value, self->gomx->gen_timestamps);
            break;
        case ARG_X_SINK_0:
			g_value_set_uint(value,self->x[0]);
			break;
		case ARG_Y_SINK_0:
			g_value_set_uint(value,self->y[0]);
			break;
		case ARG_X_SINK_1:
			g_value_set_uint(value,self->x[1]);
			break;
		case ARG_Y_SINK_1:
			g_value_set_uint(value,self->y[1]);
			break;	
        case ARG_NUM_INPUT_BUFFERS:
        case ARG_NUM_OUTPUT_BUFFERS:
            {
                OMX_PARAM_PORTDEFINITIONTYPE param;
                GOmxPort *port = (prop_id == ARG_NUM_INPUT_BUFFERS) ?
                        self->in_port[0] : self->out_port;

                G_OMX_PORT_GET_DEFINITION (port, &param);

                g_value_set_uint (value, param.nBufferCountActual);
            }
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
            break;
    }
}
static void
type_instance_init (GTypeInstance *instance,
                    gpointer g_class)
{
    GstOmxBaseFilter21 *omx_base;

    omx_base = GST_OMX_BASE_FILTER21 (instance);
	omx_base->omx_setup = omx_setup;
    GST_DEBUG_OBJECT (omx_base, "start");
}
static gboolean
sink_setcaps (GstPad *pad,
              GstCaps *caps)
{
    GstStructure *structure;
    GstOmxBaseFilter21 *self;
    GOmxCore *gomx;
    GstVideoFormat format;
    int sink_number;
    self = GST_OMX_BASE_FILTER21 (GST_PAD_PARENT (pad));
	if(strcmp(GST_PAD_NAME(pad), "sink_00") == 0){
		sink_number=0;
	}
	else if(strcmp(GST_PAD_NAME(pad), "sink_01") == 0){
		sink_number=1;
	}
    gomx = (GOmxCore *) self->gomx;
	GST_INFO_OBJECT (self, "setcaps (sink): %d", sink_number);
    GST_INFO_OBJECT (self, "setcaps (sink): %" GST_PTR_FORMAT, caps);
	
    g_return_val_if_fail (caps, FALSE);
    g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);

    structure = gst_caps_get_structure (caps, 0);

    g_return_val_if_fail (structure, FALSE);
    if (!gst_video_format_parse_caps_strided (caps,
            &format, &self->in_width[sink_number], &self->in_height[sink_number], &self->in_stride[sink_number]))
    {
        GST_WARNING_OBJECT (self, "width and/or height is not set in caps");
        return FALSE;
    }

    if (!self->in_stride[sink_number]) 
    {
        self->in_stride[sink_number] = gstomx_calculate_stride (self->in_width[sink_number], format);
    }

    {
        /* Output framerate correspond to the minimum input framerate */
        const GValue *sink_framerate = NULL;
        sink_framerate = gst_structure_get_value (structure, "framerate");
        if( GST_VALUE_HOLDS_FRACTION(sink_framerate) )
        {
            if( self->out_framerate == NULL || gst_value_compare(sink_framerate, self->out_framerate) == GST_VALUE_LESS_THAN )
            {
                self->out_framerate = sink_framerate;
                self->duration = gst_util_uint64_scale_int(GST_SECOND, gst_value_get_fraction_denominator(sink_framerate),
                                                                       gst_value_get_fraction_numerator(sink_framerate));
            }
        }
    }

    return gst_pad_set_caps (pad, caps);
}
static gboolean
activate_push (GstPad *pad,
               gboolean active)
{
    gboolean result = TRUE;
    GstOmxBaseFilter21 *self;
	int i;

    self = GST_OMX_BASE_FILTER21 (gst_pad_get_parent (pad));

    if (active)
    {
        GST_DEBUG_OBJECT (self, "activate");
        self->last_pad_push_return = GST_FLOW_OK;

        /* we do not start the task yet if the pad is not connected */
        if (gst_pad_is_linked (pad))
        {
            if (self->ready)
            {
                /** @todo link callback function also needed */
				for (i = 0; i < NUM_INPUTS; i++)
					g_omx_port_resume (self->in_port[i]);
					
               	g_omx_port_resume (self->out_port);

                //result = gst_pad_start_task (pad, output_loop, pad);
            }
        }
    }
    else
    {
        GST_DEBUG_OBJECT (self, "deactivate");

        if (self->ready)
        {

            /* unlock loops */
			for (i = 0; i < NUM_INPUTS; i++)
				g_omx_port_pause (self->in_port[i]);
				
           	g_omx_port_pause (self->out_port);
        }

        /* make sure streaming finishes */
        result = gst_pad_stop_task (pad);
    }

    gst_object_unref (self);

    return result;
}
static gboolean
src_setcaps (GstPad *pad, GstCaps *caps)
{
    GstOmxBaseFilter21 *self;
    GstVideoFormat format;
    GstStructure *structure;

    self = GST_OMX_BASE_FILTER21 (GST_PAD_PARENT (pad));
    structure = gst_caps_get_structure (caps, 0);

    GST_INFO_OBJECT (self, "setcaps (src): %" GST_PTR_FORMAT, caps);
    g_return_val_if_fail (caps, FALSE);
    g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);

    if (!gst_video_format_parse_caps_strided (caps, &format, &self->out_width, &self->out_height, &self->out_stride))
    {
        GST_WARNING_OBJECT (self, "width and/or height is not set in caps");
        return FALSE;
    }

    if (!self->out_stride)
    {
        self->out_stride = gstomx_calculate_stride (self->out_width, format);
    }

    /* Set output framerate already calculated in sink_setcaps */
    if( self->out_framerate == NULL ) {
        GST_WARNING_OBJECT (self, "unable to calculate output framerate");
        return FALSE;
    }

    gint out_framerate_num = gst_value_get_fraction_numerator(self->out_framerate);
    gint out_framerate_denom = gst_value_get_fraction_denominator(self->out_framerate);

    gst_structure_set(structure, "framerate", GST_TYPE_FRACTION, out_framerate_num, out_framerate_denom, NULL);
    
    GST_INFO_OBJECT(self, "output framerate is: %d/%d", out_framerate_num, out_framerate_denom);

    /* save the src caps later needed by omx transport buffer */
    if (self->out_port->caps)
        gst_caps_unref (self->out_port->caps);

    self->out_port->caps = gst_caps_copy (caps);

    return TRUE;
}
static GstCaps * create_src_caps (GstOmxBaseFilter21 *omx_base)
{
    GstCaps *caps;    
    GstOmxBaseFilter21 *self;
    int width, height;
    GstStructure *struc;

    self = GST_OMX_BASE_FILTER21 (omx_base);
    caps = gst_pad_peer_get_caps (omx_base->srcpad);

    if (gst_caps_is_empty (caps))
    {

        width = 1920;
        height = 1088;

    }
    else
    {
        GstStructure *s;

        s = gst_caps_get_structure (caps, 0);

        if (!(gst_structure_get_int (s, "width", &width) &&
            gst_structure_get_int (s, "height", &height)))
        {

			width = 1920;
			height = 1088;

        }
    }

    caps = gst_caps_new_empty ();
    struc = gst_structure_new (("video/x-raw-yuv"),
            "width",  G_TYPE_INT, width,
            "height", G_TYPE_INT, height,
            "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'),
            NULL);


    gst_caps_append_structure (caps, struc);

    return caps;
}
static void
finalize (GObject *obj)
{
    GstOmxBaseFilter21 *self;

    self = GST_OMX_BASE_FILTER21 (obj);

    if (self->codec_data)
    {
        gst_buffer_unref (self->codec_data);
        self->codec_data = NULL;
    }

    g_omx_core_free (self->gomx);

    g_free (self->omx_role);
    g_free (self->omx_component);
    g_free (self->omx_library);

    g_mutex_free (self->ready_lock);

    G_OBJECT_CLASS (parent_class)->finalize (obj);
}
static void
omx_setup (GstOmxBaseFilter21 *omx_base)
{
	int i;
	GOmxCore *gomx;
	OMX_ERRORTYPE eError = OMX_ErrorNone;
	OMX_PARAM_BUFFER_MEMORYTYPE memTypeCfg;
	OMX_PARAM_PORTDEFINITIONTYPE paramPort;
	OMX_CONFIG_VSWMOSAIC_CREATEMOSAICLAYOUT  sMosaic;
	OMX_CONFIG_VSWMOSAIC_SETBACKGROUNDCOLOR  sMosaicBg;
	OMX_PARAM_VSWMOSAIC_MOSAIC_PERIODICITY	 sMosaicFPS;
    GstOmxBaseFilter21 *self;
    gomx = (GOmxCore *) omx_base->gomx;
    self = GST_OMX_BASE_FILTER21(omx_base);
	
    GST_LOG_OBJECT (self, "begin");
    /* set the output cap */
    gst_pad_set_caps (self->srcpad, create_src_caps (omx_base));
    /* Setting Memory type at input port to Raw Memory */
    GST_LOG_OBJECT (self, "Setting input port to Raw memory");

    _G_OMX_INIT_PARAM (&memTypeCfg);
	memTypeCfg.eBufMemoryType = OMX_BUFFER_MEMORY_DEFAULT;

	for ( i = 0; i < NUM_INPUTS; i++) {
		memTypeCfg.nPortIndex = omx_base->in_port[i]->port_index;
		eError = OMX_SetParameter (gomx->omx_handle, OMX_TI_IndexParamBuffMemType, &memTypeCfg);
		if (eError != OMX_ErrorNone)
		{
				return;
		}
	}
	
	/* Setting Memory type at output port to Raw Memory */
    GST_LOG_OBJECT (self, "Setting output port to Raw memory");
    
    memTypeCfg.nPortIndex = omx_base->out_port->port_index;
	memTypeCfg.eBufMemoryType = OMX_BUFFER_MEMORY_DEFAULT;
	eError = OMX_SetParameter (gomx->omx_handle, OMX_TI_IndexParamBuffMemType, &memTypeCfg);

	if (eError != OMX_ErrorNone)
	{
		return;
	}

	GST_LOG_OBJECT (self, "Setting port definition (input)");


	for ( i = 0; i < NUM_INPUTS; i++) {
		/* set input height/width and color format */
		G_OMX_PORT_GET_DEFINITION (omx_base->in_port[i], &paramPort);
		paramPort.format.video.nFrameWidth  = self->in_width[i]; 
		paramPort.format.video.nFrameHeight = self->in_height[i];
		/* swmosaic is connceted to scalar, whose stride is different than width*/
		paramPort.format.video.nStride = self->in_stride[i];
		paramPort.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
		paramPort.format.video.eColorFormat = OMX_COLOR_FormatYCbYCr;
		paramPort.nBufferSize = (paramPort.format.video.nStride * paramPort.format.video.nFrameHeight);

		paramPort.nBufferAlignment = 0;
		paramPort.bBuffersContiguous = 0;
	
		G_OMX_PORT_SET_DEFINITION (omx_base->in_port[i], &paramPort);
		g_omx_port_setup (omx_base->in_port[i], &paramPort);
	}
	
	G_OMX_PORT_GET_DEFINITION (omx_base->out_port, &paramPort);
	paramPort.format.video.nFrameWidth  = self->out_width;
	paramPort.format.video.nFrameHeight = self->out_height;
	paramPort.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
	paramPort.format.video.eColorFormat = OMX_COLOR_FormatYCbYCr;
	paramPort.nBufferAlignment = 0;
	paramPort.bBuffersContiguous = 0;
	paramPort.nBufferCountActual = 4;
	paramPort.format.video.nStride = self->out_stride;
	paramPort.nBufferSize = paramPort.format.video.nStride * paramPort.format.video.nFrameHeight;
	
	G_OMX_PORT_SET_DEFINITION (omx_base->out_port, &paramPort);
	g_omx_port_setup (omx_base->out_port, &paramPort);
	
	_G_OMX_INIT_PARAM (&sMosaic);
	sMosaic.nPortIndex  = OMX_VSWMOSAIC_OUTPUT_PORT_START_INDEX;
  
	sMosaic.nOpWidth    = self->out_width;  /* Width in pixels  */
	sMosaic.nOpHeight   = self->out_height; /* Height in pixels */
	sMosaic.nOpPitch    = self->out_stride; /* Pitch in bytes   */

	sMosaic.nNumWindows = 2;
	sMosaic.sMosaicWinFmt[0].dataFormat = OMX_COLOR_FormatYCbYCr;
	sMosaic.sMosaicWinFmt[0].nPortIndex = 0;
	sMosaic.sMosaicWinFmt[0].pitch[0]   =  self->in_stride[0];
	sMosaic.sMosaicWinFmt[0].winStartX  = self->x[0];
	sMosaic.sMosaicWinFmt[0].winStartY  = self->y[0];
	sMosaic.sMosaicWinFmt[0].winWidth   = self->in_width[0];
	sMosaic.sMosaicWinFmt[0].winHeight  = self->in_height[0];
	
	sMosaic.sMosaicWinFmt[1].dataFormat = OMX_COLOR_FormatYCbYCr;
	sMosaic.sMosaicWinFmt[1].nPortIndex = 1;
	sMosaic.sMosaicWinFmt[1].pitch[0]   = self->in_stride[1];
	sMosaic.sMosaicWinFmt[1].winStartX  = self->x[1];
	sMosaic.sMosaicWinFmt[1].winStartY  = self->y[1];
	sMosaic.sMosaicWinFmt[1].winWidth   = self->in_width[1];
	sMosaic.sMosaicWinFmt[1].winHeight  = self->in_height[1];
	
	eError = OMX_SetConfig (gomx->omx_handle, 
							OMX_TI_IndexConfigVSWMOSAICCreateMosaicLayout, 
							&sMosaic);
	if (eError != OMX_ErrorNone)
	{
			printf("Error during Layout settings\n");
	}
	_G_OMX_INIT_PARAM(&sMosaicBg);
	sMosaicBg.nPortIndex  = OMX_VSWMOSAIC_OUTPUT_PORT_START_INDEX;
	sMosaicBg.uColor = BG_COLOR;
	eError = OMX_SetConfig (gomx->omx_handle, 
							OMX_TI_IndexConfigVSWMOSAICSetBackgroundColor, 
							&sMosaicBg);
	if (eError != OMX_ErrorNone)
	{
			printf("Error during background\n");
	}
	
// FPS settings didn't work actually 
#if 1
	_G_OMX_INIT_PARAM(&sMosaicFPS);
	sMosaicFPS.nPortIndex  = OMX_VSWMOSAIC_OUTPUT_PORT_START_INDEX;
	sMosaicFPS.nFps		   = 60;				
	eError = OMX_SetConfig (gomx->omx_handle, 
							OMX_TI_IndexParamVSWMOSAICMosaicPeriodicity, 
							&sMosaicFPS);
	if (eError != OMX_ErrorNone)
	{
			printf("Error during FPS settings : %s\n",g_omx_error_to_str (eError));
	}
#endif
}
static gboolean
pad_event (GstPad *pad,
           GstEvent *event)
{
    GstOmxBaseFilter21 *self;
    GOmxCore *gomx;
    gboolean ret = TRUE;
	int i;
    self = GST_OMX_BASE_FILTER21 (GST_OBJECT_PARENT (pad));
    gomx = self->gomx;

    GST_INFO_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));

    switch (GST_EVENT_TYPE (event))
    {
        case GST_EVENT_EOS:
            /* printf ("Recieved EOS event, press <CTRL+C> to terminate pipeline.\n"); */
	    g_mutex_lock (self->ready_lock);
            self->number_eos--;
            printf("EOS : %d\n",self->number_eos);
			g_mutex_unlock (self->ready_lock);
            if(self->number_eos == 0){
              ret = gst_pad_push_event (self->srcpad, event);
            } 
            else{
              gst_event_unref (event);
            }
            break;

        case GST_EVENT_FLUSH_START:
			gst_event_ref(event);
			ret &= gst_pad_push_event (self->srcpad, event);
            self->last_pad_push_return = GST_FLOW_WRONG_STATE;
            g_omx_core_flush_start (gomx);
	        gst_pad_pause_task (self->srcpad);
            ret = TRUE;
            break;

        case GST_EVENT_FLUSH_STOP:
			gst_event_ref(event);
			ret &= gst_pad_push_event (self->srcpad, event);
            self->last_pad_push_return = GST_FLOW_OK;

            g_omx_core_flush_stop (gomx);

            /*if (self->ready)
               	gst_pad_start_task (self->srcpad, output_loop, self->srcpad);*/

            ret = TRUE;
            break;

        case GST_EVENT_NEWSEGMENT:
			self->last_buf_timestamp = GST_CLOCK_TIME_NONE;
			gst_event_ref(event);
			ret &= gst_pad_push_event (self->srcpad, event);
            break;

        default:
			gst_event_ref(event);
			ret &= gst_pad_push_event (self->srcpad, event);
            break;
    }

    GST_LOG_OBJECT (self, "end");

    return ret;
}
static GstFlowReturn
pad_chain (GstPad *pad,
           GstBuffer *buf)
{
    GOmxCore *gomx;
    GOmxPort *in_port;
    GstOmxBaseFilter21 *self;
    GstFlowReturn ret = GST_FLOW_OK;
	int i;
	static sink_init = 0;
	int sink_number;
	static gboolean init_done = FALSE;
	
    self = GST_OMX_BASE_FILTER21 (GST_OBJECT_PARENT (pad));
	if(strcmp(GST_PAD_NAME(pad), "sink_00") == 0){
		sink_number=0;
        self->sink_camera_timestamp = GST_BUFFER_TIMESTAMP(buf);
	}
	else if(strcmp(GST_PAD_NAME(pad), "sink_01") == 0){
		sink_number=1;
	}
    PRINT_BUFFER (self, buf);

    gomx = self->gomx;

    GST_LOG_OBJECT (self, "begin: size=%u, state=%d, sink_number=%d", GST_BUFFER_SIZE (buf), gomx->omx_state, sink_number);
	
	/*if (G_LIKELY (gomx->omx_state != OMX_StateExecuting))
    {
		GST_INFO_OBJECT (self, "Begin - Port %d", sink_number);
		//setup_input_buffer (self, buf, sink_number);
		//sink_init++;
		//g_mutex_lock (self->ready_lock);
		if(init_done == TRUE){
			GST_INFO_OBJECT (self, "Init_done");
			//g_mutex_unlock(self->ready_lock);
		}
		if(init_done == TRUE){
			sink_init = 0;
			init_done = FALSE;

		}
		else{
			while(sink_init != 2){
				usleep(1000);
			}
		}
	}*/
	
    if (G_UNLIKELY (gomx->omx_state == OMX_StateLoaded))
    {

        GST_INFO_OBJECT (self, "omx: prepare");
        
        /** @todo this should probably go after doing preparations. */
        if (self->omx_setup)
        {
            self->omx_setup (self);
        }
        
        /* enable input port */
        for(i=0;i<NUM_INPUTS;i++){
			GST_INFO_OBJECT (self,"Enable Port %d",self->in_port[i]->port_index);
			OMX_SendCommand (gomx->omx_handle, OMX_CommandPortEnable, self->in_port[i]->port_index, NULL);
			g_sem_down (self->in_port[i]->core->port_sem);
		}
		GST_INFO_OBJECT (self,"Enable Port %d",self->out_port->port_index);
		/* enable output port */
		OMX_SendCommand (gomx->omx_handle,OMX_CommandPortEnable, self->out_port->port_index, NULL);
		g_sem_down (self->out_port->core->port_sem);

		/* indicate that port is now configured */

        setup_ports (self);

        g_omx_core_prepare (self->gomx);

        if (gomx->omx_state == OMX_StateIdle)
        {
            self->ready = TRUE;
           	//gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
        }
        
        if (gomx->omx_state != OMX_StateIdle)
            goto out_flushing;
        
        GST_INFO_OBJECT (self, "omx: end state Loaded");    
    }
    
    if (G_UNLIKELY (gomx->omx_state == OMX_StateIdle))
	{
		g_omx_core_start (gomx);
		GST_INFO_OBJECT (self, "Release Port - %d", sink_number);
		init_done = TRUE;
		//g_mutex_unlock (self->ready_lock);
		if (gomx->omx_state != OMX_StateExecuting){
			GST_INFO_OBJECT (self, "omx: executing FAILED !");
			goto out_flushing;
		
		}
	}
	
	if (G_LIKELY (self->in_port[sink_number]->enabled))
	{	      
		

		if (G_UNLIKELY (gomx->omx_state != OMX_StateExecuting))
		{
			GST_ERROR_OBJECT (self, "Whoa! very wrong");
		}

		while (TRUE)
		{
			gint sent;
			if (self->last_pad_push_return != GST_FLOW_OK ||
				!(gomx->omx_state == OMX_StateExecuting ||
				gomx->omx_state == OMX_StatePause))
			{
				GST_INFO_OBJECT (self, "last_pad_push_return=%d", self->last_pad_push_return);
				goto out_flushing;
			}
			sent = g_omx_port_send (self->in_port[sink_number], buf);
			if (G_UNLIKELY (sent < 0))
			{
				ret = GST_FLOW_WRONG_STATE;
				goto out_flushing;
			}
			else if (sent < GST_BUFFER_SIZE (buf))
			{
				GstBuffer *subbuf = gst_buffer_create_sub (buf, sent,
						GST_BUFFER_SIZE (buf) - sent);
				gst_buffer_unref (buf);
				buf = subbuf;
			}
			else
			{
				gst_buffer_unref (buf);

				break;
			}
			
		}
	}
	else
	{
		GST_WARNING_OBJECT (self, "done");
		ret = GST_FLOW_UNEXPECTED;
	}
	return ret;
leave:

    GST_LOG_OBJECT (self, "end");

    return ret;

    /* special conditions */
out_flushing:
    {
        const gchar *error_msg = NULL;

        if (gomx->omx_error)
        {
            error_msg = "Error from OpenMAX component";
        }
        else if (gomx->omx_state != OMX_StateExecuting &&
                 gomx->omx_state != OMX_StatePause)
        {
            error_msg = "OpenMAX component in wrong state";
        }

        if (error_msg)
        {
            GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), (error_msg));
            ret = GST_FLOW_ERROR;
        }

        gst_buffer_unref (buf);

        goto leave;
    }
}
static void
output_loop (gpointer data)
{
    GstPad *pad;
    GOmxCore *gomx;
    GOmxPort *out_port;
    GstOmxBaseFilter21 *self;
    GstFlowReturn ret = GST_FLOW_OK;
    GstOmxBaseFilter21Class *bclass;
    
    pad = data;
    self = GST_OMX_BASE_FILTER21 (gst_pad_get_parent (pad));
    gomx = self->gomx;

    bclass = GST_OMX_BASE_FILTER21_GET_CLASS (self);

    if (!self->ready)
    {
        g_error ("not ready");
        return;
    }

    out_port = (GOmxPort *)gst_pad_get_element_private(pad);

    if (G_LIKELY (out_port->enabled))
    {
        gpointer obj = g_omx_port_recv (out_port);
        if (G_UNLIKELY (!obj))
        {
            GST_WARNING_OBJECT (self, "null buffer: leaving");
            ret = GST_FLOW_WRONG_STATE;
            goto leave;
        }

        if (G_LIKELY (GST_IS_BUFFER (obj)))
        {
            if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (obj, GST_BUFFER_FLAG_IN_CAPS)))
            {
                GstCaps *caps = NULL;
                GstStructure *structure;
                GValue value = { 0 };

                caps = gst_pad_get_negotiated_caps (pad);
                caps = gst_caps_make_writable (caps);
                structure = gst_caps_get_structure (caps, 0);

                g_value_init (&value, GST_TYPE_BUFFER);
                gst_value_set_buffer (&value, obj);
                gst_buffer_unref (obj);
                gst_structure_set_value (structure, "codec_data", &value);
                g_value_unset (&value);

                gst_pad_set_caps (pad, caps);
            }
            else
            {
                GstBuffer *buf = GST_BUFFER (obj);
                ret = bclass->push_buffer (self, buf);
                GST_DEBUG_OBJECT (self, "ret=%s", gst_flow_get_name (ret));
				// HACK!! Dont care if one of the output pads are not connected
                ret = GST_FLOW_OK;
            }
        }
        else if (GST_IS_EVENT (obj))
        {
            GST_INFO_OBJECT (self, "got eos");
            gst_pad_push_event (pad, obj);
            ret = GST_FLOW_UNEXPECTED;
            goto leave;
        }

    }

leave:

    self->last_pad_push_return = ret;

    if (gomx->omx_error != OMX_ErrorNone)
    {
        GST_INFO_OBJECT (self, "omx_error=%s", g_omx_error_to_str (gomx->omx_error));
        ret = GST_FLOW_ERROR;
    }

    if (ret != GST_FLOW_OK)
    {
        GST_INFO_OBJECT (self, "pause task, reason:  %s",
                         gst_flow_get_name (ret));
        gst_pad_pause_task (pad);
    }

    gst_object_unref (self);
    
}
static void
set_property (GObject *obj,
              guint prop_id,
              const GValue *value,
              GParamSpec *pspec)
{
    GstOmxBaseFilter21 *self;

    self = GST_OMX_BASE_FILTER21(obj);

    switch (prop_id)
    {
        case ARG_COMPONENT_ROLE:
            g_free (self->omx_role);
            self->omx_role = g_value_dup_string (value);
            break;
        case ARG_COMPONENT_NAME:
            g_free (self->omx_component);
            self->omx_component = g_value_dup_string (value);
            break;
        case ARG_LIBRARY_NAME:
            g_free (self->omx_library);
            self->omx_library = g_value_dup_string (value);
            break;
        case ARG_USE_TIMESTAMPS:
            self->gomx->use_timestamps = g_value_get_boolean (value);
            break;
        case ARG_GEN_TIMESTAMPS:
            self->gomx->gen_timestamps = g_value_get_boolean (value);
            break;
        case ARG_X_SINK_0:
			self->x[0] = g_value_get_uint(value);
			break;
		case ARG_Y_SINK_0:
			self->y[0] = g_value_get_uint(value);
			break;
		case ARG_X_SINK_1:
			self->x[1] = g_value_get_uint(value);
			break;
		case ARG_Y_SINK_1:
			self->y[1] = g_value_get_uint(value);
			break;	
        case ARG_NUM_INPUT_BUFFERS:
            {
                OMX_PARAM_PORTDEFINITIONTYPE param;
                OMX_U32 nBufferCountActual = g_value_get_uint (value);
                int i;
                for (i = 0; i < NUM_INPUTS; i++) {
					G_OMX_PORT_GET_DEFINITION (self->in_port[i], &param);
					g_return_if_fail (nBufferCountActual >= param.nBufferCountMin);
					param.nBufferCountActual = nBufferCountActual;
					G_OMX_PORT_SET_DEFINITION (self->in_port[i], &param);
				}
            }
            break;
        case ARG_NUM_OUTPUT_BUFFERS:
            {
                OMX_PARAM_PORTDEFINITIONTYPE param;
                OMX_U32 nBufferCountActual = g_value_get_uint (value);
				G_OMX_PORT_GET_DEFINITION (self->out_port, &param);
				g_return_if_fail (nBufferCountActual >= param.nBufferCountMin);
				param.nBufferCountActual = nBufferCountActual;
				G_OMX_PORT_SET_DEFINITION (self->out_port, &param);
            }
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
            break;
    }
}
static GstStateChangeReturn
change_state (GstElement *element,
              GstStateChange transition)
{
    GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
    GstOmxBaseFilter21 *self;
    GOmxCore *core;
	int i;

    self = GST_OMX_BASE_FILTER21(element);
    core = self->gomx;

	printf("begin: changing state %s -> %s\n",
                     gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
                     gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
    GST_INFO_OBJECT (self, "begin: changing state %s -> %s",
                     gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
                     gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));

    switch (transition)
    {
        case GST_STATE_CHANGE_NULL_TO_READY:
            g_omx_core_init (core);
            if (core->omx_state != OMX_StateLoaded)
            {
                ret = GST_STATE_CHANGE_FAILURE;
                goto leave;
            }
            break;
            
        case GST_STATE_CHANGE_READY_TO_PAUSED:
            gst_collect_pads_start(self->collectpads);
            break;

        case GST_STATE_CHANGE_PAUSED_TO_READY:
            gst_collect_pads_stop(self->collectpads);
            break;

        default:
            break;
    }

    ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);

    if (ret == GST_STATE_CHANGE_FAILURE)
        goto leave;

    switch (transition)
    {
        case GST_STATE_CHANGE_PAUSED_TO_READY:
			printf("Paused to ready\n");
            g_mutex_lock (self->ready_lock);
            if (self->ready)
            {
                /* unlock */
                for (i = 0; i < NUM_INPUTS; i++){
					g_omx_port_finish (self->in_port[i]);
               	}
               	g_omx_port_finish (self->out_port);

                g_omx_core_stop (core);
                g_omx_core_unload (core);
                self->ready = FALSE;
            }
            g_mutex_unlock (self->ready_lock);
            if (core->omx_state != OMX_StateLoaded &&
                core->omx_state != OMX_StateInvalid)
            {
                ret = GST_STATE_CHANGE_FAILURE;
                goto leave;
            }
            break;

        case GST_STATE_CHANGE_READY_TO_NULL:
            g_omx_core_deinit (core);
            break;

        default:
            break;
    }

leave:
    GST_LOG_OBJECT (self, "end");

    return ret;
}