khronosfws/openmax_al/src/adaptation/xacameraadaptctx.c
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 16 Apr 2010 15:29:42 +0300
changeset 12 5a06f39ad45b
permissions -rw-r--r--
Revision: 201011 Kit: 201015

/*
* 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 <gst.h>
#include "XACameraAdaptCtx.h"
#include "XAAdaptation.h"
#include <photography.h>
#include "XAStaticCapsAdaptation.h"


XAboolean cameraRealized = XA_BOOLEAN_FALSE;
XACameraAdaptationCtx_* cameraCtx = NULL;

/*
 * gboolean XACameraAdapt_GstBusCb( GstBus *bus, GstMessage *message, gpointer data )
 * MediaPlayer Gst-bus message handler (Callback)
 */
gboolean XACameraAdapt_GstBusCb( GstBus *bus, GstMessage *message, gpointer data )
{
    XACameraAdaptationCtx* mCtx = (XACameraAdaptationCtx*)data;
    XAAdaptEvent event = {XA_CAMERAITFEVENTS,XA_CAMERACBEVENT_FOCUSSTATUS,1,NULL};
    XAuint32 status;

    /* only listen to pipeline messages */
    if(GST_MESSAGE_SRC(message)==(GstObject*)(mCtx->baseObj.bin) )
    {
        DEBUG_API_A2("->XACameraAdapt_GstBusCb:\"%s\" from object \"%s\"",
                        GST_MESSAGE_TYPE_NAME(message), GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));

        if ( GST_MESSAGE_TYPE(message)== GST_MESSAGE_ASYNC_DONE )
        {
            /* some async sequence ended */
            XAAdaptationBase_CompleteAsyncWait((&mCtx->baseObj));
        }
        else if (strncmp(GST_MESSAGE_TYPE_NAME(message), GST_PHOTOGRAPHY_AUTOFOCUS_DONE,
                            strlen(GST_PHOTOGRAPHY_AUTOFOCUS_DONE))==0 )
        {
            DEBUG_INFO("Autofocus done!.")
            status = XA_CAMERA_FOCUSMODESTATUS_REACHED;
            event.data = &status;
            XAAdaptationBase_SendAdaptEvents(&(mCtx->baseObj), &event );
        }
        else if ( strncmp(GST_MESSAGE_TYPE_NAME(message), GST_PHOTOGRAPHY_SHAKE_RISK,
                            strlen(GST_PHOTOGRAPHY_SHAKE_RISK)) ==0 )
        {
            DEBUG_INFO("Camera shake risk!")
        }
        DEBUG_API("<-XACameraAdapt_GstBusCb");
    }
    return TRUE;
}

/*
 * XAAdaptationBaseCtx* XACameraAdapt_Create()
 * Allocates memory for Camera Adaptation Context and makes 1st phase initialization
 * @returns XACameraAdaptationCtx* - Pointer to created context
 */
