khronosfws/openmax_al/src/adaptation/xamediarecorderadaptctx.c
author hgs
Fri, 14 May 2010 18:19:45 -0500
changeset 20 b67dd1fc57c5
parent 12 5a06f39ad45b
permissions -rw-r--r--
201019

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/

#include <string.h>
#include <assert.h>
#include <gst.h>
#include <gstappsink.h>
#include "XAMediaRecorderAdaptCtx.h"
#include "XAAdaptation.h"
#include "XAMetadataAdaptation.h"
#include "XAStaticCapsAdaptation.h"

#define XA_ADAPTID_UNINITED 0

extern XAboolean cameraRealized;
extern XACameraAdaptationCtx_* cameraCtx;

/*forward declarations*/
GstElement* XAMediaRecorderAdapt_CreateEncodeBin(
        XAMediaRecorderAdaptationCtx* ctx);
XAresult XAMediaRecorderAdapt_CreatePipeline(
        XAMediaRecorderAdaptationCtx* ctx);
XAresult XAMediaRecorderAdapt_CreatePipeline_New(
        XAMediaRecorderAdaptationCtx* ctx);
void XAMediaRecorderAdapt_BufferAvailable(GstElement* sink,
        gpointer user_data);

/*
 * gboolean XAMediaRecorderAdapt_GstBusCb( GstBus *bus, GstMessage *message, gpointer data )
 * MediaPlayer Gst-bus message handler (Callback)
 */
