/* =========================================================================

FILE: AEEMediaUtil.c

SERVICES: IMedia utility functions

DESCRIPTION
  This file contains IMedia related utility functions that apps can use
  to develop BREW multimedia applications.

PUBLIC CLASSES:  
   N/A

INITIALIZATION AND SEQUENCING REQUIREMENTS:  N/A


           Copyright © 2000-2002 QUALCOMM Incorporated.
                     All Rights Reserved.
                   QUALCOMM Proprietary/GTDR
========================================================================= */


/*=========================================================================
                     INCLUDES AND VARIABLE DEFINITIONS
========================================================================= */
#include "OEMFeatures.h"

#if defined(FEATURE_BREW_MULTIMEDIA)

#include "cmx.h"

#include "OEMHeap.h"
#include "OEMFS.h"
#include "OEMObjectMgr.h"
#include "OEMCriticalSection.h"
#include "AEE_OEM.h"
#include "AEE_OEMDispatch.h"
#include "AEE_OEMFile.h"
#include "AEEMediaUtil.h"
#include "AEEStdLib.h"   

/*=========================================================================

                      DEFINES

========================================================================= */
#define OEMMM_ENTER_CRITICAL_SECTION()    OEMCriticalSection_Enter(&gMediaUtilCriticalSection); {
#define OEMMM_LEAVE_CRITICAL_SECTION()  ;} OEMCriticalSection_Leave(&gMediaUtilCriticalSection);

#if defined(FEATURE_AUDIO_POSTCARD) && !defined(FEATURE_BRIDLE)
#define FEATURE_PMD_ENCODE
#endif

/*=========================================================================

                      IMediaUtil DECLARATIONS

=========================================================================*/
struct IMediaUtil
{
   const AEEVTBL(IMediaUtil) *pvt;
   int32                m_nRefs;
   IShell *             m_pIShell;

   // EncodeMedia() info
   AEEObjectHandle      m_hObjEncode;
   AEEMediaEncodeResult *  m_per;
};

extern int     IMediaUtil_New(IShell * ps, AEECLSID cls, void **ppif);
//static void    IMediaUtil_Delete(IMediaUtil * pme);
static uint32  IMediaUtil_AddRef(IMediaUtil * pme);
static uint32  IMediaUtil_Release(IMediaUtil * pme);
static int     IMediaUtil_QueryInterface(IMediaUtil * pme, AEECLSID idReq, void ** ppo);
static int     IMediaUtil_CreateMedia(IMediaUtil * pme, AEEMediaData * pmd, IMedia ** ppm);
static int     IMediaUtil_EncodeMedia(IMediaUtil * pme, AEEMediaEncodeResult * per, AEECLSID clsDest, AEEMediaEncodeInfo * pei, AEECallback * pcb);

static const AEEVTBL(IMediaUtil) gvtIMediaUtil =
{
   IMediaUtil_AddRef,
   IMediaUtil_Release,
   IMediaUtil_QueryInterface,
   IMediaUtil_CreateMedia,
   IMediaUtil_EncodeMedia
};

static IMediaUtil gsMediaUtil = { 0 };

#ifdef FEATURE_PMD_ENCODE
static OEMCriticalSection gMediaUtilCriticalSection;
#endif // FEATURE_PMD_ENCODE

/*=========================================================================

                     IMediaUtil FUNCTION DEFINITIONS

=========================================================================*/

/*==================================================================

==================================================================*/
int IMediaUtil_New(IShell * ps, AEECLSID cls, void **ppif)
{
   IMediaUtil *   pme = &gsMediaUtil;

   if (!pme->m_nRefs)
   {
      pme->pvt = &gvtIMediaUtil;
      pme->m_nRefs = 1;
      pme->m_pIShell = ps;
   }

   if (ppif)
      *ppif = pme;

   return SUCCESS;
}

/*==================================================================

==================================================================*/
//static void IMediaUtil_Delete(IMediaUtil * pme)
//{
//}

/*==================================================================

==================================================================*/
static uint32 IMediaUtil_AddRef(IMediaUtil * pme)
{
   return 1;
}

/*==================================================================

==================================================================*/
static uint32 IMediaUtil_Release(IMediaUtil * pme)
{
   return 0;
}

