You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
537 lines
13 KiB
537 lines
13 KiB
// 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 kNumCodecsMax = 64;
|
|
unsigned g_NumCodecs = 0;
|
|
const CCodecInfo *g_Codecs[kNumCodecsMax];
|
|
|
|
// We use g_ExternalCodecs in other stages.
|
|
/*
|
|
#ifdef EXTERNAL_CODECS
|
|
extern CExternalCodecs g_ExternalCodecs;
|
|
#define CHECK_GLOBAL_CODECS \
|
|
if (!__externalCodecs || !__externalCodecs->IsSet()) __externalCodecs = &g_ExternalCodecs;
|
|
#endif
|
|
*/
|
|
|
|
#define CHECK_GLOBAL_CODECS
|
|
|
|
void RegisterCodec(const CCodecInfo *codecInfo) throw()
|
|
{
|
|
if (g_NumCodecs < kNumCodecsMax)
|
|
g_Codecs[g_NumCodecs++] = codecInfo;
|
|
}
|
|
|
|
static const unsigned kNumHashersMax = 16;
|
|
unsigned 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::Load()
|
|
{
|
|
Codecs.Clear();
|
|
Hashers.Clear();
|
|
|
|
if (GetCodecs)
|
|
{
|
|
CCodecInfoEx info;
|
|
|
|
UString s;
|
|
UInt32 num;
|
|
RINOK(GetCodecs->GetNumMethods(&num));
|
|
|
|
for (UInt32 i = 0; i < num; i++)
|
|
{
|
|
NWindows::NCOM::CPropVariant prop;
|
|
|
|
RINOK(GetCodecs->GetProperty(i, NMethodPropID::kID, &prop));
|
|
if (prop.vt != VT_UI8)
|
|
continue; // old Interface
|
|
info.Id = prop.uhVal.QuadPart;
|
|
|
|
prop.Clear();
|
|
|
|
info.Name.Empty();
|
|
RINOK(GetCodecs->GetProperty(i, NMethodPropID::kName, &prop));
|
|
if (prop.vt == VT_BSTR)
|
|
info.Name.SetFromWStr_if_Ascii(prop.bstrVal);
|
|
else if (prop.vt != VT_EMPTY)
|
|
continue;
|
|
|
|
RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kPackStreams, info.NumStreams));
|
|
{
|
|
UInt32 numUnpackStreams = 1;
|
|
RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kUnpackStreams, numUnpackStreams));
|
|
if (numUnpackStreams != 1)
|
|
continue;
|
|
}
|
|
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();
|
|
CHasherInfoEx info;
|
|
|
|
for (UInt32 i = 0; i < num; i++)
|
|
{
|
|
NWindows::NCOM::CPropVariant prop;
|
|
|
|
RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kID, &prop));
|
|
if (prop.vt != VT_UI8)
|
|
continue;
|
|
info.Id = prop.uhVal.QuadPart;
|
|
|
|
prop.Clear();
|
|
|
|
info.Name.Empty();
|
|
RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kName, &prop));
|
|
if (prop.vt == VT_BSTR)
|
|
info.Name.SetFromWStr_if_Ascii(prop.bstrVal);
|
|
else if (prop.vt != VT_EMPTY)
|
|
continue;
|
|
|
|
Hashers.Add(info);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
int FindMethod_Index(
|
|
DECL_EXTERNAL_CODECS_LOC_VARS
|
|
const AString &name,
|
|
bool encode,
|
|
CMethodId &methodId,
|
|
UInt32 &numStreams)
|
|
{
|
|
unsigned i;
|
|
for (i = 0; i < g_NumCodecs; i++)
|
|
{
|
|
const CCodecInfo &codec = *g_Codecs[i];
|
|
if ((encode ? codec.CreateEncoder : codec.CreateDecoder)
|
|
&& StringsAreEqualNoCase_Ascii(name, codec.Name))
|
|
{
|
|
methodId = codec.Id;
|
|
numStreams = codec.NumStreams;
|
|
return i;
|
|
}
|
|
}
|
|
|
|
#ifdef EXTERNAL_CODECS
|
|
|
|
CHECK_GLOBAL_CODECS
|
|
|
|
if (__externalCodecs)
|
|
for (i = 0; i < __externalCodecs->Codecs.Size(); i++)
|
|
{
|
|
const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
|
|
if ((encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned)
|
|
&& StringsAreEqualNoCase_Ascii(name, codec.Name))
|
|
{
|
|
methodId = codec.Id;
|
|
numStreams = codec.NumStreams;
|
|
return g_NumCodecs + i;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int FindMethod_Index(
|
|
DECL_EXTERNAL_CODECS_LOC_VARS
|
|
CMethodId methodId, bool encode)
|
|
{
|
|
unsigned i;
|
|
for (i = 0; i < g_NumCodecs; i++)
|
|
{
|
|
const CCodecInfo &codec = *g_Codecs[i];
|
|
if (codec.Id == methodId && (encode ? codec.CreateEncoder : codec.CreateDecoder))
|
|
return i;
|
|
}
|
|
|
|
#ifdef EXTERNAL_CODECS
|
|
|
|
CHECK_GLOBAL_CODECS
|
|
|
|
if (__externalCodecs)
|
|
for (i = 0; i < __externalCodecs->Codecs.Size(); i++)
|
|
{
|
|
const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
|
|
if (codec.Id == methodId && (encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned))
|
|
return g_NumCodecs + i;
|
|
}
|
|
|
|
#endif
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
bool FindMethod(
|
|
DECL_EXTERNAL_CODECS_LOC_VARS
|
|
CMethodId methodId,
|
|
AString &name)
|
|
{
|
|
name.Empty();
|
|
|
|
unsigned 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
|
|
|
|
CHECK_GLOBAL_CODECS
|
|
|
|
if (__externalCodecs)
|
|
for (i = 0; i < __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 AString &name,
|
|
CMethodId &methodId)
|
|
{
|
|
unsigned i;
|
|
for (i = 0; i < g_NumHashers; i++)
|
|
{
|
|
const CHasherInfo &codec = *g_Hashers[i];
|
|
if (StringsAreEqualNoCase_Ascii(name, codec.Name))
|
|
{
|
|
methodId = codec.Id;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
#ifdef EXTERNAL_CODECS
|
|
|
|
CHECK_GLOBAL_CODECS
|
|
|
|
if (__externalCodecs)
|
|
for (i = 0; i < __externalCodecs->Hashers.Size(); i++)
|
|
{
|
|
const CHasherInfoEx &codec = __externalCodecs->Hashers[i];
|
|
if (StringsAreEqualNoCase_Ascii(name, codec.Name))
|
|
{
|
|
methodId = codec.Id;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
void GetHashMethods(
|
|
DECL_EXTERNAL_CODECS_LOC_VARS
|
|
CRecordVector<CMethodId> &methods)
|
|
{
|
|
methods.ClearAndSetSize(g_NumHashers);
|
|
unsigned i;
|
|
for (i = 0; i < g_NumHashers; i++)
|
|
methods[i] = (*g_Hashers[i]).Id;
|
|
|
|
#ifdef EXTERNAL_CODECS
|
|
|
|
CHECK_GLOBAL_CODECS
|
|
|
|
if (__externalCodecs)
|
|
for (i = 0; i < __externalCodecs->Hashers.Size(); i++)
|
|
methods.Add(__externalCodecs->Hashers[i].Id);
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
HRESULT CreateCoder_Index(
|
|
DECL_EXTERNAL_CODECS_LOC_VARS
|
|
unsigned i, bool encode,
|
|
CMyComPtr<ICompressFilter> &filter,
|
|
CCreatedCoder &cod)
|
|
{
|
|
cod.IsExternal = false;
|
|
cod.IsFilter = false;
|
|
cod.NumStreams = 1;
|
|
|
|
if (i < g_NumCodecs)
|
|
{
|
|
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.NumStreams == 1) cod.Coder = (ICompressCoder *)p;
|
|
else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; }
|
|
return S_OK;
|
|
}
|
|
}
|
|
else
|
|
if (codec.CreateDecoder)
|
|
{
|
|
void *p = codec.CreateDecoder();
|
|
if (codec.IsFilter) filter = (ICompressFilter *)p;
|
|
else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p;
|
|
else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; }
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef EXTERNAL_CODECS
|
|
|
|
CHECK_GLOBAL_CODECS
|
|
|
|
if (__externalCodecs)
|
|
{
|
|
i -= g_NumCodecs;
|
|
cod.IsExternal = true;
|
|
if (i < __externalCodecs->Codecs.Size())
|
|
{
|
|
const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
|
|
// if (codec.Id == methodId)
|
|
{
|
|
if (encode)
|
|
{
|
|
if (codec.EncoderIsAssigned)
|
|
{
|
|
if (codec.NumStreams == 1)
|
|
{
|
|
HRESULT res = __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder, (void **)&cod.Coder);
|
|
if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE)
|
|
return res;
|
|
if (cod.Coder)
|
|
return res;
|
|
return __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter);
|
|
}
|
|
cod.NumStreams = codec.NumStreams;
|
|
return __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2);
|
|
}
|
|
}
|
|
else
|
|
if (codec.DecoderIsAssigned)
|
|
{
|
|
if (codec.NumStreams == 1)
|
|
{
|
|
HRESULT res = __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder, (void **)&cod.Coder);
|
|
if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE)
|
|
return res;
|
|
if (cod.Coder)
|
|
return res;
|
|
return __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter);
|
|
}
|
|
cod.NumStreams = codec.NumStreams;
|
|
return __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CreateCoder_Index(
|
|
DECL_EXTERNAL_CODECS_LOC_VARS
|
|
unsigned index, bool encode,
|
|
CCreatedCoder &cod)
|
|
{
|
|
CMyComPtr<ICompressFilter> filter;
|
|
HRESULT res = CreateCoder_Index(
|
|
EXTERNAL_CODECS_LOC_VARS
|
|
index, encode,
|
|
filter, cod);
|
|
|
|
if (filter)
|
|
{
|
|
cod.IsFilter = true;
|
|
CFilterCoder *coderSpec = new CFilterCoder(encode);
|
|
cod.Coder = coderSpec;
|
|
coderSpec->Filter = filter;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
HRESULT CreateCoder_Id(
|
|
DECL_EXTERNAL_CODECS_LOC_VARS
|
|
CMethodId methodId, bool encode,
|
|
CMyComPtr<ICompressFilter> &filter,
|
|
CCreatedCoder &cod)
|
|
{
|
|
int index = FindMethod_Index(EXTERNAL_CODECS_LOC_VARS methodId, encode);
|
|
if (index < 0)
|
|
return S_OK;
|
|
return CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS index, encode, filter, cod);
|
|
}
|
|
|
|
|
|
HRESULT CreateCoder_Id(
|
|
DECL_EXTERNAL_CODECS_LOC_VARS
|
|
CMethodId methodId, bool encode,
|
|
CCreatedCoder &cod)
|
|
{
|
|
CMyComPtr<ICompressFilter> filter;
|
|
HRESULT res = CreateCoder_Id(
|
|
EXTERNAL_CODECS_LOC_VARS
|
|
methodId, encode,
|
|
filter, cod);
|
|
|
|
if (filter)
|
|
{
|
|
cod.IsFilter = true;
|
|
CFilterCoder *coderSpec = new CFilterCoder(encode);
|
|
cod.Coder = coderSpec;
|
|
coderSpec->Filter = filter;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
HRESULT CreateCoder_Id(
|
|
DECL_EXTERNAL_CODECS_LOC_VARS
|
|
CMethodId methodId, bool encode,
|
|
CMyComPtr<ICompressCoder> &coder)
|
|
{
|
|
CCreatedCoder cod;
|
|
HRESULT res = CreateCoder_Id(
|
|
EXTERNAL_CODECS_LOC_VARS
|
|
methodId, encode,
|
|
cod);
|
|
coder = cod.Coder;
|
|
return res;
|
|
}
|
|
|
|
HRESULT CreateFilter(
|
|
DECL_EXTERNAL_CODECS_LOC_VARS
|
|
CMethodId methodId, bool encode,
|
|
CMyComPtr<ICompressFilter> &filter)
|
|
{
|
|
CCreatedCoder cod;
|
|
return CreateCoder_Id(
|
|
EXTERNAL_CODECS_LOC_VARS
|
|
methodId, encode,
|
|
filter, cod);
|
|
}
|
|
|
|
|
|
HRESULT CreateHasher(
|
|
DECL_EXTERNAL_CODECS_LOC_VARS
|
|
CMethodId methodId,
|
|
AString &name,
|
|
CMyComPtr<IHasher> &hasher)
|
|
{
|
|
name.Empty();
|
|
|
|
unsigned i;
|
|
for (i = 0; i < g_NumHashers; i++)
|
|
{
|
|
const CHasherInfo &codec = *g_Hashers[i];
|
|
if (codec.Id == methodId)
|
|
{
|
|
hasher = codec.CreateHasher();
|
|
name = codec.Name;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef EXTERNAL_CODECS
|
|
|
|
CHECK_GLOBAL_CODECS
|
|
|
|
if (!hasher && __externalCodecs)
|
|
for (i = 0; i < __externalCodecs->Hashers.Size(); i++)
|
|
{
|
|
const CHasherInfoEx &codec = __externalCodecs->Hashers[i];
|
|
if (codec.Id == methodId)
|
|
{
|
|
name = codec.Name;
|
|
return __externalCodecs->GetHashers->CreateHasher((UInt32)i, &hasher);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
return S_OK;
|
|
}
|