// 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;
}