1541 lines
43 KiB
C
1541 lines
43 KiB
C
/*
|
|
* @DEC_COPYRIGHT@
|
|
*/
|
|
/*
|
|
* HISTORY
|
|
* $Log: sa_api.c,v $
|
|
* Revision 1.1.8.6 1996/11/25 18:21:14 Hans_Graves
|
|
* Fix compile warnings under unix.
|
|
* [1996/11/25 18:21:00 Hans_Graves]
|
|
*
|
|
* Revision 1.1.8.5 1996/11/14 21:49:21 Hans_Graves
|
|
* AC3 buffering fixes.
|
|
* [1996/11/14 21:45:14 Hans_Graves]
|
|
*
|
|
* Revision 1.1.8.4 1996/11/13 16:10:44 Hans_Graves
|
|
* AC3 frame size calculation change.
|
|
* [1996/11/13 15:53:44 Hans_Graves]
|
|
*
|
|
* Revision 1.1.8.3 1996/11/08 21:50:27 Hans_Graves
|
|
* Added AC3 support.
|
|
* [1996/11/08 21:08:35 Hans_Graves]
|
|
*
|
|
* Revision 1.1.8.2 1996/09/18 23:45:23 Hans_Graves
|
|
* Add some some MPEG memory freeing
|
|
* [1996/09/18 21:42:12 Hans_Graves]
|
|
*
|
|
* Revision 1.1.6.8 1996/04/23 21:01:38 Hans_Graves
|
|
* Added SaDecompressQuery() and SaCompressQuery()
|
|
* [1996/04/23 20:57:47 Hans_Graves]
|
|
*
|
|
* Revision 1.1.6.7 1996/04/17 16:38:31 Hans_Graves
|
|
* Add casts where ScBitBuf_t and ScBitString_t types are used
|
|
* [1996/04/17 16:34:14 Hans_Graves]
|
|
*
|
|
* Revision 1.1.6.6 1996/04/15 14:18:32 Hans_Graves
|
|
* Change proto for SaCompress() - returns bytes processed
|
|
* [1996/04/15 14:10:27 Hans_Graves]
|
|
*
|
|
* Revision 1.1.6.5 1996/04/10 21:46:51 Hans_Graves
|
|
* Added SaGet/SetParam functions
|
|
* [1996/04/10 21:25:16 Hans_Graves]
|
|
*
|
|
* Revision 1.1.6.4 1996/04/09 16:04:23 Hans_Graves
|
|
* Remove warnings under NT
|
|
* [1996/04/09 15:55:26 Hans_Graves]
|
|
*
|
|
* Revision 1.1.6.3 1996/03/29 22:20:48 Hans_Graves
|
|
* Added MPEG_SUPPORT and GSM_SUPPORT
|
|
* [1996/03/29 21:51:24 Hans_Graves]
|
|
*
|
|
* Revision 1.1.6.2 1996/03/08 18:46:05 Hans_Graves
|
|
* Removed debugging printf
|
|
* [1996/03/08 18:42:52 Hans_Graves]
|
|
*
|
|
* Revision 1.1.4.5 1996/02/22 21:55:04 Bjorn_Engberg
|
|
* Removed a compiler warning on NT.
|
|
* [1996/02/22 21:54:39 Bjorn_Engberg]
|
|
*
|
|
* Revision 1.1.4.4 1996/02/06 22:53:51 Hans_Graves
|
|
* Moved ScBSReset() from DecompressBegin() to DecompressEnd(). Disabled FRAME callbacks.
|
|
* [1996/02/06 22:19:16 Hans_Graves]
|
|
*
|
|
* Revision 1.1.4.3 1996/01/19 15:29:27 Bjorn_Engberg
|
|
* Removed compiler wanrnings for NT.
|
|
* [1996/01/19 15:03:46 Bjorn_Engberg]
|
|
*
|
|
* Revision 1.1.4.2 1996/01/15 16:26:18 Hans_Graves
|
|
* Added SaSetBitrate(). SOme MPEG Audio encoding fix-ups
|
|
* [1996/01/15 16:07:48 Hans_Graves]
|
|
*
|
|
* Revision 1.1.2.7 1995/07/21 17:40:57 Hans_Graves
|
|
* Renamed Callback related stuff.
|
|
* [1995/07/21 17:25:44 Hans_Graves]
|
|
*
|
|
* Revision 1.1.2.6 1995/06/27 17:40:57 Hans_Graves
|
|
* Removed include <mmsystem.h>.
|
|
* [1995/06/27 17:32:20 Hans_Graves]
|
|
*
|
|
* Revision 1.1.2.5 1995/06/27 13:54:14 Hans_Graves
|
|
* Added GSM Encoding and Decoding
|
|
* [1995/06/26 21:04:12 Hans_Graves]
|
|
*
|
|
* Revision 1.1.2.4 1995/06/09 18:33:27 Hans_Graves
|
|
* Added SaGetInputBitstream().
|
|
* [1995/06/09 18:32:35 Hans_Graves]
|
|
*
|
|
* Revision 1.1.2.3 1995/06/07 19:34:39 Hans_Graves
|
|
* Enhanced sa_GetMpegAudioInfo().
|
|
* [1995/06/07 19:33:25 Hans_Graves]
|
|
*
|
|
* Revision 1.1.2.2 1995/05/31 18:07:17 Hans_Graves
|
|
* Inclusion in new SLIB location.
|
|
* [1995/05/31 17:28:50 Hans_Graves]
|
|
*
|
|
* Revision 1.1.2.3 1995/04/17 18:47:31 Hans_Graves
|
|
* Added MPEG Compression functionality
|
|
* [1995/04/17 18:47:00 Hans_Graves]
|
|
*
|
|
* Revision 1.1.2.2 1995/04/07 19:55:45 Hans_Graves
|
|
* Inclusion in SLIB
|
|
* [1995/04/07 19:55:15 Hans_Graves]
|
|
*
|
|
* $EndLog$
|
|
*/
|
|
/*****************************************************************************
|
|
** Copyright (c) Digital Equipment Corporation, 1995 **
|
|
** **
|
|
** All Rights Reserved. Unpublished rights reserved under the copyright **
|
|
** laws of the United States. **
|
|
** **
|
|
** The software contained on this media is proprietary to and embodies **
|
|
** the confidential technology of Digital Equipment Corporation. **
|
|
** Possession, use, duplication or dissemination of the software and **
|
|
** media is authorized only pursuant to a valid written license from **
|
|
** Digital Equipment Corporation. **
|
|
** **
|
|
** RESTRICTED RIGHTS LEGEND Use, duplication, or disclosure by the U.S. **
|
|
** Government is subject to restrictions as set forth in Subparagraph **
|
|
** (c)(1)(ii) of DFARS 252.227-7013, or in FAR 52.227-19, as applicable. **
|
|
******************************************************************************/
|
|
|
|
/*
|
|
#define _DEBUG_
|
|
#define _VERBOSE_
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "SC.h"
|
|
#include "SC_err.h"
|
|
#include "SA.h"
|
|
#ifdef MPEG_SUPPORT
|
|
#include "sa_mpeg.h"
|
|
#endif /* MPEG_SUPPORT */
|
|
#ifdef GSM_SUPPORT
|
|
#include "sa_gsm.h"
|
|
#endif /* GSM_SUPPORT */
|
|
#ifdef AC3_SUPPORT
|
|
#include "sa_ac3.h"
|
|
#endif /* AC3_SUPPORT */
|
|
#include "sa_intrn.h"
|
|
#include "sa_proto.h"
|
|
|
|
#ifdef MPEG_SUPPORT
|
|
static int MPEGAudioFilter(ScBitstream_t *bs)
|
|
{
|
|
int type, stat=NoErrors;
|
|
unsigned dword PacketStartCode;
|
|
ScBSPosition_t PacketStart, PacketLength=0;
|
|
|
|
while (!bs->EOI)
|
|
{
|
|
if ((int)ScBSPeekBits(bs, MPEG_SYNC_WORD_LEN)==MPEG_SYNC_WORD)
|
|
{
|
|
ScBSSetFilter(bs, NULL);
|
|
return(0);
|
|
}
|
|
PacketStartCode=(unsigned int)ScBSGetBits(bs, PACKET_START_CODE_PREFIX_LEN);
|
|
if (PacketStartCode!=PACKET_START_CODE_PREFIX) {
|
|
fprintf(stderr,"Packet cannot be located at Byte pos 0x%X; got 0x%X\n",
|
|
ScBSBytePosition(bs),PacketStartCode);
|
|
bs->EOI=TRUE;
|
|
return(-1);
|
|
}
|
|
type=(int)ScBSGetBits(bs, 8);
|
|
switch (type)
|
|
{
|
|
case AUDIO_STREAM_BASE:
|
|
PacketLength=(unsigned int)ScBSGetBits(bs, 16)*8;
|
|
PacketStart=ScBSBitPosition(bs);
|
|
sc_dprintf("Audio Packet Start=0x%X Length=0x%X (0x%X)\n",
|
|
PacketStart/8, PacketLength/8, PacketLength/8);
|
|
while (ScBSPeekBits(bs, 8)==0xFF) /* Stuffing bytes */
|
|
ScBSSkipBits(bs, 8);
|
|
if (ScBSPeekBits(bs, 2)==1) /* STD_buffer stuff */
|
|
ScBSSkipBits(bs, 2*8);
|
|
if (ScBSPeekBits(bs, 4)==2) /* Time Stamps */
|
|
ScBSSkipBits(bs, 5*8);
|
|
else if (ScBSPeekBits(bs, 4)==3) /* Time Stamps */
|
|
ScBSSkipBits(bs, 10*8);
|
|
else if (ScBSGetBits(bs, 8)!=0x0F)
|
|
fprintf(stderr, "Last byte before data not 0x0F at pos 0x%X\n",
|
|
ScBSBytePosition(bs));
|
|
return((int)(PacketStart+PacketLength));
|
|
break;
|
|
case PACK_START_BASE:
|
|
sc_dprintf("Pack Start=0x%X Length=0x%X\n",
|
|
ScBSBytePosition(bs), 8);
|
|
ScBSSkipBits(bs, 8*8);
|
|
break;
|
|
default:
|
|
PacketLength=(unsigned int)ScBSGetBits(bs, 16)*8;
|
|
ScBSSkipBits(bs, (unsigned int)PacketLength);
|
|
break;
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
#endif /* MPEG_SUPPORT */
|
|
|
|
/*
|
|
** Name: SaOpenCodec
|
|
** Purpose: Open the specified codec. Return stat code.
|
|
**
|
|
** Args: CodecType = SA_MPEG_ENCODE & SA_MPEG_DECODE are the only
|
|
** recognized codec for now.
|
|
** Sah = handle to software codec's Info structure.
|
|
*/
|
|
SaStatus_t SaOpenCodec (SaCodecType_e CodecType, SaHandle_t *Sah)
|
|
{
|
|
int stat;
|
|
SaCodecInfo_t *Info = NULL;
|
|
|
|
if ((CodecType != SA_PCM_DECODE)
|
|
&& (CodecType != SA_PCM_ENCODE)
|
|
#ifdef MPEG_SUPPORT
|
|
&& (CodecType != SA_MPEG_DECODE)
|
|
&& (CodecType != SA_MPEG_ENCODE)
|
|
#endif /* MPEG_SUPPORT */
|
|
#ifdef GSM_SUPPORT
|
|
&& (CodecType != SA_GSM_DECODE)
|
|
&& (CodecType != SA_GSM_ENCODE)
|
|
#endif /* GSM_SUPPORT */
|
|
#ifdef AC3_SUPPORT
|
|
&& (CodecType != SA_AC3_DECODE)
|
|
/* && (CodecType != SA_AC3_ENCODE) */
|
|
#endif /* AC3_SUPPORT */
|
|
#ifdef G723_SUPPORT
|
|
&& (CodecType != SA_G723_DECODE)
|
|
&& (CodecType != SA_G723_ENCODE)
|
|
#endif /* G723_SUPPORT */
|
|
)
|
|
return(SaErrorCodecType);
|
|
|
|
if (!Sah)
|
|
return (SaErrorBadPointer);
|
|
|
|
/*
|
|
** Allocate memory for the Codec Info structure:
|
|
*/
|
|
if ((Info = (SaCodecInfo_t *)ScAlloc(sizeof(SaCodecInfo_t))) == NULL)
|
|
return (SaErrorMemory);
|
|
|
|
Info->Type = CodecType;
|
|
Info->CallbackFunction=NULL;
|
|
Info->BSIn = NULL;
|
|
Info->BSOut = NULL;
|
|
stat = ScBufQueueCreate(&Info->Q);
|
|
if (stat != NoErrors)
|
|
return(stat);
|
|
|
|
/*
|
|
** Allocate memory for Info structure and clear it
|
|
*/
|
|
switch(CodecType)
|
|
{
|
|
case SA_PCM_DECODE:
|
|
case SA_PCM_ENCODE:
|
|
break;
|
|
|
|
#ifdef MPEG_SUPPORT
|
|
case SA_MPEG_DECODE:
|
|
{
|
|
SaMpegDecompressInfo_t *MDInfo;
|
|
if ((MDInfo = (SaMpegDecompressInfo_t *)
|
|
ScAlloc (sizeof(SaMpegDecompressInfo_t))) == NULL)
|
|
return(SaErrorMemory);
|
|
Info->MDInfo = MDInfo;
|
|
stat = sa_InitMpegDecoder (Info);
|
|
RETURN_ON_ERROR(stat);
|
|
}
|
|
break;
|
|
|
|
case SA_MPEG_ENCODE:
|
|
{
|
|
SaMpegCompressInfo_t *MCInfo;
|
|
if ((MCInfo = (SaMpegCompressInfo_t *)
|
|
ScAlloc (sizeof(SaMpegCompressInfo_t))) == NULL)
|
|
return(SaErrorMemory);
|
|
Info->MCInfo = MCInfo;
|
|
stat = sa_InitMpegEncoder (Info);
|
|
RETURN_ON_ERROR(stat);
|
|
}
|
|
break;
|
|
#endif /* MPEG_SUPPORT */
|
|
|
|
#ifdef AC3_SUPPORT
|
|
case SA_AC3_DECODE:
|
|
/* case SA_AC3_ENCODE: */
|
|
{
|
|
SaAC3DecompressInfo_t *AC3Info;
|
|
if ((AC3Info = (SaAC3DecompressInfo_t *)
|
|
ScAlloc (sizeof(SaAC3DecompressInfo_t))) == NULL)
|
|
return(SaErrorMemory);
|
|
Info->AC3Info = AC3Info;
|
|
|
|
/* Initialize Dolby subroutine */
|
|
stat = sa_InitAC3Decoder(Info);
|
|
}
|
|
break;
|
|
#endif /* AC3_SUPPORT */
|
|
|
|
|
|
#ifdef GSM_SUPPORT
|
|
case SA_GSM_DECODE:
|
|
case SA_GSM_ENCODE:
|
|
{
|
|
SaGSMInfo_t *GSMInfo;
|
|
if ((GSMInfo = (SaGSMInfo_t *)ScAlloc (sizeof(SaGSMInfo_t)))==NULL)
|
|
return(SaErrorMemory);
|
|
Info->GSMInfo = GSMInfo;
|
|
stat = sa_InitGSM(GSMInfo);
|
|
RETURN_ON_ERROR(stat);
|
|
}
|
|
break;
|
|
#endif /* GSM_SUPPORT */
|
|
|
|
#ifdef G723_SUPPORT
|
|
case SA_G723_DECODE:
|
|
{
|
|
SaG723Info_t *pSaG723Info;
|
|
if ((pSaG723Info = (SaG723Info_t *)
|
|
ScAlloc (sizeof(SaG723Info_t))) == NULL)
|
|
return(SaErrorMemory);
|
|
|
|
Info->pSaG723Info = pSaG723Info;
|
|
saG723DecompressInit(pSaG723Info);
|
|
}
|
|
break;
|
|
|
|
case SA_G723_ENCODE:
|
|
{
|
|
SaG723Info_t *pSaG723Info;
|
|
if ((pSaG723Info = (SaG723Info_t *)
|
|
ScAlloc (sizeof(SaG723Info_t))) == NULL)
|
|
return(SaErrorMemory);
|
|
|
|
Info->pSaG723Info = pSaG723Info;
|
|
saG723CompressInit(pSaG723Info);
|
|
SaSetParamInt((SaHandle_t)Info, SA_PARAM_BITRATE, 6400);
|
|
}
|
|
break;
|
|
#endif /* G723_SUPPORT */
|
|
|
|
default:
|
|
return(SaErrorCodecType);
|
|
}
|
|
*Sah = (SaHandle_t) Info; /* Return handle */
|
|
Info->wfIn=NULL;
|
|
Info->wfOut=NULL;
|
|
|
|
return(NoErrors);
|
|
}
|
|
|
|
/*
|
|
** Name: SaCloseCodec
|
|
** Purpose: Closes the specified codec. Free the Info structure
|
|
**
|
|
** Args: Sah = handle to software codec's Info structure.
|
|
**
|
|
*/
|
|
SaStatus_t SaCloseCodec (SaHandle_t Sah)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
|
|
if (!Info)
|
|
return(SaErrorCodecHandle);
|
|
|
|
ScBufQueueDestroy(Info->Q);
|
|
|
|
switch (Info->Type)
|
|
{
|
|
#ifdef MPEG_SUPPORT
|
|
case SA_MPEG_DECODE:
|
|
if (Info->MDInfo)
|
|
{
|
|
sa_EndMpegDecoder(Info);
|
|
ScFree(Info->MDInfo);
|
|
}
|
|
break;
|
|
case SA_MPEG_ENCODE:
|
|
if (Info->MCInfo)
|
|
{
|
|
sa_EndMpegEncoder(Info);
|
|
ScFree(Info->MCInfo);
|
|
}
|
|
break;
|
|
#endif /* MPEG_SUPPORT */
|
|
#ifdef AC3_SUPPORT
|
|
case SA_AC3_DECODE:
|
|
/* case SA_AC3_ENCODE: */
|
|
sa_EndAC3Decoder(Info);
|
|
if (Info->AC3Info)
|
|
ScFree(Info->AC3Info);
|
|
break;
|
|
#endif /* AC3_SUPPORT */
|
|
#ifdef GSM_SUPPORT
|
|
case SA_GSM_DECODE:
|
|
case SA_GSM_ENCODE:
|
|
if (Info->GSMInfo)
|
|
ScFree(Info->GSMInfo);
|
|
break;
|
|
#endif /* GSM_SUPPORT */
|
|
|
|
#ifdef G723_SUPPORT
|
|
case SA_G723_DECODE:
|
|
if (Info->pSaG723Info)
|
|
{
|
|
saG723DecompressFree(Info->pSaG723Info);
|
|
ScFree(Info->pSaG723Info);
|
|
}
|
|
break;
|
|
case SA_G723_ENCODE:
|
|
if (Info->pSaG723Info)
|
|
{
|
|
saG723CompressFree(Info->pSaG723Info);
|
|
ScFree(Info->pSaG723Info);
|
|
}
|
|
break;
|
|
#endif /* G723_SUPPORT */
|
|
}
|
|
|
|
if (Info->wfIn)
|
|
ScFree(Info->wfIn);
|
|
if (Info->wfOut)
|
|
ScFree(Info->wfOut);
|
|
|
|
/*
|
|
** Free Info structure
|
|
*/
|
|
if (Info->BSIn)
|
|
ScBSDestroy(Info->BSIn);
|
|
if (Info->BSOut)
|
|
ScBSDestroy(Info->BSOut);
|
|
|
|
ScFree(Info);
|
|
|
|
return(NoErrors);
|
|
}
|
|
|
|
/*
|
|
** Name: SaRegisterCallback
|
|
** Purpose: Specify the user-function that will be called during processing
|
|
** to determine if the codec should abort the frame.
|
|
** Args: Sah = handle to software codec's Info structure.
|
|
** Callback = callback function to register
|
|
**
|
|
*/
|
|
SaStatus_t SaRegisterCallback (SaHandle_t Sah,
|
|
int (*Callback)(SaHandle_t, SaCallbackInfo_t *, SaInfo_t *),
|
|
void *UserData)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
|
|
if (!Info)
|
|
return(SaErrorCodecHandle);
|
|
|
|
if (!Callback)
|
|
return(SaErrorBadPointer);
|
|
|
|
Info->CallbackFunction = Callback;
|
|
if (Info->BSIn)
|
|
{
|
|
Info->BSIn->Callback=(int (*)(ScHandle_t, ScCallbackInfo_t *, void *))Callback;
|
|
Info->BSIn->UserData=UserData;
|
|
}
|
|
if (Info->BSOut)
|
|
{
|
|
Info->BSOut->Callback=(int (*)(ScHandle_t, ScCallbackInfo_t *, void *))Callback;
|
|
Info->BSOut->UserData=UserData;
|
|
}
|
|
return(NoErrors);
|
|
}
|
|
|
|
/*
|
|
** Name: SaGetInputBitstream
|
|
** Purpose: Returns the current input bitstream being used by
|
|
** the Codec.
|
|
** Return: NULL if there no associated bitstream
|
|
*/
|
|
ScBitstream_t *SaGetInputBitstream (SaHandle_t Sah)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
|
|
if (Info)
|
|
return(Info->BSIn);
|
|
return(NULL);
|
|
}
|
|
|
|
/***************************** Decompression *******************************/
|
|
/*
|
|
** Name: SaDecompressQuery
|
|
** Purpose: Check if input and output formats are supported.
|
|
*/
|
|
SaStatus_t SaDecompressQuery(SaHandle_t Sah, WAVEFORMATEX *wfIn,
|
|
WAVEFORMATEX *wfOut)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
|
|
/*
|
|
* This stuff should really be pushed down to the individual codecs
|
|
* unless it has to be here - tfm
|
|
*/
|
|
if (!Info)
|
|
return(SaErrorCodecHandle);
|
|
|
|
if (wfIn)
|
|
{
|
|
if (wfIn->nChannels!=1 && wfIn->nChannels!=2)
|
|
return(SaErrorUnrecognizedFormat);
|
|
}
|
|
if (wfOut)
|
|
{
|
|
if (wfOut->wFormatTag != WAVE_FORMAT_PCM)
|
|
return(SaErrorUnrecognizedFormat);
|
|
if (wfOut->nChannels!=1 && wfOut->nChannels!=2 && wfOut->nChannels!=4)
|
|
return(SaErrorUnrecognizedFormat);
|
|
}
|
|
if (wfIn && wfOut)
|
|
{
|
|
if (wfIn->nSamplesPerSec != wfOut->nSamplesPerSec)
|
|
return(SaErrorUnrecognizedFormat);
|
|
|
|
if (wfIn->wBitsPerSample !=16 &&
|
|
(wfOut->wBitsPerSample !=16 || wfOut->wBitsPerSample !=8))
|
|
return(SaErrorUnrecognizedFormat);
|
|
}
|
|
return(SaErrorNone);
|
|
}
|
|
|
|
/*
|
|
** Name: SaDecompressBegin
|
|
** Purpose: Initialize the Decompression Codec. Call after SaOpenCodec &
|
|
** before SaDecompress (SaDecompress will call SaDecompressBegin
|
|
** on first call to codec after open if user doesn't call it)
|
|
**
|
|
** Args: Sah = handle to software codec's Info structure.
|
|
** wfIn = format of input (compressed) audio
|
|
** wfOut = format of output (uncompressed) audio
|
|
*/
|
|
SaStatus_t SaDecompressBegin (SaHandle_t Sah, WAVEFORMATEX *wfIn,
|
|
WAVEFORMATEX *wfOut)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
SaStatus_t status;
|
|
|
|
if (!Info)
|
|
return(SaErrorCodecHandle);
|
|
|
|
if (!wfIn || !wfOut)
|
|
return(SaErrorBadPointer);
|
|
|
|
status=SaDecompressQuery(Sah, wfIn, wfOut);
|
|
if (status!=SaErrorNone)
|
|
return(status);
|
|
|
|
switch (Info->Type)
|
|
{
|
|
case SA_PCM_DECODE:
|
|
break;
|
|
#ifdef MPEG_SUPPORT
|
|
case SA_MPEG_DECODE:
|
|
if (Info->MDInfo->DecompressStarted = FALSE)
|
|
Info->MDInfo->DecompressStarted = TRUE;
|
|
break;
|
|
#endif /* MPEG_SUPPORT */
|
|
#ifdef AC3_SUPPORT
|
|
case SA_AC3_DECODE:
|
|
if (Info->AC3Info->DecompressStarted = FALSE)
|
|
Info->AC3Info->DecompressStarted = TRUE;
|
|
break;
|
|
#endif /* AC3_SUPPORT */
|
|
|
|
#ifdef G723_SUPPORT
|
|
/*
|
|
case SA_G723_DECODE:
|
|
if (Info->pSaG723Info->DecompressStarted = FALSE)
|
|
Info->pSaG723Info->DecompressStarted = TRUE;
|
|
break;
|
|
*/
|
|
#endif /* G723_SUPPORT */
|
|
}
|
|
if ((Info->wfIn = (WAVEFORMATEX *)ScAlloc(sizeof(WAVEFORMATEX)+
|
|
wfIn->cbSize)) == NULL)
|
|
return (SaErrorMemory);
|
|
if ((Info->wfOut = (WAVEFORMATEX *)ScAlloc(sizeof(WAVEFORMATEX)+
|
|
wfOut->cbSize)) == NULL)
|
|
return (SaErrorMemory);
|
|
memcpy(Info->wfOut, wfOut, sizeof(WAVEFORMATEX)+wfOut->cbSize);
|
|
memcpy(Info->wfIn, wfIn, sizeof(WAVEFORMATEX)+wfIn->cbSize);
|
|
return(NoErrors);
|
|
}
|
|
|
|
/*
|
|
** Name: SaDecompress
|
|
** Purpose: Decompress a frame CompData -> PCM
|
|
**
|
|
** Args: Sah = handle to software codec's Info structure.
|
|
** CompData = Pointer to compressed data (INPUT)
|
|
** CompLen = Length of CompData buffer
|
|
** DcmpData = buffer for decompressed data (OUTPUT)
|
|
** DcmpLen = Size of output buffer
|
|
**
|
|
*/
|
|
SaStatus_t SaDecompress (SaHandle_t Sah, u_char *CompData, unsigned int CompLen,
|
|
u_char *DcmpData, unsigned int *DcmpLen)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
unsigned int MaxDcmpLen = *DcmpLen;
|
|
int stat=NoErrors;
|
|
|
|
|
|
if (Sah==NULL)
|
|
return(SaErrorCodecHandle);
|
|
|
|
if (!DcmpData || !DcmpLen)
|
|
return(SaErrorBadPointer);
|
|
|
|
switch (Info->Type)
|
|
{
|
|
#ifdef MPEG_SUPPORT
|
|
case SA_MPEG_DECODE:
|
|
stat=sa_DecompressMPEG(Info, DcmpData, MaxDcmpLen, DcmpLen);
|
|
Info->Info.NumBytesOut += *DcmpLen;
|
|
break;
|
|
case SA_PCM_DECODE:
|
|
stat=ScBSGetBytes(Info->BSIn, DcmpData, MaxDcmpLen, DcmpLen);
|
|
Info->Info.NumBytesIn += *DcmpLen;
|
|
Info->Info.NumBytesOut += *DcmpLen;
|
|
break;
|
|
#endif /* MPEG_SUPPORT */
|
|
|
|
#ifdef AC3_SUPPORT
|
|
case SA_AC3_DECODE:
|
|
stat=sa_DecompressAC3(Info, &DcmpData, MaxDcmpLen, DcmpLen);
|
|
Info->Info.NumBytesOut += *DcmpLen;
|
|
break;
|
|
#endif /* AC3_SUPPORT */
|
|
|
|
#ifdef GSM_SUPPORT
|
|
case SA_GSM_DECODE:
|
|
stat=sa_GSMDecode(Info->GSMInfo, CompData, (word *)DcmpData);
|
|
if (stat==NoErrors)
|
|
{
|
|
*DcmpLen = 160 * 2;
|
|
Info->Info.NumBytesIn += 33;
|
|
Info->Info.NumBytesOut += 160 * 2;
|
|
}
|
|
else
|
|
*DcmpLen = 0;
|
|
break;
|
|
#endif /* GSM_SUPPORT */
|
|
|
|
#ifdef G723_SUPPORT
|
|
case SA_G723_DECODE:
|
|
//Can add a Param for to have CRC or not
|
|
{
|
|
word Crc = 0;
|
|
|
|
stat = saG723Decompress( Info,(word *)DcmpData,
|
|
(char *)CompData, Crc ) ;
|
|
if(stat == SaErrorNone)
|
|
{
|
|
*DcmpLen = 480; //G723 240 samples(16-bit)= 240*2 = 480 bytes
|
|
Info->Info.NumBytesOut += *DcmpLen;
|
|
}
|
|
else
|
|
*DcmpLen = 0;
|
|
}
|
|
break;
|
|
/*
|
|
case SA_PCM_DECODE:
|
|
stat=ScBSGetBytes(Info->BSIn, DcmpData, MaxDcmpLen, DcmpLen);
|
|
Info->Info.NumBytesIn += *DcmpLen;
|
|
Info->Info.NumBytesOut += *DcmpLen;
|
|
break;
|
|
*/
|
|
#endif /* G723_SUPPORT */
|
|
default:
|
|
*DcmpLen=0;
|
|
return(SaErrorUnrecognizedFormat);
|
|
}
|
|
#if 0
|
|
if (*DcmpLen && Info->CallbackFunction)
|
|
{
|
|
SaCallbackInfo_t CB;
|
|
CB.Message = CB_FRAME_READY;
|
|
CB.Data = DcmpData;
|
|
CB.DataSize = CB_DATA_AUDIO;
|
|
CB.DataSize = MaxDcmpLen;
|
|
CB.DataUsed = *DcmpLen;
|
|
CB.Action = CB_ACTION_CONTINUE;
|
|
(*Info->CallbackFunction)(Sah, &CB, &Info->Info);
|
|
}
|
|
#endif
|
|
|
|
return(stat);
|
|
}
|
|
|
|
/*
|
|
** Name: SaDecompressEx
|
|
** Purpose: Decompress a frame CompData -> PCM
|
|
**
|
|
** Args: Sah = handle to software codec's Info structure.
|
|
** CompData = Pointer to compressed data (INPUT)
|
|
** CompLen = Length of CompData buffer
|
|
** DcmpData = Array of pointers to buffer for decompressed data (OUTPUT)
|
|
** DcmpLen = Size of decompressed buffers (all must be the same size)
|
|
**
|
|
*/
|
|
SaStatus_t SaDecompressEx (SaHandle_t Sah, u_char *CompData, unsigned int CompLen,
|
|
u_char **DcmpData, unsigned int *DcmpLen)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
unsigned int MaxDcmpLen = *DcmpLen;
|
|
int stat=NoErrors;
|
|
|
|
|
|
if (Sah==NULL)
|
|
return(SaErrorCodecHandle);
|
|
|
|
if (!DcmpData || !DcmpLen)
|
|
return(SaErrorBadPointer);
|
|
|
|
switch (Info->Type)
|
|
{
|
|
#ifdef AC3_SUPPORT
|
|
case SA_AC3_DECODE:
|
|
|
|
stat=sa_DecompressAC3(Info, DcmpData, MaxDcmpLen, DcmpLen);
|
|
Info->Info.NumBytesOut += *DcmpLen;
|
|
break;
|
|
#endif /* AC3_SUPPORT */
|
|
}
|
|
|
|
return(stat);
|
|
}
|
|
|
|
|
|
/*
|
|
** Name: SaDecompressEnd
|
|
** Purpose: Terminate the Decompression Codec. Call after all calls to
|
|
** SaDecompress are done.
|
|
**
|
|
** Args: Sah = handle to software codec's Info structure.
|
|
*/
|
|
SaStatus_t SaDecompressEnd (SaHandle_t Sah)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
|
|
if (!Info)
|
|
return(SaErrorCodecHandle);
|
|
|
|
switch (Info->Type)
|
|
{
|
|
#ifdef MPEG_SUPPORT
|
|
case SA_MPEG_DECODE:
|
|
Info->MDInfo->DecompressStarted = FALSE;
|
|
break;
|
|
#endif /* MPEG_SUPPORT */
|
|
#ifdef AC3_SUPPORT
|
|
case SA_AC3_DECODE:
|
|
Info->AC3Info->DecompressStarted = FALSE;
|
|
break;
|
|
#endif /* AC3_SUPPORT */
|
|
#ifdef G723_SUPPORT
|
|
case SA_G723_DECODE:
|
|
//Info->pSaG723Info->DecompressStarted = FALSE;
|
|
break;
|
|
#endif /* G723_SUPPORT */
|
|
default:
|
|
break;
|
|
}
|
|
if (Info->BSIn)
|
|
ScBSReset(Info->BSIn); /* frees up any remaining compressed buffers */
|
|
return(NoErrors);
|
|
}
|
|
|
|
/****************************** Compression ********************************/
|
|
/*
|
|
** Name: SaCompressQuery
|
|
** Purpose: Check if input and output formats are supported.
|
|
*/
|
|
SaStatus_t SaCompressQuery(SaHandle_t Sah, WAVEFORMATEX *wfIn,
|
|
WAVEFORMATEX *wfOut)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
if (!Info)
|
|
return(SaErrorCodecHandle);
|
|
|
|
if (!wfIn || !wfOut)
|
|
return(SaErrorBadPointer);
|
|
|
|
if (wfIn)
|
|
{
|
|
if (wfIn->wFormatTag != WAVE_FORMAT_PCM)
|
|
return(SaErrorUnrecognizedFormat);
|
|
if (wfIn->nChannels!=1 && wfIn->nChannels!=2)
|
|
return(SaErrorUnrecognizedFormat);
|
|
}
|
|
if (wfOut)
|
|
{
|
|
if (wfOut->nChannels!=1 && wfOut->nChannels!=2)
|
|
return(SaErrorUnrecognizedFormat);
|
|
}
|
|
|
|
if (wfIn && wfOut)
|
|
{
|
|
if (wfIn->nSamplesPerSec != wfOut->nSamplesPerSec)
|
|
return(SaErrorUnrecognizedFormat);
|
|
|
|
if (wfIn->wBitsPerSample!=16 &&
|
|
(wfOut->wBitsPerSample !=16 || wfOut->wBitsPerSample !=8))
|
|
return(SaErrorUnrecognizedFormat);
|
|
}
|
|
return(SaErrorNone);
|
|
}
|
|
|
|
/*
|
|
** Name: SaCompressBegin
|
|
** Purpose: Initialize the Compression Codec. Call after SaOpenCodec &
|
|
** before SaCompress (SaCompress will call SaCompressBegin
|
|
** on first call to codec after open if user doesn't call it)
|
|
**
|
|
** Args: Sah = handle to software codec's Info structure.
|
|
** wfIn = format of input (uncompressed) audio
|
|
** wfOut = format of output (compressed) audio
|
|
*/
|
|
SaStatus_t SaCompressBegin (SaHandle_t Sah, WAVEFORMATEX *wfIn,
|
|
WAVEFORMATEX *wfOut)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
SaStatus_t status;
|
|
|
|
if (!Info)
|
|
return(SaErrorCodecHandle);
|
|
|
|
if (!wfIn || !wfOut)
|
|
return(SaErrorBadPointer);
|
|
|
|
status=SaCompressQuery(Sah, wfIn, wfOut);
|
|
if (status!=SaErrorNone)
|
|
return(status);
|
|
|
|
switch (Info->Type)
|
|
{
|
|
#ifdef MPEG_SUPPORT
|
|
case SA_MPEG_ENCODE:
|
|
SaSetParamInt(Sah, SA_PARAM_SAMPLESPERSEC, wfIn->nSamplesPerSec);
|
|
SaSetParamInt(Sah, SA_PARAM_CHANNELS, wfIn->nChannels);
|
|
sa_MpegVerifyEncoderSettings(Sah);
|
|
if (Info->MCInfo->CompressStarted = FALSE)
|
|
Info->MCInfo->CompressStarted = TRUE;
|
|
break;
|
|
#endif /* MPEG_SUPPORT */
|
|
#ifdef GSM_SUPPORT
|
|
case SA_GSM_ENCODE:
|
|
break;
|
|
#endif /* GSM_SUPPORT */
|
|
#ifdef AC3_SUPPORT
|
|
#if 0
|
|
case SA_AC3_ENCODE:
|
|
break;
|
|
#endif
|
|
#endif /* AC3_SUPPORT */
|
|
#ifdef G723_SUPPORT
|
|
case SA_G723_ENCODE:
|
|
//SaSetParamInt(Sah, SA_PARAM_SAMPLESPERSEC, wfIn->nSamplesPerSec);
|
|
//SaSetParamInt(Sah, SA_PARAM_CHANNELS, wfIn->nChannels);
|
|
//sa_MpegVerifyEncoderSettings(Sah);
|
|
/*
|
|
if (Info->pSaG723Info->CompressStarted = FALSE)
|
|
Info->pSaG723Info->CompressStarted = TRUE;
|
|
*/
|
|
break;
|
|
#endif /* G723_SUPPORT */
|
|
case SA_PCM_ENCODE:
|
|
break;
|
|
default:
|
|
return(SaErrorUnrecognizedFormat);
|
|
}
|
|
if ((Info->wfIn = (WAVEFORMATEX *)ScAlloc(sizeof(WAVEFORMATEX)+
|
|
wfIn->cbSize)) == NULL)
|
|
return (SaErrorMemory);
|
|
if ((Info->wfOut = (WAVEFORMATEX *)ScAlloc(sizeof(WAVEFORMATEX)+
|
|
wfOut->cbSize)) == NULL)
|
|
return (SaErrorMemory);
|
|
memcpy(Info->wfOut, wfOut, sizeof(WAVEFORMATEX)+wfOut->cbSize);
|
|
memcpy(Info->wfIn, wfIn, sizeof(WAVEFORMATEX)+wfIn->cbSize);
|
|
return(NoErrors);
|
|
}
|
|
|
|
/*
|
|
** Name: SaCompress
|
|
** Purpose: Compress PCM audio ->CompData
|
|
**
|
|
** Args: Sah = handle to software codec's Info structure.
|
|
** DcmpData = buffer for decompressed data (INPUT)
|
|
** DcmpLen = Number of Bytes Compressed (return bytes processed)
|
|
** CompData = Pointer to compressed data (OUTPUT)
|
|
** CompLen = Length of CompData buffer
|
|
**
|
|
*/
|
|
SaStatus_t SaCompress(SaHandle_t Sah,
|
|
u_char *DcmpData, unsigned int *DcmpLen,
|
|
u_char *CompData, unsigned int *CompLen)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
unsigned int MaxCompLen = *CompLen, NumBytesIn=0;
|
|
int stat=NoErrors;
|
|
|
|
if (Sah==NULL)
|
|
return(SaErrorCodecHandle);
|
|
|
|
if (!DcmpData || !DcmpLen || !CompLen)
|
|
return(SaErrorBadPointer);
|
|
|
|
*CompLen = 0;
|
|
switch (Info->Type)
|
|
{
|
|
#ifdef MPEG_SUPPORT
|
|
case SA_MPEG_ENCODE:
|
|
{
|
|
unsigned int DcmpBytes, CompBytes, Offset;
|
|
Offset=0;
|
|
*CompLen=0;
|
|
do {
|
|
DcmpBytes=*DcmpLen-Offset;
|
|
if (DcmpBytes<sa_GetMPEGSampleSize(Info)*2)
|
|
break;
|
|
_SlibDebug(_DEBUG_,
|
|
printf("sa_CompressMPEG(Offset=%d) Address=%p Len=%d\n", Offset,
|
|
DcmpData, DcmpBytes) );
|
|
stat=sa_CompressMPEG(Info, DcmpData+Offset, &DcmpBytes,
|
|
&CompBytes);
|
|
if (stat==NoErrors)
|
|
{
|
|
if (CompBytes && Info->CallbackFunction)
|
|
{
|
|
SaCallbackInfo_t CB;
|
|
CB.Message = CB_FRAME_READY;
|
|
CB.Data = DcmpData+Offset;
|
|
CB.DataType = CB_DATA_COMPRESSED;
|
|
CB.DataSize = *DcmpLen-Offset;
|
|
CB.DataUsed = CompBytes;
|
|
CB.Action = CB_ACTION_CONTINUE;
|
|
(*Info->CallbackFunction)(Sah, &CB, &Info->Info);
|
|
}
|
|
Offset+=DcmpBytes;
|
|
NumBytesIn += DcmpBytes;
|
|
*CompLen+=CompBytes;
|
|
}
|
|
} while (stat==NoErrors && DcmpBytes>0 && Offset<*DcmpLen);
|
|
}
|
|
break;
|
|
#endif /* MPEG_SUPPORT */
|
|
#ifdef GSM_SUPPORT
|
|
case SA_GSM_ENCODE:
|
|
{
|
|
unsigned int DcmpBytes, CompBytes, Offset;
|
|
Offset=0;
|
|
*CompLen=0;
|
|
if (!Info->BSOut && !CompData)
|
|
return(SaErrorBadPointer);
|
|
do {
|
|
DcmpBytes=*DcmpLen-Offset;
|
|
stat=sa_GSMEncode(Info->GSMInfo, (word *)(DcmpData+Offset),
|
|
&DcmpBytes, CompData, Info->BSOut);
|
|
if (stat==NoErrors)
|
|
{
|
|
Offset+=DcmpBytes;
|
|
NumBytesIn += DcmpBytes;
|
|
*CompLen += 33;
|
|
if (CompData)
|
|
CompData += 33;
|
|
}
|
|
} while (stat==NoErrors && Offset<*DcmpLen);
|
|
}
|
|
break;
|
|
#endif /* GSM_SUPPORT */
|
|
#ifdef AC3_SUPPORT
|
|
#if 0 /* no AC-3 Encode yet */
|
|
case SA_AC3_ENCODE:
|
|
{
|
|
unsigned int DcmpBytes, CompBytes, Offset;
|
|
Offset=0;
|
|
*CompLen=0;
|
|
if (!Info->BSOut && !CompData)
|
|
return(SaErrorBadPointer);
|
|
do {
|
|
DcmpBytes=*DcmpLen-Offset;
|
|
stat=sa_AC3Encode(Info->AC3Info, (word *)(DcmpData+Offset),
|
|
&DcmpBytes, CompData, Info->BSOut);
|
|
if (stat==NoErrors)
|
|
{
|
|
Offset+=DcmpBytes;
|
|
NumBytesIn += DcmpBytes;
|
|
*CompLen += 33;
|
|
if (CompData)
|
|
CompData += 33;
|
|
}
|
|
} while (stat==NoErrors && Offset<*DcmpLen);
|
|
}
|
|
break;
|
|
#endif
|
|
#endif /* AC3_SUPPORT */
|
|
#ifdef G723_SUPPORT
|
|
case SA_G723_ENCODE:
|
|
{
|
|
/* Call SaG723Compress (audiobufsize/480) times
|
|
* Need to store unprocessed stuff in Info->AudiobufUsed.
|
|
* (This is done in SlibWriteAudio)
|
|
* G723 encodes 240 samples at a time.=240*2 =480
|
|
*/
|
|
unsigned int Offset;
|
|
int iTimes = (int)(*DcmpLen / 480);
|
|
int iLoop =0;
|
|
Offset=0;
|
|
*CompLen=0;
|
|
while (stat==SaErrorNone && iLoop<iTimes)
|
|
{
|
|
stat = saG723Compress(Info,(word *)(DcmpData+Offset),
|
|
(char *)CompData);
|
|
Offset+=480; /* Input :240 samples (240*2 = 480 bytes) */
|
|
NumBytesIn += 480;
|
|
*CompLen+=24;/* 24 for 6.3 ;20 for 5.3 rate */
|
|
iLoop++;
|
|
}
|
|
}
|
|
break;
|
|
#endif /* G723_SUPPORT */
|
|
case SA_PCM_ENCODE:
|
|
ScBSPutBytes(Info->BSOut, DcmpData, *DcmpLen);
|
|
*CompLen = *DcmpLen;
|
|
NumBytesIn = *DcmpLen;
|
|
break;
|
|
default:
|
|
*CompLen=0;
|
|
return(SaErrorUnrecognizedFormat);
|
|
}
|
|
*DcmpLen = NumBytesIn;
|
|
Info->Info.NumBytesIn += NumBytesIn;
|
|
Info->Info.NumBytesOut += *CompLen;
|
|
|
|
return(stat);
|
|
}
|
|
|
|
/*
|
|
** Name: SaCompressEnd
|
|
** Purpose: Terminate the Compression Codec. Call after all calls to
|
|
** SaCompress are done.
|
|
**
|
|
** Args: Sah = handle to software codec's Info structure.
|
|
*/
|
|
SaStatus_t SaCompressEnd (SaHandle_t Sah)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
|
|
if (!Info)
|
|
return(SaErrorCodecHandle);
|
|
|
|
switch (Info->Type)
|
|
{
|
|
#ifdef MPEG_SUPPORT
|
|
case SA_MPEG_ENCODE:
|
|
Info->MCInfo->CompressStarted = FALSE;
|
|
break;
|
|
#endif /* MPEG_SUPPORT */
|
|
#ifdef G723_SUPPORT
|
|
case SA_G723_ENCODE:
|
|
//Info->pSaG723Info->CompressStarted = FALSE;
|
|
break;
|
|
#endif /* G723_SUPPORT */
|
|
default:
|
|
break;
|
|
}
|
|
if (Info->BSOut)
|
|
ScBSFlush(Info->BSOut); /* flush out any remaining compressed buffers */
|
|
|
|
/*
|
|
if (Info->CallbackFunction)
|
|
{
|
|
CB.Message = CB_CODEC_DONE;
|
|
CB.Data = NULL;
|
|
CB.DataSize = 0;
|
|
CB.DataUsed = 0;
|
|
CB.DataType = CB_DATA_NONE;
|
|
CB.TimeStamp = 0;
|
|
CB.Flags = 0;
|
|
CB.Value = 0;
|
|
CB.Format = NULL;
|
|
CB.Action = CB_ACTION_CONTINUE;
|
|
(*Info->CallbackFunction)(Sah, &CB, NULL);
|
|
_SlibDebug(_DEBUG_,
|
|
printf("SaDecompressEnd Callback: CB_CODEC_DONE Action = %d\n",
|
|
CB.Action) );
|
|
if (CB.Action == CB_ACTION_END)
|
|
return (ScErrorClientEnd);
|
|
}
|
|
*/
|
|
return(NoErrors);
|
|
}
|
|
|
|
|
|
/***************************** Miscellaneous *******************************/
|
|
/*
|
|
** Name: SaSetDataSource
|
|
** Purpose: Set the data source used by the MPEG bitstream parsing code
|
|
** to either the Buffer Queue or File input. The default is
|
|
** to use the Buffer Queue where data buffers are added by calling
|
|
** SaAddBuffer. When using file IO, the data is read from a file
|
|
** descriptor into a buffer supplied by the user.
|
|
**
|
|
** Args: Sah = handle to software codec's Info structure.
|
|
** Source = SU_USE_QUEUE or SU_USE_FILE
|
|
** Fd = File descriptor to use if Source = SV_USE_FILE
|
|
** Buf = Pointer to buffer to use if Source = SV_USE_FILE
|
|
** BufSize= Size of buffer when Source = SV_USE_FILE
|
|
*/
|
|
SaStatus_t SaSetDataSource (SaHandle_t Sah, int Source, int Fd,
|
|
void *Buffer_UserData, int BufSize)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
int stat=NoErrors;
|
|
int DataType;
|
|
|
|
if (!Info)
|
|
return(SaErrorCodecHandle);
|
|
|
|
if (Info->Type==SA_MPEG_DECODE || Info->Type==SA_GSM_DECODE ||
|
|
Info->Type==SA_AC3_DECODE || Info->Type == SA_G723_DECODE )
|
|
DataType=CB_DATA_COMPRESSED;
|
|
else
|
|
DataType=CB_DATA_AUDIO;
|
|
|
|
if (Info->BSIn)
|
|
{
|
|
ScBSDestroy(Info->BSIn);
|
|
Info->BSIn=NULL;
|
|
}
|
|
|
|
switch (Source)
|
|
{
|
|
#ifdef MPEG_SUPPORT
|
|
case SA_USE_SAME:
|
|
if (Info->Type==SA_MPEG_DECODE)
|
|
ScBSSetFilter(Info->BSIn, MPEGAudioFilter);
|
|
break;
|
|
#endif /* MPEG_SUPPORT */
|
|
case SA_USE_BUFFER:
|
|
stat=ScBSCreateFromBuffer(&Info->BSIn, Buffer_UserData, BufSize);
|
|
#ifdef MPEG_SUPPORT
|
|
if (stat==NoErrors && Info->Type==SA_MPEG_DECODE)
|
|
ScBSSetFilter(Info->BSIn, MPEGAudioFilter);
|
|
#endif /* MPEG_SUPPORT */
|
|
break;
|
|
|
|
case SA_USE_BUFFER_QUEUE:
|
|
stat=ScBSCreateFromBufferQueue(&Info->BSIn, Sah, DataType, Info->Q,
|
|
(int (*)(ScHandle_t, ScCallbackInfo_t *, void *))Info->CallbackFunction,
|
|
(void *)Buffer_UserData);
|
|
break;
|
|
|
|
case SA_USE_FILE:
|
|
stat=ScBSCreateFromFile(&Info->BSIn, Fd, Buffer_UserData, BufSize);
|
|
#ifdef MPEG_SUPPORT
|
|
if (stat==NoErrors && Info->Type==SA_MPEG_DECODE)
|
|
ScBSSetFilter(Info->BSIn, MPEGAudioFilter);
|
|
#endif /* MPEG_SUPPORT */
|
|
break;
|
|
|
|
default:
|
|
stat=SaErrorBadArgument;
|
|
}
|
|
if (stat==NoErrors && Info->BSIn)
|
|
ScBSReset(Info->BSIn);
|
|
return(stat);
|
|
}
|
|
|
|
SaStatus_t SaSetDataDestination (SaHandle_t Sah, int Dest, int Fd,
|
|
void *Buffer_UserData, int BufSize)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
int stat=NoErrors;
|
|
int DataType;
|
|
|
|
if (!Info)
|
|
return(SaErrorCodecHandle);
|
|
|
|
if (Info->Type==SA_MPEG_ENCODE || Info->Type==SA_GSM_ENCODE
|
|
/* || Info->Type==SA_AC3_ENCODE */ ||Info->Type==SA_G723_ENCODE)
|
|
DataType=CB_DATA_COMPRESSED;
|
|
else
|
|
DataType=CB_DATA_AUDIO;
|
|
|
|
if (Info->BSOut)
|
|
{
|
|
ScBSDestroy(Info->BSOut);
|
|
Info->BSOut=NULL;
|
|
}
|
|
|
|
switch (Dest)
|
|
{
|
|
case SA_USE_SAME:
|
|
break;
|
|
case SA_USE_BUFFER:
|
|
stat=ScBSCreateFromBuffer(&Info->BSOut, Buffer_UserData, BufSize);
|
|
break;
|
|
|
|
case SA_USE_BUFFER_QUEUE:
|
|
stat=ScBSCreateFromBufferQueue(&Info->BSOut, Sah, DataType, Info->Q,
|
|
(int (*)(ScHandle_t, ScCallbackInfo_t *, void *))Info->CallbackFunction,
|
|
(void *)Buffer_UserData);
|
|
break;
|
|
|
|
case SA_USE_FILE:
|
|
stat=ScBSCreateFromFile(&Info->BSOut, Fd, Buffer_UserData, BufSize);
|
|
break;
|
|
|
|
default:
|
|
stat=SaErrorBadArgument;
|
|
}
|
|
/*
|
|
if (stat==NoErrors && Info->BSOut)
|
|
ScBSReset(Info->BSOut);
|
|
*/
|
|
return(stat);
|
|
}
|
|
|
|
|
|
/*
|
|
** Name: SaGetDataSource
|
|
** Purpose: Returns the current input bitstream being used by
|
|
** the Codec.
|
|
** Return: NULL if there no associated bitstream
|
|
*/
|
|
ScBitstream_t *SaGetDataSource (SaHandle_t Sah)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
|
|
if (!Info)
|
|
return(NULL);
|
|
|
|
return(Info->BSIn);
|
|
}
|
|
|
|
/*
|
|
** Name: SaGetDataDestination
|
|
** Purpose: Returns the current input bitstream being used by
|
|
** the Codec.
|
|
** Return: NULL if there no associated bitstream
|
|
*/
|
|
ScBitstream_t *SaGetDataDestination(SaHandle_t Sah)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
|
|
if (!Info)
|
|
return(NULL);
|
|
|
|
return(Info->BSOut);
|
|
}
|
|
|
|
/*
|
|
** Name: SaAddBuffer
|
|
** Purpose: Add a buffer of MPEG bitstream data to the CODEC or add an image
|
|
** buffer to be filled by the CODEC (in streaming mode)
|
|
**
|
|
** Args: Sah = handle to software codec's Info structure.
|
|
** BufferInfo = structure describing buffer's address, type & size
|
|
*/
|
|
SaStatus_t SaAddBuffer (SaHandle_t Sah, SaCallbackInfo_t *BufferInfo)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
|
|
if (!Info)
|
|
return(SaErrorCodecHandle);
|
|
|
|
if (BufferInfo->DataType != CB_DATA_COMPRESSED)
|
|
return(SaErrorBadArgument);
|
|
|
|
if (!BufferInfo->Data || (BufferInfo->DataSize <= 0))
|
|
return(SaErrorBadArgument);
|
|
|
|
ScBufQueueAdd(Info->Q, BufferInfo->Data, BufferInfo->DataSize);
|
|
|
|
return(NoErrors);
|
|
}
|
|
|
|
#ifdef MPEG_SUPPORT
|
|
/*
|
|
** Name: sa_GetMpegAudioInfo()
|
|
** Purpose: Extract info about audio packets in an MPEG file.
|
|
** Notes: If an "info" structure is passed to this function,
|
|
** the entire file will be read for extended info.
|
|
** Return: Not 0 = error
|
|
*/
|
|
SaStatus_t sa_GetMpegAudioInfo(int fd, WAVEFORMATEX *wf, SaInfo_t *info)
|
|
{
|
|
int stat, sync;
|
|
ScBitstream_t *bs;
|
|
SaFrameParams_t fr_ps;
|
|
SaLayer_t layer;
|
|
unsigned long aframes=0, samples=0;
|
|
/* Default info parameters */
|
|
if (info)
|
|
{
|
|
info->Name[0]=0;
|
|
info->Description[0]=0;
|
|
info->Version=0;
|
|
info->CodecStarted=FALSE;
|
|
info->MS=0;
|
|
info->NumBytesIn=0;
|
|
info->NumBytesOut=0;
|
|
info->NumFrames=0;
|
|
info->TotalFrames=0;
|
|
info->TotalMS=0;
|
|
}
|
|
|
|
/* Default wave parameters */
|
|
wf->wFormatTag = WAVE_FORMAT_PCM;
|
|
wf->nChannels = 2;
|
|
wf->nSamplesPerSec = 44100;
|
|
wf->wBitsPerSample = 16;
|
|
wf->cbSize = 0;
|
|
|
|
stat=ScBSCreateFromFile(&bs, fd, NULL, 1024);
|
|
if (stat!=NoErrors)
|
|
{
|
|
fprintf(stderr, "Error creating bitstream.\n");
|
|
return(-1);
|
|
}
|
|
if (ScBSPeekBits(bs, PACK_START_CODE_LEN)!=PACK_START_CODE_BIN
|
|
&& ScBSPeekBits(bs, MPEG_SYNC_WORD_LEN)!=MPEG_SYNC_WORD)
|
|
stat=SaErrorUnrecognizedFormat;
|
|
else
|
|
{
|
|
if (ScBSPeekBits(bs, MPEG_SYNC_WORD_LEN)==MPEG_SYNC_WORD)
|
|
printf("No MPEG packs found in file; assuming Audio stream only.\n");
|
|
else
|
|
ScBSSetFilter(bs, MPEGAudioFilter); /* Use the MPEG audio filter */
|
|
|
|
fr_ps.header = &layer;
|
|
fr_ps.tab_num = -1; /* no table loaded */
|
|
fr_ps.alloc = NULL;
|
|
|
|
sync = ScBSSeekAlign(bs, MPEG_SYNC_WORD, MPEG_SYNC_WORD_LEN);
|
|
if (!sync) {
|
|
sc_vprintf(stderr,"sa_GetMpegAudioInfo: Frame cannot be located\n");
|
|
return(SaErrorSyncLost);
|
|
}
|
|
/* Decode the first header to see what kind of audio we have */
|
|
sa_DecodeInfo(bs, &fr_ps);
|
|
sa_hdr_to_frps(&fr_ps);
|
|
#ifdef _VERBOSE_
|
|
sa_ShowHeader(&fr_ps);
|
|
#endif
|
|
|
|
/* Save no. of channels & sample rate return parameters for caller */
|
|
wf->nChannels = fr_ps.stereo;
|
|
wf->nSamplesPerSec = s_freq_int[fr_ps.header->sampling_frequency];
|
|
wf->wBitsPerSample = 16;
|
|
stat=SaErrorNone;
|
|
if (info) /* Read through all frames if there's a info structure */
|
|
{
|
|
sc_vprintf("Counting frames...\n");
|
|
aframes=0;
|
|
while (!bs->EOI && sync)
|
|
{
|
|
sync = ScBSSeekAlign(bs, MPEG_SYNC_WORD, MPEG_SYNC_WORD_LEN);
|
|
if (sync)
|
|
{
|
|
sc_dprintf("0x%X: Frame found\n",
|
|
ScBSBytePosition(bs)-4);
|
|
aframes++;
|
|
}
|
|
sa_DecodeInfo(bs, &fr_ps);
|
|
if (wf->nChannels<2) /* take the maximum number of channels */
|
|
{
|
|
sa_hdr_to_frps(&fr_ps);
|
|
wf->nChannels = fr_ps.stereo;
|
|
}
|
|
if (layer.lay==1)
|
|
samples+=384;
|
|
else
|
|
samples+=1152;
|
|
|
|
}
|
|
info->TotalFrames=aframes;
|
|
info->TotalMS=(samples*1000)/wf->nSamplesPerSec;
|
|
info->NumBytesOut=samples * wf->nChannels * 2;
|
|
sc_vprintf("Total Audio Frames = %u Bytes = %d MS = %d\n",
|
|
info->TotalFrames, info->NumBytesOut, info->TotalMS);
|
|
}
|
|
}
|
|
/* Reset the bitstream back to the beginning */
|
|
ScBSReset(bs);
|
|
/* Close the bit stream */
|
|
ScBSDestroy(bs);
|
|
/* Calculate additional parameters */
|
|
wf->nBlockAlign = (wf->wBitsPerSample>>3) * wf->nChannels;
|
|
wf->nAvgBytesPerSec = wf->nBlockAlign*wf->nSamplesPerSec;
|
|
return(stat);
|
|
}
|
|
#endif /* MPEG_SUPPORT */
|
|
|
|
/*
|
|
** Name: sa_ConvertFormat()
|
|
** Purpose: Do simple PCM data conversion (i.e. 16 to 8 bit,
|
|
** Stereo to Mono, etc.)
|
|
*/
|
|
static int sa_ConvertPCMFormat(SaCodecInfo_t *Info, u_char *data, int length)
|
|
{
|
|
int skip, rbytes;
|
|
u_char *fromptr, *toptr;
|
|
/* convert 16 bit to 8 bit if necessary */
|
|
if (Info->wfOut->wBitsPerSample == 8)
|
|
{
|
|
if (Info->wfOut->nChannels==1 && Info->wfOut->nChannels==2)
|
|
skip=4;
|
|
else
|
|
skip=2;
|
|
length/=skip;
|
|
toptr = data;
|
|
fromptr = data+1;
|
|
for (rbytes=length; rbytes; rbytes--, toptr++, fromptr+=skip)
|
|
*toptr = *fromptr;
|
|
}
|
|
return(length);
|
|
}
|
|
|
|
SaStatus_t SaSetParamBoolean(SaHandle_t Sah, SaParameter_t param,
|
|
ScBoolean_t value)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
if (!Info)
|
|
return(SaErrorCodecHandle);
|
|
_SlibDebug(_VERBOSE_, printf("SaSetParamBoolean()\n") );
|
|
switch (Info->Type)
|
|
{
|
|
#ifdef MPEG_SUPPORT
|
|
case SA_MPEG_ENCODE:
|
|
saMpegSetParamBoolean(Sah, param, value);
|
|
break;
|
|
#endif
|
|
|
|
#ifdef G723_SUPPORT
|
|
case SA_G723_ENCODE:
|
|
saG723SetParamBoolean(Sah, param, value);
|
|
break;
|
|
#endif
|
|
default:
|
|
return(SaErrorCodecType);
|
|
}
|
|
return(NoErrors);
|
|
}
|
|
|
|
SaStatus_t SaSetParamInt(SaHandle_t Sah, SaParameter_t param, qword value)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
if (!Info)
|
|
return(SaErrorCodecHandle);
|
|
_SlibDebug(_VERBOSE_, printf("SaSetParamInt()\n") );
|
|
switch (Info->Type)
|
|
{
|
|
#ifdef MPEG_SUPPORT
|
|
case SA_MPEG_DECODE:
|
|
case SA_MPEG_ENCODE:
|
|
saMpegSetParamInt(Sah, param, value);
|
|
break;
|
|
#endif
|
|
|
|
#ifdef AC3_SUPPORT
|
|
case SA_AC3_DECODE:
|
|
/* case SA_AC3_ENCODE: */
|
|
saAC3SetParamInt(Sah, param, value);
|
|
break;
|
|
#endif
|
|
|
|
#ifdef G723_SUPPORT
|
|
case SA_G723_DECODE:
|
|
case SA_G723_ENCODE:
|
|
saG723SetParamInt(Sah, param, value);
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
return(SaErrorCodecType);
|
|
}
|
|
return(NoErrors);
|
|
}
|
|
|
|
ScBoolean_t SaGetParamBoolean(SaHandle_t Sah, SaParameter_t param)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
if (!Info)
|
|
return(FALSE);
|
|
switch (Info->Type)
|
|
{
|
|
#ifdef MPEG_SUPPORT
|
|
case SA_MPEG_DECODE:
|
|
case SA_MPEG_ENCODE:
|
|
return(saMpegGetParamBoolean(Sah, param));
|
|
break;
|
|
#endif
|
|
|
|
#ifdef G723_SUPPORT
|
|
case SA_G723_DECODE:
|
|
case SA_G723_ENCODE:
|
|
return(saG723GetParamBoolean(Sah, param));
|
|
break;
|
|
#endif
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
qword SaGetParamInt(SaHandle_t Sah, SaParameter_t param)
|
|
{
|
|
SaCodecInfo_t *Info = (SaCodecInfo_t *)Sah;
|
|
if (!Info)
|
|
return(0);
|
|
switch (Info->Type)
|
|
{
|
|
#ifdef MPEG_SUPPORT
|
|
case SA_MPEG_DECODE:
|
|
case SA_MPEG_ENCODE:
|
|
return(saMpegGetParamInt(Sah, param));
|
|
break;
|
|
#endif
|
|
|
|
#ifdef G723_SUPPORT
|
|
case SA_G723_DECODE:
|
|
case SA_G723_ENCODE:
|
|
return(saG723GetParamInt(Sah, param));
|
|
break;
|
|
#endif
|
|
}
|
|
return(0);
|
|
}
|
|
|