gboolean XAMediaRecorderAdapt_GstBusCb(GstBus *bus, GstMessage *message,
        gpointer data)
    {
    XAAdaptationBaseCtx* bCtx = (XAAdaptationBaseCtx*) data;
    /* only listen to pipeline messages */
    if (GST_MESSAGE_SRC(message)==GST_OBJECT(bCtx->bin))
        {
        XAMediaRecorderAdaptationCtx* mCtx = NULL;
        DEBUG_API_A2("->XAMediaRecorderAdapt_GstBusCb:\"%s\" from object \"%s\"",
                        GST_MESSAGE_TYPE_NAME(message), GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
        mCtx = (XAMediaRecorderAdaptationCtx*)data;

        switch( GST_MESSAGE_TYPE(message))
        {
            case GST_MESSAGE_EOS:
            {
                /* stop position tracking */
                if(mCtx->runpositiontimer > 0)
                {
                    g_source_remove(mCtx->runpositiontimer);
                    mCtx->runpositiontimer=0;
                }

                /* complete any ongoing client async operations */
                XAAdaptationBase_CompleteAsyncWait(bCtx);

                /* send needed events */
                {
                    XAAdaptEvent event = {XA_RECORDITFEVENTS, XA_RECORDEVENT_HEADATLIMIT, 0, NULL };
                    XAAdaptationBase_SendAdaptEvents(bCtx, &event );
                }
                if(mCtx->positionCb)
                {
                    mCtx->positionCb(bCtx);
                }
                bCtx->binWantedState = GST_STATE_PAUSED;
                break;
            }
            case GST_MESSAGE_STATE_CHANGED:
            {
                GstState oldstate, newstate, pendingstate, gsttargetstate;
                gst_message_parse_state_changed(message, &oldstate, &newstate, &pendingstate);
                gsttargetstate = GST_STATE_TARGET(bCtx->bin);
                DEBUG_INFO_A4("old %d -> new %d (-> pending %d -> gsttarget %d)",
                               oldstate, newstate, pendingstate, gsttargetstate);
                if(gsttargetstate!=bCtx->binWantedState)
                {
                    DEBUG_ERR_A1("WARNING: Gst target is not wanted target [%d]!!!", bCtx->binWantedState);
                }
                /* print out some more info */
                if( pendingstate == GST_STATE_VOID_PENDING )
                {
                    if( newstate != bCtx->binWantedState )
                    {
                        DEBUG_INFO_A2("Gst in intermediate state transition (curr %d, target %d)",
                                    newstate,bCtx->binWantedState);
                    }
                    else
                    {
                        DEBUG_INFO_A1("Gst in wanted target state (%d)",newstate);
                    }
                }
                if( oldstate!=GST_STATE_PLAYING && newstate==GST_STATE_PLAYING )
                {
                    XAAdaptEvent event = {XA_RECORDITFEVENTS, XA_RECORDEVENT_HEADMOVING, 0, NULL };
                    /* send needed events */
                    XAAdaptationBase_SendAdaptEvents(bCtx, &event );
                    /* enable position tracking if needed */
                    if( mCtx->runpositiontimer==0 && mCtx->trackpositionenabled && mCtx->positionCb )
                    {
                        mCtx->runpositiontimer = g_timeout_add(XA_ADAPT_PU_INTERVAL, mCtx->positionCb, mCtx);
                    }
                }
                break;
            }

            case GST_MESSAGE_ASYNC_DONE:
            {
                /* some async sequence ended */
                XAAdaptationBase_CompleteAsyncWait(bCtx);
                break;
            }

            case GST_MESSAGE_ERROR:
            {
                GError* error;
                gchar* debug;
                gst_message_parse_error(message, &error, &debug);
                DEBUG_ERR_A1("Gst reports error \"%s\"", debug);
                /* stop waiting any ongoing async operations */
                XAAdaptationBase_CompleteAsyncWait(bCtx);
                break;
            }

            default:
                break;
        }
    DEBUG_API("<-XAMediaRecorderAdapt_GstBusCb");
    }
    return TRUE;
    }

/*
 * XAAdaptationBaseCtx* XAMediaRecorderAdapt_Create()
 * Allocates memory for Media Recorder Adaptation Context and makes 1st phase initialization
 * @param XADataSource *pAudioSrc - pointer to OMX-AL audio source
 * @param XADataSource *pImageVideoSrc - pointer image/video source
 * @param XADataSink *pDataSnk - pointer to OMX-AL sink
 * @returns XAMediaRecorderAdaptationCtx* - Pointer to created context, NULL if error occurs.
 */
XAAdaptationBaseCtx* XAMediaRecorderAdapt_Create(XADataSource* pAudioSrc,
        XADataSource* pImageVideoSrc, XADataSink* pDataSnk, XAuint8 recModes)
    {
    XAMediaRecorderAdaptationCtx *pSelf = NULL;
    XAuint32 locType = 0;
    XADataLocator_IODevice *ioDevice;
    DEBUG_API("->XAMediaRecorderAdapt_Create");

    pSelf = calloc(1, sizeof(XAMediaRecorderAdaptationCtx));
    if (pSelf)
        {
        if (XAAdaptationBase_Init(&(pSelf->baseObj),
                XAMediaRecorderAdaptation) != XA_RESULT_SUCCESS)
            {
            DEBUG_ERR("Failed to init base context!!!");
            free(pSelf);
            pSelf = NULL;
            }
        else
            {
            pSelf->xaAudioSource = pAudioSrc;
            pSelf->xaVideoSource = pImageVideoSrc;
            pSelf->xaSink = pDataSnk;
            pSelf->baseObj.pipeSinkThrCtx.state = CPStateNull;
            pSelf->xaRecordState = XA_RECORDSTATE_STOPPED;
            pSelf->curMirror = XA_VIDEOMIRROR_NONE;
            pSelf->curRotation = 0;
            pSelf->recModes = recModes;
            pSelf->isRecord = XA_BOOLEAN_FALSE;

            /* defaults from API spec */
            pSelf->imageEncSettings.width = 640;
            pSelf->imageEncSettings.height = 480;
            pSelf->imageEncSettings.compressionLevel = 0;
            pSelf->imageEncSettings.encoderId = XA_IMAGECODEC_JPEG;
            pSelf->imageEncSettings.colorFormat = XA_COLORFORMAT_UNUSED;
            /* no specified defaults for rest, determined later from container type */
            pSelf->videoEncSettings.encoderId = XA_ADAPTID_UNINITED;
            pSelf->videoEncSettings.width = 640;
            pSelf->videoEncSettings.height = 480;
            pSelf->videoEncSettings.frameRate = 15;
            pSelf->audioEncSettings.encoderId = XA_ADAPTID_UNINITED;
            pSelf->audioEncSettings.channelsIn = 2;
            pSelf->audioEncSettings.channelsOut = 2;
            pSelf->audioEncSettings.bitsPerSample = 8;
            pSelf->audioEncSettings.bitRate = 128;
            pSelf->audioEncSettings.sampleRate = 44100;
            }

        if (pImageVideoSrc)
            {
            locType = *((XAuint32*) (pImageVideoSrc->pLocator));
            if (locType == XA_DATALOCATOR_IODEVICE)
                {
                ioDevice
                        = (XADataLocator_IODevice*) (pImageVideoSrc->pLocator);
                if (ioDevice->deviceType == XA_IODEVICE_CAMERA
                        && !cameraRealized)
                    {
                    DEBUG_ERR("Preconditions violated - Camera object not realized");
                    XAAdaptationBase_Free(&pSelf->baseObj);
                    free(pSelf);
                    pSelf = NULL;
                    }
                }
            }
        }

    DEBUG_API("<-XAMediaRecorderAdapt_Create");
    return (XAAdaptationBaseCtx*) pSelf;
    }

/*
 * XAresult XAMediaRecorderAdapt_PostInit()
 * 2nd phase initialization of Media Recorder Adaptation Context
 * @param XAAdaptationBaseCtx* ctx - pointer to Media Recorder adaptation context
 * @return XAresult - Success value
 */
XAresult XAMediaRecorderAdapt_PostInit(XAAdaptationBaseCtx* bCtx)
    {
    GstStateChangeReturn gret;

    XAresult ret = XA_RESULT_SUCCESS;
    XAMediaRecorderAdaptationCtx* ctx = NULL;
    DEBUG_API("->XAMediaRecorderAdapt_PostInit");
    if (bCtx == NULL || bCtx->ctxId != XAMediaRecorderAdaptation)
        {
        DEBUG_ERR("Invalid parameter!!");DEBUG_API("<-XAMediaRecorderAdapt_PostInit");
        return XA_RESULT_PARAMETER_INVALID;
        }
    ctx = (XAMediaRecorderAdaptationCtx*) bCtx;

    ret = XAAdaptationBase_PostInit(bCtx);
    if (ret != XA_RESULT_SUCCESS)
        {
        DEBUG_ERR("Base context postinit failed!!");
        return ret;
        }

    /* top level bin for media recorder */
    bCtx->bin = gst_pipeline_new("media_recorder");

    /* Create Gst bus listener. */
    ret = XAAdaptationBase_InitGstListener(bCtx);
    if (ret != XA_RESULT_SUCCESS)
        {
        DEBUG_ERR("Bus listener creation failed!!");
        return ret;
        }
    /* Add Media Recorder specific handler */
    if (bCtx->bus)
        {
        bCtx->busCb = XAMediaRecorderAdapt_GstBusCb;
        gst_bus_add_signal_watch(bCtx->bus);
        g_signal_connect(bCtx->bus, "message::eos", G_CALLBACK(bCtx->busCb), ctx );
        g_signal_connect(bCtx->bus, "message::error", G_CALLBACK(bCtx->busCb), ctx );
        g_signal_connect(bCtx->bus, "message::warning", G_CALLBACK(bCtx->busCb), ctx );
        g_signal_connect(bCtx->bus, "message::state-changed", G_CALLBACK(bCtx->busCb), ctx );
        g_signal_connect(bCtx->bus, "message::segment-done", G_CALLBACK(bCtx->busCb), ctx );
        g_signal_connect(bCtx->bus, "message::async-done", G_CALLBACK(bCtx->busCb), ctx );
        }
    else
        {
        DEBUG_ERR("Failed to create message bus");
        return XA_RESULT_INTERNAL_ERROR;
        }

    XAMetadataAdapt_PreInit(bCtx);

    /* create pipeline */
    ret = XAMediaRecorderAdapt_CreatePipeline(ctx);
    //ret = XAMediaRecorderAdapt_CreatePipeline_New(ctx);
    if (ret != XA_RESULT_SUCCESS)
        {
        DEBUG_ERR("Failed to create recorder pipeline");
        return XA_RESULT_INTERNAL_ERROR;
        }

    /* Init content pipe if used */
    if (ctx->xaSink && ctx->xaSink->pLocator
            && *(XAuint32*) (ctx->xaSink->pLocator)
                    == XA_DATALOCATOR_CONTENTPIPE)
        {
        XAMediaRecorderAdapt_InitContentPipeSink(ctx);
        }

#ifdef XA_IMPL_MEASURE_GST_DELAY
    bCtx->startTime = clock();
#endif /* XA_IMPL_MEASURE_GST_DELAY */
    /* roll up bin */
    bCtx->binWantedState = GST_STATE_PAUSED;
    XAAdaptationBase_PrepareAsyncWait(bCtx);
    gret = gst_element_set_state(GST_ELEMENT(bCtx->bin), bCtx->binWantedState);
    if (gret == GST_STATE_CHANGE_ASYNC)
        {
        DEBUG_INFO("Wait for preroll");
        XAAdaptationBase_StartAsyncWait(bCtx);DEBUG_INFO("Preroll ready");
        }
    else if (gret == GST_STATE_CHANGE_FAILURE)
        {
        DEBUG_ERR("Preroll FAILED");
        /*ret = XA_RESULT_INTERNAL_ERROR;*/
        }
#ifdef XA_IMPL_MEASURE_GST_DELAY
    bCtx->endTime = clock();
    double diff = bCtx->endTime - bCtx->startTime;
    diff = diff / CLOCKS_PER_SEC;
    DEBUG_API_A1( "Starting up bin took %.4lf secs",diff);
#endif /* XA_IMPL_MEASURE_GST_DELAY */
    XAMetadataAdapt_PostInit(bCtx);

    bCtx->waitingasyncop = XA_BOOLEAN_FALSE;

    DEBUG_API("<-XAMediaRecorderAdapt_PostInit");
    return ret;
    }

/*
 * void XAMediaRecorderAdapt_Destroy( XAAdaptationBaseCtx* bCtx )
 * Destroys Media Recorder Adaptation Context
 * @param ctx - Media Recorder Adaptation context to be destroyed
 */
void XAMediaRecorderAdapt_Destroy(XAAdaptationBaseCtx* bCtx)
    {
    XAMediaRecorderAdaptationCtx* ctx = NULL;
    char* fname = NULL;
    DEBUG_API("->XAMediaRecorderAdapt_Destroy");

    if (bCtx == NULL || bCtx->ctxId != XAMediaRecorderAdaptation)
        {
        DEBUG_ERR("Invalid parameter!!");DEBUG_API("<-XAMediaRecorderAdapt_Destroy");
        return;
        }
    ctx = (XAMediaRecorderAdaptationCtx*) bCtx;

    if (ctx->isRecord == XA_BOOLEAN_FALSE)
        {
        DEBUG_INFO("Removing unnecessary file.");

        if (ctx->xaSink && *((XAuint32*) (ctx->xaSink->pLocator))
                == XA_DATALOCATOR_URI)
            {
            if (strncmp(
                    (char *) ((XADataLocator_URI*) (ctx->xaSink->pLocator))->URI,
                    "file://", 7) == 0)
                {
                fname
                        = (char *) &(((XADataLocator_URI*) (ctx->xaSink->pLocator))->URI[7]);
                }
            else
                {
                fname
                        = (char *) ((XADataLocator_URI*) (ctx->xaSink->pLocator))->URI;
                }

            if (remove(fname) != 0)
                {
                DEBUG_ERR_A1("Cannot remove file %s", fname);
                }
            }
        }

    if (ctx->isobjvsrc && ctx->videosource)
        { /* external source, unlink now */
        gst_element_unlink(ctx->videosource, ctx->codecbin);
        GST_OBJECT_FLAG_SET(GST_OBJECT(ctx->videosource),GST_OBJECT_FLOATING);
        }
    if (bCtx->bus)
        {
        gst_bus_remove_signal_watch(bCtx->bus);
        }
    XAAdaptationBase_CancelAsyncWait(bCtx);

    if (ctx->runpositiontimer)
        {
        g_source_remove(ctx->runpositiontimer);
        }
    XAAdaptationBase_Free(bCtx);

    free(ctx);
    ctx = NULL;

    DEBUG_API("<-XAMediaRecorderAdapt_Destroy");
    }

/***************** INTERNAL FUNCTIONS *******************************/

XAresult XAMediaRecorderAdapt_CreatePipeline_New(
        XAMediaRecorderAdaptationCtx* ctx)
    {
    XADataLocator_URI* uri;
    GstCaps* caps;
    gboolean ok;

    //Create gst source
    ctx->audiosource
            = gst_element_factory_make("devsoundsrc", "record_audio");
    if (!ctx->audiosource)
        {
        g_print("could not create \"record\" element!");
        return XA_RESULT_INTERNAL_ERROR;
        }

    ctx->datasink = gst_element_factory_make("filesink", "filesink");
    if (!ctx->datasink)
        {
        g_print("could not create \"filesink\" element!");
        return XA_RESULT_INTERNAL_ERROR;
        }

    ctx->codecbin = gst_element_factory_make("wavenc", "wavencoder");
    if (!ctx->codecbin)
        {
        g_print("could not create \"wavenc\" element!");
        return XA_RESULT_INTERNAL_ERROR;
        }
    uri = (XADataLocator_URI*) ctx->xaSink->pLocator;

    if (uri->URI != NULL)
        {
        XAchar *fname;
        DEBUG_INFO_A1("URI: %s", uri->URI);
        if (strncmp((char *) uri->URI, "file://", 7) == 0)
            {
            fname = &((uri->URI)[7]);
            }
        else
            {
            fname = uri->URI;
            }DEBUG_INFO_A1("->filesystem path %s", fname);
        g_object_set( G_OBJECT(ctx->datasink),"location", fname,
         "async", FALSE,
         "qos", FALSE,
         "max-lateness", (gint64)(-1),
         NULL);
        
        //g_object_set(G_OBJECT(ctx->datasink), "location", fname, NULL);
        }
    
   // ctx->audioppbin = XAAdaptationBase_CreateAudioPP( );
    //gst_bin_add_many(GST_BIN (ctx->baseObj.bin), ctx->audiosource,  ctx->audioppbin, ctx->codecbin,ctx->datasink, NULL);
    
    gst_bin_add_many(GST_BIN (ctx->baseObj.bin), ctx->audiosource, ctx->codecbin,ctx->datasink, NULL);
    
    caps = gst_caps_new_simple ("audio/x-raw-int",
              "width", G_TYPE_INT, 16,
              "depth", G_TYPE_INT, 16,
              "signed",G_TYPE_BOOLEAN, TRUE,
              "endianness",G_TYPE_INT, G_BYTE_ORDER,
              "rate", G_TYPE_INT, 16000,
              "channels", G_TYPE_INT, 1, NULL);
    
    ok = gst_element_link_filtered (ctx->audiosource, ctx->codecbin, caps);
    if(!ok)
        {
        DEBUG_ERR("Could not link audiosrc to codecbin!!");
        }
    ok = gst_element_link (ctx->codecbin, ctx->datasink);
    if(!ok)
        {
        DEBUG_ERR("Could not link codecbin to datasink!!");
        }
    gst_caps_unref (caps);
    
    return XA_RESULT_SUCCESS;
    }
    /*
     * void XAMediaRecorderAdapt_CreatePipeline( XAMediaRecorderAdaptationCtx* ctx );
     */
    XAresult XAMediaRecorderAdapt_CreatePipeline(
            XAMediaRecorderAdaptationCtx* ctx)
        {
        XAresult ret = XA_RESULT_SUCCESS;
        GstCaps* encSrcCaps = NULL;
        DEBUG_API("->XAMediaRecorderAdapt_CreatePipeline");

        /* create and add video pipeline */
        ctx->codecbin = XAMediaRecorderAdapt_CreateEncodeBin(ctx);
        if (ctx->codecbin)
            {
            if (gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->codecbin))
                {
                DEBUG_API("->XAMediaRecorderAdapt_CreatePipeline: gst_bin_add success");
                }
            else
                {
                DEBUG_ERR("Could not add codec bin");
                return XA_RESULT_INTERNAL_ERROR;
                }
            }
        else
            {
            DEBUG_ERR("Could not create encoding bin!!!");
            return XA_RESULT_INTERNAL_ERROR;
            }

        /* create and add video pipeline if video source available and codec supports video */
        if (ctx->xaVideoSource
                && gst_element_get_pad(ctx->codecbin, "v_sink"))
            {
            /* create video pipe source */
            ctx->videosource = XAAdaptationBase_CreateGstSource(
                    ctx->xaVideoSource, "videosource", &(ctx->isobjvsrc),
                    NULL, NULL );
            if (!ctx->videosource)
                {
                DEBUG_ERR("Could not create video source!!!!");
                return XA_RESULT_INTERNAL_ERROR;
                }

            if (!ctx->isobjvsrc)
                { /* Add other than camera sources to media recorder bin */
                gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->videosource);
                }
            else
                { /* Don't add camera source to media recorder bin */
                GstCaps * encSrcCaps;
                encSrcCaps = gst_caps_new_simple( "video/x-raw-yuv", 
                "format", GST_TYPE_FOURCC,GST_MAKE_FOURCC('I','4','2','0'),
                "framerate", GST_TYPE_FRACTION, ctx->videoEncSettings.frameRate, 1,
                        NULL);
                DEBUG_INFO_A1("new camera encoding filter: %s",gst_caps_to_string(encSrcCaps));
                g_object_set( G_OBJECT(ctx->videosource), "filter-caps",encSrcCaps,NULL);
                gst_caps_unref(encSrcCaps);
                }
            /* create video filter for video encoder settings */
            ctx->videofilter = gst_element_factory_make("capsfilter", "videofilter");
            if( ctx->videofilter )
                {
                GstCaps* encSrcCaps;
                gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->videofilter);
                encSrcCaps = gst_caps_new_simple("video/x-raw-yuv",
                        "width", G_TYPE_INT, ctx->videoEncSettings.width,
                        "height", G_TYPE_INT, ctx->videoEncSettings.height,
                        "framerate", GST_TYPE_FRACTION, ctx->videoEncSettings.frameRate, 1,
                        NULL);
                DEBUG_INFO_A1("video encoder config from settings: %s",gst_caps_to_string(encSrcCaps));
                g_object_set( G_OBJECT(ctx->videofilter), "caps",encSrcCaps,NULL);
                gst_caps_unref(encSrcCaps);
                if ( ! ctx->isobjvsrc )
                    {
                    if(!gst_element_link(ctx->videosource, ctx->videofilter))
                        {
                        DEBUG_ERR("Could not link videopp to videofilter!!");
                        return XA_RESULT_INTERNAL_ERROR;
                        }
                    }
                else
                    { /* For camera source used ghost-pads for linking, because elements are in different bins */
                    GstStateChangeReturn gret;
                    GstElement *camTee=NULL;
                    GstPad *cameraBinGhostPad=NULL;
                    GstPad *ghost=NULL;
                    GstPad *mrGhostSink=NULL;

                    DEBUG_INFO("Set ext-source PAUSED for pipeline manipulation");
                    gret = gst_element_set_state( GST_ELEMENT(ctx->videosource), GST_STATE_READY);
                    gret = gst_element_get_state( GST_ELEMENT(ctx->videosource), NULL,NULL,XA_ADAPT_ASYNC_TIMEOUT_SHORT_NSEC);

                    /* Add new ghost-pad to external camera source */
                    camTee = gst_bin_get_by_name( GST_BIN(ctx->videosource), "CamTee");
                    if ( !camTee )
                        {
                        DEBUG_ERR("Could not get tee-element from camera");
                        }
                    cameraBinGhostPad = gst_element_get_request_pad( camTee, "src%d" );
                    if ( !cameraBinGhostPad )
                        {
                        DEBUG_ERR("Could not get new src-pad from CamTee element");
                        }
                    gst_element_add_pad(ctx->videosource, gst_ghost_pad_new("MRObjSrc",cameraBinGhostPad));
                    ghost = gst_element_get_static_pad( GST_ELEMENT(ctx->videosource), "MRObjSrc" );
                    DEBUG_INFO_A2("Setting element:%s pad:%s to blocking.",
                            gst_element_get_name(ctx->baseObj.bin),
                            gst_pad_get_name(ghost));
                    /* Set newly created pad to blocking */
                    gst_pad_set_blocked_async(ghost, TRUE, XAAdaptationBase_PadBlockCb, NULL);

                    mrGhostSink = gst_element_get_static_pad( GST_ELEMENT(ctx->videofilter), "sink");
                    gst_element_add_pad(ctx->baseObj.bin, gst_ghost_pad_new("MRObjSink",mrGhostSink));
                    if ( !gst_element_link_pads( GST_ELEMENT(ctx->videosource), "MRObjSrc",
                                    GST_ELEMENT(ctx->baseObj.bin), "MRObjSink") )
                        {
                        DEBUG_ERR("Could not link camera:MRObjSrc to videofilter:MRObjSink");
                        return XA_RESULT_INTERNAL_ERROR;
                        }

                    if ( cameraBinGhostPad )
                        {
                        gst_object_unref( cameraBinGhostPad );
                        }
                    if ( ghost )
                        {
                        gst_object_unref( ghost );
                        }
                    if ( mrGhostSink )
                        {
                        gst_object_unref( mrGhostSink );
                        }
                    if ( camTee )
                        {
                        gst_object_unref( camTee );
                        }
                    }
                }
            /* create video processing pipeline */
