PALMAP.C

/**************************************************************************** 
*
* PALMAP.C
*
* Stream handler to map to a palette.
*
***************************************************************************/

/**************************************************************************
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
* PURPOSE.
*
* Copyright 1992 - 1998 Microsoft Corporation. All Rights Reserved.
*
**************************************************************************/

#define INC_OLE2
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <vfw.h>
#include <string.h>

#include "dibmap.h"
#include "palmap.h"
#include "palmap.rc"

#defineINITGUID
#include <initguid.h>

// Bring in the external GUIDs we need. Apparently compobj.lib doesn't define
DEFINE_OLEGUID(IID_IUnknown,0x00000000L, 0, 0);


HINSTANCEghMod;

STDAPI AVIStreamMakePalette(
PAVISTREAM pavi,
LONG lSkip,
HPALETTE FAR *lphpal,
LPBYTE lp16to8,
int nColors)
{
LPHISTOGRAM lpHist = NULL;
LONGl, lEnd;
LONGlRet = AVIERR_OK;
PGETFRAMEpgf = NULL;

if (!pavi || !lphpal || nColors < 2 || nColors > 256)
return ResultFromScode(AVIERR_BADPARAM);

if (lSkip < 1)
lSkip = 1;

lpHist = InitHistogram(NULL);
if (!lpHist)
return ResultFromScode(AVIERR_MEMORY);

pgf = AVIStreamGetFrameOpen(pavi, NULL);

l = AVIStreamStart(pavi);
lEnd = l + AVIStreamLength(pavi);
for (l = AVIStreamStart(pavi), lEnd = l + AVIStreamLength(pavi);
l < lEnd;
l += lSkip) {
LPBITMAPINFOHEADER lpbi;

lpbi = AVIStreamGetFrame(pgf, l);

if (!lpbi) {
lRet = AVIERR_INTERNAL;
goto error;
}

DibHistogram(lpbi, NULL, 0, 0, -1, -1, lpHist);
}

*lphpal = HistogramPalette(lpHist, lp16to8, nColors);

if (!*lphpal)
lRet = AVIERR_MEMORY;

error:
if (pgf)
AVIStreamGetFrameClose(pgf);

if (lpHist)
FreeHistogram(lpHist);

return ResultFromScode(lRet);
}



typedef struct {
IAVIStreamVtbl FAR *lpVtbl;

ULONGulRefCount;

//
// instance data
//
PAVISTREAMpavi;
PGETFRAMEpgf;
AVISTREAMINFOsinfo;
HPALETTEhpal;
LPBYTElp16to8;
LONGlLastFrame;
LPBITMAPINFOHEADERlpdibLast;
} PALMAPSTREAM, FAR*PPALMAPSTREAM;

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

HRESULT STDMETHODCALLTYPE PalMapStreamQueryInterface(
PAVISTREAM ps,
REFIID riid,
LPVOID FAR* ppvObj);
HRESULT STDMETHODCALLTYPE PalMapStreamCreate(
PAVISTREAM ps,
LONG lParam1,
LONG lParam2);
ULONGSTDMETHODCALLTYPE PalMapStreamAddRef(
PAVISTREAM ps);
ULONGSTDMETHODCALLTYPE PalMapStreamRelease(
PAVISTREAM ps);
HRESULT STDMETHODCALLTYPE PalMapStreamInfo(
PAVISTREAM ps,
AVISTREAMINFOW FAR * psi,
LONG lSize);
LONGSTDMETHODCALLTYPE PalMapStreamFindKeyFrame(
PAVISTREAM ps,
LONG lPos,
LONG lFlags);
HRESULT STDMETHODCALLTYPE PalMapStreamReadFormat(
PAVISTREAM ps,
LONG lPos,
LPVOID lpFormat,
LONG FAR *lpcbFormat);
HRESULT STDMETHODCALLTYPE PalMapStreamSetFormat(
PAVISTREAM ps,
LONG lPos,
LPVOID lpFormat,
LONG cbFormat);
HRESULT STDMETHODCALLTYPE PalMapStreamRead(
PAVISTREAM ps,
LONG lStart,
LONG lSamples,
LPVOID lpBuffer,
LONG cbBuffer,
LONG FAR * plBytes,
LONG FAR * plSamples);
HRESULT STDMETHODCALLTYPE PalMapStreamWrite(
PAVISTREAM ps,
LONG lStart,
LONG lSamples,
LPVOID lpBuffer,
LONG cbBuffer,
DWORD dwFlags,
LONG FAR *plSampWritten,
LONG FAR *plBytesWritten);
HRESULT STDMETHODCALLTYPE PalMapStreamDelete(
PAVISTREAM ps,
LONG lStart,
LONG lSamples);
HRESULT STDMETHODCALLTYPE PalMapStreamReadData(
PAVISTREAM ps,
DWORD fcc,
LPVOID lp,
LONG FAR *lpcb);
HRESULT STDMETHODCALLTYPE PalMapStreamWriteData(
PAVISTREAM ps,
DWORD fcc,
LPVOID lp,
LONG cb);
HRESULT STDMETHODCALLTYPE PalMapStreamSetInfo(
PAVISTREAM ps,
AVISTREAMINFOW FAR * psi,
LONG lSize);