XAAdaptationBaseCtx* XACameraAdapt_Create(XAuint32 deviceID)
{
    XACameraAdaptationCtx *pSelf = calloc(1, sizeof(XACameraAdaptationCtx));
    DEBUG_API("->XACameraAdapt_Create");
    if ( pSelf)
    {
        if( XAAdaptationBase_Init(&(pSelf->baseObj),XACameraAdaptation)
                    != XA_RESULT_SUCCESS )
        {
            DEBUG_ERR("Failed to init base context!!!");
            free(pSelf);
            pSelf = NULL;
        }
        else
        {
            pSelf->deviceID = deviceID;
            pSelf->curMirror = XA_VIDEOMIRROR_NONE;
            pSelf->curRotation = 0;
            pSelf->recording = XA_BOOLEAN_FALSE;
            pSelf->playing = XA_BOOLEAN_FALSE;
            pSelf->snapshotting = XA_BOOLEAN_FALSE;
            cameraCtx = pSelf; /* Store global pointer */
            DEBUG_INFO_A1("Stored global camera ponter to %x", cameraCtx);
            cameraRealized = XA_BOOLEAN_FALSE;
        }
    }

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

/*
 * XAresult XACameraAdapt_PostInit()
 * 2nd phase initialization of Camera Adaptation Context
 */
XAresult XACameraAdapt_PostInit(XAAdaptationBaseCtx* bCtx)
{
    XAresult ret = XA_RESULT_SUCCESS;

    XACameraAdaptationCtx* ctx = NULL;
    DEBUG_API("->XACameraAdapt_PostInit");
    if(bCtx == NULL || bCtx->ctxId != XACameraAdaptation)
    {
        DEBUG_ERR("Invalid parameter!!");
        DEBUG_API("<-XACameraAdapt_PostInit");
        return XA_RESULT_PARAMETER_INVALID;
    }
    ctx = (XACameraAdaptationCtx*)bCtx;

    if ( !ctx )
    {
        return XA_RESULT_INTERNAL_ERROR;
    }

    XAAdaptationBase_PostInit( &(ctx->baseObj) );

    ctx->baseObj.bin = gst_element_factory_make( "camerabin", "camera");
    if ( !ctx->baseObj.bin )
    {
        DEBUG_ERR("Failed to create CameraBin");
        return XA_RESULT_INTERNAL_ERROR;
    }

    /* Create Gst bus listener. */
    ret = XAAdaptationBase_InitGstListener(&(ctx->baseObj));
    if( ret!=XA_RESULT_SUCCESS )
    {
        DEBUG_ERR("Bus listener creation failed!!");
        return ret;
    }
    /* Add Camera specific handler */
    if(ctx->baseObj.bus)
    {
        ctx->baseObj.busCb = XACameraAdapt_GstBusCb;
        gst_bus_add_signal_watch( ctx->baseObj.bus);
        g_signal_connect(ctx->baseObj.bus, "message::autofocus-done", G_CALLBACK(ctx->baseObj.busCb), ctx );
        g_signal_connect(ctx->baseObj.bus, "message::shake-risk", G_CALLBACK(ctx->baseObj.busCb), ctx );
        g_signal_connect(ctx->baseObj.bus, "message::async-done", G_CALLBACK(ctx->baseObj.busCb), ctx );
    }
    else
    {
        DEBUG_ERR("Failed to create message bus");
        return XA_RESULT_INTERNAL_ERROR;
    }


    /* SET UP CAMERABIN */

    /* use test video source if set, camerabin default (v4l2src) otherwise */
#ifdef XA_USE_TEST_PLUGINS
    if(ctx->deviceID == XA_ADAPTID_VIDEOTESTSRC || ctx->deviceID == XA_DEFAULTDEVICEID_CAMERA )
#else
    if(ctx->deviceID == XA_ADAPTID_VIDEOTESTSRC )
#endif
    {
        g_object_set( G_OBJECT(ctx->baseObj.bin), "videosrc", gst_element_factory_make("videotestsrc", "videotestsrc"), NULL );
    }

    /* set viewfinder element to be fake for the time of preroll.. if ghost pad added now,
     * stupid camerabin makes circular linking...
     */
    g_object_set( G_OBJECT(ctx->baseObj.bin), "vfsink" ,gst_element_factory_make("fakesink", "fakevfsink"), NULL );

    /* Setup camerabin to produce raw video */
    g_object_set( G_OBJECT(ctx->baseObj.bin), "videomux",NULL, NULL );
    g_object_set( G_OBJECT(ctx->baseObj.bin), "videoenc",NULL, NULL );
    g_object_set( G_OBJECT(ctx->baseObj.bin), "mute", TRUE, NULL );
    g_object_set( G_OBJECT(ctx->baseObj.bin), "async-handling", FALSE, NULL);
	g_object_set( G_OBJECT(ctx->baseObj.bin), "mode",(gint)1, NULL);


    /* drive camerabin to READY to create the elements inside bin */
    gst_element_set_state( GST_ELEMENT(ctx->baseObj.bin), GST_STATE_READY);

    if(ctx->deviceID == XA_ADAPTID_VIDEOTESTSRC)
    {   /* set properties for videotestsrc */
        GstElement *testsrc = gst_bin_get_by_name(GST_BIN(ctx->baseObj.bin), "videotestsrc");
        g_object_set( G_OBJECT(testsrc),"is-live", TRUE, NULL);
        g_object_set( G_OBJECT(testsrc),"do-timestamp", TRUE, NULL);
        gst_object_unref(G_OBJECT(testsrc));
    }

    /* do some filter optimization */
#ifdef XA_USE_TEST_PLUGINS
    g_object_set( G_OBJECT(ctx->baseObj.bin), "filter-caps",
                    gst_caps_new_simple("video/x-raw-yuv",
                                        "format", GST_TYPE_FOURCC,GST_MAKE_FOURCC('I','4','2','0'),
                                        "framerate",GST_TYPE_FRACTION_RANGE,0,1,30,1, NULL)
                ,NULL );
#else
    g_object_set( G_OBJECT(ctx->baseObj.bin), "filter-caps",
                    gst_caps_new_simple("video/x-raw-yuv",
                                        "format", GST_TYPE_FOURCC,GST_MAKE_FOURCC('Y','U','Y','2'),
                                        "framerate",GST_TYPE_FRACTION_RANGE,0,1,30,1, NULL)
                ,NULL );
#endif


    /* now, unlink fake sink, create camera post processing pipeline and create ghost pad from it */
    {
        GstElement *fakesink = gst_bin_get_by_name(GST_BIN(ctx->baseObj.bin),"fakevfsink");
        GstPad *fakepad = gst_element_get_static_pad(fakesink,"sink");
        GstPad *linkedpad = gst_pad_get_peer(fakepad);
        GstElement *linkedelement = gst_pad_get_parent_element(linkedpad);
        GstElement * cameraPP = NULL;
        GstElement * camfilter = NULL;
        GstElement *tee = NULL;

        /* Unlink fakesink */
        gst_element_unlink(linkedelement,fakesink);
        /* Create VideoPP pipeline for Camera object */
        cameraPP = XAAdaptationBase_CreateVideoPP();
        g_object_set( G_OBJECT(cameraPP),"name", "videopp_camera", NULL);
        gst_bin_add( GST_BIN(ctx->baseObj.bin), cameraPP );
        /*Link videoPP into camera bin last element */
        gst_element_link( linkedelement, cameraPP );

        /* Add extra filter for caps negotiable after post processing*/
        camfilter = gst_element_factory_make("capsfilter", "camfilter");
        gst_bin_add( GST_BIN(ctx->baseObj.bin), camfilter );
        gst_element_link( cameraPP, camfilter );

        /* Add tee element into camerabin */
        tee = gst_element_factory_make( "tee", "CamTee");
        gst_bin_add( GST_BIN(ctx->baseObj.bin), tee);
        gst_element_link( camfilter, tee );

		/* Unref */
        gst_object_unref(linkedelement);
        gst_object_unref(linkedpad);
        gst_object_unref(fakepad);
        gst_bin_remove(GST_BIN(ctx->baseObj.bin),fakesink);
        gst_object_unparent(GST_OBJECT(fakesink));
    }

    if ( ret == XA_RESULT_SUCCESS )
    {
    	cameraRealized = XA_BOOLEAN_TRUE;
    }

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

/*
 * void XACameraAdapt_Destroy(XACameraAdaptationCtx* ctx)
 * Destroys Camera Adaptation Context
 * @param ctx - Camera Adaptation context to be destroyed
 */
void XACameraAdapt_Destroy(XAAdaptationBaseCtx* bCtx)
{
	XACameraAdaptationCtx* ctx = NULL;

	DEBUG_API("->XACameraAdapt_Destroy");
	if(bCtx == NULL || bCtx->ctxId != XACameraAdaptation )
	{
		DEBUG_ERR("Invalid parameter!!");
		DEBUG_API("<-XACameraAdapt_Destroy");
		return;
	}
	ctx = (XACameraAdaptationCtx*)bCtx;

    XAAdaptationBase_Free(&(ctx->baseObj));

    free(ctx);
    ctx = NULL;
    cameraCtx = NULL;
    cameraRealized = XA_BOOLEAN_FALSE;
    DEBUG_API("<-XACameraAdapt_Destroy");
}