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