/****************************************************************************/
/*                                                                          */
/* CODECSRV.C: Codec generic services.                                      */
/*     You shoudn't need to update this source file unless you want to      */
/*     change the entry point from "SampleCodecEntry" to something more     */
/*     specific to your algorithm.  Note also that you must change the      */
/*     entry point name in the .DEF building portion of your makefile.      */
/*                                                                          */
/* Copyright (c) IBM Corporation 1991,1992,1993        All Rights Reserved  */
/*                                                                          */
/****************************************************************************/

/* OS/2 INCLUDES */
#define  INCL_WIN
#define  INCL_GPI
#define  INCL_DOSSEMAPHORES
#define  INCL_DOSEXCEPTIONS
#define  INCL_DOSERRORS
#define  INCL_DOSPROCESS
#define  INCL_OS2MM
#define  INCL_MMIO_CODEC
#include <os2.h>
#include <os2me.h>
#include <string.h>
#include "hhpheap.h"
#include "svsh.h"
#include "codecsrv.h"



/* These are the mandatory codec's capabilities as defined in SAMPGDAT.C.   */
extern ULONG ulGlobalCapsFlags;


LONG APIENTRY SampleCodecEntry (
      PVOID ppcodec_inst,  /* Pointer to MMIOINFO status structure.         */
      WORD  wMessage,      /* MMIO specific message from FFIOproc.          */
      LONG  lParam1,       /* Primary message dependent parameter.          */
      LONG  lParam2 )      /* Secondary message dependent parameter.        */

   {
   ULONG rc= MMIOERR_UNSUPPORTED_MESSAGE;  /* Initialize the return as fail.*/

   switch ( wMessage )
      {
      case MMIOM_CODEC_OPEN:

         /* Allocate the instance data for this codec.  The first call to   */
         /* open must have the ppcodec_inst parameter as NULL.              */
         rc= OpenCodec ( (PCODEC_INST *) ppcodec_inst, (PCODECOPEN) lParam1 );
         break;

      case MMIOM_CODEC_CLOSE:

         /* Deallocate the instance data for this codec.                    */
         rc= CloseCodec ( (PCODEC_INST *) ppcodec_inst );
         break;

      case MMIOM_CODEC_COMPRESS:

         /* Check to see if the compress message is supported, and make the */
         /* call to the function in SAMPMAIN.C to compress the buffer.      */
         if ( codecfns.pfnCompressBuffer )
            rc= codecfns.pfnCompressBuffer ( (PMMCOMPRESS)lParam1,
                                             *(PCODEC_INST *)ppcodec_inst );
         break;

      case MMIOM_CODEC_DECOMPRESS:

         /* Check to see if the decompress message is supported, and make   */
         /* the call to the function in SAMPMAIN.C to compress the buffer.  */
         if ( codecfns.pfnDecompressBuffer )
            rc= codecfns.pfnDecompressBuffer ( (PMMDECOMPRESS)lParam1,
                                              *(PCODEC_INST *)ppcodec_inst );
         break;

      case MMIOM_CODEC_QUERYNAMELENGTH:

         /* Check to see if the query name length message is supported, and */
         /* make the call to the function in CDCSRV.C to do the query.      */
         if ( codecfns.pfnQryNameLength )
            rc= codecfns.pfnQryNameLength ( (PCODEC_INST *) ppcodec_inst,
                        (WORD) wMessage, (PULONG) lParam1, (LONG) lParam2 );
         break;

      case MMIOM_CODEC_QUERYNAME:

         /* Check to see if the query name message is supported, and        */
         /* make the call to the function in CDCSRV.C to do the query.      */
         if ( codecfns.pfnQryNameString )
            rc= codecfns.pfnQryNameString ( (PCODEC_INST *) ppcodec_inst,
                        (WORD) wMessage, (PSZ) lParam1, (PULONG) lParam2 );
         break;
      }

   /* Return the results of the message.                                    */
   return (rc);
   }




/****************************************************************************/
/*                                                                          */
/* SUBROUTINE NAME: OpenCodec                                               */
/*     This function does a validity check on the capability flags passed   */
/*     from mmio to those of the codec.  If the validuity check passes, the */
/*     codec initializes shared instance data and calls the codec specific  */
/*     initilization function.  This funct returns with a pointer to its    */
/*     private data storage and this is stored in the CODEC_INST chain that */
/*     is attached to the shared instance data.                             */
/*                                                                          */
/****************************************************************************/