IAVIStreamVtbl PalMapStreamHandler = {
PalMapStreamQueryInterface,
PalMapStreamAddRef,
PalMapStreamRelease,
PalMapStreamCreate,
PalMapStreamInfo,
PalMapStreamFindKeyFrame,
PalMapStreamReadFormat,
PalMapStreamSetFormat,
PalMapStreamRead,
PalMapStreamWrite,
PalMapStreamDelete,
PalMapStreamReadData,
PalMapStreamWriteData,
PalMapStreamSetInfo
};

STDAPI AVICreateMappedStream(PAVISTREAM FAR *ppsMapped,
PAVISTREAM ps,
int nColors)
{
PPALMAPSTREAMpavi;
HRESULThr;

*ppsMapped = 0;

pavi = (PPALMAPSTREAM) GlobalAllocPtr(GHND, sizeof(PALMAPSTREAM));
if (pavi == NULL)
return ResultFromScode(AVIERR_MEMORY);

pavi->lpVtbl = &PalMapStreamHandler;

hr = (pavi->lpVtbl->Create)((PAVISTREAM) pavi, (LONG) ps, nColors);

if (hr != NOERROR) {
(pavi->lpVtbl->Release)((PAVISTREAM) pavi);
return hr;
}

*ppsMapped = (PAVISTREAM) pavi;

return AVIERR_OK;


}

///////////////////////////////////////////////////////////////////////////
//
// PalMapStreamOpen()
//
// open a single stream of a particular type from a AVI file.
//
// params:
// szFile - PAVISTREAM
// fccType - must be streamtypeVIDEO
// lParam - nColors
//
// returns:
// a PAVISTREAM for the specifed stream or NULL.
//
///////////////////////////////////////////////////////////////////////////

HRESULT STDMETHODCALLTYPE PalMapStreamCreate(
PAVISTREAM ps,
LONG lParam1,
LONG lParam2)
{
PPALMAPSTREAMpavi = (PPALMAPSTREAM) ps;
TCHARachTemp[128];
TCHARachTemplate[64];

LONGlRet = AVIERR_OK;

pavi->ulRefCount = 1;

AVIStreamAddRef((PAVISTREAM) lParam1);

pavi->pavi = (PAVISTREAM) lParam1;

AVIStreamInfo(pavi->pavi, &pavi->sinfo, sizeof(pavi->sinfo));

if (pavi->sinfo.fccType != streamtypeVIDEO) {
lRet = AVIERR_INTERNAL;
goto error;
}

pavi->pgf = AVIStreamGetFrameOpen(pavi->pavi, NULL);

if (!pavi->pgf) {
lRet = AVIERR_INTERNAL;
goto error;
}

pavi->sinfo.fccHandler = 0;

// Fix up stream name
LoadString(ghMod, IDS_STREAMNAME, achTemplate,
sizeof(achTemplate) / sizeof(TCHAR));
wsprintf(achTemp, achTemplate, pavi->sinfo.szName, lParam2);
lstrcpyn(pavi->sinfo.szName, achTemp,
sizeof(pavi->sinfo.szName) / sizeof(TCHAR));
pavi->sinfo.szName[sizeof(pavi->sinfo.szName) / sizeof(TCHAR) - 1] =
TEXT('\0');

// default to 256 colors
if (lParam2 < 2 || lParam2 > 256)
lParam2 = 256;

pavi->lp16to8 = GlobalAllocPtr(GMEM_MOVEABLE, 32768L);
if (!pavi->lp16to8) {
lRet = AVIERR_MEMORY;
goto error;
}

lRet = GetScode(AVIStreamMakePalette(pavi->pavi,
AVIStreamLength(pavi->pavi) / 30,
&pavi->hpal, pavi->lp16to8,
(int) lParam2));

pavi->lLastFrame = -1;

error:
return ResultFromScode(lRet);
}

