khronosfws/openmax_al/src/adaptation/xasnapshotitfadaptation.c
changeset 12 5a06f39ad45b
equal deleted inserted replaced
0:71ca22bcf22a 12:5a06f39ad45b
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 #include <string.h>
       
    19 #include <gst.h>
       
    20 #include <gstappsrc.h>
       
    21 #include <gstappsink.h>
       
    22 #include "XAAdaptation.h"
       
    23 #include "XASnapShotItfAdaptation.h"
       
    24 #include "XAMediaRecorderAdaptCtx.h"
       
    25 #include "XAMetadataAdaptation.h"
       
    26 #include "XAStaticCapsAdaptation.h"
       
    27 
       
    28 #define SSMAXPIC 30
       
    29 #define SSMAXFPS 30 /*technically, same as FPS of video stream*/
       
    30 #define SSMINFPS 1
       
    31 
       
    32 extern XAboolean cameraRealized;
       
    33 extern XACameraAdaptationCtx_* cameraCtx;
       
    34 
       
    35 /* Forward declarations for internal methods */
       
    36 XAresult XASnapshotItfAdaptation_CreateSnapshotPipeline(XAAdaptationBaseCtx* bCtx);
       
    37 XAresult XASnapshotItfAdaptation_FreeSnapshot();
       
    38 const char* XASnapshotItfAdaptation_GetFileSuffix(XADataFormat_MIME* format);
       
    39 void XASnapshotItfAdaptation_AllocNextFilename(char** fname, const char* template);
       
    40 void XASnapshotItfAdaptation_StopSnapshotting(XAAdaptationBaseCtx* bCtx);
       
    41 
       
    42 /* callbacks */
       
    43 gboolean XASnapshotItfAdaptation_SnapshotBusCb( GstBus *bus, GstMessage *message, gpointer data );
       
    44 void XASnapshotItfAdaptation_BufferHandoffCb( GstElement *extract, GstBuffer *buffer, gpointer data);
       
    45 
       
    46 /*********************************
       
    47  * SnapshotItf adaptation methods
       
    48  *********************************/
       
    49 
       
    50 /*
       
    51  * XAresult XASnapshotItfAdaptation_InitiateSnapshot(XAAdaptationBaseCtx* bCtx,
       
    52  *                                                 XAuint32 numberOfPictures,
       
    53  *                                                 XAuint32 fps,
       
    54  *                                                 XAboolean freezeViewFinder,
       
    55  *                                                 XADataSink* sink)
       
    56  */
       
    57 XAresult XASnapshotItfAdaptation_InitiateSnapshot(XAAdaptationBaseCtx* bCtx,
       
    58                                                   XAuint32 numberOfPictures,
       
    59                                                   XAuint32 fps,
       
    60                                                   XAboolean freezeViewFinder,
       
    61                                                   XADataSink* sink)
       
    62 {
       
    63     XAMediaRecorderAdaptationCtx* mCtx = (XAMediaRecorderAdaptationCtx*)bCtx;
       
    64     XADataLocator_URI* uri=NULL;
       
    65 
       
    66     DEBUG_API("->XASnapshotItfAdaptation_InitiateSnapshot");
       
    67     /* Store initialization variables */
       
    68     mCtx->snapshotVars.numpics = numberOfPictures;
       
    69     mCtx->snapshotVars.fps = fps;
       
    70     mCtx->snapshotVars.freeze =freezeViewFinder;
       
    71     mCtx->snapshotVars.parsenegotiated = FALSE;
       
    72     mCtx->snapshotVars.snapshotbuffer = NULL;
       
    73 
       
    74     if( sink )
       
    75     {   /* parse file sink name*/
       
    76         if( sink->pLocator && *((XAuint32*)(sink->pLocator)) == XA_DATALOCATOR_URI )
       
    77         {
       
    78             uri = (XADataLocator_URI*)sink->pLocator;
       
    79             if ( uri->URI != NULL )
       
    80             {
       
    81                 /* parse filename template: <prefix><nnnn><suffix> */
       
    82                 mCtx->snapshotVars.fnametemplate = calloc(1,strlen((char*)uri->URI)+10);
       
    83                 DEBUG_INFO_A1("URI: %s", uri->URI);
       
    84                 if(strncmp((char*)uri->URI, "file://", 7) == 0)
       
    85                 {
       
    86                     strcat(mCtx->snapshotVars.fnametemplate, (char*)&((uri->URI)[7]));
       
    87                 }
       
    88                 else
       
    89                 {
       
    90                     strcat(mCtx->snapshotVars.fnametemplate, (char*)uri->URI);
       
    91                 }
       
    92                 strcat(mCtx->snapshotVars.fnametemplate, "%04d.");
       
    93                 strcat(mCtx->snapshotVars.fnametemplate,
       
    94                         XASnapshotItfAdaptation_GetFileSuffix(sink->pFormat));
       
    95                 DEBUG_INFO_A1("->template name %s", mCtx->snapshotVars.fnametemplate);
       
    96             }
       
    97             else
       
    98             {
       
    99                 DEBUG_ERR("No uri specified.");
       
   100                 return XA_RESULT_PARAMETER_INVALID;
       
   101             }
       
   102         }
       
   103         else
       
   104         { /* take snapshot to memory buffer */
       
   105             if( mCtx->snapshotVars.fnametemplate )
       
   106             {
       
   107                 free( mCtx->snapshotVars.fnametemplate );
       
   108             }
       
   109             mCtx->snapshotVars.fnametemplate = NULL;
       
   110         }
       
   111         if( sink->pFormat && *((XAuint32*)(sink->pFormat)) == XA_DATAFORMAT_RAWIMAGE )
       
   112         {
       
   113             XADataFormat_RawImage* img = ((XADataFormat_RawImage*)sink->pFormat);
       
   114             /*set needed image settings from the sink structure*/
       
   115             mCtx->imageEncSettings.encoderId = XA_IMAGECODEC_RAW;
       
   116             mCtx->imageEncSettings.width = img->width;
       
   117             mCtx->imageEncSettings.height = img->height;
       
   118             mCtx->imageEncSettings.colorFormat = img->colorFormat;
       
   119         }
       
   120     }
       
   121     else
       
   122     {
       
   123         DEBUG_ERR("XASnapshotItfAdaptation_InitiateSnapshot, invalid data sink!");
       
   124         DEBUG_ERR("XA_RESULT_PARAMETER_INVALID");
       
   125         DEBUG_API("<-XASnapshotItfAdaptation_InitiateSnapshot");
       
   126         return XA_RESULT_PARAMETER_INVALID;
       
   127     }
       
   128 
       
   129 
       
   130     if( mCtx->snapshotVars.sspipeline )
       
   131     {
       
   132         XASnapshotItfAdaptation_FreeSnapshot(bCtx);
       
   133     }
       
   134     if( XASnapshotItfAdaptation_CreateSnapshotPipeline(bCtx) != XA_RESULT_SUCCESS )
       
   135     {
       
   136         DEBUG_ERR("Failed to create pipeline!!");
       
   137         DEBUG_ERR("XA_RESULT_INTERNAL_ERROR");
       
   138         DEBUG_API("<-XASnapshotItfAdaptation_InitiateSnapshot");
       
   139         return XA_RESULT_INTERNAL_ERROR;
       
   140     }
       
   141     DEBUG_API("<-XASnapshotItfAdaptation_InitiateSnapshot");
       
   142     return XA_RESULT_SUCCESS;
       
   143 }
       
   144 
       
   145 /*
       
   146  * XAresult XASnapshotItfAdaptation_TakeSnapshot(XAAdaptationBaseCtx* bCtx)
       
   147  */
       
   148 XAresult XASnapshotItfAdaptation_TakeSnapshot(XAAdaptationBaseCtx* bCtx)
       
   149 {
       
   150     XAMediaRecorderAdaptationCtx* mCtx = NULL;
       
   151 
       
   152     DEBUG_API("->XASnapshotItfAdaptation_TakeSnapshot");
       
   153     if(!bCtx || bCtx->ctxId != XAMediaRecorderAdaptation )
       
   154     {
       
   155         DEBUG_ERR("XA_RESULT_PARAMETER_INVALID");
       
   156         DEBUG_API("<-XASnapshotItfAdaptation_TakeSnapshot");
       
   157         /* invalid parameter */
       
   158         return XA_RESULT_PARAMETER_INVALID;
       
   159     }
       
   160     mCtx = (XAMediaRecorderAdaptationCtx*)bCtx;
       
   161     /*to get buffer, base pipeline must be playing...*/
       
   162     if( GST_STATE(mCtx->baseObj.bin) != GST_STATE_PLAYING )
       
   163     {
       
   164         DEBUG_INFO_A1("Parent bin in state %d, set to PLAYING", GST_STATE(mCtx->baseObj.bin));
       
   165         gst_element_set_state( GST_ELEMENT(mCtx->baseObj.bin), GST_STATE_PLAYING );
       
   166         gst_element_get_state( GST_ELEMENT(mCtx->baseObj.bin), NULL,NULL, XA_ADAPT_ASYNC_TIMEOUT_SHORT_NSEC);
       
   167     }
       
   168     if ( mCtx->isobjvsrc && mCtx->videosource && cameraCtx && cameraRealized )
       
   169     {
       
   170     	GstPad *pad=NULL;
       
   171     	GstPad *pad1=NULL;
       
   172 
       
   173     	cameraCtx->snapshotting = XA_BOOLEAN_TRUE;
       
   174     	pad = gst_element_get_static_pad( GST_ELEMENT(cameraCtx->baseObj.bin), "MRObjSrc");
       
   175 		if( pad && gst_pad_is_linked(pad) )
       
   176 		{
       
   177 			DEBUG_INFO_A2("unblock element:%s pad:%s",
       
   178 					gst_element_get_name(cameraCtx->baseObj.bin),
       
   179 					gst_pad_get_name(pad));
       
   180 			gst_pad_set_blocked_async(pad, FALSE, XAAdaptationBase_PadBlockCb, NULL);
       
   181 		}
       
   182 
       
   183     	pad1 = gst_element_get_static_pad( GST_ELEMENT(cameraCtx->baseObj.bin), "MPObjSrc");
       
   184 		if( pad1 && gst_pad_is_linked(pad1) )
       
   185 		{
       
   186 			DEBUG_INFO_A2("unblock element:%s pad:%s",
       
   187 					gst_element_get_name(cameraCtx->baseObj.bin),
       
   188 					gst_pad_get_name(pad1));
       
   189 			gst_pad_set_blocked_async(pad, FALSE, XAAdaptationBase_PadBlockCb, NULL);
       
   190 		}
       
   191 
       
   192     	DEBUG_INFO_A1("Using camera from global pointer %x", cameraCtx);
       
   193     	if ( GST_STATE( GST_ELEMENT(cameraCtx->baseObj.bin)) != GST_STATE_PLAYING )
       
   194 		{
       
   195 			cameraCtx->baseObj.binWantedState = GST_STATE(cameraCtx->baseObj.bin);
       
   196 			DEBUG_INFO_A1("Camerabin state %d, set to PLAYING", GST_STATE(GST_ELEMENT(cameraCtx->baseObj.bin)));
       
   197 			gst_element_set_state( GST_ELEMENT(cameraCtx->baseObj.bin), GST_STATE_PLAYING );
       
   198 			gst_element_get_state( GST_ELEMENT(cameraCtx->baseObj.bin), NULL,NULL, XA_ADAPT_ASYNC_TIMEOUT_SHORT_NSEC);
       
   199 		}
       
   200 	}
       
   201 
       
   202     /* Connect signal for getting current buffer from video pipeline*/
       
   203     mCtx->snapshotVars.numpicstaken = 0;
       
   204     mCtx->snapshotVars.waitforbuffer = TRUE;
       
   205     if(mCtx->videoextract)
       
   206     {
       
   207         mCtx->snapshotVars.sighandler = g_signal_connect(mCtx->videoextract, "handoff",
       
   208                                 G_CALLBACK (XASnapshotItfAdaptation_BufferHandoffCb),mCtx);
       
   209     }
       
   210     if( mCtx->snapshotVars.sighandler==0 )
       
   211     {
       
   212         DEBUG_ERR("XA_RESULT_INTERNAL_ERROR");
       
   213         DEBUG_API("<-XASnapshotItfAdaptation_TakeSnapshot");
       
   214         return XA_RESULT_INTERNAL_ERROR;
       
   215     }
       
   216     DEBUG_API("<-XASnapshotItfAdaptation_TakeSnapshot");
       
   217     return XA_RESULT_SUCCESS;
       
   218 }
       
   219 
       
   220 /*
       
   221  * XAresult XASnapshotItfAdaptation_CancelSnapshot(XAAdaptationBaseCtx* bCtx)
       
   222  */
       
   223 XAresult XASnapshotItfAdaptation_CancelSnapshot(XAAdaptationBaseCtx* bCtx)
       
   224 {
       
   225     DEBUG_API("->XASnapshotItfAdaptation_CancelSnapshot");
       
   226     if(!bCtx || bCtx->ctxId != XAMediaRecorderAdaptation )
       
   227     {
       
   228         DEBUG_ERR("XA_RESULT_PARAMETER_INVALID");
       
   229         DEBUG_API("<-XASnapshotItfAdaptation_CancelSnapshot");
       
   230         /* invalid parameter */
       
   231         return XA_RESULT_PARAMETER_INVALID;
       
   232     }
       
   233 
       
   234     XASnapshotItfAdaptation_FreeSnapshot(bCtx);
       
   235 
       
   236     DEBUG_API("<-XASnapshotItfAdaptation_CancelSnapshot");
       
   237     return XA_RESULT_SUCCESS;
       
   238 }
       
   239 
       
   240 /*
       
   241  * XAresult XASnapshotItfAdaptation_GetMaxPicsPerBurst(XAAdaptationBaseCtx* bCtx,
       
   242  *                                              XAuint32 *maxNumberOfPictures)
       
   243  */
       
   244 XAresult XASnapshotItfAdaptation_GetMaxPicsPerBurst(XAAdaptationBaseCtx* bCtx,
       
   245                                               XAuint32 *maxNumberOfPictures)
       
   246 {
       
   247     DEBUG_API("->XASnapshotItfAdaptation_GetMaxPicsPerBurst");
       
   248     if(!bCtx || bCtx->ctxId != XAMediaRecorderAdaptation )
       
   249     {
       
   250         DEBUG_ERR("XA_RESULT_PARAMETER_INVALID");
       
   251         DEBUG_API("<-XASnapshotItfAdaptation_GetMaxPicsPerBurst");
       
   252         return XA_RESULT_PARAMETER_INVALID;
       
   253     }
       
   254     *maxNumberOfPictures = SSMAXPIC;
       
   255     DEBUG_API("<-XASnapshotItfAdaptation_GetMaxPicsPerBurst");
       
   256     return XA_RESULT_SUCCESS;
       
   257 }
       
   258 
       
   259 /*
       
   260  * XAresult XASnapshotItfAdaptation_GetBurstFPSRange(XAAdaptationBaseCtx* bCtx,
       
   261  *                                            XAuint32 *minFPS,
       
   262  *                                           XAuint32 *maxFPS)
       
   263  */
       
   264 XAresult XASnapshotItfAdaptation_GetBurstFPSRange(XAAdaptationBaseCtx* bCtx,
       
   265                                             XAuint32 *minFPS,
       
   266                                             XAuint32 *maxFPS)
       
   267 {
       
   268     DEBUG_API("->XASnapshotItfAdaptation_GetBurstFPSRange");
       
   269     if(!bCtx || bCtx->ctxId != XAMediaRecorderAdaptation )
       
   270         {
       
   271             DEBUG_ERR("XA_RESULT_PARAMETER_INVALID");
       
   272             DEBUG_API("<-XASnapshotItfAdaptation_GetBurstFPSRange");
       
   273             return XA_RESULT_PARAMETER_INVALID;
       
   274         }
       
   275     *minFPS = SSMINFPS;
       
   276     *maxFPS = SSMAXFPS;
       
   277 
       
   278     DEBUG_API("<-XASnapshotItfAdaptation_GetBurstFPSRange");
       
   279     return XA_RESULT_SUCCESS;
       
   280 }
       
   281 
       
   282 /*
       
   283  * XAresult XASnapshotItfAdaptation_SetShutterFeedback(XAAdaptationBaseCtx* bCtx,
       
   284  *                                              XAboolean enabled)
       
   285  */
       
   286 XAresult XASnapshotItfAdaptation_SetShutterFeedback(XAAdaptationBaseCtx* bCtx,
       
   287                                               XAboolean enabled)
       
   288 {
       
   289     DEBUG_API("->XASnapshotItfAdaptation_SetShutterFeedback");
       
   290     if(!bCtx || bCtx->ctxId != XAMediaRecorderAdaptation )
       
   291     {
       
   292         DEBUG_ERR("XA_RESULT_PARAMETER_INVALID");
       
   293         DEBUG_API("<-XASnapshotItfAdaptation_SetShutterFeedback");
       
   294         /* invalid parameter */
       
   295         return XA_RESULT_PARAMETER_INVALID;
       
   296     }
       
   297     /* stubbed, no implementation */
       
   298     DEBUG_API("<-XASnapshotItfAdaptation_SetShutterFeedback");
       
   299     return XA_RESULT_SUCCESS;
       
   300 }
       
   301 
       
   302 /********************
       
   303  * Internal methods
       
   304  ********************/
       
   305 
       
   306 /*
       
   307  * void XASnapshotItfAdaptation_StopSnapshotting(XAAdaptationBaseCtx* bCtx)
       
   308  */
       
   309 void XASnapshotItfAdaptation_StopSnapshotting(XAAdaptationBaseCtx* bCtx)
       
   310 {
       
   311     XAMediaRecorderAdaptationCtx* mCtx = (XAMediaRecorderAdaptationCtx*) bCtx;
       
   312     DEBUG_API("->XASnapshotItfAdaptation_StopSnapshotting");
       
   313     mCtx->snapshotVars.waitforbuffer = FALSE;
       
   314     mCtx->snapshotVars.snapshotbuffer = NULL;
       
   315     if(mCtx->snapshotVars.sighandler)
       
   316     {
       
   317         if(mCtx->videoextract)
       
   318         {
       
   319             g_signal_handler_disconnect(mCtx->videoextract,mCtx->snapshotVars.sighandler);
       
   320         }
       
   321         mCtx->snapshotVars.sighandler = 0;
       
   322     }
       
   323     /* did we change the state of parent pipeline?*/
       
   324     if( mCtx->baseObj.bin && (GST_STATE(mCtx->baseObj.bin) != mCtx->baseObj.binWantedState) )
       
   325     {
       
   326         gst_element_set_state( GST_ELEMENT(mCtx->baseObj.bin), mCtx->baseObj.binWantedState );
       
   327     }
       
   328 
       
   329     if ( cameraCtx && (GST_STATE(cameraCtx->baseObj.bin) != cameraCtx->baseObj.binWantedState) )
       
   330 	{
       
   331     	cameraCtx->snapshotting = XA_BOOLEAN_FALSE;
       
   332 		DEBUG_INFO_A2("Camerabin state %d, restored to %d", GST_STATE(cameraCtx->baseObj.bin), cameraCtx->baseObj.binWantedState );
       
   333 		gst_element_set_state( GST_ELEMENT(cameraCtx->baseObj.bin), cameraCtx->baseObj.binWantedState );
       
   334 		gst_element_get_state( GST_ELEMENT(cameraCtx->baseObj.bin), NULL,NULL, XA_ADAPT_ASYNC_TIMEOUT_SHORT_NSEC);
       
   335 	}
       
   336     DEBUG_API("<-XASnapshotItfAdaptation_StopSnapshotting");
       
   337 }
       
   338 
       
   339 /*
       
   340  * XAresult XASnapshotItfAdaptation_FreeSnapshot(XAAdaptationBaseCtx* bCtx)
       
   341  */
       
   342 XAresult XASnapshotItfAdaptation_FreeSnapshot(XAAdaptationBaseCtx* bCtx)
       
   343 {
       
   344     XAMediaRecorderAdaptationCtx* mCtx = NULL;
       
   345     DEBUG_API("->XASnapshotItfAdaptation_FreeSnapshot");
       
   346     if(!bCtx || bCtx->ctxId != XAMediaRecorderAdaptation)
       
   347     {
       
   348         DEBUG_ERR("XA_RESULT_PARAMETER_INVALID");
       
   349         DEBUG_API("<-XASnapshotItfAdaptation_FreeSnapshot");
       
   350         return XA_RESULT_PARAMETER_INVALID;
       
   351     }
       
   352     mCtx = (XAMediaRecorderAdaptationCtx*) bCtx;
       
   353     XASnapshotItfAdaptation_StopSnapshotting(bCtx);
       
   354     /* Clean up pipeline and set current pipeline state to null*/
       
   355     if( mCtx->snapshotVars.sspipeline )
       
   356     {
       
   357         gst_element_set_state( GST_ELEMENT(mCtx->snapshotVars.sspipeline), GST_STATE_NULL );
       
   358         gst_object_unref( GST_OBJECT(mCtx->snapshotVars.sspipeline) );
       
   359         mCtx->snapshotVars.sspipeline = NULL;
       
   360     }
       
   361     if( mCtx->snapshotVars.ssbus )
       
   362     {
       
   363         gst_object_unref( GST_OBJECT(mCtx->snapshotVars.ssbus) );
       
   364         mCtx->snapshotVars.ssbus = NULL;
       
   365     }
       
   366     if( mCtx->snapshotVars.fnametemplate )
       
   367     {
       
   368         free(mCtx->snapshotVars.fnametemplate);
       
   369         mCtx->snapshotVars.fnametemplate=NULL;
       
   370     }
       
   371     DEBUG_API("<-XASnapshotItfAdaptation_FreeSnapshot");
       
   372     return XA_RESULT_SUCCESS;
       
   373 }
       
   374 
       
   375 /*
       
   376  * XAresult XASnapshotItfAdaptation_CreateSnapshotPipeline(XAAdaptationBaseCtx* bCtx)
       
   377  */
       
   378 XAresult XASnapshotItfAdaptation_CreateSnapshotPipeline(XAAdaptationBaseCtx* bCtx)
       
   379 {
       
   380     XAMediaRecorderAdaptationCtx* mCtx = NULL;
       
   381     GstStateChangeReturn gstRet = GST_STATE_CHANGE_SUCCESS;
       
   382     XAStaticCapsData temp;
       
   383     GstCaps *imageCaps=NULL;
       
   384 
       
   385     DEBUG_API("->XASnapshotItfAdaptation_CreateSnapshotPipeline");
       
   386     if(!bCtx || bCtx->ctxId != XAMediaRecorderAdaptation)
       
   387     {
       
   388         DEBUG_ERR("XA_RESULT_PARAMETER_INVALID");
       
   389         return XA_RESULT_PARAMETER_INVALID;
       
   390     }
       
   391     mCtx = (XAMediaRecorderAdaptationCtx*) bCtx;
       
   392 
       
   393     /*Create snapshotpipeline*/
       
   394     mCtx->snapshotVars.sspipeline = gst_pipeline_new ("sspipeline");
       
   395     if( mCtx->snapshotVars.sspipeline  )
       
   396     {
       
   397         /*add listener*/
       
   398         mCtx->snapshotVars.ssbus = gst_pipeline_get_bus(GST_PIPELINE( mCtx->snapshotVars.sspipeline ) );
       
   399         if( ! mCtx->snapshotVars.ssbus )
       
   400         {
       
   401             DEBUG_API("Cannot create snapshotbus");
       
   402             DEBUG_API("<-XASnapshotItfAdaptation_CreateSnapshotPipeline - XA_RESULT_INTERNAL_ERROR");
       
   403             return XA_RESULT_INTERNAL_ERROR;
       
   404         }
       
   405         gst_bus_add_signal_watch( mCtx->snapshotVars.ssbus );
       
   406         g_signal_connect(mCtx->snapshotVars.ssbus, "message::eos",
       
   407                 G_CALLBACK(XASnapshotItfAdaptation_SnapshotBusCb), bCtx );
       
   408         g_signal_connect(mCtx->snapshotVars.ssbus, "message::state-changed",
       
   409                 G_CALLBACK(XASnapshotItfAdaptation_SnapshotBusCb), bCtx );
       
   410         g_signal_connect(mCtx->snapshotVars.ssbus, "message::async-done",
       
   411                 G_CALLBACK(XASnapshotItfAdaptation_SnapshotBusCb), bCtx );
       
   412 
       
   413         /*Create snapshotsource element*/
       
   414         mCtx->snapshotVars.ssbuffersrc = gst_element_factory_make("appsrc", "ssbuffersrc");
       
   415         if( !mCtx->snapshotVars.ssbuffersrc )
       
   416         {
       
   417             DEBUG_ERR("Cannot create ssbuffersrc!");
       
   418             DEBUG_API("<-XASnapshotItfAdaptation_CreateSnapshotPipeline - XA_RESULT_INTERNAL_ERROR");
       
   419             return XA_RESULT_INTERNAL_ERROR;
       
   420         }
       
   421         /*Frame parser*/
       
   422         mCtx->snapshotVars.ssparser =
       
   423             gst_element_factory_make("videoparse","ssparser");
       
   424         if( !mCtx->snapshotVars.ssparser )
       
   425         {
       
   426             DEBUG_ERR("Could not create snapshotparse");
       
   427             DEBUG_API("<-XASnapshotItfAdaptation_CreateSnapshotPipeline - XA_RESULT_INTERNAL_ERROR");
       
   428             return XA_RESULT_INTERNAL_ERROR;
       
   429         }
       
   430 
       
   431         /*Scaler and filter for XAImageSettings width&height*/
       
   432         mCtx->snapshotVars.ssscaler =
       
   433             gst_element_factory_make("videoscale","ssscaler");
       
   434         if( !mCtx->snapshotVars.ssscaler )
       
   435         {
       
   436             DEBUG_ERR("Could not create ssscaler");
       
   437             DEBUG_API("<-XASnapshotItfAdaptation_CreateSnapshotPipeline - XA_RESULT_INTERNAL_ERROR");
       
   438             return XA_RESULT_INTERNAL_ERROR;
       
   439         }
       
   440         mCtx->snapshotVars.ssfilter =
       
   441             gst_element_factory_make("capsfilter","ssfilter");
       
   442         if( !mCtx->snapshotVars.ssfilter )
       
   443         {
       
   444             DEBUG_ERR("Could not create ssfilter");
       
   445             DEBUG_API("<-XASnapshotItfAdaptation_CreateSnapshotPipeline - XA_RESULT_INTERNAL_ERROR");
       
   446             return XA_RESULT_INTERNAL_ERROR;
       
   447         }
       
   448 
       
   449         /*Create imageencoder */
       
   450         if(XAStaticCapsAdapt_GetCapsById(XACAP_ENCODER|XACAP_IMAGE, mCtx->imageEncSettings.encoderId, &temp) == XA_RESULT_SUCCESS)
       
   451         {
       
   452             if(temp.adaptId!=NULL)
       
   453             {
       
   454                 mCtx->snapshotVars.ssencoder = gst_element_factory_make((char*)temp.adaptId, "ssencoder");
       
   455             }
       
   456             else if(mCtx->imageEncSettings.encoderId == XA_IMAGECODEC_RAW)
       
   457             {
       
   458                 /* raw frames are internal format, so no codec needed. just insert identity for linking*/
       
   459                mCtx->snapshotVars.ssencoder = gst_element_factory_make("identity", "ssencoder");
       
   460             }
       
   461         }
       
   462         if( !mCtx->snapshotVars.ssencoder )
       
   463         {
       
   464             DEBUG_API("Cannot create image encoder");
       
   465             DEBUG_API("<-XASnapshotItfAdaptation_CreateSnapshotPipeline - XA_RESULT_INTERNAL_ERROR");
       
   466             return XA_RESULT_INTERNAL_ERROR;
       
   467         }
       
   468 
       
   469         /* Create also tag setter for JPG */
       
   470         if(mCtx->imageEncSettings.encoderId == XA_IMAGECODEC_JPEG)
       
   471         {
       
   472             mCtx->snapshotVars.sstagger = gst_element_factory_make("metadatamux", "sstagger");
       
   473             if( !mCtx->snapshotVars.sstagger || !gst_bin_add(GST_BIN(mCtx->snapshotVars.sspipeline),mCtx->snapshotVars.sstagger))
       
   474             {
       
   475                 DEBUG_API("Cannot create metadatamux");
       
   476                 DEBUG_API("<-XASnapshotItfAdaptation_CreateSnapshotPipeline - XA_RESULT_INTERNAL_ERROR");
       
   477             }
       
   478             g_object_set( G_OBJECT(mCtx->snapshotVars.sstagger), "xmp", TRUE, "exif", TRUE, "iptc", TRUE, NULL );
       
   479         }
       
   480 
       
   481         /*Create sink*/
       
   482         if(mCtx->snapshotVars.fnametemplate)
       
   483         {
       
   484             DEBUG_INFO("RECORD SNAPSHOT TO FILE");
       
   485             mCtx->snapshotVars.sssink = gst_element_factory_make("filesink","ssfilesink");
       
   486             g_object_set( G_OBJECT(mCtx->snapshotVars.sssink), "location", "temp",
       
   487                                                                 "async", FALSE,
       
   488                                                                 "qos", FALSE,
       
   489                                                                 "max-lateness", (gint64)(-1),
       
   490                                                                 "buffer-mode", 2,
       
   491                                                                 NULL );
       
   492         }
       
   493         else
       
   494         {
       
   495             DEBUG_INFO("RECORD SNAPSHOT TO MEMORY");
       
   496             mCtx->snapshotVars.sssink = gst_element_factory_make("appsink","ssbuffersink");
       
   497         }
       
   498         if( !mCtx->snapshotVars.sssink )
       
   499         {
       
   500             DEBUG_ERR("Could not create sssink!!");
       
   501             DEBUG_API("<-XASnapshotItfAdaptation_CreateSnapshotPipeline - XA_RESULT_INTERNAL_ERROR");
       
   502             return XA_RESULT_INTERNAL_ERROR;
       
   503         }
       
   504         g_object_set( G_OBJECT(mCtx->snapshotVars.sssink), "async", FALSE, NULL );
       
   505 
       
   506         /*Add elements to bin*/
       
   507         gst_bin_add_many (GST_BIN (mCtx->snapshotVars.sspipeline),
       
   508                 mCtx->snapshotVars.ssbuffersrc,
       
   509                 mCtx->snapshotVars.ssparser,
       
   510                 mCtx->snapshotVars.ssscaler,
       
   511                 mCtx->snapshotVars.ssfilter,
       
   512                 mCtx->snapshotVars.ssencoder,
       
   513                 mCtx->snapshotVars.sssink,
       
   514                 NULL);
       
   515 
       
   516         /* set needed XAImageSettings properties*/
       
   517         /* set caps from imagesettings */
       
   518         imageCaps = gst_caps_new_simple("video/x-raw-yuv",
       
   519                                         "width", G_TYPE_INT, mCtx->imageEncSettings.width,
       
   520                                         "height", G_TYPE_INT, mCtx->imageEncSettings.height, NULL);
       
   521         g_object_set( G_OBJECT(mCtx->snapshotVars.ssfilter), "caps", imageCaps, NULL );
       
   522         DEBUG_INFO_A1("new caps: %s",gst_caps_to_string(imageCaps));
       
   523         gst_caps_unref(imageCaps);
       
   524 
       
   525         /* set compression level */
       
   526         if(mCtx->imageEncSettings.encoderId == XA_IMAGECODEC_JPEG)
       
   527         {
       
   528             g_object_set( G_OBJECT(mCtx->snapshotVars.ssencoder), "quality", (gint)(1000 - mCtx->imageEncSettings.compressionLevel)/10, NULL );
       
   529         }
       
   530 
       
   531         /*Chain elements together*/
       
   532         if(mCtx->snapshotVars.sstagger)
       
   533         {
       
   534             if( !gst_element_link_many(
       
   535                     mCtx->snapshotVars.ssbuffersrc,
       
   536                     mCtx->snapshotVars.ssparser,
       
   537                     mCtx->snapshotVars.ssscaler,
       
   538                     mCtx->snapshotVars.ssfilter,
       
   539                     mCtx->snapshotVars.ssencoder,
       
   540                     mCtx->snapshotVars.sstagger,
       
   541                     mCtx->snapshotVars.sssink,
       
   542                     NULL) )
       
   543             {
       
   544                 DEBUG_ERR("Could not link pipeline")
       
   545                 return XA_RESULT_INTERNAL_ERROR;
       
   546             }
       
   547         }
       
   548         else
       
   549         {
       
   550             if( !gst_element_link_many(
       
   551                     mCtx->snapshotVars.ssbuffersrc,
       
   552                     mCtx->snapshotVars.ssparser,
       
   553                     mCtx->snapshotVars.ssscaler,
       
   554                     mCtx->snapshotVars.ssfilter,
       
   555                     mCtx->snapshotVars.ssencoder,
       
   556                     mCtx->snapshotVars.sssink,
       
   557                     NULL) )
       
   558             {
       
   559                 DEBUG_ERR("Could not link pipeline")
       
   560                 return XA_RESULT_INTERNAL_ERROR;
       
   561             }
       
   562         }
       
   563         gstRet = gst_element_set_state(GST_ELEMENT(mCtx->snapshotVars.sspipeline), GST_STATE_READY);
       
   564         DEBUG_API("<-XASnapshotItfAdaptation_CreateSnapshotPipeline");
       
   565         return XA_RESULT_SUCCESS;
       
   566 
       
   567     }
       
   568     else
       
   569     {
       
   570         DEBUG_ERR("XA_RESULT_PRECONDITIONS_VIOLATED");
       
   571         DEBUG_API("<-XASnapshotItfAdaptation_CreateSnapshotPipeline");
       
   572         return  XA_RESULT_PRECONDITIONS_VIOLATED;
       
   573     }
       
   574 }
       
   575 
       
   576 /*
       
   577  * gboolean XASnapshotItfAdaptation_SnapshotBusCb( GstBus *bus, GstMessage *message, gpointer data )
       
   578  */
       
   579 gboolean XASnapshotItfAdaptation_SnapshotBusCb( GstBus *bus, GstMessage *message, gpointer data )
       
   580 {
       
   581     XAMediaRecorderAdaptationCtx* mCtx = (XAMediaRecorderAdaptationCtx*)data;
       
   582 
       
   583     GstState oldstate = GST_STATE_NULL , newstate = GST_STATE_NULL , pendingstate = GST_STATE_NULL;
       
   584 
       
   585     /* only interested in messages from snapshot pipeline */
       
   586     if( GST_MESSAGE_SRC(message) == GST_OBJECT(mCtx->snapshotVars.sspipeline) )
       
   587     {
       
   588         DEBUG_API_A2("->XASnapshotItfAdaptation_SnapshotBusCb:\"%s\" from object \"%s\"",
       
   589                 GST_MESSAGE_TYPE_NAME(message), GST_OBJECT_NAME(GST_MESSAGE_SRC(message)));
       
   590 
       
   591         switch( GST_MESSAGE_TYPE(message))
       
   592         {
       
   593             case GST_MESSAGE_EOS:
       
   594             {
       
   595                 if( gst_element_set_state(GST_ELEMENT(mCtx->snapshotVars.sspipeline), GST_STATE_READY)
       
   596                         == GST_STATE_CHANGE_FAILURE )
       
   597                 {
       
   598                     DEBUG_ERR("Error stopping snapshot pipeline!!!");
       
   599                 }
       
   600                 gst_element_get_state(mCtx->snapshotVars.sspipeline, NULL, NULL, XA_ADAPT_ASYNC_TIMEOUT_SHORT_NSEC);
       
   601 
       
   602                 DEBUG_INFO_A2("Requested %lu snapshots, taked %lu",mCtx->snapshotVars.numpics,mCtx->snapshotVars.numpicstaken+1);
       
   603                 if( ++mCtx->snapshotVars.numpicstaken >= mCtx->snapshotVars.numpics )
       
   604                 {
       
   605                     XAAdaptEvent takenevent = {XA_SNAPSHOTITFEVENTS, XA_ADAPT_SNAPSHOT_TAKEN, 0, NULL };
       
   606                     DEBUG_INFO("Snapshot burst finished");
       
   607                     XASnapshotItfAdaptation_StopSnapshotting(&(mCtx->baseObj));
       
   608                     if( mCtx->snapshotVars.fnametemplate == NULL )
       
   609                     {   /* non-datasink snapshot, return buffer */
       
   610                         GstBuffer* pullBuffer = NULL;
       
   611                         XADataSink* pullSink = NULL;
       
   612                         XADataLocator_Address* pullSinkLoc = NULL;
       
   613                         DEBUG_INFO("Get buffer from appsink");
       
   614                         pullBuffer = gst_app_sink_pull_preroll( GST_APP_SINK(mCtx->snapshotVars.sssink) );
       
   615                         /* allocate XADataSink, client should release this later*/
       
   616                         pullSink = calloc(1, sizeof(XADataSink));
       
   617                         pullSinkLoc = calloc(1, sizeof(XADataLocator_Address));
       
   618                         pullSinkLoc->length = pullBuffer->size;
       
   619                         pullSinkLoc->pAddress = calloc(1, pullBuffer->size);
       
   620                         memcpy(pullSinkLoc->pAddress, pullBuffer->data, pullBuffer->size);
       
   621                         pullSinkLoc->locatorType = XA_DATALOCATOR_ADDRESS;
       
   622                         pullSink->pLocator = pullSinkLoc;
       
   623                         pullSink->pFormat = NULL;
       
   624                         takenevent.data = pullSink;
       
   625                     }
       
   626                     /* send needed events */
       
   627                     takenevent.datasize = mCtx->snapshotVars.numpicstaken;
       
   628                     XAAdaptationBase_SendAdaptEvents(&(mCtx->baseObj), &takenevent );
       
   629                 }
       
   630                 else
       
   631                 {
       
   632                     /* videoparse element can not handle renegotiation of stream for new buffer
       
   633                      * after EOS, so recreate it */
       
   634                     gst_element_unlink_many(
       
   635                             mCtx->snapshotVars.ssbuffersrc,
       
   636                             mCtx->snapshotVars.ssparser,
       
   637                             mCtx->snapshotVars.ssscaler,
       
   638                             NULL);
       
   639                     gst_element_set_state(GST_ELEMENT(mCtx->snapshotVars.ssparser), GST_STATE_NULL);
       
   640                     gst_bin_remove(GST_BIN (mCtx->snapshotVars.sspipeline),mCtx->snapshotVars.ssparser);
       
   641                     mCtx->snapshotVars.ssparser = gst_element_factory_make("videoparse", "ssparser");
       
   642                     if( !mCtx->snapshotVars.ssparser )
       
   643                     {
       
   644                         DEBUG_ERR("Cannot create ssparser!");
       
   645                         DEBUG_API("<-XASnapshotItfAdaptation_CreateSnapshotPipeline - XA_RESULT_INTERNAL_ERROR");
       
   646                         return XA_RESULT_INTERNAL_ERROR;
       
   647                     }
       
   648                     gst_bin_add(GST_BIN (mCtx->snapshotVars.sspipeline),mCtx->snapshotVars.ssparser);
       
   649                     if( !gst_element_link_many(
       
   650                             mCtx->snapshotVars.ssbuffersrc,
       
   651                             mCtx->snapshotVars.ssparser,
       
   652                             mCtx->snapshotVars.ssscaler,
       
   653                             NULL) )
       
   654                     {
       
   655                         DEBUG_ERR("Could not link pipeline")
       
   656                         return XA_RESULT_INTERNAL_ERROR;
       
   657                     }
       
   658                     mCtx->snapshotVars.parsenegotiated = FALSE;
       
   659 
       
   660                     /*now, wait for new buffer to arrive*/
       
   661                     DEBUG_INFO("Wait for more pictures");
       
   662                     mCtx->snapshotVars.waitforbuffer = TRUE;
       
   663                     mCtx->snapshotVars.sighandler = g_signal_connect(mCtx->videoextract, "handoff",
       
   664                                             G_CALLBACK (XASnapshotItfAdaptation_BufferHandoffCb),mCtx);
       
   665                 }
       
   666                 break;
       
   667             }
       
   668             case GST_MESSAGE_STATE_CHANGED:
       
   669             {
       
   670                 gst_message_parse_state_changed(message, &oldstate, &newstate, &pendingstate);
       
   671                 DEBUG_INFO_A4("old %s -> new %s ( pending %s, gsttarget %s )",
       
   672                         gst_element_state_get_name(oldstate),
       
   673                         gst_element_state_get_name(newstate),
       
   674                         gst_element_state_get_name(pendingstate),
       
   675                         gst_element_state_get_name(GST_STATE_TARGET(mCtx->snapshotVars.sspipeline)) );
       
   676                 if( newstate==GST_STATE_READY && oldstate==GST_STATE_NULL )
       
   677                 {
       
   678                     XAAdaptEvent initevent = {XA_SNAPSHOTITFEVENTS, XA_ADAPT_SNAPSHOT_INITIATED,0, NULL };
       
   679                     DEBUG_INFO("Init complete");
       
   680                     /* send needed events */
       
   681                     XAAdaptationBase_SendAdaptEvents( &(mCtx->baseObj), &initevent);
       
   682                 }
       
   683                 else if( newstate==GST_STATE_PLAYING && oldstate==GST_STATE_PAUSED && mCtx->snapshotVars.snapshotbuffer )
       
   684                 {
       
   685                     DEBUG_INFO("Pushing buffer");
       
   686                     gst_app_src_push_buffer( GST_APP_SRC(mCtx->snapshotVars.ssbuffersrc),
       
   687                                              mCtx->snapshotVars.snapshotbuffer );
       
   688                     DEBUG_INFO_A1("Sent buffer at 0x%x to  ssbuffersrc", (int)mCtx->snapshotVars.snapshotbuffer );
       
   689                     gst_app_src_end_of_stream( GST_APP_SRC(mCtx->snapshotVars.ssbuffersrc) );
       
   690                     mCtx->snapshotVars.snapshotbuffer = NULL;
       
   691                     DEBUG_INFO("Sent EOS ssbuffersrc");
       
   692                 }
       
   693 
       
   694                 break;
       
   695             }
       
   696             default:
       
   697                 break;
       
   698         }
       
   699         DEBUG_API("<-XASnapshotItfAdaptation_SnapshotBusCb");
       
   700     }
       
   701     return TRUE;
       
   702 }
       
   703 
       
   704 /*
       
   705  * void XASnapshotItfAdaptation_BufferHandoffCb( GstElement *extract, GstBuffer  *buffer, gpointer data )
       
   706  */
       
   707 void XASnapshotItfAdaptation_BufferHandoffCb( GstElement *extract, GstBuffer  *buffer, gpointer data )
       
   708 {
       
   709     XAMediaRecorderAdaptationCtx* mCtx = (XAMediaRecorderAdaptationCtx*)data;
       
   710     gint32 width=0, height=0;
       
   711     guint32  fourcc=0, formatnum=0;
       
   712     GstPad* srcPad=NULL;
       
   713     GstCaps* srcPadCaps=NULL;
       
   714     GstStructure* capS=NULL;
       
   715     XAAdaptEvent event = {XA_SNAPSHOTITFEVENTS, XA_ADAPT_SNAPSHOT_TAKEN, 0, NULL };
       
   716     char* fname=NULL;
       
   717 
       
   718     DEBUG_API("->XASnapshotItfAdaptation_BufferHandoffCb");
       
   719     if( !mCtx->snapshotVars.waitforbuffer ||
       
   720         !GST_IS_BUFFER(buffer) )
       
   721     {   /* pass on... */
       
   722         DEBUG_API("<-XASnapshotItfAdaptation_BufferHandoffCb");
       
   723         return;
       
   724     }
       
   725 
       
   726     if(mCtx->snapshotVars.snapshotbuffer)
       
   727     {
       
   728         DEBUG_INFO("WARNING: snapshotbuffer already exists!!");
       
   729         gst_buffer_unref(GST_BUFFER(mCtx->snapshotVars.snapshotbuffer));
       
   730     }
       
   731     DEBUG_INFO("Receiced snapshotbuffer");
       
   732     mCtx->snapshotVars.snapshotbuffer = gst_buffer_copy(buffer);
       
   733     mCtx->snapshotVars.waitforbuffer = FALSE;
       
   734     g_signal_handler_disconnect(mCtx->videoextract,mCtx->snapshotVars.sighandler);
       
   735     mCtx->snapshotVars.sighandler = 0;
       
   736 
       
   737     if( GST_STATE(mCtx->snapshotVars.sspipeline)==GST_STATE_READY )
       
   738     {
       
   739         if( !(mCtx->snapshotVars.parsenegotiated) )
       
   740         {
       
   741             /*read relevant caps of extraction source and set them to videoparse*/
       
   742             srcPad = gst_element_get_pad( GST_ELEMENT(extract), "src");
       
   743             srcPadCaps = gst_pad_get_negotiated_caps( GST_PAD(srcPad) );
       
   744             capS = gst_caps_get_structure(srcPadCaps,0);
       
   745             DEBUG_INFO_A1("buffer caps from extraction source: %s",gst_caps_to_string(srcPadCaps));
       
   746             if( !gst_structure_get_int(capS,"width",&width) ||
       
   747                 !gst_structure_get_int(capS,"height",&height) ||
       
   748                 !gst_structure_get_fourcc(capS,"format",&fourcc) )
       
   749             {
       
   750                 DEBUG_ERR("ERROR! Missing crucial capabilities for buffer!!");
       
   751                 DEBUG_API("<-XASnapshotItfAdaptation_BufferHandoffCb");
       
   752                 return;
       
   753             }
       
   754             /* convert fourcc to videoparse enumeration */
       
   755             switch(fourcc)
       
   756             {
       
   757                 case GST_MAKE_FOURCC('I','4','2','0'):
       
   758                     formatnum = 0;
       
   759                     break;
       
   760                 case GST_MAKE_FOURCC('Y','V','1','2'):
       
   761                     formatnum = 1;
       
   762                     break;
       
   763                 case GST_MAKE_FOURCC('Y','U','Y','2'):
       
   764                     formatnum = 2;
       
   765                     break;
       
   766                 case GST_MAKE_FOURCC('U','Y','V','Y'):
       
   767                     formatnum = 3;
       
   768                     break;
       
   769                 case GST_MAKE_FOURCC('R','G','B',' '):
       
   770                     formatnum = 10;
       
   771                     break;
       
   772                 case GST_MAKE_FOURCC('G','R','A','Y'):
       
   773                     formatnum = 11;
       
   774                     break;
       
   775                 default:
       
   776                     formatnum = 0;
       
   777                     break;
       
   778             }
       
   779             /* set source width and height for parser */
       
   780             g_object_set(mCtx->snapshotVars.ssparser,"width",width,"height",height,"format",formatnum,NULL);
       
   781             mCtx->snapshotVars.parsenegotiated = TRUE;
       
   782         }
       
   783         if(mCtx->snapshotVars.fnametemplate)
       
   784         {   /* get actual filename from template */
       
   785             XASnapshotItfAdaptation_AllocNextFilename(&fname, mCtx->snapshotVars.fnametemplate);
       
   786             DEBUG_INFO_A1("start taking snapshot (%s)", fname);
       
   787             gst_element_set_state(GST_ELEMENT(mCtx->snapshotVars.sssink), GST_STATE_NULL);
       
   788             g_object_set( G_OBJECT(mCtx->snapshotVars.sssink), "location", fname,
       
   789                                                                 "async", FALSE,
       
   790                                                                 "qos", FALSE,
       
   791                                                                 "max-lateness", (gint64)(-1),
       
   792                                                                 NULL );
       
   793             gst_element_sync_state_with_parent(mCtx->snapshotVars.sssink);
       
   794             gst_element_get_state(mCtx->snapshotVars.sssink, NULL, NULL, XA_ADAPT_ASYNC_TIMEOUT_SHORT_NSEC);
       
   795             free(fname);
       
   796         }
       
   797         else
       
   798         {   /* take snapshot to buffer */
       
   799             DEBUG_INFO("start taking snapshot (memory buffer used)");
       
   800         }
       
   801         /* write metadata, if any */
       
   802         XAMetadataAdapt_TryWriteTags(&(mCtx->baseObj), GST_BIN(mCtx->snapshotVars.sspipeline));
       
   803         /* start buffering */
       
   804         if( gst_element_set_state(GST_ELEMENT(mCtx->snapshotVars.sspipeline), GST_STATE_PLAYING )
       
   805                 == GST_STATE_CHANGE_FAILURE )
       
   806         {
       
   807             DEBUG_ERR("Error taking picture!!!");
       
   808             /* NOTE: no event for errors in snapshotitf!!! */
       
   809             event.datasize = mCtx->snapshotVars.numpicstaken;
       
   810             XAAdaptationBase_SendAdaptEvents(&(mCtx->baseObj), &event );
       
   811         }
       
   812     }
       
   813     else
       
   814     {
       
   815         DEBUG_INFO_A1("warning: sspipeline in wrong state (%d)",
       
   816                         GST_STATE(mCtx->snapshotVars.sspipeline));
       
   817     }
       
   818     DEBUG_API("<-XASnapshotItfAdaptation_BufferHandoffCb");
       
   819 }
       
   820 
       
   821 /*
       
   822  * const char* XASnapshotItfAdaptation_GetFileSuffix(XADataFormat_MIME* format)
       
   823  */
       
   824 const char* XASnapshotItfAdaptation_GetFileSuffix(XADataFormat_MIME* format)
       
   825 {
       
   826     const char* ret=NULL;
       
   827     if( format )
       
   828     {
       
   829         if( *(XAuint32*)format == XA_DATAFORMAT_MIME )
       
   830         {
       
   831             switch (format->containerType)
       
   832             {
       
   833                 case XA_CONTAINERTYPE_JPG:
       
   834                     ret = "jpg";
       
   835                     break;
       
   836                 case XA_CONTAINERTYPE_RAW:
       
   837                     ret = "raw";
       
   838                     break;
       
   839                 case XA_CONTAINERTYPE_BMP:
       
   840                     ret = "bmp";
       
   841                     break;
       
   842                 default:
       
   843                     break;
       
   844             }
       
   845             if(!ret)
       
   846             { /*parse from mimetype*/
       
   847                 if(format->mimeType)
       
   848                 {
       
   849                     ret = strrchr((char*)format->mimeType,'/');
       
   850                     if (ret)
       
   851                     {
       
   852                         ret++;
       
   853                     }
       
   854                 }
       
   855             }
       
   856         }
       
   857         else if( *(XAuint32*)format == XA_DATAFORMAT_RAWIMAGE )
       
   858         {
       
   859             ret = "raw";
       
   860         }
       
   861     }
       
   862     if(!ret)
       
   863     {
       
   864         ret="jpg"; /*default*/
       
   865     }
       
   866     return ret;
       
   867 }
       
   868 
       
   869 /*
       
   870  * void XASnapshotItfAdaptation_AllocNextFilename(char** fname, const char* template)
       
   871  */
       
   872 void XASnapshotItfAdaptation_AllocNextFilename(char** fname, const char* template)
       
   873 {
       
   874     XAuint32 idx=0;
       
   875     XAboolean found=XA_BOOLEAN_FALSE;
       
   876     FILE* file=NULL;
       
   877     *fname = calloc(1,strlen(template)+10);
       
   878     while(!found)
       
   879     {
       
   880         sprintf(*fname, template, idx++ );
       
   881         strcat(*fname, "\0");
       
   882         file = fopen(*fname, "r");
       
   883         if(file==NULL)
       
   884         {
       
   885             found = XA_BOOLEAN_TRUE;
       
   886             break;
       
   887         }
       
   888         fclose(file);
       
   889     }
       
   890 }