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