RC OpenCodec (PCODEC_INST *ppcodec_inst, PCODECOPEN pcodecopen)
{
   RC                rc = MMIO_SUCCESS;
   PE_MOVIE_INST     pe_movie_inst;    /* shared codec data area pointer   */
   PCODEC_INST       pcodec_inst;      /* codec specific instance dats ptr */

   ENTERCRITX(rc); /* crit sect req's as playing around winth linked lists */

  /*********************************************************/
  /* validate the codec open flags,  These indicate the    */
  /* consistency between the current codec and the IO      */
  /* proc that issued the open call,   if any flags        */
  /* besides the ulGlobalCapsFlags are set then ERROR      */
  /*********************************************************/
   if (!(pcodecopen->ulFlags & (~ulGlobalCapsFlags)))
   {
     /******************************************************/
     /* The ppcodec_inst on input is either a pointer to a */
     /* previously allocated hcodec or it is null.  If it  */
     /* is null the codecopen is being called for the      */
     /* first time and the pe_movie_inst  shared date      */
     /* block needs to be allocated.                       */
     /*                                                    */
     /* If on the other hand the hcodec is non null the    */
     /* shared pe_movie_inst has already been allocated    */
     /* and needs to be extracted from the pcodec_inst     */
     /******************************************************/
      if (!(*ppcodec_inst))
      {
        /***************************************************/
        /* Null pointer => this is a new movie instance  so*/
        /* alloc resources and add to beginning of the     */
        /* list chain. and also add the movie instance to  */
        /* its linked list chain                           */
        /***************************************************/
         if (pe_movie_inst = (PE_MOVIE_INST) HhpAllocMem (hHeap,
                                             sizeof(E_MOVIE_INST)))
         {
           /************************************************/
           /* store the shared instance data and open parms*/
           /* also copy the allocated pointer field        */
           /* containing codec specific info               */
           /************************************************/
            pe_movie_inst->codecopen  = *pcodecopen;

           /************************************************/
           /* need to store source header?                 */
           /************************************************/
            if (pcodecopen->pSrcHdr)
            {
               if (pe_movie_inst->codecopen.pSrcHdr = (PVOID) HhpAllocMem (hHeap,
                                                      sizeof (CODECVIDEOHEADER)))
               {
                  memcpy (pe_movie_inst->codecopen.pSrcHdr,
                          pcodecopen->pSrcHdr,
                          sizeof (CODECVIDEOHEADER));
               }
               else
               {
                  rc = MMIOERR_OUTOFMEMORY;
               }
            }

           /************************************************/
           /* need to store destination header?            */
           /* extract the structure length                 */
           /************************************************/
            if (pcodecopen->pDstHdr && !rc)
            {
               if (pe_movie_inst->codecopen.pDstHdr = (PVOID) HhpAllocMem (hHeap,
                                                      ((PQUERYLEN)(pcodecopen->pDstHdr))->ulStructLen))
               {
                  memcpy (pe_movie_inst->codecopen.pDstHdr,
                        pcodecopen->pDstHdr,
                        ((PQUERYLEN)(pcodecopen->pDstHdr))->ulStructLen);
               }
               else
               {
                  rc = MMIOERR_OUTOFMEMORY;
               }
            }

           /************************************************/
           /* Optionally this field may have data so       */
           /* allocate and copy it                         */
           /************************************************/
            if (pcodecopen->pOtherInfo && !rc)
            {
               if (pe_movie_inst->codecopen.pOtherInfo = (PVOID) HhpAllocMem (hHeap,
                                                         ((PQUERYLEN)(pcodecopen->pOtherInfo))->ulStructLen))
               {
                  memcpy (pe_movie_inst->codecopen.pOtherInfo,
                        pcodecopen->pOtherInfo,
                        ((PQUERYLEN)(pcodecopen->pOtherInfo))->ulStructLen);
               }
               else
               {
                  rc = MMIOERR_OUTOFMEMORY;
               }
            }
            pe_movie_inst->ulNumCodecs  = 0;
         }
         else
         {
            rc = MMIOERR_OUTOFMEMORY;
         }
      }
      else /* fetch previously allocated one and check for null */
      {
         if (!(pe_movie_inst = (*ppcodec_inst)->pe_movie_inst))
         {
            rc= MMIOERR_OUTOFMEMORY;
         }
      }

     /******************************************************/
     /* allocate a codec instance structure and add it to  */
     /* the linked list, at this stage pe_movie inst points*/
     /* to the shared instance data area containing valid  */
     /* open data                                          */
     /******************************************************/
      if (!rc) /* check for errors so far */
      {
        /***************************************************/
        /* allocate codec instance data struct             */
        /***************************************************/
         if (pcodec_inst = (PCODEC_INST) HhpAllocMem (hHeap,
                                         sizeof(CODEC_INST)))
         { /* fill in pointer to (checked) shared data */
            pcodec_inst->pe_movie_inst = pe_movie_inst;

            if (codecfns.pfnAllocInstData)
            {
              /*********************************************/
              /* call the codec specific allocation routine*/
              /* note that the allocation code can find all*/
              /* necessary information in the pcodec_inst->*/
              /* pe_movie_inst->codecopen.  The allocated  */
              /* data is stored in pe_movie_inst->pPlug..  */
              /* if the call succeded this is the hCodec   */
              /* that the IO proc refers to.               */
              /*********************************************/
               if (!(rc = codecfns.pfnAllocInstData (pcodec_inst)))
               {
                 /******************************************/
                 /* attach the codec inst to the anchor pt */
                 /* as instance data correctly allocated   */
                 /******************************************/
                  pe_movie_inst->ulNumCodecs++;
                  pcodec_inst->pNextCodecInst      = pe_movie_inst->pCodecInstAnchor;
                  pe_movie_inst->pCodecInstAnchor  = (PVOID)pcodec_inst;
               }
            }
         }
         else /* error allocating codec instance data */
         {
            rc = MMIOERR_OUTOFMEMORY;
         }
      }

     /******************************************************/
     /* insert code here to deal with the MIPS             */
     /* finally return codec instance data pointer to      */
     /* FFIO proc.  The FFIO proc calls this a hCodec      */
     /******************************************************/
      if (!rc)
      {
         *ppcodec_inst = pcodec_inst;   /* FFIO stores this as ULONG */
      }

     /******************************************************/
     /* in the case of an allocation error the FFIO proc   */
     /* must send the MMIOM_CODEC_CLOSE message to the     */
     /* codec proc for each of the codec's for that movie  */
     /* as the deallocation functions are not known here   */
     /******************************************************/
   }
   else /* invalid open flags sent down so return an error */
   {
      rc = MMIO_ERROR;
   } /* endif */

   EXITCRIT;
   return rc;
}