/*==================================================================

==================================================================*/
static int IMediaUtil_QueryInterface(IMediaUtil * pme, AEECLSID idReq, void ** ppo)
{
   if (!ppo)
      return EBADPARM;

   if (NULL != IQI_SELF(pme, idReq, ppo, AEECLSID_MEDIAUTIL)) 
   {
      IQI_AddRef(*ppo);
      return SUCCESS;
   }

   return ECLASSNOTSUPPORT;
}

/*=========================================================================

========================================================================= */
static int IMediaUtil_CreateMedia(IMediaUtil * pme, AEEMediaData * pmd, IMedia ** ppm)
{
   return AEEMediaUtil_CreateMedia(pme->m_pIShell, pmd, ppm);
}

/*=========================================================================

                     ENCODING MEDIA

========================================================================= */
#if defined(FEATURE_BREW_CMX_V3)

static int  IMediaUtil_EncodeAudioPostcard(IMediaUtil * pme, AEEMediaEncodeResult * per, AEEMediaEncodeInfo * pei, AEECallback * pcb);
#ifdef FEATURE_PMD_ENCODE
static void IMediaUtil_CancelEncodeCB(AEECallback * pcb);
static void IMediaUtil_CMXAudioPostcardCB(cmx_status_type status, const void *client_data);
#endif // FEATURE_PMD_ENCODE
static void IMediaUtil_ResetEncode(IMediaUtil * pme);

/*=========================================================================

========================================================================= */
static int IMediaUtil_EncodeMedia(IMediaUtil * pme, AEEMediaEncodeResult * per, AEECLSID clsDest, AEEMediaEncodeInfo * pei, AEECallback * pcb)
{
   if (!per || !clsDest || !pei || !pei->pmdDest || !pei->nCount || !pei->pmdList)
      return EBADPARM;

   // First cancel pending callback, if any.
   if (pcb)
      CALLBACK_Cancel(pcb);

   IMediaUtil_ResetEncode(pme);

   if (AEECLSID_MEDIAPMD == clsDest)
      return IMediaUtil_EncodeAudioPostcard(pme, per, pei, pcb);
   else
      return EUNSUPPORTED;
}

/*=========================================================================

========================================================================= */
static int IMediaUtil_EncodeAudioPostcard(IMediaUtil * pme, AEEMediaEncodeResult * per, AEEMediaEncodeInfo * pei, AEECallback * pcb)
{
#if defined(FEATURE_PMD_ENCODE)
   cmx_handle_type *    ph[3] = { NULL, NULL, NULL };
   int                  i;
   int                  nRet = SUCCESS;
   cmx_cb_func_ptr_type pfn;
   void *               pUser;

   if (pei->nCount != 2)
      return EBADPARM;

   // Only files are supported.
   if (pei->pmdList[0].clsData != MMD_FILE_NAME || pei->pmdList[0].clsData != MMD_FILE_NAME
       || pei->pmdDest->clsData != MMD_FILE_NAME)
       return EUNSUPPORTED;

   //
   // Here you can verify if one media is JPEG and another is QCP...
   // Currently, assumes: first media is JPEG and second is PMD!
   //

   // First link new system callback to app callback and fill cancel info.
   // Then register system callback with ObjectMgr...
   if (pcb)
   {
      AEECallback * pcbSys;

      pcbSys = AEE_LinkSysCallback(pcb);
      if (!pcbSys)
         return ENOMEMORY;

      pcbSys->pfnCancel = IMediaUtil_CancelEncodeCB;
      pcbSys->pCancelData = pme;
      nRet = AEEObjectMgr_Register(pcbSys, &pme->m_hObjEncode);
      if (nRet)
         return nRet;
   }

   for (i = 0; i < 3; i++)
   {
      const char *cpszPath;
      int         nFullPathLen;

      ph[i] = MALLOC(sizeof(cmx_handle_type));
      if (!ph[i])
      {
         nRet = ENOMEMORY;
         goto Done;
      }

      ph[i]->source_type = ph[i]->efs.source_type = CMX_SOURCE_EFS;

      if (i < 2) {
         cpszPath = (const char *)pei->pmdList[i].pData;
      } else {
         cpszPath = (const char *)pei->pmdDest->pData;
      }

      nRet = AEE_ResolvePath(cpszPath, 0, &nFullPathLen);

      if (SUCCESS != nRet) {
         goto Done;
      }
      
      {
         char *pszFullPath;
         
         pszFullPath = (char *)sys_malloc(nFullPathLen);

         if ((char *)0 == pszFullPath) {
            return ENOMEMORY;
         }

         AEE_ResolvePath(cpszPath, pszFullPath, &nFullPathLen);
         
         nRet = AEE_CheckPathAccess(pszFullPath, AEEFP_READ, 0);
                  
         if (SUCCESS == nRet) {
            nRet = sizeof(ph[i]->efs.filename);// use nRet to hold size...
            
            // convert to EFS name
            nRet = OEMFS_GetNativePath(pszFullPath,
                                       ph[i]->efs.filename,
                                       &nRet);
         }

         sys_free(pszFullPath);

         if (nRet)
            goto Done;
      }
   }

   // Update and save the destination info...

   if (pcb)
   {
      per->clsMedia = AEECLSID_MEDIAPMD;
      per->pmdDest = pei->pmdDest;
      pme->m_per = per;
      
      pfn = IMediaUtil_CMXAudioPostcardCB;
      pUser = (void *)pme->m_hObjEncode;
   }
   else
   {
      pfn = NULL;
      pUser = NULL;
   }

   cmx_create_audiop(ph[0], ph[1], ph[2], pfn, pUser);

Done:
   for (i = 0; i < 3; i++)
   {
      FREEIF(ph[i]);
   }

   return nRet;
#else // FEATURE_PMD_ENCODE
   return EUNSUPPORTED;
#endif // FEATURE_PMD_ENCODE
}