#ifdef XA_IMPL_FIXED_VIDEO_SIZE
            ctx->videoppbin = XAAdaptationBase_CreateFixedSizeVideoPP( );
#else
            ctx->videoppbin = XAAdaptationBase_CreateVideoPP( );
#endif
            if( ctx->videoppbin )
                {
                gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->videoppbin);
                if(!gst_element_link(ctx->videofilter, ctx->videoppbin))
                    {
                    DEBUG_ERR("Could not link videofilter to videopp!!");
                    return XA_RESULT_INTERNAL_ERROR;
                    }
                }
            else
                {
                DEBUG_ERR("Could not create video pp bin!!!!");
                return XA_RESULT_INTERNAL_ERROR;
                }
            /* create identity to extract buffers from */
            ctx->videoextract = gst_element_factory_make("identity", "videoextract");
            if( ctx->videoextract )
                {
                gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->videoextract);
                if(!gst_element_link(ctx->videoppbin, ctx->videoextract))
                    {
                    DEBUG_ERR("Could not link videopp to videoextract!!");
                    return XA_RESULT_INTERNAL_ERROR;
                    }
                }
            else
                {
                DEBUG_ERR("Could not create videoextract!!!!");
                return XA_RESULT_INTERNAL_ERROR;
                }
            if( ctx->videoextract )
                {
                if( !gst_element_link_pads(ctx->videoextract, "src", ctx->codecbin, "v_sink") )
                    {
                    DEBUG_INFO("Warning: could not link videoextract to codec!!");
                    }
                }
            }
        else
            {
            DEBUG_INFO("No video input");
            }

        /* create and add audio pipeline */
        if ( ctx->xaAudioSource && gst_element_get_pad(ctx->codecbin, "sink") )
            {
            /* create audio pipe source */
            ctx->audiosource = XAAdaptationBase_CreateGstSource( ctx->xaAudioSource, "audiosource",
                    &(ctx->isobjasrc), NULL, NULL );
            if( ctx->audiosource )
                {
                if (gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->audiosource))
                    {
                    DEBUG_INFO("Added audiosource to bin");
                    }
                else
                    {
                    DEBUG_ERR("Could not add audiosource to bin");
                    return XA_RESULT_INTERNAL_ERROR;
                    }
                }
            else
                {
                DEBUG_ERR("Could not create audio source!!!!");
                return XA_RESULT_INTERNAL_ERROR;
                }
            /* create audio processing pipeline */
            ctx->audioppbin = XAAdaptationBase_CreateAudioPP( );
            if( ctx->audioppbin )
                {
                if (gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->audioppbin))
                    {
                    DEBUG_INFO("Added audioppbin to bin");
                    }
                else
                    {
                    DEBUG_ERR("Could not add audioppbin to bin");
                    return XA_RESULT_INTERNAL_ERROR;
                    }