RC CloseCodec ( PCODEC_INST *ppcodec_key )
   {
   RC                rc = MMIO_SUCCESS;
   PE_MOVIE_INST     pe_movie_inst;     /* Shared codec data area pointer.  */
   PCODEC_INST       pcodec_inst;       /* Codec specific instance dats ptr.*/

   /* Don't get caught in this with two instances at once.  This is a macro */
   /* that grabs a semaphore (rather than DosEnterCritSec).                 */
   ENTERCRITX(rc);

   /* Deallocate an instance.                                               */
   if ( pcodec_inst = *ppcodec_key )

      /* Find the shared data structure.                                    */
      if ( pe_movie_inst = (pcodec_inst->pe_movie_inst) )
         {
         if ( ! (rc= RemoveCodecChainLink (pcodec_inst)) )
            {
            /* Remove from chain, call deallocation of instance data.       */
            if ( codecfns.pfnDeallocInstData )
               rc = codecfns.pfnDeallocInstData (pcodec_inst);

            /* Free up the instance from the chain.                         */
            HhpFreeMem ( hHeap, pcodec_inst );

            /* If there are no more instances, destroy the movie instance.  */
            if ( !(pe_movie_inst->ulNumCodecs--) )
               {
               /* Destroy the shared movie instance data fields.            */
               if ( pe_movie_inst->codecopen.pSrcHdr )
                  HhpFreeMem ( hHeap, pe_movie_inst->codecopen.pSrcHdr );

               if ( pe_movie_inst->codecopen.pDstHdr )
                  HhpFreeMem ( hHeap, pe_movie_inst->codecopen.pDstHdr );

               if ( pe_movie_inst->codecopen.pOtherInfo )
                  HhpFreeMem ( hHeap, pe_movie_inst->codecopen.pOtherInfo );

               HhpFreeMem (hHeap, pe_movie_inst);
               pe_movie_inst = NULL;
               }
            }
         }
      else
         rc = MMIO_ERROR;                             /* NULL pe_movie_inst.*/

   else
      rc = MMIO_ERROR;                                /* NULL hCodec.       */

   /* Release the semaphore and return the function result.                 */
   EXITCRIT;
   return rc;
   }