///////////////////////////////////////////////////////////////////////////
//
// PalMapStreamQueryInterface()
//
// let other people know what interfaces we support
//
///////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE PalMapStreamQueryInterface(
PAVISTREAM ps,
REFIID riid,
LPVOID FAR* ppvObj)
{
PPALMAPSTREAM pavi = (PPALMAPSTREAM) ps;

if (IsEqualIID(riid, &IID_IUnknown))
*ppvObj = ps;
else if (IsEqualIID(riid, &IID_IAVIStream))
*ppvObj = ps;
else
return ResultFromScode(E_NOINTERFACE);

pavi->ulRefCount++;
return NOERROR;
}

///////////////////////////////////////////////////////////////////////////
//
// PalMapStreamAddRef()
//
// increase the reference count of the stream
//
///////////////////////////////////////////////////////////////////////////

ULONG STDMETHODCALLTYPE PalMapStreamAddRef(
PAVISTREAM ps)
{
PPALMAPSTREAM pavi = (PPALMAPSTREAM) ps;

return ++pavi->ulRefCount;
}

///////////////////////////////////////////////////////////////////////////
//
// PalMapStreamRelease()
//
// close a PalMapStream stream
//
///////////////////////////////////////////////////////////////////////////

ULONG STDMETHODCALLTYPE PalMapStreamRelease(
PAVISTREAM ps)
{
PPALMAPSTREAM pavi = (PPALMAPSTREAM) ps;

if (!pavi)
return 0;

if (--pavi->ulRefCount)
return pavi->ulRefCount;

if (pavi->pgf)
AVIStreamGetFrameClose(pavi->pgf);
pavi->pgf = 0;

if (pavi->pavi)
AVIStreamClose(pavi->pavi);
pavi->pavi = 0;

if (pavi->lp16to8) {
GlobalFreePtr(pavi->lp16to8);
pavi->lp16to8 = 0;
}

if (pavi->hpal) {
DeletePalette(pavi->hpal);
pavi->hpal = 0;
}

if (pavi->lpdibLast) {
GlobalFreePtr(pavi->lpdibLast);
pavi->lpdibLast = 0;
}

GlobalFreePtr(pavi);

return 0;
}

///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

HRESULT STDMETHODCALLTYPE PalMapStreamReadFormat(
PAVISTREAM ps,
LONG lPos,
LPVOID lpFormat,
LONG FAR *lpcbFormat)
{
PPALMAPSTREAM pavi = (PPALMAPSTREAM) ps;
LONGlSize;

PalMapStreamRead(ps, lPos, 1, NULL, 0, NULL, NULL);

if (pavi->lpdibLast == 0)
return ResultFromScode(AVIERR_INTERNAL);
lSize = pavi->lpdibLast->biSize
+ pavi->lpdibLast->biClrUsed * sizeof(RGBQUAD);

if (lpFormat)
hmemcpy(lpFormat, pavi->lpdibLast,
min(*lpcbFormat, lSize));

*lpcbFormat = lSize;

return 0;
}

LONG STDMETHODCALLTYPE PalMapStreamFindKeyFrame(
PAVISTREAM ps,
LONG lPos,
LONG lFlags)
{
PPALMAPSTREAM pavi = (PPALMAPSTREAM) ps;

return lPos;
}


///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

HRESULT STDMETHODCALLTYPE PalMapStreamInfo(
PAVISTREAM ps,
AVISTREAMINFOW FAR * psi, // OLE interfaces are ALWAYS UNICODE
LONG lSize)
{
PPALMAPSTREAM pavi = (PPALMAPSTREAM) ps;

if (psi)
hmemcpy(psi, &pavi->sinfo, min(lSize, sizeof(pavi->sinfo)));

return 0;
}