/*                if(!gst_element_link(ctx->audiosource, ctx->audioppbin))
                    {
                    DEBUG_ERR("Could not link audiofilter to audiopp!!");
                    return XA_RESULT_INTERNAL_ERROR;
                    }
*/                    
                    
                }
            else
                {
                DEBUG_ERR("Could not create audio pp bin!!!!");
                return XA_RESULT_INTERNAL_ERROR;
                }
            /* create audio filter for audio encoder settings */
            ctx->audiofilter = gst_element_factory_make("capsfilter", "audiofilter");
            if( ctx->audiofilter )
                {
                //   GstCaps* encSrcCaps; TL
                if (gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->audiofilter))
                    {
                    DEBUG_INFO("Added audiofilter to bin");
                    }
                else
                    {
                    DEBUG_ERR("Could not add audio filter to bin");
                    return XA_RESULT_INTERNAL_ERROR;
                    }
                encSrcCaps = gst_caps_new_full(
                        gst_structure_new("audio/x-raw-int",
                                "width", G_TYPE_INT, 16,
                                "depth", G_TYPE_INT, 16,
                                "signed",G_TYPE_BOOLEAN, 1,
                                "endianness",G_TYPE_INT, 1234,
                                "rate", G_TYPE_INT, 16000,
                                "bitrate", G_TYPE_INT, ctx->audioEncSettings.bitRate,
                                "channels", G_TYPE_INT, 1, NULL),
                        /*gst_structure_new("audio/x-raw-int",
                         "channels", G_TYPE_INT, ctx->audioEncSettings.channelsOut,
                         "rate", G_TYPE_INT, ctx->audioEncSettings.sampleRate,
                         "bitrate", G_TYPE_INT, ctx->audioEncSettings.bitRate,
                         NULL),*/
                        gst_structure_new("audio/x-raw-float",
                                "channels", G_TYPE_INT, ctx->audioEncSettings.channelsOut,
                                "width", G_TYPE_INT, ctx->audioEncSettings.bitsPerSample,
                                "rate", G_TYPE_INT, ctx->audioEncSettings.sampleRate,
                                "bitrate", G_TYPE_INT, ctx->audioEncSettings.bitRate,
                                NULL),
                        NULL);
                DEBUG_INFO_A1("audio encoder config from settings: %s",gst_caps_to_string(encSrcCaps));
                g_object_set( G_OBJECT(ctx->audiofilter), "caps",encSrcCaps,NULL);

                if(!gst_element_link(ctx->audiosource, ctx->audiofilter))
                    {
                    DEBUG_ERR("Could not link audiosource to audiofilter!!");
                    return XA_RESULT_INTERNAL_ERROR;
                    }
                    
                }