/****************************************************************************/
/*                                                                          */
/* SUBROUTINE NAME: RemoveCodecChainLink                                    */
/*     Removes a hCodec Link from the linked list.  You should not need to  */
/*     change this function.                                                */
/*                                                                          */
/*  NOTE: pPlugInstData has already been deallocated from the hCodec        */
/*        allowing this structure to be deallocated from the heap           */
/*                                                                          */
/****************************************************************************/

RC RemoveCodecChainLink ( PCODEC_INST pcodec_key )
   {
   RC              rc= MMIO_SUCCESS;
   PCODEC_INST     pcodec_inst;     /* Codec_inst chain pointer.            */
   PCODEC_INST     pcodec_temp;     /* Linked list codec_inst temp pointer. */
   BOOL            fFound;          /* Used to indicate if link found.      */
   PE_MOVIE_INST   pe_movie_inst;   /* Pointer to the shared movie data.    */

   /* Get the shared data, search for a match, if found repair the chain.   */
   if ( pcodec_key )                                               /* null? */
      if ( pe_movie_inst= pcodec_key->pe_movie_inst )              /* null? */
         if ( pe_movie_inst->pCodecInstAnchor )                    /* null? */
            {
            if ( pcodec_key == pe_movie_inst->pCodecInstAnchor )
               {
               pcodec_temp= ((PCODEC_INST)(pe_movie_inst->pCodecInstAnchor))
                                             -> pNextCodecInst;
               pe_movie_inst->pCodecInstAnchor= pcodec_temp; /* May be NULL.*/
               }
            else
               /* This is not the first element in the chain.               */
               for ( pcodec_inst= pe_movie_inst->pCodecInstAnchor, fFound = FALSE;
                     pcodec_inst->pNextCodecInst && !fFound; /* 1st is true.*/
                     pcodec_inst= pcodec_inst->pNextCodecInst )

                  if ( pcodec_inst->pNextCodecInst == pcodec_key )
                     {
                     pcodec_temp = pcodec_inst->pNextCodecInst
                        ->pNextCodecInst;  /* NULL if the end of the Chain. */
                     HhpFreeMem (hHeap, pcodec_inst->pNextCodecInst);
                     pcodec_inst->pNextCodecInst = pcodec_temp;
                     fFound = FALSE;
                     }

            if ( !fFound )
               rc = MMIO_WARNING; /* Indicate that nothing deallocated.     */

            }

         else
            rc= MMIO_ERROR;  /* Indicate that nothing deallocated.          */

   /* Return the error code.                                                */
   return rc;
   }






#pragma linkage (_DLL_InitTerm, system)
ULONG _DLL_InitTerm ( ULONG hmod, ULONG fTerm )
   {
   #define   DLLINITTERM_SUCCESS  1L  /* Reverse logic for the return codes.*/
   #define   DLLINITTERM_FAILURE  0L  /* Reverse logic for the return codes.*/
   LONG rc= DLLINITTERM_FAILURE; /* Initialize function to failure.         */

   /* Check if we are initializing or terminating.                          */
   if ( !fTerm )
      {
      /* This is an initialize call.                                        */
      if ( !(_CRT_init()) )
         if ( hHeap = HhpCreateHeap ( HEAP_SIZE, 0 ) )
            if ( !DosCreateMutexSem ( NULL, &hmtxGlobalData,
                                   DC_SEM_SHARED, FALSE ) )
               rc = DLLINITTERM_SUCCESS;
      }

   else
      /* Terminate DLL request.                                             */
      {
      DosCloseMutexSem ( hmtxGlobalData );
      if ( !HhpDestroyHeap(hHeap) )
         rc = DLLINITTERM_SUCCESS;
      }

   /* Return the result of the function initialization or termination.      */
   return rc;
   }