///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////

HRESULT STDMETHODCALLTYPE PalMapStreamRead(
PAVISTREAMps,
LONGlStart,
LONGlSamples,
LPVOIDlpBuffer,
LONGcbBuffer,
LONG FAR *plBytes,
LONG FAR *plSamples)
{
PPALMAPSTREAM pavi = (PPALMAPSTREAM) ps;

LPBITMAPINFOHEADERlpbi;
LPVOIDlp;

if (lStart != pavi->lLastFrame) {
pavi->lLastFrame = -1;
lpbi = AVIStreamGetFrame(pavi->pgf, lStart);

if (!lpbi)
goto ReadNothing;

if (pavi->lpdibLast) {
GlobalFreePtr(pavi->lpdibLast);
pavi->lpdibLast = 0;
}

pavi->lpdibLast = DibReduce(lpbi, NULL, pavi->hpal, pavi->lp16to8);
pavi->lLastFrame = lStart;
}

lpbi = pavi->lpdibLast;
//
// a NULL buffer means return the size buffer needed to read
// the given sample.
//
lp = (LPBYTE) lpbi + lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD);

if (plBytes)
*plBytes = lpbi->biSizeImage;

if (plSamples)
*plSamples = 1;

if (lpBuffer) {
if (cbBuffer >= (LONG) lpbi->biSizeImage)
hmemcpy(lpBuffer, lp, lpbi->biSizeImage);
else
goto ReadNothing;
}

return 0;

ReadNothing:
if (plBytes)
*plBytes = 0;

if (plSamples)
*plSamples = 0;

return ResultFromScode(AVIERR_BUFFERTOOSMALL);
}



//
//
// Extra unimplemented functions.....
//
//
//
HRESULT STDMETHODCALLTYPE PalMapStreamReadData(
PAVISTREAM ps,
DWORD fcc,
LPVOID lp,
LONG FAR *lpcb)
{
PPALMAPSTREAM pavi = (PPALMAPSTREAM) ps;
return ResultFromScode(AVIERR_UNSUPPORTED);
}

HRESULT STDMETHODCALLTYPE PalMapStreamSetFormat(
PAVISTREAM ps,
LONG lPos,
LPVOID lpFormat,
LONG cbFormat)
{
PPALMAPSTREAM pavi = (PPALMAPSTREAM) ps;
return ResultFromScode(AVIERR_UNSUPPORTED);
}

HRESULT STDMETHODCALLTYPE PalMapStreamWriteData(
PAVISTREAM ps,
DWORD fcc,
LPVOID lp,
LONG cb)
{
PPALMAPSTREAM pavi = (PPALMAPSTREAM) ps;
return ResultFromScode(AVIERR_UNSUPPORTED);
}

HRESULT STDMETHODCALLTYPE PalMapStreamWrite(
PAVISTREAM ps,
LONG lStart,
LONG lSamples,
LPVOID lpBuffer,
LONG cbBuffer,
DWORD dwFlags,
LONG FAR *plSampWritten,
LONG FAR *plBytesWritten)
{
PPALMAPSTREAM pavi = (PPALMAPSTREAM) ps;
return ResultFromScode(AVIERR_UNSUPPORTED);
}

HRESULT STDMETHODCALLTYPE PalMapStreamDelete(
PAVISTREAM ps,
LONG lStart,
LONG lSamples)
{
PPALMAPSTREAM pavi = (PPALMAPSTREAM) ps;
return ResultFromScode(AVIERR_UNSUPPORTED);
}

HRESULT STDMETHODCALLTYPE PalMapStreamSetInfo(
PAVISTREAM ps,
AVISTREAMINFOW FAR * psi,
LONG lSize)
{
return ResultFromScode(AVIERR_UNSUPPORTED);
}

EXTERN_C int CALLBACK WEP(
BOOL fSystemExit)
{
return TRUE;
}


EXTERN_C BOOL APIENTRY DllMain(HANDLE, DWORD, LPVOID);
EXTERN_C BOOL APIENTRY DllMain(
HANDLE hModule,
DWORD dwReason,
LPVOID lpReserved )
{
switch( dwReason)
{
case DLL_PROCESS_ATTACH:
if(ghMod == NULL)
ghMod = (HMODULE)hModule;
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}