#if defined(FEATURE_PMD_ENCODE)
/*=========================================================================

========================================================================= */
static void IMediaUtil_CancelEncodeCB(AEECallback * pcb)
{
   IMediaUtil  *  pme = (IMediaUtil *)pcb->pCancelData;

   if (!pme)
      return;

   pcb->pfnCancel = NULL;
   pcb->pCancelData = NULL;

   IMediaUtil_ResetEncode(pme);
}

/*=========================================================================

========================================================================= */
static void IMediaUtil_CMXAudioPostcardCB(cmx_status_type status, const void *client_data)
{
   OEMMM_ENTER_CRITICAL_SECTION()

   AEECallback *  pcb = (AEECallback *)AEEObjectMgr_GetObject((AEEObjectHandle)client_data);
   IMediaUtil  *  pme;

   if (!pcb)
      goto CBExit;

   pme = (IMediaUtil *)pcb->pCancelData;

   pme->m_per->nResult = (status == CMX_SUCCESS) ? SUCCESS : EFAILED;
   pme->m_per->pEncodeSpec = NULL;
   pme->m_per->dwSpecSize = 0;

   if (status != CMX_SUCCESS)
   {
      pme->m_per->clsMedia = 0;
      pme->m_per->pmdDest = NULL;
   }

   ISHELL_Resume(pme->m_pIShell, pcb);

   IMediaUtil_ResetEncode(pme);

CBExit:
   OEMMM_LEAVE_CRITICAL_SECTION()
}
#endif // FEATURE_PMD_ENCODE

/*=========================================================================

========================================================================= */
static void IMediaUtil_ResetEncode(IMediaUtil * pme)
{
   if (!pme->m_per)
      return;

   pme->m_per = NULL;

   AEEObjectMgr_Unregister(pme->m_hObjEncode);
   pme->m_hObjEncode = 0;
}

#else // CMX 2.x

/*=========================================================================

========================================================================= */
static int IMediaUtil_EncodeMedia(IMediaUtil * pme, AEEMediaEncodeResult * per, AEECLSID clsDest, AEEMediaEncodeInfo * pei, AEECallback * pcb)
{
   return EUNSUPPORTED;
}

#endif // defined(FEATURE_BREW_CMX_V3) 

#endif // defined(FEATURE_BREW_MULTIMEDIA)

/* ============= End of File =============================================== */