/*            if( !gst_element_link_pads_filtered(ctx->audiofilter, "src", ctx->codecbin, "sink", encSrcCaps) )
                {
                DEBUG_INFO("Warning: could not link audiopp to codec!!");
                return XA_RESULT_INTERNAL_ERROR;
                }
*/
                if (!gst_element_link_filtered( ctx->audiofilter , ctx->audioppbin ,encSrcCaps))
                    {
                    DEBUG_INFO("Warning: could not link audiosource to audiopp!!");
                    return XA_RESULT_INTERNAL_ERROR;
                    }
                if(!gst_element_link(ctx->audioppbin, ctx->codecbin))
                    {
                    DEBUG_INFO("Warning: could not link audioppbin to codecbin!!");
                    return XA_RESULT_INTERNAL_ERROR;
                    }
            }
        else
            {
            DEBUG_INFO("No audio input");
            }
        gst_caps_unref(encSrcCaps);

        /* create and add data sink */
        ctx->datasink = XAAdaptationBase_CreateGstSink( ctx->xaSink, "datasink", &(ctx->isobjsink) );
        if( ctx->datasink )
            {
            if ( GST_IS_APP_SINK(ctx->datasink) )
                {
                gst_app_sink_set_emit_signals( GST_APP_SINK(ctx->datasink), TRUE );
                }
            if (gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->datasink))
                {
                DEBUG_INFO("Added datasink to bin");
                }
            else
                {
                DEBUG_ERR("Could not add datasink to bin");
                return XA_RESULT_INTERNAL_ERROR;
                }
            if(!gst_element_link(ctx->codecbin, ctx->datasink))
                {
                DEBUG_ERR("Could not link codec to sink!!");
                return XA_RESULT_INTERNAL_ERROR;
                }
            /* NOTE: no actual object sinks applicable, variable used to imply appsrc (recording to memory)*/
            if(ctx->isobjsink)
                {
                g_signal_connect(ctx->datasink, "new-buffer",
                        G_CALLBACK (XAMediaRecorderAdapt_BufferAvailable),ctx);

                ret = XAImpl_CreateSemaphore( &(ctx->recThrCtx.bufInsufficientSem));
                if ( ret != XA_RESULT_SUCCESS )
                    {
                    DEBUG_ERR("WARN: Could not create semaphore for recorder event handler!");
                    }
                XAImpl_CreateThreadHandle( &(ctx->recordingEventThr) );
                }
            }
        else
            {
            DEBUG_ERR("Could not create data sink!!!");
            return XA_RESULT_INTERNAL_ERROR;
            }
        DEBUG_API("<-XAMediaRecorderAdapt_CreatePipeline");
        return ret;
        }

    /*
     * XAresult XAMediaRecorderAdapt_CheckCodec( XAMediaRecorderAdaptationCtx_* mCtx );
     * Check codec compatibility and support with initiated datasink content
     */
    XAresult XAMediaRecorderAdapt_CheckCodec( XAMediaRecorderAdaptationCtx_* mCtx, XACapsType encType, XAuint32 encoderId )
        {
        XAresult ret = XA_RESULT_SUCCESS;
        XAuint32 format;
        XAStaticCapsData temp;

        DEBUG_API("->XAMediaRecorderAdapt_CheckCodec");

        /*first, check if codec supported at all*/
        ret = XAStaticCapsAdapt_GetCapsById(XACAP_ENCODER|encType, encoderId, &temp);

        if( ret==XA_RESULT_SUCCESS )
            {
            if(encType & (XACAP_VIDEO|XACAP_AUDIO))
                {
                if(mCtx->xaSink && mCtx->xaSink->pFormat)
                    {
                    format = *(XAuint32*)(mCtx->xaSink->pFormat);
                    }
                else
                    {
                    ret=XA_RESULT_FEATURE_UNSUPPORTED;
                    }
                }
            else
                {
                if(mCtx->snapshotVars.xaSink && mCtx->snapshotVars.xaSink->pFormat)
                    {
                    format = *(XAuint32*)(mCtx->snapshotVars.xaSink->pFormat);
                    }
                else
                    {
                    ret=XA_RESULT_FEATURE_UNSUPPORTED;
                    }
                }
            if(ret==XA_RESULT_SUCCESS) switch ( format )
                {
                case XA_DATAFORMAT_PCM:
                if ( (encType == XACAP_AUDIO) && (encoderId == XA_AUDIOCODEC_PCM) )
                    {
                    ret=XA_RESULT_SUCCESS;
                    }
                else
                    {
                    ret=XA_RESULT_FEATURE_UNSUPPORTED;
                    }
                break;

                case XA_DATAFORMAT_RAWIMAGE:
                if ( (encType == XACAP_IMAGE) && (encoderId == XA_IMAGECODEC_RAW) )
                    {
                    ret=XA_RESULT_SUCCESS;
                    }
                else
                    {
                    ret=XA_RESULT_FEATURE_UNSUPPORTED;
                    }
                break;

                case XA_DATAFORMAT_MIME:
                DEBUG_INFO("XA_DATAFORMAT_MIME ");
                    {
                    XADataFormat_MIME* mime = ((XADataFormat_MIME*)mCtx->xaSink->pFormat);
                    DEBUG_INFO_A1("mime->containerType:%u",(int)mime->containerType);
                    DEBUG_INFO_A1("mime->mimeType:%s",mime->mimeType);
                    switch ( mime->containerType )
                        {
                        case XA_CONTAINERTYPE_RAW:
                        if( ((encType == XACAP_AUDIO) && (encoderId == XA_AUDIOCODEC_PCM)) ||
                                ((encType == XACAP_VIDEO) && (encoderId == XA_ADAPTID_RAWVIDEO)) ||
                                ((encType == XACAP_IMAGE) && (encoderId == XA_IMAGECODEC_RAW)) )
                            {
                            ret=XA_RESULT_SUCCESS;
                            }
                        else
                            {
                            ret=XA_RESULT_FEATURE_UNSUPPORTED;
                            }
                        break;

                        case XA_CONTAINERTYPE_AVI:
                        if(encType == XACAP_VIDEO)
                            {
                            switch(encoderId)
                                {
                                case XA_ADAPTID_MOTIONJPEG:
                                case XA_ADAPTID_RAWVIDEO:
                                ret=XA_RESULT_SUCCESS;
                                break;
                                default:
                                ret=XA_RESULT_FEATURE_UNSUPPORTED;
                                break;
                                }
                            }
                        else if(encType == XACAP_AUDIO)
                            {
                            switch(encoderId)
                                {
                                case XA_AUDIOCODEC_PCM:
                                ret=XA_RESULT_SUCCESS;
                                break;
                                default:
                                ret=XA_RESULT_FEATURE_UNSUPPORTED;
                                break;
                                }
                            }
                        else
                            {
                            ret=XA_RESULT_FEATURE_UNSUPPORTED;
                            }
                        break;

                        case XA_CONTAINERTYPE_WAV:
                        if(encType == XACAP_AUDIO)
                            {
                            switch(encoderId)
                                {
                                case XA_AUDIOCODEC_PCM:
                                ret=XA_RESULT_SUCCESS;
                                break;
                                default:
                                ret=XA_RESULT_FEATURE_UNSUPPORTED;
                                break;
                                }
                            }
                        else
                            {
                            ret=XA_RESULT_FEATURE_UNSUPPORTED;
                            }
                        break;

                        case XA_CONTAINERTYPE_JPG:
                        if(encType == XACAP_VIDEO)
                            {
                            switch(encoderId)
                                {
                                case XA_ADAPTID_MOTIONJPEG:
                                ret=XA_RESULT_SUCCESS;
                                break;
                                default:
                                ret=XA_RESULT_FEATURE_UNSUPPORTED;
                                break;
                                }
                            }
                        else if(encType == XACAP_IMAGE)
                            {
                            switch(encoderId)
                                {
                                case XA_IMAGECODEC_JPEG:
                                ret=XA_RESULT_SUCCESS;
                                break;
                                default:
                                ret=XA_RESULT_FEATURE_UNSUPPORTED;
                                break;
                                }
                            }
                        else
                            {
                            ret=XA_RESULT_FEATURE_UNSUPPORTED;
                            }
                        break;

                        case XA_CONTAINERTYPE_UNSPECIFIED:
                        if(strstr( (char *) mime->mimeType, "/ogg") != 0)
                            {
                            if(encType == XACAP_VIDEO)
                                {
                                switch(encoderId)
                                    {
                                    case XA_ADAPTID_THEORA:
                                    ret=XA_RESULT_SUCCESS;
                                    break;
                                    default:
                                    ret=XA_RESULT_FEATURE_UNSUPPORTED;
                                    break;
                                    }
                                }
                            else if(encType == XACAP_AUDIO)
                                {
                                switch(encoderId)
                                    {
                                    case XA_ADAPTID_VORBIS:
                                    ret=XA_RESULT_SUCCESS;
                                    break;
                                    default:
                                    ret=XA_RESULT_FEATURE_UNSUPPORTED;
                                    break;
                                    }
                                }
                            else
                                {
                                ret=XA_RESULT_FEATURE_UNSUPPORTED;
                                }
                            }
                        else
                            {
                            ret=XA_RESULT_FEATURE_UNSUPPORTED;
                            }
                        break;

                        default: /*switch (containertype)*/
                        ret = XA_RESULT_FEATURE_UNSUPPORTED;
                        break;
                        }
                    break;
                    }
                default: /*switch (format)*/
                ret = XA_RESULT_CONTENT_UNSUPPORTED;
                break;
                }
            }
        if( ret!=XA_RESULT_SUCCESS )
            {
            DEBUG_ERR("cannot accommodate given codec & datasink pair!!!");
            }
        DEBUG_API("<-XAMediaRecorderAdapt_CheckCodec");
        return ret;
        }
    /*
     * XAresult XAMediaRecorderAdapt_ChangeEncoders( XAMediaRecorderAdaptationCtx* mCtx );
     * re-create encodebin based on new encoder settings
     */
    XAresult XAMediaRecorderAdapt_ChangeEncoders( XAMediaRecorderAdaptationCtx* mCtx )
        {
        XAresult ret = XA_RESULT_SUCCESS;
        XAAdaptationBaseCtx* bCtx = &(mCtx->baseObj);

        DEBUG_API("->XAMediaRecorderAdapt_ChangeEncoders");
        /* check state */
        if(GST_STATE(mCtx->baseObj.bin)<GST_STATE_PLAYING)
            {
            GstElement* newBin = XAMediaRecorderAdapt_CreateEncodeBin(mCtx);
            if(newBin)
                { /* replace old bin with new */
                GstStateChangeReturn gret;
                GstPad *asink=NULL, *linkedasrc=NULL;
                GstPad *vsink=NULL, *linkedvsrc=NULL;
                GstPad *src=NULL, *linkedsink=NULL;
                GstPad *moSrc=NULL, *moSink=NULL;
                GstCaps* encSrcCaps = NULL;

                /* pipeline must be unrolled for renegotiation */
                DEBUG_INFO("Unroll pipeline");
                bCtx->binWantedState = GST_STATE_READY;
                gret = gst_element_set_state( GST_ELEMENT(bCtx->bin), bCtx->binWantedState);
                gret = gst_element_get_state( GST_ELEMENT(bCtx->bin), NULL, NULL, XA_ADAPT_ASYNC_TIMEOUT_SHORT_NSEC);

                /*set new stream settings*/
                if( mCtx->videofilter )
                    {
                    encSrcCaps = gst_caps_new_simple("video/x-raw-yuv",
                            "format", GST_TYPE_FOURCC,GST_MAKE_FOURCC('I','4','2','0'),
                            "width", G_TYPE_INT, mCtx->videoEncSettings.width,
                            "height", G_TYPE_INT, mCtx->videoEncSettings.height,
                            "framerate", GST_TYPE_FRACTION, mCtx->videoEncSettings.frameRate, 1,
                            NULL);
                    DEBUG_INFO_A1("new video encoder config from settings: %s",gst_caps_to_string(encSrcCaps));
                    g_object_set( G_OBJECT(mCtx->videofilter), "caps",encSrcCaps,NULL);
                    gst_caps_unref(encSrcCaps);
                    }
                if( mCtx->audiofilter )
                    {
                    encSrcCaps = gst_caps_new_full(
                            gst_structure_new("audio/x-raw-int",
                                    "channels", G_TYPE_INT, mCtx->audioEncSettings.channelsOut,
                                    "rate", G_TYPE_INT, mCtx->audioEncSettings.sampleRate,
                                    "bitrate", G_TYPE_INT, mCtx->audioEncSettings.bitRate,
                                    NULL),
                            gst_structure_new("audio/x-raw-float",
                                    "channels", G_TYPE_INT, mCtx->audioEncSettings.channelsOut,
                                    "width", G_TYPE_INT, mCtx->audioEncSettings.bitsPerSample,
                                    "rate", G_TYPE_INT, mCtx->audioEncSettings.sampleRate,
                                    "bitrate", G_TYPE_INT, mCtx->audioEncSettings.bitRate,
                                    NULL),
                            NULL);
                    DEBUG_INFO_A1("new audio encoder config from settings: %s",gst_caps_to_string(encSrcCaps));
                    g_object_set( G_OBJECT(mCtx->audiofilter), "caps",encSrcCaps,NULL);
                    gst_caps_unref(encSrcCaps);
                    }

                if(mCtx->isobjvsrc)
                    {
                    moSrc = gst_element_get_static_pad(mCtx->videosource,"MRObjSrc");
                    moSink = gst_pad_get_peer(moSrc);
                    if(moSink)
                        {
                        gst_pad_unlink(moSrc,moSink);
                        }
                    moSrc = gst_element_get_static_pad(mCtx->videosource,"mediaobjectsrc");
                    encSrcCaps = gst_caps_new_simple("video/x-raw-yuv",
                            "format", GST_TYPE_FOURCC,GST_MAKE_FOURCC('I','4','2','0'),
                            "framerate", GST_TYPE_FRACTION, mCtx->videoEncSettings.frameRate, 1,
                            NULL);
                    DEBUG_INFO_A1("new camera encoding filter: %s",gst_caps_to_string(encSrcCaps));
                    g_object_set( G_OBJECT(mCtx->videosource), "filter-caps",encSrcCaps,NULL);
                    gst_caps_unref(encSrcCaps);
                    }

                DEBUG_INFO("Unlink and remove old encodebin");
                asink = gst_element_get_static_pad(mCtx->codecbin,"sink");
                if(asink)
                    {
                    linkedasrc = gst_pad_get_peer(asink);
                    if(linkedasrc)
                        {
                        gst_pad_unlink(linkedasrc,asink);
                        }
                    }
                vsink = gst_element_get_static_pad(mCtx->codecbin,"v_sink");
                if(vsink)
                    {
                    linkedvsrc = gst_pad_get_peer(vsink);
                    if(linkedvsrc)
                        {
                        gst_pad_unlink(linkedvsrc,vsink);
                        }
                    }
                src = gst_element_get_static_pad(mCtx->codecbin,"src");
                if(src)
                    {
                    linkedsink = gst_pad_get_peer(src);
                    if(linkedsink)
                        {
                        gst_pad_unlink(src,linkedsink);
                        }
                    }

                gst_element_set_state( GST_ELEMENT(mCtx->codecbin), GST_STATE_NULL );
                gst_element_get_state( GST_ELEMENT(mCtx->codecbin),NULL,NULL,1000 );
                gst_bin_remove( GST_BIN(bCtx->bin), mCtx->codecbin );
                /*reset filesink too*/
                gst_element_set_state(GST_ELEMENT(mCtx->datasink),GST_STATE_NULL);
                gst_element_sync_state_with_parent(mCtx->datasink);
                gst_element_get_state(mCtx->datasink,NULL,NULL,XA_ADAPT_ASYNC_TIMEOUT_SHORT_NSEC);

                DEBUG_INFO("Link new encodebin");
                mCtx->codecbin = newBin;
                gst_bin_add(GST_BIN(bCtx->bin), mCtx->codecbin);
                asink = gst_element_get_static_pad(mCtx->codecbin,"sink");
                if(asink && linkedasrc)
                    {
                    gst_pad_link(linkedasrc,asink);
                    }
                vsink = gst_element_get_static_pad(mCtx->codecbin,"v_sink");
                if(vsink && linkedvsrc)
                    {
                    gst_pad_link(linkedvsrc,vsink);
                    }
                src = gst_element_get_static_pad(mCtx->codecbin,"src");
                if(src && linkedsink)
                    {
                    gst_pad_link(src,linkedsink);
                    }

                if(mCtx->isobjvsrc)
                    {
                    moSrc = gst_element_get_static_pad(mCtx->videosource,"MRObjSrc");
                    if(moSink&&moSrc)
                        {
                        gst_pad_link(moSrc,moSink);
                        }
                    }

                /*re-roll*/
                DEBUG_INFO("Reroll pipeline");
                bCtx->binWantedState = GST_STATE_PAUSED;
                gret = gst_element_set_state( GST_ELEMENT(bCtx->bin), bCtx->binWantedState);
                if( gret == GST_STATE_CHANGE_ASYNC )
                    {
                    DEBUG_INFO("Wait for reroll");
                    XAAdaptationBase_StartAsyncWait(bCtx);
                    }
                else if( gret == GST_STATE_CHANGE_FAILURE )
                    {
                    DEBUG_ERR("reroll FAILED");
                    ret = XA_RESULT_INTERNAL_ERROR;
                    }
                bCtx->waitingasyncop = XA_BOOLEAN_FALSE;
                DEBUG_INFO_A1("Pipeline in state %s",gst_element_state_get_name(GST_STATE(bCtx->bin)));
                }
            else
                {
                /* could not support wanted encoders */
                DEBUG_ERR("Failed to create encodebin with new settings, using old one!");
                ret = XA_RESULT_FEATURE_UNSUPPORTED;
                }
            }
        else
            { /* n/a while playing */
            DEBUG_ERR("Cannot change encoder when recording ongoing!");
            ret = XA_RESULT_PRECONDITIONS_VIOLATED;
            }
        DEBUG_API("<-XAMediaRecorderAdapt_ChangeEncoders");
        return ret;
        }

    /**
     * GstElement* XAMediaRecorderAdapt_CreateEncodeBin( XAMediaRecorderAdaptationCtx* ctx )
     * @return GstElement* - pointer to created bin element
     * Decription: Create encoder/muxer element based on given format and encoder settings
     */
    GstElement* XAMediaRecorderAdapt_CreateEncodeBin( XAMediaRecorderAdaptationCtx* ctx )
        {
        XAresult ret = XA_RESULT_SUCCESS;
        GstElement *audioenc = NULL, *videoenc=NULL, *mux=NULL;
        GstElement *codecbin = gst_bin_new( "mrcodecbin" );
        GstPad *ghostsrc = NULL, *ghostaudiosink = NULL, *ghostvideosink = NULL;
        XAuint32 format;
        XAStaticCapsData temp;

        DEBUG_API("->XAMediaRecorderAdapt_CreateEncodeBin");
        if(ctx->recModes & XA_RECMODE_STREAM)
            {
            if(ctx->xaSink && ctx->xaSink->pFormat)
                {
                format = *(XAuint32*)(ctx->xaSink->pFormat);
                switch ( format )
                    {
                    case XA_DATAFORMAT_PCM:
                    DEBUG_INFO("XA_DATAFORMAT_PCM");
                        {
                        XADataFormat_PCM* pcm = ((XADataFormat_PCM*)ctx->xaSink->pFormat);
                        if(!ctx->xaAudioSource)
                            {
                            DEBUG_ERR("Unsupported dataformat for given data sources");
                            return NULL;
                            }
                        /* no need for codec, just pass data on */
                        mux = gst_element_factory_make("identity", "mux");
                        gst_bin_add(GST_BIN(codecbin), mux);
                        ghostsrc = gst_element_get_static_pad(mux,"src");
                        ghostaudiosink = gst_element_get_static_pad(mux,"sink");
                        /*set usable audio settings from the sink structure*/
                        ctx->audioEncSettings.encoderId = XA_AUDIOCODEC_PCM;
                        ctx->audioEncSettings.channelsOut = pcm->numChannels;
                        ctx->audioEncSettings.bitsPerSample = pcm->bitsPerSample;
                        }
                    break;

                    case XA_DATAFORMAT_RAWIMAGE:
                    DEBUG_INFO("XA_DATAFORMAT_RAWIMAGE");
                        {
                        XADataFormat_RawImage* img = ((XADataFormat_RawImage*)ctx->xaSink->pFormat);
                        if(!ctx->xaVideoSource)
                            {
                            DEBUG_ERR("Unsupported dataformat for given data sources");
                            return NULL;
                            }
                        /* no need for codec, just pass data on */
                        mux = gst_element_factory_make("identity", "mux");
                        gst_bin_add(GST_BIN(codecbin), mux);
                        ghostsrc = gst_element_get_static_pad(mux,"src");
                        ghostvideosink = gst_element_get_static_pad(mux,"sink");
                        /*set needed image settings from the sink structure*/
                        ctx->imageEncSettings.encoderId = XA_IMAGECODEC_RAW;
                        ctx->imageEncSettings.width = img->width;
                        ctx->imageEncSettings.height = img->height;
                        ctx->imageEncSettings.colorFormat = img->colorFormat;
                        }
                    break;

                    case XA_DATAFORMAT_MIME:
                    DEBUG_INFO("XA_DATAFORMAT_MIME ");
                        {
                        XADataFormat_MIME* mime = ((XADataFormat_MIME*)ctx->xaSink->pFormat);
                        DEBUG_INFO_A1("mime->containerType:%u",(int)mime->containerType);
                        DEBUG_INFO_A1("mime->mimeType:%s",mime->mimeType);
                        switch ( mime->containerType )
                            {
                            case XA_CONTAINERTYPE_AVI:
                            DEBUG_INFO("XA_CONTAINERTYPE_AVI");
                            mux = gst_element_factory_make("avimux", "mux");
                            if(mux)
                                {
                                if (gst_bin_add(GST_BIN(codecbin), mux))
                                    {
                                    DEBUG_INFO("Added mux to codecbin");
                                    }
                                else
                                    {
                                    DEBUG_ERR("Could not add mux to codecbin");
                                    return NULL;
                                    }
                                /*use this as linkpoint*/
                                ghostsrc = gst_element_get_static_pad(mux,"src");
                                }
                            /* Add and link audio/video codecs */
                            /*set video defaults*/
                            if(ctx->videoEncSettings.encoderId == XA_ADAPTID_UNINITED)
                            ctx->videoEncSettings.encoderId = XA_ADAPTID_MOTIONJPEG;
                            if(ctx->xaVideoSource)
                                {
                                if(XAStaticCapsAdapt_GetCapsById(XACAP_ENCODER|XACAP_VIDEO, ctx->videoEncSettings.encoderId, &temp) == XA_RESULT_SUCCESS)
                                    {
                                    if(temp.adaptId)
                                        {
                                        videoenc = gst_element_factory_make((char*)temp.adaptId, "videoenc");
                                        }
                                    }
                                if(videoenc)
                                    {
                                    gst_bin_add(GST_BIN(codecbin), videoenc);
                                    if(!gst_element_link(videoenc, mux))
                                        {
                                        DEBUG_ERR("Could not link videoenc to mux!!");
                                        DEBUG_API("<-XAMediaRecorderAdapt_CreateEncodeBin");
                                        return NULL;
                                        }
                                    ghostvideosink = gst_element_get_static_pad(videoenc,"sink");
                                    }
                                else
                                    {
                                    /*no video codec but video source = raw video case, request video pad directly from mux*/
                                    ghostvideosink = gst_element_get_request_pad(mux,"video_%d");
                                    }
                                }
                            /*set audio defaults*/
                            if(ctx->audioEncSettings.encoderId == XA_ADAPTID_UNINITED)
                            ctx->audioEncSettings.encoderId = XA_AUDIOCODEC_PCM;
                            if(ctx->xaAudioSource)
                                {
                                if(XAStaticCapsAdapt_GetCapsById(XACAP_ENCODER|XACAP_AUDIO, ctx->audioEncSettings.encoderId, &temp) == XA_RESULT_SUCCESS)
                                    {
                                    if(temp.adaptId)
                                        {
                                        audioenc = gst_element_factory_make((char*)temp.adaptId, "audioenc");
                                        }
                                    }
                                if(audioenc)
                                    {
                                    gst_bin_add(GST_BIN(codecbin), audioenc);
                                    if(!gst_element_link(audioenc, mux))
                                        {
                                        DEBUG_ERR("Could not link audioenc to mux!!");
                                        DEBUG_API("<-XAMediaRecorderAdapt_CreateEncodeBin");
                                        return NULL;
                                        }
                                    ghostaudiosink = gst_element_get_static_pad(audioenc,"sink");
                                    }
                                else
                                    {
                                    /*no audio codec but audio source = PCM case, explicity request audio pad*/
                                    ghostaudiosink = gst_element_get_request_pad(mux,"audio_%d");
                                    }
                                }
                            break;

                            case XA_CONTAINERTYPE_WAV:
                            DEBUG_INFO("XA_CONTAINERTYPE_WAV");
                            audioenc = gst_element_factory_make("wavenc", "audioenc");
                            if(audioenc)
                                {
                                if (gst_bin_add(GST_BIN(codecbin), audioenc))
                                    {
                                    DEBUG_INFO("added audioenc to codecbin");
                                    }
                                else
                                    {
                                    DEBUG_ERR("Could not add audioenc to codecbin");
                                    return NULL;
                                    }
                                /*use this as linkpoint*/
                                ghostsrc = gst_element_get_static_pad(audioenc,"src");
                                ghostaudiosink = gst_element_get_static_pad(audioenc,"sink");
                                if ( ghostsrc == NULL || ghostaudiosink == NULL)
                                    {
                                    DEBUG_ERR("Could not get src or sink ghoset element(s)");
                                    return NULL;
                                    }
                                }
                            /* no other codecs needed */
                            break;
                            case XA_CONTAINERTYPE_JPG:
                            /*motion jpeg*/
                            DEBUG_INFO("XA_CONTAINERTYPE_JPG");
                            /*set defaults*/
                            if(ctx->videoEncSettings.encoderId == XA_ADAPTID_UNINITED)
                            ctx->videoEncSettings.encoderId = XA_ADAPTID_MOTIONJPEG;
                            if(XAStaticCapsAdapt_GetCapsById(XACAP_ENCODER|XACAP_VIDEO, ctx->videoEncSettings.encoderId, &temp) == XA_RESULT_SUCCESS)
                                {
                                videoenc = gst_element_factory_make((char*)temp.adaptId, "videoenc");
                                }
                            if(videoenc)
                                {
                                gst_bin_add(GST_BIN(codecbin), videoenc);
                                /*use this as linkpoint*/
                                ghostsrc = gst_element_get_static_pad(videoenc,"src");
                                ghostvideosink = gst_element_get_static_pad(videoenc,"sink");
                                }
                            /* no other codecs needed */
                            break;
                            case XA_CONTAINERTYPE_RAW:
                            DEBUG_INFO("XA_CONTAINERTYPE_RAW");
                            /* no need for codec, just pass data on */
                            if(strncmp((char *)mime->mimeType, "video", 5) == 0 && ctx->xaVideoSource)
                                {
                                mux = gst_element_factory_make("identity", "mux");
                                gst_bin_add(GST_BIN(codecbin), mux);
                                ghostvideosink = gst_element_get_static_pad(mux,"sink");
                                }
                            else if (strncmp((char *)mime->mimeType, "audio", 5) == 0 && ctx->xaAudioSource)
                                {
                                mux = gst_element_factory_make("identity", "mux");
                                gst_bin_add(GST_BIN(codecbin), mux);
                                ghostaudiosink = gst_element_get_static_pad(mux,"sink");
                                }
                            else
                                {
                                ret = XA_RESULT_CONTENT_UNSUPPORTED;
                                DEBUG_ERR("Content mismatch with given sources!!!")
                                }
                            ghostsrc = gst_element_get_static_pad(mux,"src");
                            break;
                            case XA_CONTAINERTYPE_UNSPECIFIED:
                            DEBUG_INFO("No support for requested encoder...try to select encoder from mime string");
                            if(strstr( (char *) mime->mimeType, "/ogg") != 0)
                                {
                                DEBUG_INFO("XA_CONTAINERTYPE_UNSPECIFIED - mimetype ogg detected");
                                mux = gst_element_factory_make("oggmux", "mux");
                                if(mux)
                                    {
                                    gst_bin_add(GST_BIN(codecbin), mux);
                                    /*use this as linkpoint*/
                                    ghostsrc = gst_element_get_static_pad(mux,"src");
                                    /*set defaults*/
                                    if(ctx->audioEncSettings.encoderId == XA_ADAPTID_UNINITED)
                                        {
                                        ctx->audioEncSettings.encoderId = XA_ADAPTID_VORBIS;
                                        ctx->audioEncSettings.bitsPerSample=32;
                                        }
                                    if(ctx->videoEncSettings.encoderId == XA_ADAPTID_UNINITED)
                                        {
                                        ctx->videoEncSettings.encoderId = XA_ADAPTID_THEORA;
                                        }
                                    if(ctx->xaAudioSource)
                                        {
                                        if(XAStaticCapsAdapt_GetCapsById(XACAP_ENCODER|XACAP_AUDIO, ctx->audioEncSettings.encoderId, &temp) == XA_RESULT_SUCCESS)
                                            {
                                            audioenc = gst_element_factory_make((char*)temp.adaptId, "audioenc");
                                            }
                                        if(audioenc)
                                            {
                                            gst_bin_add(GST_BIN(codecbin), audioenc);
                                            gst_element_link(audioenc, mux);
                                            ghostaudiosink = gst_element_get_static_pad(audioenc,"sink");
                                            }
                                        }
                                    if(strncmp((char *)mime->mimeType, "video", 5) == 0 && ctx->xaVideoSource)
                                        {
                                        if(XAStaticCapsAdapt_GetCapsById(XACAP_ENCODER|XACAP_VIDEO, ctx->videoEncSettings.encoderId, &temp) == XA_RESULT_SUCCESS)
                                            {
                                            videoenc = gst_element_factory_make((char*)temp.adaptId, "videoenc");
                                            }
                                        if(videoenc)
                                            {
                                            gst_bin_add(GST_BIN(codecbin), videoenc);
                                            gst_element_link(videoenc, mux);
                                            ghostvideosink = gst_element_get_static_pad(videoenc,"sink");
                                            }
                                        }
                                    }
                                }
                            else
                                {
                                DEBUG_INFO("No support for requested mime/container type.");
                                ret = XA_RESULT_CONTENT_UNSUPPORTED;
                                }
                            break;
                            case XA_CONTAINERTYPE_MOBILE_DLS:
                            case XA_CONTAINERTYPE_MP4:
                            case XA_CONTAINERTYPE_AMR:
                            case XA_CONTAINERTYPE_3GPP:
                            case XA_CONTAINERTYPE_BMP:
                            case XA_CONTAINERTYPE_ASF:
                            case XA_CONTAINERTYPE_M4A:
                            case XA_CONTAINERTYPE_MP3:
                            case XA_CONTAINERTYPE_JPG2000:
                            case XA_CONTAINERTYPE_MPEG_ES:
                            case XA_CONTAINERTYPE_MPEG_PS:
                            case XA_CONTAINERTYPE_MPEG_TS:
                            case XA_CONTAINERTYPE_QT:
                            case XA_CONTAINERTYPE_XMF_0:
                            case XA_CONTAINERTYPE_XMF_1:
                            case XA_CONTAINERTYPE_XMF_2:
                            case XA_CONTAINERTYPE_XMF_3:
                            case XA_CONTAINERTYPE_XMF_GENERIC:
                            case XA_CONTAINERTYPE_AAC:
                            case XA_CONTAINERTYPE_3GA:
                            case XA_CONTAINERTYPE_RM:
                            case XA_CONTAINERTYPE_DMF:
                            default:
                            DEBUG_INFO("No support for requested container type.");
                            ret = XA_RESULT_CONTENT_UNSUPPORTED;
                            break;
                            }
                        break;
                        }
                    default:
                    DEBUG_ERR("Incorrect data format type.");
                    ret = XA_RESULT_PARAMETER_INVALID;
                    break;
                    }
                }
            else
                {
                DEBUG_ERR("Invalid data sink for stream recording!!");
                ret = XA_RESULT_PARAMETER_INVALID;
                }
            }
        else
            {/* stream recording not requested, datasink ignored, use uncoded recordstream*/
            mux = gst_element_factory_make("identity", "mux");
            gst_bin_add(GST_BIN(codecbin), mux);
            ghostsrc = gst_element_get_static_pad(mux,"src");
            ghostvideosink = gst_element_get_static_pad(mux,"sink");
            }

        /*set default codecs for unrecognized*/
        if(ctx->audioEncSettings.encoderId == XA_ADAPTID_UNINITED)
        ctx->audioEncSettings.encoderId = XA_AUDIOCODEC_PCM;
        if(ctx->imageEncSettings.encoderId == XA_ADAPTID_UNINITED)
        ctx->imageEncSettings.encoderId = XA_IMAGECODEC_RAW;
        if(ctx->videoEncSettings.encoderId == XA_ADAPTID_UNINITED)
        ctx->videoEncSettings.encoderId = XA_ADAPTID_RAWVIDEO;

        if ( ret != XA_RESULT_SUCCESS )
            {
            gst_object_unref(codecbin);
            codecbin=NULL;
            }
        else
            {
            /*add ghost pad(s) to link to*/
            if(ghostsrc)
                {
                gst_element_add_pad(codecbin, gst_ghost_pad_new("src",ghostsrc));
                gst_object_unref(GST_OBJECT(ghostsrc));
                }
            if(ghostaudiosink)
                {
                gst_element_add_pad(codecbin, gst_ghost_pad_new("sink",ghostaudiosink));
                gst_object_unref(GST_OBJECT(ghostaudiosink));
                }
            if(ghostvideosink)
                {
                gst_element_add_pad(codecbin, gst_ghost_pad_new("v_sink",ghostvideosink));
                gst_object_unref(GST_OBJECT(ghostvideosink));
                }
            DEBUG_INFO_A1("Created encoder bin at %x", (int)codecbin);
            }

        DEBUG_API("<-XAMediaRecorderAdapt_CreateEncodeBin");
        return codecbin;

        }

    /*
     * void XAMediaRecorderAdapt_BufferAvailable(GstElement* sink, gpointer user_data)
     * called when new buffer is available at appsink
     */
    void XAMediaRecorderAdapt_BufferAvailable(GstElement* sink, gpointer user_data)
        {
        GstBuffer *buffer=NULL;
        XAMediaRecorderAdaptationCtx* mCtx = (XAMediaRecorderAdaptationCtx*)user_data;
        DEBUG_API("->XAMediaRecorderAdapt_BufferAvailable");
        if(!mCtx || !mCtx->xaSink)
            {
            DEBUG_ERR("Invalid context")
            return;
            }
        /* get the buffer */
        buffer = gst_app_sink_pull_buffer(GST_APP_SINK(sink));
        if(buffer)
            {
            guint size;
            XADataLocator_Address* address;
            size = GST_BUFFER_SIZE(buffer);
            DEBUG_INFO_A1("Pulled new buffer of size %d", size);
            address = (XADataLocator_Address*)(mCtx->xaSink->pLocator);
            if( !address || *(XAuint32*)address != XA_DATALOCATOR_ADDRESS )
                {
                DEBUG_ERR("Invalid address datalocator")
                return;
                }

            if(mCtx->writepos + size < address->length )
                { /*enough room in buffer*/
                memcpy(((char*)(address->pAddress) + mCtx->writepos),
                        GST_BUFFER_DATA (buffer), size);
                mCtx->writepos+=size;
                }
            else
                { /*not enough room in buffer*/
                XAAdaptEvent event =
                    {XA_RECORDITFEVENTS, XA_RECORDEVENT_BUFFER_FULL, 0, NULL};

                size = address->length - mCtx->writepos;
                memcpy(((char*)(address->pAddress) + mCtx->writepos),
                        GST_BUFFER_DATA (buffer), size);
                DEBUG_INFO_A1("Buffer insufficient, wrote %d bytes", size);
                /* send event */
                XAAdaptationBase_SendAdaptEvents(&(mCtx->baseObj), &event);
                /* "recordhead to start" i.e. reset write position */
                mCtx->writepos=0;
                mCtx->recThrCtx.buffer_insufficient = XA_BOOLEAN_TRUE;
                if ( XAImpl_PostSemaphore( mCtx->recThrCtx.bufInsufficientSem ) != XA_RESULT_SUCCESS)
                    {
                    DEBUG_ERR("Posting buffer-insufficien semaphore FAILED!");
                    }
                }
            gst_buffer_unref (buffer);
            }
        else
            {
            DEBUG_ERR("Could not pull buffer from appsink!");
            }
        DEBUG_API("<-XAMediaRecorderAdapt_BufferAvailable");
        }

    /*
     * XAresult XAMediaRecorderAdapt_InitContentPipeSink(ctx);
     */
    XAresult XAMediaRecorderAdapt_InitContentPipeSink(XAMediaRecorderAdaptationCtx* ctx)
        {
        XAresult ret = XA_RESULT_SUCCESS;
        CPresult res;
        GstStateChangeReturn gstRet = GST_STATE_CHANGE_SUCCESS;
        DEBUG_API("->XAMediaRecorderAdapt_InitContentPipeSink");
        ctx->baseObj.pipeSinkThrCtx.appSink = GST_APP_SINK(ctx->datasink);
        ctx->baseObj.pipeSinkThrCtx.pipe = (XADataLocator_ContentPipe*)(ctx->xaSink->pLocator);

        /* Create thread for content pipe source */
        ret = XAImpl_CreateThreadHandle( &(ctx->baseObj.pipeSinkThr) );
        if ( ret != XA_RESULT_SUCCESS )
            {
            DEBUG_ERR("Could not create thread for content pipe sink!");
            DEBUG_API("<-XAMediaRecorderAdapt_InitContentPipeSink");
            return ret;
            }

        /* Create semaphore for content pipe source */
        ret = XAImpl_CreateSemaphore( &(ctx->baseObj.pipeSinkThrCtx.stateSem));
        if ( ret != XA_RESULT_SUCCESS )
            {
            DEBUG_ERR("Could not create semaphore for content pipe source!");
            DEBUG_API("<-XAMediaRecorderAdapt_InitContentPipeSink");
            return ret;
            }

        /* Open content pipe */
        res = ctx->baseObj.pipeSinkThrCtx.pipe->pContentPipe->Open(&(ctx->baseObj.pipeSinkThrCtx.dataHandle),
                (CPstring)(ctx->baseObj.pipeSinkThrCtx.pipe->URI),
                CP_AccessWrite );
        if ( res == EXIT_FAILURE )
            { /* Could not open content pipe data handle, try to create new one */
            res = ctx->baseObj.pipeSinkThrCtx.pipe->pContentPipe->Create(&(ctx->baseObj.pipeSinkThrCtx.dataHandle),
                    (CPstring)(ctx->baseObj.pipeSinkThrCtx.pipe->URI));
            if ( res == EXIT_FAILURE)
                {
                DEBUG_ERR("Could not create Content Pipe data handle!")
                return XA_RESULT_INTERNAL_ERROR;
                }
            res = ctx->baseObj.pipeSinkThrCtx.pipe->pContentPipe->Open(&(ctx->baseObj.pipeSinkThrCtx.dataHandle),
                    (CPstring)(ctx->baseObj.pipeSinkThrCtx.pipe->URI),
                    CP_AccessWrite );
            if ( res == EXIT_FAILURE)
                {
                DEBUG_ERR("Could not open newly created Content Pipe data handle!")
                return XA_RESULT_INTERNAL_ERROR;
                }
            }

        res = ctx->baseObj.pipeSinkThrCtx.pipe->pContentPipe->RegisterCallback( &(ctx->baseObj.pipeSinkThrCtx.dataHandle), &XAAdaptationBase_ContentPipeSinkCb);
        if ( res == EXIT_FAILURE )
            {
            DEBUG_ERR("Could not register content pipe callbacks!")
            return XA_RESULT_INTERNAL_ERROR;
            }

        gstRet = gst_element_set_state( GST_ELEMENT(ctx->datasink), GST_STATE_PAUSED);

        ctx->baseObj.pipeSinkThrCtx.state = CPStateStarted;
        XAImpl_StartThread( &(ctx->baseObj.pipeSrcThr), NULL, &XAAdaptationBase_ContentPipeSinkThrFunc, &(ctx->baseObj.pipeSinkThrCtx) );

        DEBUG_API("<-XAMediaRecorderAdapt_InitContentPipeSink");
        return ret;
        }

    /*
     * void* XAMediaRecorderAdapt_RecordEventThr( void* ctx )
     */
    void* XAMediaRecorderAdapt_RecordEventThr( void* ctx )
        {
        XAMediaRecorderAdaptationCtx* mrCtx = (XAMediaRecorderAdaptationCtx*)ctx;
        GstStateChangeReturn gret;
        XAresult ret;
        DEBUG_API("->XAMediaRecorderAdapt_RecordEventThr");

        /* Wait semaphore here */
        ret = XAImpl_WaitSemaphore( mrCtx->recThrCtx.bufInsufficientSem );
        if ( ret != XA_RESULT_SUCCESS)
            {
            DEBUG_ERR("Could not start semaphore");
            }

        if(mrCtx->recThrCtx.buffer_insufficient)
            {
            mrCtx->baseObj.binWantedState = GST_STATE_PAUSED;
            XAAdaptationBase_PrepareAsyncWait(&(mrCtx->baseObj));
            gret = gst_element_set_state( GST_ELEMENT(mrCtx->baseObj.bin), mrCtx->baseObj.binWantedState);
            if( gret == GST_STATE_CHANGE_ASYNC )
                {
                DEBUG_INFO("Start to wait recoder state change.");
                XAAdaptationBase_StartAsyncWait(&(mrCtx->baseObj));
                DEBUG_INFO("Recorder state change async. SUCCESFULL.");
                }
            else if( gret == GST_STATE_CHANGE_FAILURE )
                {
                DEBUG_INFO("Recorder state change FAILED");
                /*ret = XA_RESULT_INTERNAL_ERROR;*/
                }
            else
                {
                DEBUG_INFO("Recorder state change SUCCESFULL")
                }

            mrCtx->baseObj.waitingasyncop= XA_BOOLEAN_FALSE;
            }
        DEBUG_API("<-XAMediaRecorderAdapt_RecordEventThr");
        return NULL;
        }