diff -r 80975da52420 -r 43d09473c595 khronosfws/openmax_al/src/gst_adaptation/xamediaplayeradaptctx.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/khronosfws/openmax_al/src/gst_adaptation/xamediaplayeradaptctx.c Fri May 14 16:22:35 2010 +0300 @@ -0,0 +1,1114 @@ +/* +* 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 +#include +#include +#include +#include "xamediaplayeradaptctx.h" +#include "xamediaplayeradaptctxmmf.h" +#include "xaadaptationgst.h" +#include "xaobjectitf.h" +#include "xacameradevice.h" +#include "xaoutputmix.h" +#include "xametadataadaptation.h" +/*#include "xangavideosink.h"*/ +#include "xacameraadaptctx.h" +#include "xaoutputmixadaptctx.h" + +/* forward declarations */ +XAresult XAMediaPlayerAdapt_CreatePipeline( XAMediaPlayerAdaptationCtx* ctx ); + +void* ngaVideoSinkPtr = NULL; + + +extern XAboolean cameraRealized; +extern XACameraAdaptationCtx_* cameraCtx; + +/* + * static void XAMediaPlayerAdapt_NewPadCb (GstElement *element, GstPad *pad, gpointer data) + * Listen to codec bin dynamic pads + */ +static void XAMediaPlayerAdapt_NewPadCb (GstElement *element, GstPad *pad, gpointer data) +{ + XAMediaPlayerAdaptationCtx* mCtx = (XAMediaPlayerAdaptationCtx*)data; + gchar *name = gst_pad_get_name (pad); + DEBUG_API_A1("->XAMediaPlayerAdapt_NewPadCb: A new pad %s was created", name); + /*try first newly created pad to video pipe*/ + if( mCtx->videoppbin && !(gst_pad_is_linked(gst_element_get_static_pad(mCtx->videoppbin, "videopp_sink"))) ) + { + if(gst_element_link_pads (mCtx->codecbin, name, mCtx->videoppbin, "videopp_sink")) + { + DEBUG_INFO_A1("Pads linked, codecbin:%s to videopp:sink", name); + g_free (name); + DEBUG_API("<-XAMediaPlayerAdapt_NewPadCb"); + return; + } + } + /*..and then to audio pipe*/ + if( mCtx->audioppbin && !(gst_pad_is_linked(gst_element_get_static_pad(mCtx->audioppbin, "sink"))) ) + { + if(gst_element_link_pads (mCtx->codecbin, name, mCtx->audioppbin, "sink")) + { + DEBUG_INFO_A1("Pads linked, codecbin:%s to audiopp:sink", name); + g_free (name); + DEBUG_API("<-XAMediaPlayerAdapt_NewPadCb"); + return; + } + } + + g_free (name); + DEBUG_INFO("Warning: Could not find anything to link to new pad."); + DEBUG_API("<-XAMediaPlayerAdapt_NewPadCb"); +} + +/* + * void push_data_for_prerolling (GstElement * pipeline, GstBuffer *buffer, XAMediaPlayerAdaptationCtx* ctx) + * Called when "push-buffer" signal is emitted + */ +void push_data_for_prerolling (GstElement * pipeline, GstBuffer *buffer, XAMediaPlayerAdaptationCtx* ctx) +{ + DEBUG_API("->push_data_for_prerolling"); + gst_app_src_push_buffer( GST_APP_SRC(ctx->source), GST_BUFFER(buffer) ); + /*GstPad* prerollPad = NULL; + prerollPad = gst_element_get_static_pad(GST_ELEMENT(ctx->source),"src"); + gst_pad_push (prerollPad, buffer); + gst_element_send_event(GST_ELEMENT(ctx->source),gst_event_new_flush_start()); + gst_element_send_event(GST_ELEMENT(ctx->source),gst_event_new_flush_stop());*/ + DEBUG_API("<-push_data_for_prerolling"); +} + + +/* + * gboolean XAMediaPlayerAdapt_GstBusCb( GstBus *bus, GstMessage *message, gpointer data ) + * MediaPlayer Gst-bus message handler (Callback) + */ +gboolean XAMediaPlayerAdapt_GstBusCb( GstBus *bus, GstMessage *message, gpointer data ) +{ + XAAdaptationGstCtx* bCtx = (XAAdaptationGstCtx*)data; + /* only listen to bin messages */ + if(GST_MESSAGE_SRC(message)==(GstObject*)(bCtx->bin)) + { + XAMediaPlayerAdaptationCtx* mCtx = (XAMediaPlayerAdaptationCtx*)data; + DEBUG_API_A2("->XAMediaPlayerAdapt_GstBusCb:\"%s\" from object \"%s\"", + GST_MESSAGE_TYPE_NAME(message), GST_OBJECT_NAME(GST_MESSAGE_SRC(message))); + + switch( GST_MESSAGE_TYPE(message)) + { + case GST_MESSAGE_EOS: + { + if( mCtx && mCtx->loopingenabled && mCtx->loopend == GST_CLOCK_TIME_NONE) + { + DEBUG_INFO_A2("Restart loop from %"GST_TIME_FORMAT" to %"GST_TIME_FORMAT, + GST_TIME_ARGS(mCtx->loopstart), GST_TIME_ARGS(mCtx->loopend)); + gst_element_seek( bCtx->bin, mCtx->playrate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH|GST_SEEK_FLAG_ACCURATE), + GST_SEEK_TYPE_SET, mCtx->loopstart, + GST_SEEK_TYPE_NONE, (gint64)GST_CLOCK_TIME_NONE ); + gst_element_get_state(bCtx->bin,NULL,NULL,XA_ADAPT_ASYNC_TIMEOUT_SHORT_NSEC); + mCtx->lastpos = mCtx->loopstart; + if( mCtx && mCtx->trackpositionenabled ) + { + XAmillisecond posMsec = GST_TIME_AS_MSECONDS(mCtx->lastpos);/*Warning ok due to used API specification*/ + XAAdaptEvent event = {XA_PLAYITFEVENTS, XA_ADAPT_POSITION_UPDATE_EVT, 1, NULL}; + event.data = &posMsec; + XAAdaptationBase_SendAdaptEvents(&bCtx->baseObj, &event ); + } + } + else + { + /* stop position tracking */ + if(mCtx->runpositiontimer > 0) + { + g_source_remove(mCtx->runpositiontimer); + mCtx->runpositiontimer=0; + } + + /* complete any ongoing client async operations */ + XAAdaptationGst_CompleteAsyncWait(bCtx); + + /* send needed events */ + { + XAMediaType mediatype; +/* + if( mCtx->baseObj.pipeSrcThrCtx.pipe ) + { + XACommon_CheckDataSource((XADataSource*)mCtx->xaAudioSink, &mediatype); + } + else +*/ + { + XACommon_CheckDataSource(mCtx->xaSource, &mediatype); + } + if(mediatype!=XA_MEDIATYPE_IMAGE) + { + XAAdaptEvent event = { XA_PLAYITFEVENTS, XA_PLAYEVENT_HEADATEND, 0, NULL }; + XAAdaptationBase_SendAdaptEvents(&bCtx->baseObj, &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 %s -> new %s ( pending %s, gsttarget %s )", + gst_element_state_get_name(oldstate), + gst_element_state_get_name(newstate), + gst_element_state_get_name(pendingstate), + gst_element_state_get_name(gsttargetstate) ); + if(gsttargetstate!=bCtx->binWantedState) + { + DEBUG_ERR_A1("WARNING: Gst target is not wanted target [%s]!!!", + gst_element_state_get_name(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 %s, target %s)", + gst_element_state_get_name(newstate), + gst_element_state_get_name(bCtx->binWantedState)); + break; // TL: add to avoid extra event sent below in this case... + } + else + { + DEBUG_INFO_A1("Gst in wanted target state (%s)", + gst_element_state_get_name(newstate)); + } + } + if( oldstate!=GST_STATE_PLAYING && newstate==GST_STATE_PLAYING ) + { + /* send needed events */ + XAAdaptEvent event = {XA_PLAYITFEVENTS, XA_PLAYEVENT_HEADMOVING, 0, NULL }; + XAAdaptationBase_SendAdaptEvents(&bCtx->baseObj, &event ); + /* enable position tracking if needed */ + XAMediaPlayerAdapt_UpdatePositionCbTimer(mCtx); + } + if ( oldstate== GST_STATE_READY && newstate==GST_STATE_PAUSED) + { +/* if ( mCtx->baseObj.pipeSinkThrCtx.dataHandle ) + { + mCtx->baseObj.pipeSrcThrCtx.state = CPStateInitialized; + }*/ + } + break; + } + + case GST_MESSAGE_ASYNC_DONE: + { + /* some async sequence ended */ + XAAdaptationGst_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 */ + XAAdaptationGst_CompleteAsyncWait(bCtx); + break; + } + case GST_MESSAGE_BUFFERING: + { + gint percent; + gst_message_parse_buffering(message, &percent); + DEBUG_INFO_A1("Gst message buffering %d", percent); + mCtx->buffering = percent; + { + XAAdaptEvent event = {XA_PREFETCHITFEVENTS, XA_ADAPT_BUFFERING, 1, NULL }; + event.data = &mCtx->buffering; + XAAdaptationBase_SendAdaptEvents(&bCtx->baseObj, &event ); + } + break; + } + case GST_MESSAGE_ELEMENT: + { + DEBUG_INFO("GST_MESSAGE_ELEMENT"); + if ((gst_structure_has_name(message->structure, "graphics-surface-created")) || + (gst_structure_has_name(message->structure, "graphics-surface-updated"))) + { + DEBUG_INFO("graphics-surface-created message recived"); + } + break; + } + default: + break; + } + } + else //if (GST_MESSAGE_SRC(message)==(GstObject*)(bCtx->videosink)) + { + switch( GST_MESSAGE_TYPE(message)) + { + case GST_MESSAGE_ELEMENT: + { + DEBUG_INFO("GST_MESSAGE_ELEMENT"); + if ((gst_structure_has_name(message->structure, "graphics-surface-created")) || + (gst_structure_has_name(message->structure, "graphics-surface-updated"))) + { + guint32 surfaceid0, surfaceid1, surfaceid2, surfaceid3; + gint crop_rect_tl_x, crop_rect_tl_y, crop_rect_br_x, crop_rect_br_y; + gint aspect_ratio_num, aspect_ratio_denom; + + GstObject *sink= GST_MESSAGE_SRC(message); + + g_object_get(sink, "surfaceid0", &surfaceid0, NULL); + g_object_get(sink, "surfaceid1", &surfaceid1,NULL); + g_object_get(sink, "surfaceid2", &surfaceid2,NULL); + g_object_get(sink, "surfaceid3", &surfaceid3,NULL); + g_object_get(sink, "croprect_tl_x", &crop_rect_tl_x, NULL); + g_object_get(sink, "croprect_tl_y", &crop_rect_tl_y, NULL); + g_object_get(sink, "croprect_br_x", &crop_rect_br_x, NULL); + g_object_get(sink, "croprect_br_y", &crop_rect_br_y, NULL); + g_object_get(sink, "aspectratio_num", &aspect_ratio_num, NULL); + g_object_get(sink, "aspectratio_denom", &aspect_ratio_denom, NULL); +/* + surface_created(ngaVideoSinkPtr, surfaceid0,surfaceid1,surfaceid2,surfaceid3,crop_rect_tl_x, + crop_rect_tl_y,crop_rect_br_x,crop_rect_br_y,aspect_ratio_num,aspect_ratio_denom); +*/ + } + break; + } + default: + break; + } + } + DEBUG_API("<-XAMediaPlayerAdapt_GstBusCb"); + return TRUE; +} + +/* + * XAMediaPlayerAdaptationCtx* XAMediaPlayerAdapt_Create() + * Allocates memory for Media Player Adaptation Context and makes 1st phase initialization + * @param XADataSource *pDataSrc - pointer to OMX-AL data source + * @param XADataSource *pBankSrc - pointer to instrument bank structure in Mobile DLS, if NULL default will be used. + * @param XADataSink *pAudioSnk - pointer to OMX-AL audio sink definition + * @param XADataSink *pImageVideoSnk - pointer to OMX-AL image and video sink definition + * @returns XAMediaPlayerAdaptationCtx* - Pointer to created context, NULL if error occurs. + */ +XAAdaptationBaseCtx* XAMediaPlayerAdapt_Create(XADataSource *pDataSrc, XADataSource *pBankSrc, + XADataSink *pAudioSnk, XADataSink *pImageVideoSnk, + XADataSink *pVibra, XADataSink *pLEDArray) +{ + XAMediaPlayerAdaptationCtx *pSelf = NULL; + XAuint32 locType = 0; + XADataLocator_IODevice *ioDevice; + + DEBUG_API("->XAMediaPlayerAdapt_Create"); + + //Create NGA Video Sink class +/* if(pImageVideoSnk) + { + ngaVideoSinkPtr = nga_video_sink_init(); + }*/ + + pSelf = calloc(1, sizeof(XAMediaPlayerAdaptationCtx)); + if ( pSelf) + { + if( XAAdaptationBase_Init(&(pSelf->baseObj.baseObj),XAMediaPlayerAdaptation) + != XA_RESULT_SUCCESS ) + { + DEBUG_ERR("Failed to init base context!!!"); + free(pSelf); + pSelf = NULL; + return NULL; + } + else + { + pSelf->xaSource = pDataSrc; + pSelf->xaBankSrc = pBankSrc; + pSelf->xaAudioSink = pAudioSnk; + pSelf->xaVideoSink = pImageVideoSnk; + pSelf->xaLEDArray = pLEDArray; + pSelf->xaVibra = pVibra; + pSelf->loopstart = 0; + pSelf->loopend = (gint64)GST_CLOCK_TIME_NONE; + pSelf->playrate = 1.0; + pSelf->rateprops = (XA_RATEPROP_SMOOTHVIDEO | XA_RATEPROP_SILENTAUDIO); + pSelf->curMirror = XA_VIDEOMIRROR_NONE; + pSelf->curRotation = 0; + pSelf->isobjsrc = XA_BOOLEAN_FALSE; + pSelf->cameraSinkSynced = XA_BOOLEAN_FALSE; +/* if(pImageVideoSnk && ngaVideoSinkPtr) + { + setup_native_display(ngaVideoSinkPtr, pImageVideoSnk); + }*/ + } + + if ( pDataSrc ) + { + locType = *((XAuint32*)(pDataSrc->pLocator)); + if ( locType == XA_DATALOCATOR_IODEVICE ) + { + ioDevice = (XADataLocator_IODevice*)(pDataSrc->pLocator); + if ( ioDevice->deviceType == XA_IODEVICE_CAMERA && !cameraRealized ) + { + DEBUG_ERR("Preconditions violated - Camera object not realized"); + XAAdaptationBase_Free(&pSelf->baseObj.baseObj); + free(pSelf); + pSelf = NULL; + } + } + } + } + + DEBUG_API("<-XAMediaPlayerAdapt_Create"); + return (XAAdaptationBaseCtx*)(&pSelf->baseObj); +} + + + +/* + * XAresult XAMediaPlayerAdapt_PostInit() + * 2nd phase initialization of Media Player Adaptation Context + * @param XAMediaPlayerAdaptationCtx* ctx - pointer to Media Player adaptation context + * @return XAresult - Success value + */ +XAresult XAMediaPlayerAdapt_PostInit( XAAdaptationGstCtx* bCtx ) +{ + XAresult ret = XA_RESULT_SUCCESS; + GstStateChangeReturn gret; + + XAMediaPlayerAdaptationCtx* ctx = NULL; + GstElement *videotest=NULL; + + DEBUG_API("->XAMediaPlayerAdapt_PostInit"); + if(bCtx == NULL || bCtx->baseObj.ctxId != XAMediaPlayerAdaptation ) + { + DEBUG_ERR("Invalid parameter!!"); + DEBUG_API("<-XAMediaPlayerAdapt_PostInit"); + return XA_RESULT_PARAMETER_INVALID; + } + ctx = (XAMediaPlayerAdaptationCtx*)bCtx; + assert(ctx); + ret = XAAdaptationBase_PostInit( &bCtx->baseObj ); + if( ret!=XA_RESULT_SUCCESS ) + { + DEBUG_ERR("Base context postinit failed!!"); + return ret; + } + + /* top level bin for media player */ + ctx->baseObj.bin = gst_pipeline_new("media_player"); + /* Create Gst bus listener. */ + ret = XAAdaptationGst_InitGstListener(bCtx); + if( ret!=XA_RESULT_SUCCESS ) + { + DEBUG_ERR("Bus listener creation failed!!"); + return ret; + } + /* Add Media Player specific handler */ + if(ctx->baseObj.bus) + { + ctx->baseObj.busCb = XAMediaPlayerAdapt_GstBusCb; + gst_bus_add_signal_watch( ctx->baseObj.bus ); + gst_bus_enable_sync_message_emission( ctx->baseObj.bus ); + g_signal_connect(ctx->baseObj.bus, "message::eos", G_CALLBACK(bCtx->busCb), ctx ); + g_signal_connect(ctx->baseObj.bus, "message::error", G_CALLBACK(bCtx->busCb), ctx ); + g_signal_connect(ctx->baseObj.bus, "message::warning", G_CALLBACK(bCtx->busCb), ctx ); + g_signal_connect(ctx->baseObj.bus, "message::state-changed", G_CALLBACK(bCtx->busCb), ctx ); + g_signal_connect(ctx->baseObj.bus, "message::segment-done", G_CALLBACK(bCtx->busCb), ctx ); + g_signal_connect(ctx->baseObj.bus, "message::async-done", G_CALLBACK(bCtx->busCb), ctx ); + g_signal_connect(ctx->baseObj.bus, "message::element", G_CALLBACK(bCtx->busCb), ctx ); + } + else + { + DEBUG_ERR("Failed to create message bus"); + return XA_RESULT_INTERNAL_ERROR; + } + + XAMetadataAdapt_PreInit(bCtx); + + /* create pipeline */ + ret = XAMediaPlayerAdapt_CreatePipeline(ctx); + if ( ret != XA_RESULT_SUCCESS ) + { + DEBUG_ERR("Failed to create Media Player pipeline"); + return ret; + } + +#ifdef XA_IMPL_MEASURE_GST_DELAY + ctx->baseObj.startTime = clock(); +#endif /* XA_IMPL_MEASURE_GST_DELAY */ + /* roll up bin */ + ctx->baseObj.binWantedState = GST_STATE_PAUSED; + + XAAdaptationGst_PrepareAsyncWait(bCtx); + gret = gst_element_set_state( GST_ELEMENT(ctx->baseObj.bin), bCtx->binWantedState); + if( gret == GST_STATE_CHANGE_ASYNC ) + { + DEBUG_INFO("Wait for preroll"); + XAAdaptationGst_StartAsyncWait(bCtx); + DEBUG_INFO("Preroll ready"); + } + else if( gret == GST_STATE_CHANGE_FAILURE ) + { + DEBUG_ERR("Preroll FAILED"); + ret = XA_RESULT_INTERNAL_ERROR; + } + + bCtx->waitingasyncop = XA_BOOLEAN_FALSE; + + gret = gst_element_get_state( GST_ELEMENT(bCtx->bin), NULL, NULL, XA_ADAPT_ASYNC_TIMEOUT_SHORT_NSEC); + if(GST_STATE(bCtx->bin)audioppbin && !(gst_pad_is_linked(gst_element_get_static_pad(ctx->audioppbin, "sink"))) ) + {/*could not find suitable pad for audiopipeline - remove it*/ + DEBUG_INFO("Warning! No suitable decodebin pad for audio pipeline!"); + gst_element_set_state( GST_ELEMENT(ctx->audioppbin), GST_STATE_NULL); + gst_bin_remove(GST_BIN(bCtx->bin), ctx->audioppbin); + gst_element_set_state( GST_ELEMENT(ctx->audiosink), GST_STATE_NULL); + gst_bin_remove(GST_BIN(bCtx->bin), ctx->audiosink); + } + else if( ctx->videoppbin && !(gst_pad_is_linked(gst_element_get_static_pad(ctx->videoppbin, "videopp_sink"))) ) + {/*could not find suitable pad for videopipeline - remove it*/ + DEBUG_INFO("Warning! No suitable decodebin pad for video pipeline!"); + gst_element_set_state( GST_ELEMENT(ctx->videoppbin), GST_STATE_NULL); + gst_bin_remove(GST_BIN(bCtx->bin), ctx->videoppbin); + gst_element_set_state( GST_ELEMENT(ctx->videosink), GST_STATE_NULL); + gst_bin_remove(GST_BIN(bCtx->bin), ctx->videosink); + } + gst_element_set_state( GST_ELEMENT(bCtx->bin), bCtx->binWantedState); + gst_element_get_state( GST_ELEMENT(bCtx->bin), NULL, NULL, XA_ADAPT_ASYNC_TIMEOUT_SHORT_NSEC); + if(GST_STATE(bCtx->bin)==GST_STATE_PAUSED) + { + DEBUG_INFO("Retry preroll successful!") + ret = XA_RESULT_SUCCESS; + } + } + else + { + DEBUG_INFO("Preroll ready"); + } + +#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 */ + videotest = gst_bin_get_by_name(GST_BIN(bCtx->bin), "videotest"); + if ( videotest && !ctx->isobjsrc ) + { + gst_element_set_state( GST_ELEMENT(videotest),GST_STATE_PLAYING); + } + + XAMetadataAdapt_PostInit(bCtx); + + if ( videotest ) + { + gst_object_unref(videotest); + } + + DEBUG_API("<-XAMediaPlayerAdapt_PostInit"); + return ret; +} + +/* + * void XAMediaPlayerAdapt_Destroy( XAMediaPlayerAdaptationCtx* ctx ) + * Destroys Media Player Adaptation Context + * @param ctx - Media Player Adaptation context to be destroyed + */ +void XAMediaPlayerAdapt_Destroy( XAAdaptationGstCtx* bCtx ) +{ + XAMediaPlayerAdaptationCtx* ctx = NULL; + + DEBUG_API("->XAMediaPlayerAdapt_Destroy"); + if(bCtx == NULL || bCtx->baseObj.ctxId != XAMediaPlayerAdaptation ) + { + DEBUG_ERR("Invalid parameter!!"); + DEBUG_API("<-XAMediaPlayerAdapt_Destroy"); + return; + } + ctx = (XAMediaPlayerAdaptationCtx*)bCtx; + + if( ctx->isobjsrc ) + { /* external source, unlink and remove now */ + /*gst_object_unparent( GST_OBJECT(ctx->source) );*/ + gst_element_unlink( ctx->source, ctx->codecbin ); + /*gst_bin_remove( GST_BIN(bCtx->bin), ctx->source );*/ + GST_OBJECT_FLAG_SET(GST_OBJECT(ctx->source),GST_OBJECT_FLOATING); + } +#if 0 + if ( ctx->xaSource ) + { + XAuint32 locType = *(XAuint32*)(ctx->xaSource->pLocator); + switch (locType ) + { + case XA_DATALOCATOR_IODEVICE: + { + XADataLocator_IODevice* ioDevice = (XADataLocator_IODevice*)(ctx->xaSource->pLocator); + if ( ioDevice->deviceType == XA_IODEVICE_RADIO ) + { + gst_object_unparent( GST_OBJECT(ctx->source) ); + gst_element_unlink( ctx->source, ctx->codecbin ); + gst_bin_remove( GST_BIN(bCtx->bin), ctx->source ); + GST_OBJECT_FLAG_SET(GST_OBJECT(ctx->source),GST_OBJECT_FLOATING); + } + } + default: + break; + } + } +#endif + + if( ctx->isobjasink && ctx->xaAudioSink && ctx->xaAudioSink->pLocator ) + { + XAuint32 locType = *(XAuint32*)(ctx->xaAudioSink->pLocator); + switch ( locType ) + { + case XA_DATALOCATOR_OUTPUTMIX: + { + XADataLocator_OutputMix* omix = (XADataLocator_OutputMix*)(ctx->xaAudioSink->pLocator); + XAOMixImpl* omixDevice = (XAOMixImpl*)(*omix->outputMix); + if(omixDevice) + { + XAOutputMixAdapt_DisconnectObject((XAAdaptationGstCtx*)omixDevice->adaptationCtx, bCtx); + } + break; + } + default: + /* Vibra and LED need no handling */ + break; + } + + } + + if( bCtx->bus ) + { + gst_bus_remove_signal_watch( bCtx->bus ); + gst_bus_disable_sync_message_emission ( bCtx->bus ); + } + XAAdaptationGst_CancelAsyncWait(bCtx); + + if( ctx->runpositiontimer ) + { + g_source_remove(ctx->runpositiontimer); + } + XAMetadataAdapt_FreeVars(ctx->metadatavars); + XAAdaptationBase_Free( &bCtx->baseObj ); + free(ctx); + ctx = NULL; + + DEBUG_API("<-XAMediaPlayerAdapt_Destroy"); +} + + +/* + * void XAMediaPlayerAdapt_CreatePipeline( XAMediaPlayerAdaptationCtx* ctx ); + */ +XAresult XAMediaPlayerAdapt_CreatePipeline( XAMediaPlayerAdaptationCtx* ctx ) +{ + XAresult ret = XA_RESULT_SUCCESS; + XAboolean delayedlink = XA_BOOLEAN_FALSE; + XAboolean isPCM = XA_BOOLEAN_FALSE; + XAboolean isRawImage = XA_BOOLEAN_FALSE; + XAMediaType mediatype; + XAuint32 locType = 0; + GstCaps* encSrcCaps = NULL; + DEBUG_API("->XAMediaPlayerAdapt_CreatePipeline"); + + /* create and add data source */ + XACommon_CheckDataSource(ctx->xaSource, &mediatype); + ctx->source = XAAdaptationGst_CreateGstSource( ctx->xaSource, "datasrc", &(ctx->isobjsrc), &isPCM, &isRawImage); + if( !(ctx->source) ) + { + DEBUG_ERR("Could not create data source!!!"); + return XA_RESULT_INTERNAL_ERROR; + } + else + { + if(mediatype != XA_MEDIATYPE_AUDIO) + { + //temporary work around for video + encSrcCaps = gst_caps_new_simple ("video/h263-2000", + "framerate", GST_TYPE_FRACTION, 25, 1, + "pixel-aspect-ratio", GST_TYPE_FRACTION, 16, 9, + "width", G_TYPE_INT, 176, + "height", G_TYPE_INT, 144, + NULL); + g_object_set(G_OBJECT(ctx->source), "caps", encSrcCaps, NULL); + } + + //boolRetVal = gst_bin_add(GST_BIN(pipeline), appsrc); + + + } + + if ( !ctx->isobjsrc ) + { /* Add other than camera source to media player bin */ + DEBUG_INFO("No camera source"); + gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->source); + } + else + { + 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, 30, 1, + NULL); + DEBUG_INFO_A1("new camera encoding filter: %s",gst_caps_to_string(encSrcCaps)); + g_object_set( G_OBJECT(ctx->source), "filter-caps",encSrcCaps,NULL); + gst_caps_unref(encSrcCaps); + } + + /* create and add codec bin */ + if( !(ctx->isobjsrc || isPCM) ) + { + DEBUG_INFO("Create decodebin"); + if(mediatype == XA_MEDIATYPE_AUDIO) + { + ctx->codecbin = gst_element_factory_make( "decodebin" , "mpcodecbin" ); + } + else + { + ctx->codecbin = gst_element_factory_make( "identity" , "mpcodecbin" ); + } + } + else if(ctx->isobjsrc ) + { /* object sources produce framed raw data, decodebin only causes trouble */ //shyward + DEBUG_INFO("Create identity") + ctx->codecbin = gst_element_factory_make( "identity" , "mpcodecbin" ); + } + else if(isPCM) + { /* decodebin does not know how to handle PCM files */ + DEBUG_INFO("Create audioparse") + ctx->codecbin = gst_element_factory_make( "audioparse" , "mpcodecbin" ); + } + else if ( isRawImage) + { /* decodebin does not know how to handle raw unframed video data */ + DEBUG_INFO("Create videoparse") + ctx->codecbin = gst_element_factory_make( "videoparse", "mpcodecbin" ); + } + + if( ctx->codecbin ) + { + gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->codecbin); + if ( !ctx->isobjsrc ) + { + if(mediatype == XA_MEDIATYPE_AUDIO) + { + if( !gst_element_link(ctx->source, ctx->codecbin) ) + { + DEBUG_ERR("Could not link source to decodebin!!"); + return XA_RESULT_INTERNAL_ERROR; + } + } + else + { + if( !gst_element_link_filtered(ctx->source, ctx->codecbin, encSrcCaps ) ) + { + DEBUG_ERR("Could not link source to decodebin!!"); + return XA_RESULT_INTERNAL_ERROR; + } + } + } + else + { /* Link camera source by using ghost-pads, because elements are in different bins */ + + GstPad *cameraBinGhostPad=NULL; + GstPad* ghost=NULL; + GstElement *camTee=NULL; + GstStateChangeReturn gret; + GstPad *mpGhostSink=NULL; + + /* Set external camera source to ready for pipeline manipulation */ + DEBUG_INFO("Set ext-source PAUSED for pipeline manipulation"); + gret = gst_element_set_state( GST_ELEMENT(ctx->source), GST_STATE_READY); + if(gret == GST_STATE_CHANGE_SUCCESS) + { + gret = gst_element_get_state( GST_ELEMENT(ctx->source), 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->source), "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->source, gst_ghost_pad_new("MPObjSrc",cameraBinGhostPad)); + ghost = gst_element_get_static_pad( GST_ELEMENT(ctx->source), "MPObjSrc" ); + 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, XAAdaptationGst_PadBlockCb, NULL); + + + /* Create new ghost-pad to media player pipeline where external camera is connected */ + mpGhostSink = gst_element_get_static_pad( GST_ELEMENT(ctx->codecbin), "sink"); + gst_element_add_pad(ctx->baseObj.bin, gst_ghost_pad_new("MPObjSink",mpGhostSink)); + + if ( !gst_element_link_pads( GST_ELEMENT(ctx->source), "MPObjSrc", + GST_ELEMENT(ctx->baseObj.bin), "MPObjSink") ) + { + DEBUG_ERR("Could not link camera:MPObjSrc to videofilter:MPObjSink"); + return XA_RESULT_INTERNAL_ERROR; + } + + if ( cameraBinGhostPad ) + { + gst_object_unref( cameraBinGhostPad ); + } + if ( ghost ) + { + gst_object_unref( ghost ); + } + if ( mpGhostSink ) + { + gst_object_unref( mpGhostSink ); + } + if ( camTee ) + { + gst_object_unref( camTee ); + } + } + } + else + { + DEBUG_ERR("Could not create decoder bin!!!"); + return XA_RESULT_INTERNAL_ERROR; + } + + /* create and add video stream pipeline */ + if(!ctx->xaLEDArray && !ctx->xaVibra && mediatype!=XA_MEDIATYPE_AUDIO) /*no video for these*/ + { + /* create video processing pipeline */ + ctx->videoppbin = XAAdaptationGst_CreateVideoPP( ); + if( ctx->videoppbin ) + { + gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->videoppbin); + //shyward ---link filtered??? + // boolRetVal = gst_element_link_filtered(appsrc, videosink, caps); + //if(!gst_element_link(ctx->codecbin, ctx->videoppbin)) + if(!gst_element_link_filtered(ctx->codecbin, ctx->videoppbin,encSrcCaps)) + { + /* probably dynamic pads in codecbin */ + DEBUG_INFO("Could not link codec to videopp, trying delayed link"); + delayedlink = XA_BOOLEAN_TRUE; + } + ctx->videoScrSrcPad = gst_element_get_static_pad(ctx->videoppbin, "videopp_src"); + } + else + { + DEBUG_ERR("Could not create video pp bin!!!!"); + return XA_RESULT_INTERNAL_ERROR; + } + //shyward + /* Black screen pipeline not needed under Symbian. May need to revist for acceptance testing + ctx->videoppBScrbin = XAAdaptationBase_CreateVideoPPBlackScr( ); + if( ctx->videoppBScrbin ) + { + gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->videoppBScrbin); + ctx->blackScrSrcPad = gst_element_get_static_pad(ctx->videoppBScrbin, "videoppBSrc_src"); + } + else + { + DEBUG_ERR("Could not create video pp bin for black screen!!!!"); + return XA_RESULT_INTERNAL_ERROR; + } + */ + ctx->inputSelector = XAAdaptationGst_CreateInputSelector( ); + if( ctx->inputSelector ) + { + gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->inputSelector); + ctx->videoScrSinkPad = gst_element_get_request_pad(ctx->inputSelector, "sink%d"); + ctx->blackScrSinkPad = gst_element_get_request_pad(ctx->inputSelector, "sink%d"); + gst_pad_link(ctx->blackScrSrcPad, ctx->blackScrSinkPad); + gst_pad_link(ctx->videoScrSrcPad, ctx->videoScrSinkPad); + } + + //shyward - We have no video filter at this time + /* + ctx->filter = gst_element_factory_make("ffmpegcolorspace", "videofilter"); + gst_bin_add( GST_BIN(ctx->baseObj.bin), ctx->filter); + if ( !gst_element_link( ctx->inputSelector, ctx->filter ) ) + { + DEBUG_ERR("Could not link ctx->filter <-> ctx->inputSelector"); + return XA_RESULT_INTERNAL_ERROR; + } + */ + /* create video pipe sink */ + ctx->videosink = XAAdaptationGst_CreateGstSink( ctx->xaVideoSink, "videosink", &(ctx->isobjvsink) ); + /* NOTE: no valid object sinks for video output available */ + if( ctx->videosink ) + { + gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->videosink); + + //shyward + //if(!gst_element_link(ctx->filter, ctx->videosink)) + if(!gst_element_link_filtered(ctx->videoppbin, ctx->videosink,encSrcCaps)) + { + DEBUG_ERR("Could not link videopp to videosink!!"); + return XA_RESULT_INTERNAL_ERROR; + } + else + { + gst_caps_unref(encSrcCaps); + } + } + else + { + DEBUG_ERR("Could not create video sink!!!!"); + return XA_RESULT_INTERNAL_ERROR; + } + } + else + { + DEBUG_INFO("Media does not contain video!"); + } + + /* create and add audio stream pipeline */ + + if(!ctx->xaLEDArray && !ctx->xaVibra && mediatype!=XA_MEDIATYPE_IMAGE) /*no audio for these*/ + { + /* create audio post processing pipeline */ + ctx->audioppbin = XAAdaptationGst_CreateAudioPP( ); + if( ctx->audioppbin ) + { + gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->audioppbin); + if(!gst_element_link(ctx->codecbin, ctx->audioppbin)) + { + DEBUG_INFO("Could not link codec to audiopp, trying delayed link"); + delayedlink = XA_BOOLEAN_TRUE; + } + } + else + { + DEBUG_ERR("Could not create audio pp bin!!!!"); + return XA_RESULT_INTERNAL_ERROR; + } + /* create audio pipe sink */ + ctx->audiosink = XAAdaptationGst_CreateGstSink( ctx->xaAudioSink, "audiosink", &(ctx->isobjasink) ); + if( ctx->audiosink ) + { + if( ctx->isobjasink && ctx->xaAudioSink && ctx->xaAudioSink->pLocator ) + { + locType = *(XAuint32*)(ctx->xaAudioSink->pLocator); + switch ( locType ) + { + case XA_DATALOCATOR_OUTPUTMIX: + { + XADataLocator_OutputMix* omix = (XADataLocator_OutputMix*)(ctx->xaAudioSink->pLocator); + XAOMixImpl* omixDevice = (XAOMixImpl*)(*omix->outputMix); + if(omixDevice) + { + XAOutputMixAdapt_ConnectObject((XAAdaptationGstCtx*)omixDevice->adaptationCtx, &(ctx->baseObj), ctx->audiosink); + } + break; + } + default: + /* Vibra and LED need no handling */ + break; + } + } + gst_bin_add(GST_BIN(ctx->baseObj.bin), ctx->audiosink); + if(!gst_element_link(ctx->audioppbin, ctx->audiosink)) + { + DEBUG_ERR("Could not link audiopp to audiosink!!"); + return XA_RESULT_INTERNAL_ERROR; + } + } + else + { + DEBUG_ERR("Could not create audio sink!!!!"); + return XA_RESULT_INTERNAL_ERROR; + } + } + else + { + DEBUG_INFO("Media does not contain audio!"); + } + + if(delayedlink) + { + /* listen for dynamically created pads */ + g_signal_connect (ctx->codecbin, "pad-added", G_CALLBACK (XAMediaPlayerAdapt_NewPadCb), ctx); + } + locType = *((XAuint32*)(ctx->xaSource->pLocator)); + + DEBUG_API("<-XAMediaPlayerAdapt_CreatePipeline"); + return ret; +} + +/* + * gboolean XAMediaPlayerAdapt_PositionUpdate(gpointer ctx) + * callback. + * If position tracking enabled, periodic timer calls this method every XA_ADAPT_PU_INTERVAL msecs + * @return false to stop periodic calls + */ +gboolean XAMediaPlayerAdapt_PositionUpdate(gpointer ctx) +{ + XAAdaptationGstCtx *bCtx = (XAAdaptationGstCtx*) ctx; + XAMediaPlayerAdaptationCtx* mCtx = (XAMediaPlayerAdaptationCtx*) ctx; + gint64 position; + XAmillisecond posMsec; + GstFormat format = GST_FORMAT_TIME; + XAAdaptEvent event = {XA_PLAYITFEVENTS, XA_ADAPT_POSITION_UPDATE_EVT, 1, NULL}; + + DEBUG_API("->XAMediaPlayerAdapt_PositionUpdate"); + if ( !gst_element_query_position( GST_ELEMENT(bCtx->bin), &format, &position ) ) + { + DEBUG_ERR("Gst: Failed to get position"); + return( mCtx->runpositiontimer ); + } + DEBUG_INFO_A1("Current position %"GST_TIME_FORMAT, GST_TIME_ARGS(position)); + if( mCtx && mCtx->trackpositionenabled ) + { + posMsec = GST_TIME_AS_MSECONDS(position);/*Warning ok due to used API specification*/ + DEBUG_INFO_A1("mCtx->trackpositionenabled sending update, position:&ld ", posMsec); + /* send needed events */ + event.data=&posMsec; + XAAdaptationBase_SendAdaptEvents(&bCtx->baseObj, &event ); + } + if( mCtx && mCtx->loopingenabled) + { + DEBUG_INFO_A2("mCtx->loopingenabled, current position:%lu, loopend:%lu ", position, mCtx->loopend); + if( (position >= mCtx->loopend) && + (mCtx->lastpos < mCtx->loopend) ) + { + DEBUG_INFO_A2("Restart loop from %"GST_TIME_FORMAT" to %"GST_TIME_FORMAT, + GST_TIME_ARGS(mCtx->loopstart), GST_TIME_ARGS(mCtx->loopend)); + gst_element_seek( bCtx->bin, mCtx->playrate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH|GST_SEEK_FLAG_ACCURATE), + GST_SEEK_TYPE_SET, mCtx->loopstart, + GST_SEEK_TYPE_NONE, (gint64)GST_CLOCK_TIME_NONE ); + mCtx->lastpos = mCtx->loopstart; + if( mCtx && mCtx->trackpositionenabled ) + { + DEBUG_INFO_A1("mCtx->trackpositionenabled sending looping update, position:%&u ", posMsec); + posMsec = GST_TIME_AS_MSECONDS(mCtx->lastpos);/*Warning ok due to used API specification*/ + /* send needed events */ + event.data=&posMsec; + XAAdaptationBase_SendAdaptEvents(&bCtx->baseObj, &event ); + } + } + else + { + mCtx->lastpos = position; + } + } + DEBUG_API("<-XAMediaPlayerAdapt_PositionUpdate"); + /* return false to stop timer */ + return( mCtx->runpositiontimer ); +} + +/* + * XAresult XAMediaPlayerAdapt_UpdatePositionCbTimer + * Enable/disable periodic position tracking callback timer + */ +XAresult XAMediaPlayerAdapt_UpdatePositionCbTimer(XAMediaPlayerAdaptationCtx* mCtx) +{ + DEBUG_API_A2("->XAMediaPlayerAdapt_UpdatePositionCbTimer: trackposition %u, tracklooping %u", + mCtx->trackpositionenabled, mCtx->loopingenabled); + + if(mCtx->runpositiontimer==0 && (mCtx->trackpositionenabled || mCtx->loopingenabled)) + { + DEBUG_INFO("Start position tracking timer"); + mCtx->positionCb = &XAMediaPlayerAdapt_PositionUpdate; + /* if play is already on, create a timer to track position of playback */ + if( GST_STATE(mCtx->baseObj.bin) == GST_STATE_PLAYING ) + { + mCtx->runpositiontimer = g_timeout_add(XA_ADAPT_PU_INTERVAL, mCtx->positionCb, mCtx); + } + } + else if (mCtx->runpositiontimer!=0 && !(mCtx->trackpositionenabled || mCtx->loopingenabled)) + { + DEBUG_INFO("Stop position tracking timer"); + mCtx->trackpositionenabled = XA_BOOLEAN_FALSE; + if(mCtx->runpositiontimer > 0) + { + g_source_remove(mCtx->runpositiontimer); + mCtx->runpositiontimer=0; + } + } + DEBUG_API("<-XAMediaPlayerAdapt_UpdatePositionCbTimer"); + return XA_RESULT_SUCCESS; +} + +/* + * XAresult XAMediaPlayerAdapt_InitContentPipeSrc(ctx) + * CP code: can be moved to context base + */ +/*XAresult XAMediaPlayerAdapt_InitContentPipeSrc(XAMediaPlayerAdaptationCtx* ctx) +{ + XAresult ret = XA_RESULT_SUCCESS; + CPresult res; + GstStateChangeReturn gstRet = GST_STATE_CHANGE_SUCCESS; + DEBUG_API("->XAMediaPlayerAdapt_InitContentPipeSrc"); + ctx->baseObj.pipeSrcThrCtx.appSrc = GST_APP_SRC(ctx->source); + ctx->baseObj.pipeSrcThrCtx.pipe = (XADataLocator_ContentPipe*)(ctx->xaSource->pLocator); + + Create thread for content pipe source + ret = XAImpl_CreateThreadHandle( &(ctx->baseObj.pipeSrcThr) ); + if ( ret != XA_RESULT_SUCCESS ) + { + DEBUG_ERR("Could not create thread for content pipe source!"); + DEBUG_API("<-XAMediaPlayerAdapt_InitContentPipeSrc"); + return ret; + } + + Create semaphore for content pipe source + ret = XAImpl_CreateSemaphore( &(ctx->baseObj.pipeSrcThrCtx.stateSem)); + if ( ret != XA_RESULT_SUCCESS ) + { + DEBUG_ERR("Could not create semaphore for content pipe source!"); + DEBUG_API("<-XAMediaPlayerAdapt_InitContentPipeSrc"); + return ret; + } + + Open content pipe + res = ctx->baseObj.pipeSrcThrCtx.pipe->pContentPipe->Open(&(ctx->baseObj.pipeSrcThrCtx.dataHandle), + (CPstring)(ctx->baseObj.pipeSrcThrCtx.pipe->URI), + CP_AccessRead ); + if ( res == EXIT_FAILURE ) + { + DEBUG_ERR("Could not open Content Pipe!") + return XA_RESULT_INTERNAL_ERROR; + } + + res = ctx->baseObj.pipeSrcThrCtx.pipe->pContentPipe->RegisterCallback( &(ctx->baseObj.pipeSrcThrCtx.dataHandle), &XAAdaptationBase_ContentPipeSrcCb); + 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->source), GST_STATE_PAUSED); + gst_element_sync_state_with_parent( GST_ELEMENT( ctx->source)); + + XAImpl_StartThread( &(ctx->baseObj.pipeSrcThr), NULL, &XAAdaptationBase_ContentPipeScrThrFunc, &(ctx->baseObj.pipeSrcThrCtx) ); + + DEBUG_API("<-XAMediaPlayerAdapt_InitContentPipeSrc"); + return ret; +}*/