📄 dmo_win32.c
字号:
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->Output.Node->Set(p->Output.Node,p->Output.No,&Packet,sizeof(packet));
}
return Result;
}
static bool_t DecodePacket( dmo* p )
{
DWORD Status;
IOwnMediaBuffer* Buffer;
IOwnMediaBuffer* LastBuffer;
LastBuffer = NULL;
if (p->OutputPrev >= 0 && p->OutputPrev != p->OutputNext)
LastBuffer = (IOwnMediaBuffer*) p->OutputBuffer[p->OutputPrev].pBuffer;
if (p->Packet.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);
//DebugMessage(T("DMO%d CurrTime:%d Drop"),p->FormatType,p->Packet.CurrTime);
}
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 (p->Packet.DropLevel > 0)
continue;
if (p->OutputBuffer[p->OutputNext].dwStatus & DMO_OUTPUT_DATA_BUFFERF_TIME)
p->Packet.RefTime = (tick_t)(p->OutputBuffer[p->OutputNext].rtTimestamp * TICKSPERSEC / 10000000);
else
p->Packet.RefTime = -1;
if (p->ConstSize)
{
BITMAPINFOHEADER* Info = Buffer->Data;
p->Packet.Length = Buffer->Length - Info->biSize;
p->Packet.Data[0] = (char*)Buffer->Data + Info->biSize;
p->Packet.LastData[0] = NULL;
if (LastBuffer)
p->Packet.LastData[0] = (char*)LastBuffer->Data + Info->biSize;
if (p->Packet.Length <= 0)
continue; // empty frame (i guess)
}
else
{
p->Packet.Length = Buffer->Length;
p->Packet.Data[0] = Buffer->Data;
p->Packet.LastData[0] = NULL;
if (LastBuffer)
p->Packet.LastData[0] = LastBuffer->Data;
}
//DebugMessage(T("DMO%d CurrTime:%d RefTime:%d Diff:%d"),p->FormatType,p->Packet.CurrTime,p->Packet.RefTime,p->Packet.CurrTime-p->Packet.RefTime);
//DEBUG_MSG4(-1,T("DMO%d Output Time:%d Length:%d LastData:%d"),p->FormatType,p->Packet.RefTime,p->Packet.Length,p->Packet.LastData[0] != NULL);
p->First = 0;
p->TotalBytes += p->Packet.Length;
return 1;
}
return 0;
}
static int Decode( dmo* p, const packet* Packet )
{
IMediaBuffer* Buffer;
REFERENCE_TIME TimeStamp;
DWORD Status;
int Result = ERR_NONE;
p->Packet.CurrTime = Packet->CurrTime;
p->Packet.DropLevel = p->First ? 0:Packet->DropLevel;
if (p->Pending)
{
do
{
if (p->Output.Node->Set(p->Output.Node,p->Output.No,
&p->Packet,sizeof(packet)) == ERR_BUFFER_FULL)
return ERR_BUFFER_FULL;
p->OutputPrev = p->OutputNext;
p->OutputNext = (p->OutputNext+1) & p->OutputNoMask;
}
while (DecodePacket(p));
p->Pending = 0;
}
if (!Packet->Length)
return ERR_NEED_MORE_DATA;
p->TotalPackets++;
if (Packet->DropLevel > 0)
{
++p->DroppedPackets;
if (Packet->DropLevel > 1)
{
DEBUG_MSG3(DEBUG_VIDEO,T("DMO%d DropLevel2 Curr:%d Time:%d"),p->FormatType,Packet->CurrTime,Packet->RefTime);
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;
}
//DEBUG_MSG3(-1,T("DMO%d Input Time:%d Size:%d"),p->FormatType,Packet->RefTime,Packet->Length);
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,Buffer,Status,TimeStamp,0);
Buffer->VMT->Release(Buffer);
}
if (DecodePacket(p))
{
Result = ERR_NONE;
do
{
int i = p->Output.Node->Set(p->Output.Node,p->Output.No,
&p->Packet,sizeof(packet));
if (i == ERR_BUFFER_FULL)
{
p->Pending = 1;
//return last result
break;
}
p->OutputPrev = p->OutputNext;
p->OutputNext = (p->OutputNext+1) & p->OutputNoMask;
Result = i;
}
while (DecodePacket(p));
}
else
Result = ERR_NEED_MORE_DATA; // if no frame decoded: need more packet
return Result;
}
static bool_t IsEmpty( dmo* p )
{
packet Zero;
if (!p->InputFormat)
return 1;
p->Media->VMT->Discontinuity(p->Media,0);
Zero.CurrTime = -1;
Zero.DropLevel = p->Packet.DropLevel;
Zero.Length = 0;
Zero.Data[0] = NULL;
Zero.RefTime = -1;
return Decode(p,&Zero) == ERR_NEED_MORE_DATA;
}
const datadef DMOParams[] =
{
{ DMO_CLASS, TYPE_CLASS },
{ DMO_INPUT, TYPE_PACKET, DF_INPUT, -1 },
{ DMO_OUTPUT, TYPE_PIN, DF_OUTPUT, -1 },
DATADEF_END
};
static int Enum( dmo* p, int No, datadef* Param )
{
int Result = NodeEnumType(&No,Param,NodeParams,FlowParams,DMOParams,NULL);
if (Result != ERR_NONE && p->FormatType == PACKET_VIDEO)
Result = NodeEnumType(&No,Param,FlowBufferParams,NULL);
if (Result == ERR_NONE && Param->Class == DMO_CLASS &&
(Param->No == DMO_INPUT || Param->No == DMO_OUTPUT))
Param->Format1 = p->FormatType;
return Result;
}
static int GetTotal( dmo* p )
{
if (p->FormatType == PACKET_VIDEO)
return p->TotalPackets;
if (p->FormatType == PACKET_AUDIO && p->OutputFormat)
{
int BlockAlign = ((audio*)p->OutputFormat)->BlockAlign;
if (BlockAlign)
return p->TotalBytes / BlockAlign;
}
return 0;
}
static int GetDropped( dmo* p )
{
if (p->FormatType == PACKET_VIDEO)
return p->DroppedPackets;
return 0;
}
static int Get( dmo* p, int No, void* Data, int Size )
{
int Result = ERR_INVALID_PARAM;
switch (No)
{
case NODE_ID: GETVALUE(p->Id,int); break;
case DMO_INPUT | PACKET_FORMAT:
if (Size == p->FormatSize)
{
if (p->InputFormat)
memcpy(Data,p->InputFormat,p->FormatSize);
else
memset(Data,0,p->FormatSize);
Result = ERR_NONE;
}
break;
case DMO_OUTPUT | PACKET_FORMAT:
if (Size == p->FormatSize)
{
if (p->OutputFormat)
memcpy(Data,p->OutputFormat,p->FormatSize);
else
memset(Data,0,p->FormatSize);
Result = ERR_NONE;
}
break;
case DMO_OUTPUT: GETVALUE(p->Output,pin); break;
case FLOW_TOTAL:GETVALUE(GetTotal(p),int); break;
case FLOW_DROPPED:GETVALUE(GetDropped(p),int); break;
case FLOW_EMPTY:GETVALUE(IsEmpty(p),bool_t); break;
}
return Result;
}
static int Set( dmo* p, int No, const void* Data, int Size )
{
int Result = ERR_INVALID_PARAM;
switch (No)
{
case DMO_INPUT | PACKET_FORMAT:
if (!Size) Data = NULL;
Result = SetFormat(p,(const audio*)Data,Size);
break;
case DMO_INPUT:
if (Size == sizeof(packet))
Result = Decode(p,(const packet*)Data);
break;
case DMO_OUTPUT:
if (Size == sizeof(pin))
Result = NodeSetPin(&p->Output,(pin*)Data,p->OutputFormat,p->FormatSize);
break;
case FLOWBUFFER_RESEND:
Result = Resend(p);
break;
case FLOW_TOTAL:
p->TotalPackets = 0;
p->TotalBytes = 0;
break;
case FLOW_DROPPED:
p->DroppedPackets = 0;
break;
case FLOW_EMPTY:
p->OutputPrev = -1;
p->Media->VMT->Discontinuity(p->Media,0);
p->Media->VMT->Flush(p->Media);
p->Pending = 0;
p->First = p->UseDropping;
break;
}
return Result;
}
static dmo* Chain = NULL;
bool_t DMO_Load( const CLSID* ClassId,const tchar_t* FileNamePPC,const tchar_t* FileNameCOM,
int Id,int FormatType, ... )
{
dmo* p;
const int* List = (const int*)&FormatType+1;
if (!FuncMoInitMediaType || !FuncMoFreeMediaType)
return 0;
p = (dmo*) CAlloc(sizeof(dmo),1);
p->Id = Id;
p->ClassId = ClassId;
p->FormatType = FormatType;
for (;*List;++List)
p->FourCC[p->FourCCCount++] = *List;
if (FileNamePPC)
p->Module = LoadLibrary(FileNamePPC);
if (!p->Module && FileNameCOM)
p->Module = LoadLibrary(FileNameCOM);
if (p->Module)
{
*(FARPROC*)&p->CreateCodecDMO = GetProcAddress(p->Module,TWIN("CreateCodecDMO"));
*(FARPROC*)&p->QueryUnloadCodecDMO = GetProcAddress(p->Module,TWIN("QueryUnloadCodecDMO"));
*(FARPROC*)&p->DllGetClassObject = GetProcAddress(p->Module,TWIN("DllGetClassObject"));
*(FARPROC*)&p->DllCanUnloadNow = GetProcAddress(p->Module,TWIN("DllCanUnloadNow"));
}
if (!p->CreateCodecDMO && !p->DllGetClassObject)
{
if (p->Module)
FreeLibrary(p->Module);
Free(p);
return 0;
}
#if defined(_WIN32_WCE)
p->WMPVersion = 9;
{
HKEY Key;
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, T("SOFTWARE\\Microsoft\\MediaPlayer\\ASFCodecs"), 0, ACCESS_LOAD, &Key ) == ERROR_SUCCESS)
{
p->WMPVersion = 10;
RegCloseKey( Key );
// wmp10 wm video only works with rgb16
// which is currently not supported by BetaPlayer
if (TcsICmp(FileNamePPC,T("wmvdecoder.dll"))==0 && p->CreateCodecDMO)
{
if (p->Module)
FreeLibrary(p->Module);
Free(p);
return 0;
}
}
}
#else
p->WMPVersion = 0;
#endif
p->VMT.Enum = Enum;
p->VMT.Get = Get;
p->VMT.Set = Set;
p->Chain = Chain;
Chain = p;
NodeRegister(&p->VMT,PRI_DEFAULT-100); // we prefer native codecs
return 1;
}
static HMODULE MSDMODLL = NULL;
void DMO_Init()
{
CoInitializeEx(NULL,COINIT_MULTITHREADED);
MSDMODLL = LoadLibrary(T("msdmo.dll"));
if (!MSDMODLL)
return;
*(FARPROC*)&FuncMoInitMediaType = GetProcAddress(MSDMODLL,TWIN("MoInitMediaType"));
*(FARPROC*)&FuncMoFreeMediaType = GetProcAddress(MSDMODLL,TWIN("MoFreeMediaType"));
}
void DMO_Done()
{
dmo* i = Chain;
while (i)
{
dmo* j=i->Chain;
NodeUnRegister(&i->VMT);
SetFormat(i,NULL,0);
if (i->Module &&
(!i->QueryUnloadCodecDMO || i->QueryUnloadCodecDMO()) &&
(!i->DllCanUnloadNow || i->DllCanUnloadNow()==S_OK))
FreeLibrary(i->Module);
Free(i);
i=j;
}
Chain = NULL;
if (MSDMODLL)
{
FreeLibrary(MSDMODLL);
MSDMODLL = NULL;
}
CoUninitialize();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -