1186 lines
35 KiB
C
Executable File
1186 lines
35 KiB
C
Executable File
/*****************************************************************************
|
|
*
|
|
* This program is free software ; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* $Id: dmo_win32.c 622 2006-01-31 19:02:53Z picard $
|
|
*
|
|
* The Core Pocket Media Player
|
|
* Copyright (c) 2004-2005 Gabor Kovacs
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "../common.h"
|
|
|
|
#if defined(TARGET_WIN32) || defined(TARGET_WINCE)
|
|
|
|
#ifndef STRICT
|
|
#define STRICT
|
|
#endif
|
|
#define _WIN32_WINNT 0x0400
|
|
#define INITGUID
|
|
#include <objbase.h>
|
|
|
|
#define DMO_CLASS FOURCC('A','D','M','O')
|
|
|
|
// string table
|
|
#define DMO_MODULE 0x200
|
|
#define DMO_MODULEPPC 0x201
|
|
#define DMO_CLASSID 0x202
|
|
|
|
// registry
|
|
#define DMO_FOUND 0x400
|
|
|
|
#define WMV_ID FOURCC('W','M','V','_')
|
|
#define WMS_ID FOURCC('W','M','S','_')
|
|
#define WMVA_ID FOURCC('W','M','V','A')
|
|
#define WMA_ID FOURCC('W','M','A','_')
|
|
#define WMAV_ID FOURCC('W','M','A','V')
|
|
|
|
#define DMO_INPUT_STATUSF_ACCEPT_DATA 0x00000001
|
|
|
|
#define DMO_INPUT_DATA_BUFFERF_SYNCPOINT 0x00000001
|
|
#define DMO_INPUT_DATA_BUFFERF_TIME 0x00000002
|
|
#define DMO_INPUT_DATA_BUFFERF_TIMELENGTH 0x00000004
|
|
|
|
#define DMO_INPUT_STREAMF_WHOLE_SAMPLES 0x00000001
|
|
#define DMO_INPUT_STREAMF_SINGLE_SAMPLE_PER_BUFFER 0x00000002
|
|
#define DMO_INPUT_STREAMF_FIXED_SAMPLE_SIZE 0x00000004
|
|
#define DMO_INPUT_STREAMF_HOLDS_BUFFERS 0x00000008
|
|
|
|
#define DMO_SET_TYPEF_TEST_ONLY 0x00000001
|
|
#define DMO_SET_TYPEF_CLEAR 0x00000002
|
|
|
|
#define DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER 0x00000001
|
|
|
|
#define DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT 0x00000001
|
|
#define DMO_OUTPUT_DATA_BUFFERF_TIME 0x00000002
|
|
#define DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH 0x00000004
|
|
#define DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE 0x01000000
|
|
|
|
const guid ID_IMEDIABUFFER = {0x59eff8b9,0x938c,0x4a26,{0x82,0xf2,0x95,0xcb,0x84,0xcd,0xc8,0x37}};
|
|
const guid ID_IUNKNOWN = {0x00000000,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
|
|
const guid ID_ICLASSFACTORY = {00000001,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
|
|
const guid ID_IDMOQUALITYCONTROL = {0x65abea96,0xcf36,0x453f,{0xaf,0x8a,0x70,0x5e,0x98,0xf1,0x62,0x60}};
|
|
const guid WMCMEDIATYPE_Video = {0x73646976, 0x0000, 0x0010,{0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
|
|
const guid WMCMEDIATYPE_Audio = {0x73647561, 0x0000, 0x0010,{0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
|
|
const guid WMCFORMAT_VideoInfo = {0x05589f80, 0xc356, 0x11ce,{0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
|
|
const guid WMCFORMAT_WaveFormatEx = {0x05589f81, 0xc356, 0x11ce,{0xbf, 0x01, 0x00, 0xaa, 0x00, 0x55, 0x59, 0x5a}};
|
|
const guid WMCMEDIASUBTYPE = {0x00000000,0x0000, 0x0010,{0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71}};
|
|
const guid WMCMEDIASUBTYPE_RGB565 = {0xe436eb7b, 0x524f, 0x11ce,{0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}};
|
|
const guid IID_IMediaObject = { 0xd8ad0f58, 0x5494, 0x4102,{0x97, 0xc5, 0xec, 0x79, 0x8e, 0x59, 0xbc, 0xf4}};
|
|
|
|
typedef int64_t REFERENCE_TIME;
|
|
|
|
struct IMediaObject;
|
|
struct IMediaBuffer;
|
|
struct IDMOQualityControl;
|
|
|
|
typedef struct VIDEOINFOHEADER
|
|
{
|
|
RECT rcSource;
|
|
RECT rcTarget;
|
|
DWORD dwBitRate;
|
|
DWORD dwBitErrorRate;
|
|
REFERENCE_TIME AvgTimePerFrame;
|
|
BITMAPINFOHEADER bmiHeader;
|
|
|
|
} VIDEOINFOHEADER;
|
|
|
|
typedef struct DMO_MEDIA_TYPE
|
|
{
|
|
guid majortype;
|
|
guid subtype;
|
|
BOOL bFixedSizeSamples;
|
|
BOOL bTemporalCompression;
|
|
ULONG lSampleSize;
|
|
guid formattype;
|
|
IUnknown* pUnk;
|
|
ULONG cbFormat;
|
|
BYTE* pbFormat;
|
|
|
|
} DMO_MEDIA_TYPE;
|
|
|
|
typedef struct DMO_OUTPUT_DATA_BUFFER
|
|
{
|
|
struct IMediaBuffer* pBuffer;
|
|
DWORD dwStatus;
|
|
REFERENCE_TIME rtTimestamp;
|
|
REFERENCE_TIME rtTimelength;
|
|
|
|
} DMO_OUTPUT_DATA_BUFFER;
|
|
|
|
typedef struct IMediaBufferVMT
|
|
{
|
|
HRESULT (STDCALL *QueryInterface)(void* This, const guid* riid, void **ppvObject);
|
|
ULONG (STDCALL *AddRef)(void* This);
|
|
ULONG (STDCALL *Release)(void* This);
|
|
HRESULT (STDCALL *SetLength)(void* This, DWORD cbLength);
|
|
HRESULT (STDCALL *GetMaxLength)(void* This, DWORD *pcbMaxLength);
|
|
HRESULT (STDCALL *GetBufferAndLength)(void* This, BYTE **ppBuffer, DWORD *pcbLength);
|
|
|
|
} IMediaBufferVMT;
|
|
|
|
typedef struct IMediaBuffer
|
|
{
|
|
struct IMediaBufferVMT *VMT;
|
|
|
|
} IMediaBuffer;
|
|
|
|
typedef struct IDMOQualityControlVMT
|
|
{
|
|
HRESULT (STDCALL *QueryInterface)(struct IDMOQualityControl* This, const guid* riid, void** ppvObject);
|
|
ULONG (STDCALL *AddRef)(struct IDMOQualityControl* This);
|
|
ULONG (STDCALL *Release)(struct IDMOQualityControl* This);
|
|
HRESULT (STDCALL *SetNow)(struct IDMOQualityControl* This, REFERENCE_TIME rtNow);
|
|
HRESULT (STDCALL *SetStatus)(struct IDMOQualityControl* This, DWORD dwFlags);
|
|
HRESULT (STDCALL *GetStatus)(struct IDMOQualityControl* This, DWORD *pdwFlags);
|
|
|
|
} IDMOQualityControlVMT;
|
|
|
|
typedef struct IDMOQualityControl
|
|
{
|
|
IDMOQualityControlVMT *VMT;
|
|
|
|
} IDMOQualityControl;
|
|
|
|
typedef struct IMediaObjectVMT
|
|
{
|
|
HRESULT (STDCALL *QueryInterface)(struct IMediaObject * This, const guid* riid, void** ppvObject);
|
|
ULONG (STDCALL *AddRef)(struct IMediaObject * This);
|
|
ULONG (STDCALL *Release)(struct IMediaObject * This);
|
|
HRESULT (STDCALL *GetStreamCount)(struct IMediaObject * This, DWORD *pcInputStreams, DWORD *pcOutputStreams);
|
|
HRESULT (STDCALL *GetInputStreamInfo)(struct IMediaObject * This, DWORD dwInputStreamIndex, DWORD *pdwFlags);
|
|
HRESULT (STDCALL *GetOutputStreamInfo)(struct IMediaObject * This, DWORD dwOutputStreamIndex, DWORD *pdwFlags);
|
|
HRESULT (STDCALL *GetInputType)(struct IMediaObject * This, DWORD dwInputStreamIndex, DWORD dwTypeIndex, DMO_MEDIA_TYPE *pmt);
|
|
HRESULT (STDCALL *GetOutputType)(struct IMediaObject * This, DWORD dwOutputStreamIndex, DWORD dwTypeIndex, DMO_MEDIA_TYPE *pmt);
|
|
HRESULT (STDCALL *SetInputType)(struct IMediaObject * This, DWORD dwInputStreamIndex, const DMO_MEDIA_TYPE *pmt, DWORD dwFlags);
|
|
HRESULT (STDCALL *SetOutputType)(struct IMediaObject * This, DWORD dwOutputStreamIndex,const DMO_MEDIA_TYPE *pmt, DWORD dwFlags);
|
|
HRESULT (STDCALL *GetInputCurrentType)(struct IMediaObject * This, DWORD dwInputStreamIndex, DMO_MEDIA_TYPE *pmt);
|
|
HRESULT (STDCALL *GetOutputCurrentType)(struct IMediaObject * This, DWORD dwOutputStreamIndex, DMO_MEDIA_TYPE *pmt);
|
|
HRESULT (STDCALL *GetInputSizeInfo)(struct IMediaObject * This, DWORD dwInputStreamIndex, DWORD *pcbSize, DWORD *pcbMaxLookahead, DWORD *pcbAlignment);
|
|
HRESULT (STDCALL *GetOutputSizeInfo)(struct IMediaObject * This, DWORD dwOutputStreamIndex, DWORD *pcbSize, DWORD *pcbAlignment);
|
|
HRESULT (STDCALL *GetInputMaxLatency)(struct IMediaObject * This, DWORD dwInputStreamIndex, REFERENCE_TIME *prtMaxLatency);
|
|
HRESULT (STDCALL *SetInputMaxLatency)(struct IMediaObject * This, DWORD dwInputStreamIndex, REFERENCE_TIME rtMaxLatency);
|
|
HRESULT (STDCALL *Flush)(struct IMediaObject * This);
|
|
HRESULT (STDCALL *Discontinuity)(struct IMediaObject * This, DWORD dwInputStreamIndex);
|
|
HRESULT (STDCALL *AllocateStreamingResources)(struct IMediaObject * This);
|
|
HRESULT (STDCALL *FreeStreamingResources)(struct IMediaObject * This);
|
|
HRESULT (STDCALL *GetInputStatus)(struct IMediaObject * This,DWORD dwInputStreamIndex,DWORD *dwFlags);
|
|
HRESULT (STDCALL *ProcessInput)(struct IMediaObject * This, DWORD dwInputStreamIndex, IMediaBuffer *pBuffer, DWORD dwFlags, REFERENCE_TIME rtTimestamp, REFERENCE_TIME rtTimelength);
|
|
HRESULT (STDCALL *ProcessOutput)(struct IMediaObject * This, DWORD dwFlags, DWORD cOutputBufferCount, DMO_OUTPUT_DATA_BUFFER *pOutputBuffers, DWORD *pdwStatus);
|
|
HRESULT (STDCALL *Lock)(struct IMediaObject * This, LONG bLock);
|
|
|
|
} IMediaObjectVMT;
|
|
|
|
typedef struct IMediaObject
|
|
{
|
|
IMediaObjectVMT *VMT;
|
|
|
|
} IMediaObject;
|
|
|
|
#define DMO_INPUT 0x100
|
|
#define DMO_OUTPUT 0x101
|
|
|
|
typedef struct IOwnMediaBuffer
|
|
{
|
|
struct IMediaBufferVMT *VMT;
|
|
|
|
int RefCount;
|
|
int Length;
|
|
int Allocated; // -1 for external allocated buffer
|
|
void* Data;
|
|
|
|
struct IOwnMediaBuffer** Chain;
|
|
struct IOwnMediaBuffer* Next;
|
|
|
|
} IOwnMediaBuffer;
|
|
|
|
typedef struct dmo
|
|
{
|
|
codec Codec;
|
|
|
|
HMODULE Module;
|
|
guid ClassId;
|
|
int (STDCALL *CreateCodecDMO)(IMediaObject**);
|
|
int (STDCALL *CreateCodecDMOEx)(int Code,IMediaObject**);
|
|
int (STDCALL *QueryUnloadCodecDMO)();
|
|
int (STDCALL *DllGetClassObject)(const guid*,const guid*,IClassFactory**);
|
|
int (STDCALL *DllCanUnloadNow)();
|
|
|
|
IMediaObject* Media;
|
|
IOwnMediaBuffer* InputBuffers;
|
|
DMO_OUTPUT_DATA_BUFFER OutputBuffer[2];
|
|
int OutputNoMask;
|
|
int OutputNext;
|
|
int OutputPrev;
|
|
|
|
DMO_MEDIA_TYPE InType;
|
|
DMO_MEDIA_TYPE OutType;
|
|
int ConstSize;
|
|
BITMAPINFOHEADER* Const;
|
|
|
|
int WMPVersion;
|
|
bool_t First;
|
|
bool_t UseDropping;
|
|
|
|
} dmo;
|
|
|
|
static HRESULT STDCALL MoInitMediaType(DMO_MEDIA_TYPE* p, DWORD Size)
|
|
{
|
|
p->pUnk = NULL;
|
|
p->pbFormat = NULL;
|
|
p->cbFormat = Size;
|
|
if (Size)
|
|
{
|
|
p->pbFormat = CoTaskMemAlloc(Size);
|
|
if (!p->pbFormat)
|
|
{
|
|
p->cbFormat = 0;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT STDCALL MoFreeMediaType(DMO_MEDIA_TYPE* p)
|
|
{
|
|
if (p->pUnk)
|
|
{
|
|
p->pUnk->lpVtbl->Release(p->pUnk);
|
|
p->pUnk = NULL;
|
|
}
|
|
if (p->pbFormat)
|
|
{
|
|
CoTaskMemFree(p->pbFormat);
|
|
p->pbFormat = NULL;
|
|
}
|
|
p->cbFormat = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT STDCALL MBQueryInterface(IOwnMediaBuffer * p, const guid* riid, void **ppvObject)
|
|
{
|
|
if (memcmp(riid,&ID_IMEDIABUFFER,sizeof(GUID))==0 ||
|
|
memcmp(riid,&ID_IUNKNOWN,sizeof(GUID))==0)
|
|
{
|
|
if (ppvObject)
|
|
{
|
|
++p->RefCount;
|
|
*ppvObject = p;
|
|
}
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static ULONG STDCALL MBAddRef(IOwnMediaBuffer * p)
|
|
{
|
|
p->RefCount++;
|
|
return 0;
|
|
}
|
|
|
|
static HRESULT STDCALL MBSetMaxLength(IOwnMediaBuffer * p, DWORD cbLength)
|
|
{
|
|
if (cbLength > 0)
|
|
{
|
|
if ((int)cbLength > p->Allocated)
|
|
{
|
|
void* Data = realloc(p->Data,cbLength);
|
|
if (!Data && cbLength)
|
|
return E_OUTOFMEMORY;
|
|
p->Data = Data;
|
|
p->Allocated = cbLength;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
free(p->Data);
|
|
p->Data = NULL;
|
|
p->Allocated = 0;
|
|
}
|
|
if (p->Length > p->Allocated)
|
|
p->Length = p->Allocated;
|
|
return 0;
|
|
}
|
|
|
|
static ULONG STDCALL MBRelease(IOwnMediaBuffer * p)
|
|
{
|
|
if (--p->RefCount<=0)
|
|
{
|
|
p->Length = 0;
|
|
if (p->Chain)
|
|
{
|
|
p->Next = *p->Chain;
|
|
*p->Chain = p;
|
|
}
|
|
else
|
|
{
|
|
free(p->Data);
|
|
free(p);
|
|
return 0;
|
|
}
|
|
}
|
|
return p->RefCount;
|
|
}
|
|
|
|
static HRESULT STDCALL MBSetLength(IOwnMediaBuffer * p, DWORD cbLength)
|
|
{
|
|
DEBUG_MSG2(DEBUG_VIDEO,T("MediaBuffer_SetLength %d (%d)"),cbLength,p->Allocated);
|
|
if ((int)cbLength > p->Allocated)
|
|
return -1;
|
|
p->Length = cbLength;
|
|
return 0;
|
|
}
|
|
|
|
static HRESULT STDCALL MBGetMaxLength(IOwnMediaBuffer * p, DWORD *pcbMaxLength)
|
|
{
|
|
DEBUG_MSG1(DEBUG_VIDEO,T("MediaBuffer_GetMaxLength %d"),p->Allocated);
|
|
if (pcbMaxLength)
|
|
*pcbMaxLength = p->Allocated;
|
|
return 0;
|
|
}
|
|
|
|
static HRESULT STDCALL MBGetBufferAndLength(IOwnMediaBuffer * p, BYTE **ppBuffer, DWORD *pcbLength)
|
|
{
|
|
DEBUG_MSG1(DEBUG_VIDEO,T("MediaBuffer_GetBufferAndLength %d"),p->Length);
|
|
if (ppBuffer)
|
|
*ppBuffer = (BYTE*)p->Data;
|
|
if (pcbLength)
|
|
*pcbLength = p->Length;
|
|
return 0;
|
|
}
|
|
|
|
static IMediaBufferVMT MediaBufferVMT =
|
|
{
|
|
MBQueryInterface,
|
|
MBAddRef,
|
|
MBRelease,
|
|
MBSetLength,
|
|
MBGetMaxLength,
|
|
MBGetBufferAndLength,
|
|
};
|
|
|
|
static void FreeBuffers(IOwnMediaBuffer** Chain)
|
|
{
|
|
while (*Chain)
|
|
{
|
|
IOwnMediaBuffer* p = (*Chain)->Next;
|
|
MBSetMaxLength(*Chain,0);
|
|
free(*Chain);
|
|
*Chain = p;
|
|
}
|
|
}
|
|
|
|
static INLINE void AppendBuffer(IOwnMediaBuffer* p, int Length, const void* Data)
|
|
{
|
|
memcpy((char*)p->Data + p->Length, Data, Length);
|
|
p->Length += Length;
|
|
}
|
|
|
|
static IOwnMediaBuffer* AllocBuffer(int MaxLength,IOwnMediaBuffer** Chain)
|
|
{
|
|
IOwnMediaBuffer* p = Chain ? *Chain : NULL;
|
|
|
|
if (MaxLength <= 0)
|
|
return NULL;
|
|
|
|
if (p)
|
|
*Chain = p->Next;
|
|
else
|
|
{
|
|
p = (IOwnMediaBuffer*)malloc(sizeof(IOwnMediaBuffer));
|
|
if (!p)
|
|
return NULL;
|
|
memset(p,0,sizeof(IOwnMediaBuffer));
|
|
p->VMT = &MediaBufferVMT;
|
|
}
|
|
|
|
p->Chain = Chain;
|
|
p->Length = 0;
|
|
|
|
MBSetMaxLength(p,MaxLength);
|
|
|
|
p->VMT->AddRef(p);
|
|
return p;
|
|
}
|
|
|
|
static bool_t BuildI420(dmo* p)
|
|
{
|
|
// manual video format guessing (for wince4 non pocketpc)
|
|
VIDEOINFOHEADER* VideoInfo;
|
|
|
|
PacketFormatClear(&p->Codec.Out.Format);
|
|
p->Codec.Out.Format.Type = PACKET_VIDEO;
|
|
|
|
memcpy(&p->Codec.Out.Format.Format.Video,&p->Codec.In.Format.Format.Video,sizeof(video));
|
|
p->Codec.Out.Format.Format.Video.Pixel.Flags = PF_FOURCC;
|
|
p->Codec.Out.Format.Format.Video.Pixel.FourCC = FOURCC_I420;
|
|
p->Codec.Out.Format.Format.Video.Pixel.BitCount = 16;
|
|
p->Codec.Out.Format.Format.Video.Pitch = p->Codec.Out.Format.Format.Video.Width;
|
|
|
|
if (MoInitMediaType(&p->OutType,sizeof(VIDEOINFOHEADER)) != S_OK)
|
|
return 0;
|
|
|
|
VideoInfo = (VIDEOINFOHEADER*)p->OutType.pbFormat;
|
|
memset(VideoInfo,0,sizeof(VIDEOINFOHEADER));
|
|
|
|
VideoInfo->bmiHeader.biSize = sizeof(VideoInfo->bmiHeader);
|
|
VideoInfo->bmiHeader.biWidth = p->Codec.Out.Format.Format.Video.Width;
|
|
VideoInfo->bmiHeader.biHeight = p->Codec.Out.Format.Format.Video.Height;
|
|
VideoInfo->bmiHeader.biCompression = p->Codec.Out.Format.Format.Video.Pixel.FourCC;
|
|
VideoInfo->bmiHeader.biBitCount = (WORD)p->Codec.Out.Format.Format.Video.Pixel.BitCount;
|
|
VideoInfo->bmiHeader.biPlanes = 1;
|
|
VideoInfo->bmiHeader.biSizeImage = (p->Codec.Out.Format.Format.Video.Width *
|
|
p->Codec.Out.Format.Format.Video.Height * p->Codec.Out.Format.Format.Video.Pixel.BitCount)/8;
|
|
|
|
VideoInfo->rcSource.left = 0;
|
|
VideoInfo->rcSource.top = 0;
|
|
VideoInfo->rcSource.right = p->Codec.Out.Format.Format.Video.Width;
|
|
VideoInfo->rcSource.bottom = p->Codec.Out.Format.Format.Video.Height;
|
|
VideoInfo->rcTarget = VideoInfo->rcSource;
|
|
|
|
p->OutType.majortype = WMCMEDIATYPE_Video;
|
|
p->OutType.formattype = WMCFORMAT_VideoInfo;
|
|
p->OutType.subtype = WMCMEDIASUBTYPE;
|
|
p->OutType.subtype.v1 = FOURCC_YUY2; // tricky
|
|
p->OutType.bTemporalCompression = 0;
|
|
p->OutType.bFixedSizeSamples = 1;
|
|
p->OutType.lSampleSize = 0;
|
|
return 1;
|
|
}
|
|
|
|
static bool_t BuildRGB16(dmo* p)
|
|
{
|
|
// wmp10 enumerates falsely the input extra info for rgb16 output (wmv9 advanced profile)
|
|
// we have to build our own version
|
|
VIDEOINFOHEADER* VideoInfo;
|
|
|
|
PacketFormatClear(&p->Codec.Out.Format);
|
|
p->Codec.Out.Format.Type = PACKET_VIDEO;
|
|
|
|
memcpy(&p->Codec.Out.Format.Format.Video,&p->Codec.In.Format.Format.Video,sizeof(video));
|
|
DefaultRGB(&p->Codec.Out.Format.Format.Video.Pixel,16,5,6,5,0,0,0);
|
|
p->Codec.Out.Format.Format.Video.Pitch = p->Codec.Out.Format.Format.Video.Width*2;
|
|
p->Codec.Out.Format.Format.Video.Direction = DIR_MIRRORUPDOWN;
|
|
|
|
if (MoInitMediaType(&p->OutType,sizeof(VIDEOINFOHEADER)+3*4) != S_OK)
|
|
return 0;
|
|
|
|
VideoInfo = (VIDEOINFOHEADER*)p->OutType.pbFormat;
|
|
memset(VideoInfo,0,sizeof(VIDEOINFOHEADER));
|
|
|
|
VideoInfo->bmiHeader.biSize = sizeof(VideoInfo->bmiHeader)+3*4;
|
|
VideoInfo->bmiHeader.biWidth = p->Codec.Out.Format.Format.Video.Width;
|
|
VideoInfo->bmiHeader.biHeight = p->Codec.Out.Format.Format.Video.Height;
|
|
VideoInfo->bmiHeader.biCompression = 3;
|
|
VideoInfo->bmiHeader.biBitCount = (WORD)p->Codec.Out.Format.Format.Video.Pixel.BitCount;
|
|
VideoInfo->bmiHeader.biPlanes = 1;
|
|
VideoInfo->bmiHeader.biSizeImage = (p->Codec.Out.Format.Format.Video.Width *
|
|
p->Codec.Out.Format.Format.Video.Height * p->Codec.Out.Format.Format.Video.Pixel.BitCount)/8;
|
|
((int32_t*)(VideoInfo+1))[0] = p->Codec.Out.Format.Format.Video.Pixel.BitMask[0];
|
|
((int32_t*)(VideoInfo+1))[1] = p->Codec.Out.Format.Format.Video.Pixel.BitMask[1];
|
|
((int32_t*)(VideoInfo+1))[2] = p->Codec.Out.Format.Format.Video.Pixel.BitMask[2];
|
|
|
|
VideoInfo->rcSource.left = 0;
|
|
VideoInfo->rcSource.top = 0;
|
|
VideoInfo->rcSource.right = p->Codec.Out.Format.Format.Video.Width;
|
|
VideoInfo->rcSource.bottom = p->Codec.Out.Format.Format.Video.Height;
|
|
VideoInfo->rcTarget = VideoInfo->rcSource;
|
|
|
|
p->OutType.majortype = WMCMEDIATYPE_Video;
|
|
p->OutType.formattype = WMCFORMAT_VideoInfo;
|
|
p->OutType.subtype = WMCMEDIASUBTYPE_RGB565;
|
|
p->OutType.bTemporalCompression = 0;
|
|
p->OutType.bFixedSizeSamples = 0;
|
|
p->OutType.lSampleSize = 0;
|
|
return 1;
|
|
}
|
|
|
|
// mode0 yuv420
|
|
// mode1 rgb16
|
|
// mode2 rgb32
|
|
|
|
static bool_t MatchOutVideo(dmo* p,int Mode)
|
|
{
|
|
int No;
|
|
for (No=0;;++No)
|
|
{
|
|
if (p->Media->VMT->GetOutputType(p->Media, 0, No, &p->OutType) != S_OK)
|
|
break;
|
|
|
|
if (memcmp(&p->OutType.formattype,&WMCFORMAT_VideoInfo,sizeof(GUID))==0 &&
|
|
p->OutType.cbFormat >= sizeof(VIDEOINFOHEADER) &&
|
|
p->OutType.pbFormat)
|
|
{
|
|
VIDEOINFOHEADER *Info = (VIDEOINFOHEADER*) p->OutType.pbFormat;
|
|
|
|
PacketFormatClear(&p->Codec.Out.Format);
|
|
p->Codec.Out.Format.Type = PACKET_VIDEO;
|
|
p->Codec.Out.Format.Format.Video.Pixel.FourCC = Info->bmiHeader.biCompression;
|
|
p->Codec.Out.Format.Format.Video.Pixel.BitCount = Info->bmiHeader.biBitCount;
|
|
p->Codec.Out.Format.Format.Video.Width = Info->bmiHeader.biWidth;
|
|
p->Codec.Out.Format.Format.Video.Height = Info->bmiHeader.biHeight;
|
|
p->Codec.Out.Format.Format.Video.Aspect = ASPECT_ONE; //todo: fix
|
|
if (Info->bmiHeader.biCompression == 3)
|
|
{
|
|
p->Codec.Out.Format.Format.Video.Pixel.BitMask[0] = 0xF800;
|
|
p->Codec.Out.Format.Format.Video.Pixel.BitMask[1] = 0x07E0;
|
|
p->Codec.Out.Format.Format.Video.Pixel.BitMask[2] = 0x001F;
|
|
}
|
|
PacketFormatDefault(&p->Codec.Out.Format);
|
|
|
|
switch (Mode)
|
|
{
|
|
case 0:
|
|
if (PlanarYUV420(&p->Codec.Out.Format.Format.Video.Pixel))
|
|
return 1;
|
|
break;
|
|
case 1:
|
|
if (p->Codec.Out.Format.Format.Video.Pixel.BitCount==16 &&
|
|
Info->bmiHeader.biCompression==3)
|
|
return 1;
|
|
break;
|
|
case 2:
|
|
if (p->Codec.Out.Format.Format.Video.Pixel.BitCount==32 &&
|
|
Info->bmiHeader.biCompression==0)
|
|
return 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
MoFreeMediaType(&p->OutType);
|
|
memset(&p->OutType,0,sizeof(p->OutType));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static bool_t BuildPCM(dmo* p)
|
|
{
|
|
// manual audio format guessing
|
|
|
|
WAVEFORMATEX *WaveFormat;
|
|
if (MoInitMediaType(&p->OutType,sizeof(WAVEFORMATEX)) != S_OK)
|
|
return 0;
|
|
|
|
PacketFormatPCM(&p->Codec.Out.Format,&p->Codec.In.Format,16);
|
|
|
|
WaveFormat = (WAVEFORMATEX*) p->OutType.pbFormat;
|
|
WaveFormat->wFormatTag = (WORD)p->Codec.Out.Format.Format.Audio.Format;
|
|
WaveFormat->nChannels = (WORD)p->Codec.Out.Format.Format.Audio.Channels;
|
|
WaveFormat->nSamplesPerSec = p->Codec.Out.Format.Format.Audio.SampleRate;
|
|
WaveFormat->nAvgBytesPerSec = p->Codec.Out.Format.ByteRate;
|
|
WaveFormat->nBlockAlign = (WORD)p->Codec.Out.Format.Format.Audio.BlockAlign;
|
|
WaveFormat->wBitsPerSample = (WORD)p->Codec.Out.Format.Format.Audio.Bits;
|
|
WaveFormat->cbSize = 0;
|
|
|
|
p->OutType.majortype = WMCMEDIATYPE_Audio;
|
|
p->OutType.formattype = WMCFORMAT_WaveFormatEx;
|
|
p->OutType.subtype = WMCMEDIASUBTYPE;
|
|
p->OutType.subtype.v1 = AUDIOFMT_PCM;
|
|
p->OutType.bTemporalCompression = 0;
|
|
p->OutType.bFixedSizeSamples = 1;
|
|
p->OutType.lSampleSize = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int Resend(dmo* p)
|
|
{
|
|
int Result = ERR_INVALID_DATA;
|
|
if (p->OutputPrev >= 0 && p->OutputPrev != p->OutputNext)
|
|
{
|
|
IOwnMediaBuffer* Buffer = (IOwnMediaBuffer*) p->OutputBuffer[p->OutputPrev].pBuffer;
|
|
packet Packet;
|
|
flowstate State;
|
|
|
|
State.CurrTime = TIME_RESEND;
|
|
State.DropLevel = 0;
|
|
|
|
memset(&Packet,0,sizeof(Packet));
|
|
Packet.RefTime = TIME_UNKNOWN;
|
|
|
|
if (p->ConstSize)
|
|
{
|
|
BITMAPINFOHEADER* Info = Buffer->Data;
|
|
Packet.Length = Buffer->Length - Info->biSize;
|
|
Packet.Data[0] = (char*)Buffer->Data + Info->biSize;
|
|
}
|
|
else
|
|
{
|
|
Packet.Length = Buffer->Length;
|
|
Packet.Data[0] = Buffer->Data;
|
|
}
|
|
|
|
if (Packet.Length > 0)
|
|
Result = p->Codec.Out.Process(p->Codec.Out.Pin.Node,&Packet,&State);
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
static int UpdateInput(dmo* p)
|
|
{
|
|
VIDEOINFOHEADER* VideoInfo;
|
|
WAVEFORMATEX* WaveFormat;
|
|
int Dummy;
|
|
int BufferSize;
|
|
int AutoBufferSize;
|
|
int No,Extra;
|
|
bool_t ForceRGB;
|
|
bool_t Found;
|
|
bool_t MinBufferSize = 0;
|
|
|
|
for (No=0;No<=p->OutputNoMask;++No)
|
|
if (p->OutputBuffer[No].pBuffer)
|
|
{
|
|
p->OutputBuffer[No].pBuffer->VMT->Release(p->OutputBuffer[No].pBuffer);
|
|
p->OutputBuffer[No].pBuffer = NULL;
|
|
}
|
|
|
|
p->Codec.ReSend = NULL;
|
|
p->ConstSize = 0;
|
|
p->Const = NULL;
|
|
p->WMPVersion = QueryPlatform(PLATFORM_WMPVERSION);
|
|
|
|
MoFreeMediaType(&p->InType);
|
|
memset(&p->InType,0,sizeof(p->InType));
|
|
|
|
MoFreeMediaType(&p->OutType);
|
|
memset(&p->OutType,0,sizeof(p->OutType));
|
|
|
|
if (p->Media)
|
|
{
|
|
p->Media->VMT->FreeStreamingResources(p->Media);
|
|
p->Media->VMT->Release(p->Media);
|
|
p->Media = NULL;
|
|
}
|
|
|
|
if (p->Codec.In.Format.Type != PACKET_NONE)
|
|
{
|
|
uint32_t FourCC;
|
|
switch (p->Codec.In.Format.Type)
|
|
{
|
|
case PACKET_VIDEO:
|
|
FourCC = p->Codec.In.Format.Format.Video.Pixel.FourCC;
|
|
break;
|
|
|
|
case PACKET_AUDIO:
|
|
FourCC = p->Codec.In.Format.Format.Audio.Format;
|
|
break;
|
|
|
|
default:
|
|
FourCC = 0;
|
|
break;
|
|
}
|
|
|
|
if (FourCC && p->CreateCodecDMOEx)
|
|
p->CreateCodecDMOEx(FourCC,&p->Media);
|
|
else
|
|
if (p->CreateCodecDMO)
|
|
p->CreateCodecDMO(&p->Media);
|
|
else
|
|
if (p->DllGetClassObject)
|
|
{
|
|
IClassFactory* Class = NULL;
|
|
if (p->DllGetClassObject(&p->ClassId,&ID_ICLASSFACTORY,&Class) == S_OK)
|
|
{
|
|
Class->lpVtbl->CreateInstance(Class,NULL,(REFIID)&IID_IMediaObject,&p->Media);
|
|
Class->lpVtbl->Release(Class);
|
|
}
|
|
}
|
|
if (!p->Media)
|
|
return ERR_INVALID_PARAM;
|
|
|
|
switch (p->Codec.In.Format.Type)
|
|
{
|
|
case PACKET_VIDEO:
|
|
|
|
Extra = p->Codec.In.Format.ExtraLength;
|
|
if ((p->Codec.In.Format.Format.Video.Pixel.FourCC == FOURCC('W','M','V','3') ||
|
|
p->Codec.In.Format.Format.Video.Pixel.FourCC == FOURCC('W','M','V','2')) && Extra>4)
|
|
Extra = 4; //hope this is right...
|
|
|
|
if (MoInitMediaType(&p->InType,sizeof(VIDEOINFOHEADER)+Extra) != S_OK)
|
|
return ERR_OUT_OF_MEMORY;
|
|
|
|
VideoInfo = (VIDEOINFOHEADER*)p->InType.pbFormat;
|
|
memset(VideoInfo,0,sizeof(VIDEOINFOHEADER));
|
|
VideoInfo->bmiHeader.biSize = sizeof(VideoInfo->bmiHeader)+Extra;
|
|
VideoInfo->bmiHeader.biWidth = p->Codec.In.Format.Format.Video.Width;
|
|
VideoInfo->bmiHeader.biHeight = p->Codec.In.Format.Format.Video.Height;
|
|
VideoInfo->bmiHeader.biCompression = p->Codec.In.Format.Format.Video.Pixel.FourCC;
|
|
VideoInfo->bmiHeader.biBitCount = (WORD)p->Codec.In.Format.Format.Video.Pixel.BitCount;
|
|
VideoInfo->bmiHeader.biPlanes = 1;
|
|
VideoInfo->bmiHeader.biSizeImage = (p->Codec.In.Format.Format.Video.Width *
|
|
p->Codec.In.Format.Format.Video.Height * p->Codec.In.Format.Format.Video.Pixel.BitCount)/8;
|
|
if (p->WMPVersion > 9)
|
|
VideoInfo->bmiHeader.biSizeImage = 0;
|
|
if (Extra)
|
|
memcpy(VideoInfo+1,p->Codec.In.Format.Extra,Extra);
|
|
|
|
VideoInfo->rcSource.left = 0;
|
|
VideoInfo->rcSource.top = 0;
|
|
VideoInfo->rcSource.right = p->Codec.In.Format.Format.Video.Width;
|
|
VideoInfo->rcSource.bottom = p->Codec.In.Format.Format.Video.Height;
|
|
VideoInfo->rcTarget = VideoInfo->rcSource;
|
|
|
|
if (p->Codec.In.Format.PacketRate.Num)
|
|
{
|
|
VideoInfo->AvgTimePerFrame = (REFERENCE_TIME)p->Codec.In.Format.PacketRate.Den * 10000000 / p->Codec.In.Format.PacketRate.Num;
|
|
VideoInfo->dwBitRate = Scale(VideoInfo->bmiHeader.biSizeImage*8,p->Codec.In.Format.PacketRate.Num,p->Codec.In.Format.PacketRate.Den);
|
|
}
|
|
|
|
p->InType.majortype = WMCMEDIATYPE_Video;
|
|
p->InType.formattype = WMCFORMAT_VideoInfo;
|
|
p->InType.subtype = WMCMEDIASUBTYPE;
|
|
p->InType.subtype.v1 = p->Codec.In.Format.Format.Video.Pixel.FourCC;
|
|
|
|
if (p->Media->VMT->SetInputType(p->Media, 0, &p->InType, 0) != S_OK)
|
|
return ERR_INVALID_DATA;
|
|
|
|
// for some reason using planar yuv fails with Window Mobile WMP10 :(
|
|
ForceRGB = p->CreateCodecDMO && p->WMPVersion==10;
|
|
|
|
// some version of C550 ROM uses low level stuff which raises exception in non Kernel mode (default on smartphone)
|
|
Found = 0;
|
|
TRY_BEGIN
|
|
// first try I420 (sometimes it's not enumarated as supported format, even if it is)
|
|
if (!(ForceRGB?BuildRGB16(p):BuildI420(p)) || p->Media->VMT->SetOutputType(p->Media,0, &p->OutType, 0) != S_OK)
|
|
{
|
|
MoFreeMediaType(&p->OutType);
|
|
memset(&p->OutType,0,sizeof(p->OutType));
|
|
|
|
if (ForceRGB || !MatchOutVideo(p,0))
|
|
{
|
|
video Desktop;
|
|
QueryDesktop(&Desktop);
|
|
if (Desktop.Pixel.BitCount!=16 || !MatchOutVideo(p,1))
|
|
{
|
|
if (!MatchOutVideo(p,2))
|
|
return ERR_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
if (p->Media->VMT->SetOutputType(p->Media,0, &p->OutType, 0) != S_OK)
|
|
return ERR_INVALID_DATA;
|
|
}
|
|
Found = 1;
|
|
TRY_END
|
|
if (!Found)
|
|
return ERR_INVALID_DATA;
|
|
|
|
if (p->WMPVersion==9 && PlanarYUV420(&p->Codec.Out.Format.Format.Video.Pixel))
|
|
{
|
|
// override default pitch, it has to be dword aligned
|
|
p->Codec.Out.Format.Format.Video.Pitch = (p->Codec.Out.Format.Format.Video.Pitch+3) & ~3;
|
|
MinBufferSize = 1;
|
|
}
|
|
|
|
AutoBufferSize = GetImageSize(&p->Codec.Out.Format.Format.Video);
|
|
|
|
if (p->CreateCodecDMO)
|
|
{
|
|
AutoBufferSize += VideoInfo->bmiHeader.biSize;
|
|
p->ConstSize = VideoInfo->bmiHeader.biSize;
|
|
p->Const = &VideoInfo->bmiHeader;
|
|
}
|
|
|
|
p->Codec.ReSend = Resend;
|
|
p->OutputNoMask = 1;
|
|
p->UseDropping = 1;
|
|
break;
|
|
|
|
case PACKET_AUDIO:
|
|
|
|
if (MoInitMediaType(&p->InType,sizeof(WAVEFORMATEX)+p->Codec.In.Format.ExtraLength) != S_OK)
|
|
return ERR_OUT_OF_MEMORY;
|
|
|
|
WaveFormat = (WAVEFORMATEX*)p->InType.pbFormat;
|
|
memset(WaveFormat,0,sizeof(WAVEFORMATEX));
|
|
|
|
WaveFormat->wFormatTag = (WORD)p->Codec.In.Format.Format.Audio.Format;
|
|
WaveFormat->nChannels = (WORD)p->Codec.In.Format.Format.Audio.Channels;
|
|
WaveFormat->nSamplesPerSec = p->Codec.In.Format.Format.Audio.SampleRate;
|
|
WaveFormat->nAvgBytesPerSec = p->Codec.In.Format.ByteRate;
|
|
WaveFormat->nBlockAlign = (WORD)p->Codec.In.Format.Format.Audio.BlockAlign;
|
|
WaveFormat->wBitsPerSample = (WORD)p->Codec.In.Format.Format.Audio.Bits;
|
|
WaveFormat->cbSize = (WORD)p->Codec.In.Format.ExtraLength;
|
|
if (p->Codec.In.Format.ExtraLength)
|
|
{
|
|
// PocketPC WMP9
|
|
if (p->CreateCodecDMO && p->WMPVersion==9 && WaveFormat->wFormatTag == AUDIOFMT_WMA9 && p->Codec.In.Format.ExtraLength==10)
|
|
{
|
|
char* e = (char*)(WaveFormat+1);
|
|
e[0] = e[1] = 0;
|
|
e[8] = e[9] = 0;
|
|
memcpy(e+2,p->Codec.In.Format.Extra,6);
|
|
}
|
|
else
|
|
memcpy(WaveFormat+1,p->Codec.In.Format.Extra,p->Codec.In.Format.ExtraLength);
|
|
}
|
|
|
|
p->InType.majortype = WMCMEDIATYPE_Audio;
|
|
p->InType.formattype = WMCFORMAT_WaveFormatEx;
|
|
p->InType.subtype = WMCMEDIASUBTYPE;
|
|
p->InType.subtype.v1 = p->Codec.In.Format.Format.Audio.Format;
|
|
p->InType.bTemporalCompression = 0;
|
|
p->InType.bFixedSizeSamples = 1;
|
|
p->InType.lSampleSize = 0;
|
|
|
|
if (p->Media->VMT->SetInputType(p->Media, 0, &p->InType, 0) != S_OK)
|
|
return ERR_INVALID_DATA;
|
|
|
|
if (!BuildPCM(p))
|
|
return ERR_INVALID_DATA;
|
|
|
|
Found = 0;
|
|
TRY_BEGIN
|
|
if (p->Media->VMT->SetOutputType(p->Media,0, &p->OutType, 0) != S_OK)
|
|
return ERR_INVALID_DATA;
|
|
Found = 1;
|
|
TRY_END
|
|
if (!Found)
|
|
return ERR_INVALID_DATA;
|
|
|
|
// it seems pocketpc can't split output data
|
|
if (WaveFormat->nBlockAlign && WaveFormat->nAvgBytesPerSec)
|
|
{
|
|
AutoBufferSize = Scale(p->Codec.Out.Format.ByteRate,WaveFormat->nBlockAlign,WaveFormat->nAvgBytesPerSec);
|
|
AutoBufferSize *= 4; // just to be safe
|
|
if (AutoBufferSize < 128*1024)
|
|
AutoBufferSize = 128*1024;
|
|
}
|
|
else
|
|
AutoBufferSize = 128*1024;
|
|
|
|
p->OutputNoMask = 0;
|
|
p->UseDropping = 0;
|
|
break;
|
|
|
|
default:
|
|
return ERR_INVALID_DATA;
|
|
}
|
|
|
|
BufferSize = 0;
|
|
if (p->Media->VMT->GetOutputSizeInfo(p->Media, 0, (DWORD*)&BufferSize, (DWORD*)&Dummy) != S_OK)
|
|
return ERR_INVALID_DATA;
|
|
|
|
if (BufferSize<=0 || (MinBufferSize && BufferSize < AutoBufferSize))
|
|
BufferSize = AutoBufferSize;
|
|
else
|
|
if (p->WMPVersion>9)
|
|
BufferSize += 4096;
|
|
|
|
for (No=0;No<=p->OutputNoMask;++No)
|
|
{
|
|
p->OutputBuffer[No].pBuffer = (IMediaBuffer*) AllocBuffer(BufferSize,NULL);
|
|
if (!p->OutputBuffer[No].pBuffer)
|
|
return ERR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
p->First = p->UseDropping;
|
|
p->OutputNext = 0;
|
|
p->OutputPrev = -1;
|
|
p->Media->VMT->AllocateStreamingResources(p->Media);
|
|
}
|
|
|
|
FreeBuffers(&p->InputBuffers);
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static int Process(dmo* p, const packet* Packet, const flowstate* State)
|
|
{
|
|
REFERENCE_TIME TimeStamp;
|
|
DWORD Status;
|
|
IOwnMediaBuffer* Buffer;
|
|
IOwnMediaBuffer* LastBuffer;
|
|
|
|
if (Packet)
|
|
{
|
|
if (State->DropLevel > 1)
|
|
{
|
|
p->Media->VMT->Discontinuity(p->Media,0);
|
|
p->First = p->UseDropping;
|
|
return ERR_NONE;
|
|
}
|
|
|
|
if (p->Media->VMT->GetInputStatus(p->Media, 0, &Status)==0 &&
|
|
!(Status & DMO_INPUT_STATUSF_ACCEPT_DATA)) // this shouldn't happen
|
|
p->Media->VMT->Discontinuity(p->Media,0);
|
|
|
|
Status = 0;
|
|
if (Packet->Key)
|
|
Status |= DMO_INPUT_DATA_BUFFERF_SYNCPOINT;
|
|
else
|
|
if (p->First)
|
|
return ERR_NEED_MORE_DATA;
|
|
|
|
TimeStamp = 0;
|
|
if (Packet->RefTime >= 0)
|
|
{
|
|
Status |= DMO_INPUT_DATA_BUFFERF_TIME;
|
|
TimeStamp = ((REFERENCE_TIME)Packet->RefTime * 10000000 + (TICKSPERSEC/2)) / TICKSPERSEC;
|
|
}
|
|
|
|
Buffer = AllocBuffer(Packet->Length+p->ConstSize,&p->InputBuffers);
|
|
if (Buffer)
|
|
{
|
|
if (p->Const)
|
|
{
|
|
if (p->WMPVersion>9) p->Const->biSizeImage = Packet->Length;
|
|
AppendBuffer((IOwnMediaBuffer*)Buffer,p->ConstSize,p->Const);
|
|
}
|
|
|
|
if (Packet->Data[0])
|
|
AppendBuffer((IOwnMediaBuffer*)Buffer,Packet->Length,Packet->Data[0]);
|
|
|
|
p->Media->VMT->ProcessInput(p->Media,0,(IMediaBuffer*)Buffer,Status,TimeStamp,0);
|
|
Buffer->VMT->Release(Buffer);
|
|
}
|
|
}
|
|
|
|
LastBuffer = NULL;
|
|
if (p->OutputPrev >= 0 && p->OutputPrev != p->OutputNext)
|
|
LastBuffer = (IOwnMediaBuffer*) p->OutputBuffer[p->OutputPrev].pBuffer;
|
|
|
|
if (State && State->DropLevel > 0)
|
|
{
|
|
DMO_OUTPUT_DATA_BUFFER Discard;
|
|
Discard.dwStatus = 0;
|
|
Discard.pBuffer = NULL;
|
|
|
|
p->Media->VMT->ProcessOutput(p->Media, DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER, 1, &Discard, &Status);
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
Buffer = (IOwnMediaBuffer*) p->OutputBuffer[p->OutputNext].pBuffer;
|
|
Buffer->Length = 0;
|
|
|
|
p->OutputBuffer[p->OutputNext].dwStatus = 0;
|
|
|
|
if (p->Media->VMT->ProcessOutput(p->Media, 0, 1, &p->OutputBuffer[p->OutputNext], &Status) != S_OK || Buffer->Length==0)
|
|
break;
|
|
|
|
if (State && State->DropLevel > 0)
|
|
{
|
|
p->Codec.Out.Process(p->Codec.Out.Pin.Node,NULL,State);
|
|
continue;
|
|
}
|
|
|
|
if (p->OutputBuffer[p->OutputNext].dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIME)
|
|
p->Codec.Packet.RefTime = (tick_t)((p->OutputBuffer[p->OutputNext].rtTimestamp * TICKSPERSEC + 5000000) / 10000000);
|
|
else
|
|
p->Codec.Packet.RefTime = -1;
|
|
|
|
if (p->ConstSize)
|
|
{
|
|
BITMAPINFOHEADER* Info = Buffer->Data;
|
|
p->Codec.Packet.Length = Buffer->Length - Info->biSize;
|
|
p->Codec.Packet.Data[0] = (char*)Buffer->Data + Info->biSize;
|
|
p->Codec.Packet.LastData[0] = NULL;
|
|
if (LastBuffer)
|
|
p->Codec.Packet.LastData[0] = (char*)LastBuffer->Data + Info->biSize;
|
|
if (p->Codec.Packet.Length <= 0)
|
|
p->Codec.Packet.Data[0] = NULL;
|
|
}
|
|
else
|
|
{
|
|
p->Codec.Packet.Length = Buffer->Length;
|
|
p->Codec.Packet.Data[0] = Buffer->Data;
|
|
p->Codec.Packet.LastData[0] = NULL;
|
|
if (LastBuffer)
|
|
p->Codec.Packet.LastData[0] = LastBuffer->Data;
|
|
}
|
|
|
|
p->OutputPrev = p->OutputNext;
|
|
p->OutputNext = (p->OutputNext+1) & p->OutputNoMask;
|
|
p->First = 0;
|
|
return ERR_NONE;
|
|
}
|
|
|
|
return ERR_NEED_MORE_DATA;
|
|
}
|
|
|
|
static int Flush(dmo* p)
|
|
{
|
|
if (p->Media)
|
|
{
|
|
p->Media->VMT->Discontinuity(p->Media,0);
|
|
p->Media->VMT->Flush(p->Media);
|
|
}
|
|
p->OutputPrev = -1;
|
|
p->First = p->UseDropping;
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static int Create(dmo* p)
|
|
{
|
|
p->Module = LoadLibrary(LangStr(p->Codec.Node.Class,DMO_MODULEPPC));
|
|
GetProc(&p->Module,&p->CreateCodecDMO,T("CreateCodecDMO"),0);
|
|
GetProc(&p->Module,&p->CreateCodecDMOEx,T("CreateCodecDMOEx"),1);
|
|
GetProc(&p->Module,&p->QueryUnloadCodecDMO,T("QueryUnloadCodecDMO"),1);
|
|
|
|
if (!p->Module && StringToGUID(LangStr(p->Codec.Node.Class,DMO_CLASSID),&p->ClassId))
|
|
{
|
|
p->Module = LoadLibrary(LangStr(p->Codec.Node.Class,DMO_MODULE));
|
|
GetProc(&p->Module,&p->DllGetClassObject,T("DllGetClassObject"),0);
|
|
GetProc(&p->Module,&p->DllCanUnloadNow,T("DllCanUnloadNow"),1);
|
|
}
|
|
|
|
if (!p->Module)
|
|
return ERR_NOT_SUPPORTED;
|
|
|
|
p->Codec.Flush = Flush;
|
|
p->Codec.Process = Process;
|
|
p->Codec.UpdateInput = UpdateInput;
|
|
return ERR_NONE;
|
|
}
|
|
|
|
static void Delete(dmo* p)
|
|
{
|
|
if ((p->QueryUnloadCodecDMO==NULL || p->QueryUnloadCodecDMO()) &&
|
|
(p->DllCanUnloadNow==NULL || p->DllCanUnloadNow()==S_OK))
|
|
FreeLibrary(p->Module);
|
|
}
|
|
|
|
static const nodedef DMO =
|
|
{
|
|
sizeof(dmo)|CF_ABSTRACT,
|
|
DMO_CLASS,
|
|
CODEC_CLASS,
|
|
PRI_DEFAULT-100,
|
|
(nodecreate)Create,
|
|
(nodedelete)Delete,
|
|
};
|
|
|
|
static const nodedef WMV =
|
|
{
|
|
0, // parent size
|
|
WMV_ID,
|
|
DMO_CLASS,
|
|
PRI_DEFAULT-100,
|
|
};
|
|
|
|
static const nodedef WMS =
|
|
{
|
|
0, // parent size
|
|
WMS_ID,
|
|
DMO_CLASS,
|
|
PRI_DEFAULT-100,
|
|
};
|
|
|
|
static const nodedef WMVA =
|
|
{
|
|
0, // parent size
|
|
WMVA_ID,
|
|
DMO_CLASS,
|
|
PRI_DEFAULT-95,
|
|
};
|
|
|
|
static const nodedef WMA =
|
|
{
|
|
0, // parent size
|
|
WMA_ID,
|
|
DMO_CLASS,
|
|
PRI_DEFAULT-100,
|
|
};
|
|
|
|
static const nodedef WMAV =
|
|
{
|
|
0, // parent size
|
|
WMAV_ID,
|
|
DMO_CLASS,
|
|
PRI_DEFAULT-100,
|
|
};
|
|
|
|
//todo: auto find supported content-types
|
|
static int Find(int Class)
|
|
{
|
|
if (CheckModule(LangStr(Class,DMO_MODULEPPC)))
|
|
return 2;
|
|
if (CheckModule(LangStr(Class,DMO_MODULE)))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
void DMO_Init()
|
|
{
|
|
int WMPVersion = QueryPlatform(PLATFORM_WMPVERSION);
|
|
|
|
#ifndef TARGET_WIN32
|
|
// shellexecute won't work under win32
|
|
CoInitializeEx(NULL,COINIT_MULTITHREADED);
|
|
#endif
|
|
|
|
NodeRegisterClass(&DMO);
|
|
|
|
if (Find(WMV_ID))
|
|
{
|
|
NodeRegisterClass(&WMV);
|
|
NodeRegisterClass(&WMVF);
|
|
}
|
|
|
|
if (Find(WMVA_ID))
|
|
{
|
|
NodeRegisterClass(&WMVA);
|
|
NodeRegisterClass(&WMVF);
|
|
}
|
|
|
|
if (Find(WMS_ID))
|
|
{
|
|
NodeRegisterClass(&WMS);
|
|
NodeRegisterClass(&WMVF);
|
|
}
|
|
|
|
if (Find(WMA_ID))
|
|
{
|
|
NodeRegisterClass(&WMA);
|
|
NodeRegisterClass(&WMAF);
|
|
}
|
|
|
|
if (Find(WMAV_ID))
|
|
{
|
|
NodeRegisterClass(&WMAV);
|
|
NodeRegisterClass(&WMAF);
|
|
|
|
if (WMPVersion==9 && QueryPlatform(PLATFORM_CAPS) & CAPS_ARM_XSCALE)
|
|
{
|
|
DWORD Disp=0;
|
|
HKEY Key;
|
|
tchar_t* Base = T("SOFTWARE\\Microsoft\\Windows Media Player\\Codecs\\WMAVoice");
|
|
|
|
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, Base, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &Key, &Disp) == ERROR_SUCCESS)
|
|
{
|
|
DWORD Value = 1;
|
|
RegSetValueEx(Key, T("CPUPerformance"), 0, REG_DWORD, (LPBYTE)&Value, sizeof(Value));
|
|
RegCloseKey(Key);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DMO_Done()
|
|
{
|
|
NodeUnRegisterClass(DMO_CLASS);
|
|
NodeUnRegisterClass(WMAF_ID);
|
|
NodeUnRegisterClass(WMVF_ID);
|
|
|
|
#ifndef TARGET_WIN32
|
|
CoUninitialize();
|
|
#endif
|
|
}
|
|
|
|
#endif
|