// CreateCoder.cpp | |
#include "StdAfx.h" | |
#include "../../Windows/Defs.h" | |
#include "../../Windows/PropVariant.h" | |
#include "CreateCoder.h" | |
#include "FilterCoder.h" | |
#include "RegisterCodec.h" | |
static const unsigned int kNumCodecsMax = 64; | |
unsigned int g_NumCodecs = 0; | |
const CCodecInfo *g_Codecs[kNumCodecsMax]; | |
void RegisterCodec(const CCodecInfo *codecInfo) throw() | |
{ | |
if (g_NumCodecs < kNumCodecsMax) | |
g_Codecs[g_NumCodecs++] = codecInfo; | |
} | |
static const unsigned int kNumHashersMax = 16; | |
unsigned int g_NumHashers = 0; | |
const CHasherInfo *g_Hashers[kNumHashersMax]; | |
void RegisterHasher(const CHasherInfo *hashInfo) throw() | |
{ | |
if (g_NumHashers < kNumHashersMax) | |
g_Hashers[g_NumHashers++] = hashInfo; | |
} | |
#ifdef EXTERNAL_CODECS | |
static HRESULT ReadNumberOfStreams(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, UInt32 &res) | |
{ | |
NWindows::NCOM::CPropVariant prop; | |
RINOK(codecsInfo->GetProperty(index, propID, &prop)); | |
if (prop.vt == VT_EMPTY) | |
res = 1; | |
else if (prop.vt == VT_UI4) | |
res = prop.ulVal; | |
else | |
return E_INVALIDARG; | |
return S_OK; | |
} | |
static HRESULT ReadIsAssignedProp(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, bool &res) | |
{ | |
NWindows::NCOM::CPropVariant prop; | |
RINOK(codecsInfo->GetProperty(index, propID, &prop)); | |
if (prop.vt == VT_EMPTY) | |
res = true; | |
else if (prop.vt == VT_BOOL) | |
res = VARIANT_BOOLToBool(prop.boolVal); | |
else | |
return E_INVALIDARG; | |
return S_OK; | |
} | |
HRESULT CExternalCodecs::LoadCodecs() | |
{ | |
if (GetCodecs) | |
{ | |
UInt32 num; | |
RINOK(GetCodecs->GetNumberOfMethods(&num)); | |
for (UInt32 i = 0; i < num; i++) | |
{ | |
CCodecInfoEx info; | |
NWindows::NCOM::CPropVariant prop; | |
RINOK(GetCodecs->GetProperty(i, NMethodPropID::kID, &prop)); | |
// if (prop.vt != VT_BSTR) | |
// info.Id.IDSize = (Byte)SysStringByteLen(prop.bstrVal); | |
// memcpy(info.Id.ID, prop.bstrVal, info.Id.IDSize); | |
if (prop.vt != VT_UI8) | |
continue; // old Interface | |
info.Id = prop.uhVal.QuadPart; | |
prop.Clear(); | |
RINOK(GetCodecs->GetProperty(i, NMethodPropID::kName, &prop)); | |
if (prop.vt == VT_BSTR) | |
info.Name = prop.bstrVal; | |
else if (prop.vt != VT_EMPTY) | |
return E_INVALIDARG; | |
RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kInStreams, info.NumInStreams)); | |
RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kOutStreams, info.NumOutStreams)); | |
RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned)); | |
RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned)); | |
Codecs.Add(info); | |
} | |
} | |
if (GetHashers) | |
{ | |
UInt32 num = GetHashers->GetNumHashers(); | |
for (UInt32 i = 0; i < num; i++) | |
{ | |
CHasherInfoEx info; | |
NWindows::NCOM::CPropVariant prop; | |
RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kID, &prop)); | |
if (prop.vt != VT_UI8) | |
continue; | |
info.Id = prop.uhVal.QuadPart; | |
prop.Clear(); | |
RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kName, &prop)); | |
if (prop.vt == VT_BSTR) | |
info.Name = prop.bstrVal; | |
else if (prop.vt != VT_EMPTY) | |
return E_INVALIDARG; | |
Hashers.Add(info); | |
} | |
} | |
return S_OK; | |
} | |
#endif | |
bool FindMethod(DECL_EXTERNAL_CODECS_LOC_VARS | |
const UString &name, CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams) | |
{ | |
UInt32 i; | |
for (i = 0; i < g_NumCodecs; i++) | |
{ | |
const CCodecInfo &codec = *g_Codecs[i]; | |
if (name.IsEqualToNoCase(codec.Name)) | |
{ | |
methodId = codec.Id; | |
numInStreams = codec.NumInStreams; | |
numOutStreams = 1; | |
return true; | |
} | |
} | |
#ifdef EXTERNAL_CODECS | |
if (__externalCodecs) | |
for (i = 0; i < (UInt32)__externalCodecs->Codecs.Size(); i++) | |
{ | |
const CCodecInfoEx &codec = __externalCodecs->Codecs[i]; | |
if (codec.Name.IsEqualToNoCase(name)) | |
{ | |
methodId = codec.Id; | |
numInStreams = codec.NumInStreams; | |
numOutStreams = codec.NumOutStreams; | |
return true; | |
} | |
} | |
#endif | |
return false; | |
} | |
bool FindMethod(DECL_EXTERNAL_CODECS_LOC_VARS | |
CMethodId methodId, UString &name) | |
{ | |
UInt32 i; | |
for (i = 0; i < g_NumCodecs; i++) | |
{ | |
const CCodecInfo &codec = *g_Codecs[i]; | |
if (methodId == codec.Id) | |
{ | |
name = codec.Name; | |
return true; | |
} | |
} | |
#ifdef EXTERNAL_CODECS | |
if (__externalCodecs) | |
for (i = 0; i < (UInt32)__externalCodecs->Codecs.Size(); i++) | |
{ | |
const CCodecInfoEx &codec = __externalCodecs->Codecs[i]; | |
if (methodId == codec.Id) | |
{ | |
name = codec.Name; | |
return true; | |
} | |
} | |
#endif | |
return false; | |
} | |
bool FindHashMethod(DECL_EXTERNAL_CODECS_LOC_VARS | |
const UString &name, | |
CMethodId &methodId) | |
{ | |
UInt32 i; | |
for (i = 0; i < g_NumHashers; i++) | |
{ | |
const CHasherInfo &codec = *g_Hashers[i]; | |
if (name.IsEqualToNoCase(codec.Name)) | |
{ | |
methodId = codec.Id; | |
return true; | |
} | |
} | |
#ifdef EXTERNAL_CODECS | |
if (__externalCodecs) | |
for (i = 0; i < (UInt32)__externalCodecs->Hashers.Size(); i++) | |
{ | |
const CHasherInfoEx &codec = __externalCodecs->Hashers[i]; | |
if (codec.Name.IsEqualToNoCase(name)) | |
{ | |
methodId = codec.Id; | |
return true; | |
} | |
} | |
#endif | |
return false; | |
} | |
void GetHashMethods(DECL_EXTERNAL_CODECS_LOC_VARS | |
CRecordVector<CMethodId> &methods) | |
{ | |
methods.ClearAndSetSize(g_NumHashers); | |
UInt32 i; | |
for (i = 0; i < g_NumHashers; i++) | |
methods[i] = (*g_Hashers[i]).Id; | |
#ifdef EXTERNAL_CODECS | |
if (__externalCodecs) | |
for (i = 0; i < (UInt32)__externalCodecs->Hashers.Size(); i++) | |
methods.Add(__externalCodecs->Hashers[i].Id); | |
#endif | |
} | |
HRESULT CreateCoder( | |
DECL_EXTERNAL_CODECS_LOC_VARS | |
CMethodId methodId, | |
CMyComPtr<ICompressFilter> &filter, | |
CMyComPtr<ICompressCoder> &coder, | |
CMyComPtr<ICompressCoder2> &coder2, | |
bool encode, bool onlyCoder) | |
{ | |
UInt32 i; | |
for (i = 0; i < g_NumCodecs; i++) | |
{ | |
const CCodecInfo &codec = *g_Codecs[i]; | |
if (codec.Id == methodId) | |
{ | |
if (encode) | |
{ | |
if (codec.CreateEncoder) | |
{ | |
void *p = codec.CreateEncoder(); | |
if (codec.IsFilter) filter = (ICompressFilter *)p; | |
else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p; | |
else coder2 = (ICompressCoder2 *)p; | |
break; | |
} | |
} | |
else | |
if (codec.CreateDecoder) | |
{ | |
void *p = codec.CreateDecoder(); | |
if (codec.IsFilter) filter = (ICompressFilter *)p; | |
else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p; | |
else coder2 = (ICompressCoder2 *)p; | |
break; | |
} | |
} | |
} | |
#ifdef EXTERNAL_CODECS | |
if (!filter && !coder && !coder2 && __externalCodecs) | |
for (i = 0; i < (UInt32)__externalCodecs->Codecs.Size(); i++) | |
{ | |
const CCodecInfoEx &codec = __externalCodecs->Codecs[i]; | |
if (codec.Id == methodId) | |
{ | |
if (encode) | |
{ | |
if (codec.EncoderIsAssigned) | |
{ | |
if (codec.IsSimpleCodec()) | |
{ | |
HRESULT result = __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder, (void **)&coder); | |
if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE) | |
return result; | |
if (!coder) | |
{ | |
RINOK(__externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter)); | |
} | |
} | |
else | |
{ | |
RINOK(__externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder2, (void **)&coder2)); | |
} | |
break; | |
} | |
} | |
else | |
if (codec.DecoderIsAssigned) | |
{ | |
if (codec.IsSimpleCodec()) | |
{ | |
HRESULT result = __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder, (void **)&coder); | |
if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE) | |
return result; | |
if (!coder) | |
{ | |
RINOK(__externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter)); | |
} | |
} | |
else | |
{ | |
RINOK(__externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder2, (void **)&coder2)); | |
} | |
break; | |
} | |
} | |
} | |
#endif | |
if (onlyCoder && filter) | |
{ | |
CFilterCoder *coderSpec = new CFilterCoder; | |
coder = coderSpec; | |
coderSpec->Filter = filter; | |
} | |
return S_OK; | |
} | |
HRESULT CreateCoder( | |
DECL_EXTERNAL_CODECS_LOC_VARS | |
CMethodId methodId, | |
CMyComPtr<ICompressCoder> &coder, | |
CMyComPtr<ICompressCoder2> &coder2, | |
bool encode) | |
{ | |
CMyComPtr<ICompressFilter> filter; | |
return CreateCoder( | |
EXTERNAL_CODECS_LOC_VARS | |
methodId, | |
filter, coder, coder2, encode, true); | |
} | |
HRESULT CreateCoder( | |
DECL_EXTERNAL_CODECS_LOC_VARS | |
CMethodId methodId, | |
CMyComPtr<ICompressCoder> &coder, bool encode) | |
{ | |
CMyComPtr<ICompressFilter> filter; | |
CMyComPtr<ICompressCoder2> coder2; | |
return CreateCoder( | |
EXTERNAL_CODECS_LOC_VARS | |
methodId, | |
coder, coder2, encode); | |
} | |
HRESULT CreateFilter( | |
DECL_EXTERNAL_CODECS_LOC_VARS | |
CMethodId methodId, | |
CMyComPtr<ICompressFilter> &filter, | |
bool encode) | |
{ | |
CMyComPtr<ICompressCoder> coder; | |
CMyComPtr<ICompressCoder2> coder2; | |
return CreateCoder( | |
EXTERNAL_CODECS_LOC_VARS | |
methodId, | |
filter, coder, coder2, encode, false); | |
} | |
HRESULT CreateHasher( | |
DECL_EXTERNAL_CODECS_LOC_VARS | |
CMethodId methodId, | |
UString &name, | |
CMyComPtr<IHasher> &hasher) | |
{ | |
UInt32 i; | |
for (i = 0; i < g_NumHashers; i++) | |
{ | |
const CHasherInfo &codec = *g_Hashers[i]; | |
if (codec.Id == methodId) | |
{ | |
hasher = (IHasher *)codec.CreateHasher(); | |
name = codec.Name; | |
break; | |
} | |
} | |
#ifdef EXTERNAL_CODECS | |
if (!hasher && __externalCodecs) | |
for (i = 0; i < (UInt32)__externalCodecs->Hashers.Size(); i++) | |
{ | |
const CHasherInfoEx &codec = __externalCodecs->Hashers[i]; | |
if (codec.Id == methodId) | |
{ | |
name = codec.Name; | |
return __externalCodecs->GetHashers->CreateHasher(i, &hasher); | |
} | |
} | |
#endif | |
return S_OK; | |
} |