1// CreateCoder.cpp
2
3#include "StdAfx.h"
4
5#include "../../Windows/Defs.h"
6#include "../../Windows/PropVariant.h"
7
8#include "CreateCoder.h"
9
10#include "FilterCoder.h"
11#include "RegisterCodec.h"
12
13static const unsigned int kNumCodecsMax = 64;
14unsigned int g_NumCodecs = 0;
15const CCodecInfo *g_Codecs[kNumCodecsMax];
16void RegisterCodec(const CCodecInfo *codecInfo) throw()
17{
18  if (g_NumCodecs < kNumCodecsMax)
19    g_Codecs[g_NumCodecs++] = codecInfo;
20}
21
22static const unsigned int kNumHashersMax = 16;
23unsigned int g_NumHashers = 0;
24const CHasherInfo *g_Hashers[kNumHashersMax];
25void RegisterHasher(const CHasherInfo *hashInfo) throw()
26{
27  if (g_NumHashers < kNumHashersMax)
28    g_Hashers[g_NumHashers++] = hashInfo;
29}
30
31#ifdef EXTERNAL_CODECS
32static HRESULT ReadNumberOfStreams(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, UInt32 &res)
33{
34  NWindows::NCOM::CPropVariant prop;
35  RINOK(codecsInfo->GetProperty(index, propID, &prop));
36  if (prop.vt == VT_EMPTY)
37    res = 1;
38  else if (prop.vt == VT_UI4)
39    res = prop.ulVal;
40  else
41    return E_INVALIDARG;
42  return S_OK;
43}
44
45static HRESULT ReadIsAssignedProp(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, bool &res)
46{
47  NWindows::NCOM::CPropVariant prop;
48  RINOK(codecsInfo->GetProperty(index, propID, &prop));
49  if (prop.vt == VT_EMPTY)
50    res = true;
51  else if (prop.vt == VT_BOOL)
52    res = VARIANT_BOOLToBool(prop.boolVal);
53  else
54    return E_INVALIDARG;
55  return S_OK;
56}
57
58HRESULT CExternalCodecs::LoadCodecs()
59{
60  if (GetCodecs)
61  {
62    UInt32 num;
63    RINOK(GetCodecs->GetNumberOfMethods(&num));
64    for (UInt32 i = 0; i < num; i++)
65    {
66      CCodecInfoEx info;
67      NWindows::NCOM::CPropVariant prop;
68      RINOK(GetCodecs->GetProperty(i, NMethodPropID::kID, &prop));
69      // if (prop.vt != VT_BSTR)
70      // info.Id.IDSize = (Byte)SysStringByteLen(prop.bstrVal);
71      // memcpy(info.Id.ID, prop.bstrVal, info.Id.IDSize);
72      if (prop.vt != VT_UI8)
73        continue; // old Interface
74      info.Id = prop.uhVal.QuadPart;
75      prop.Clear();
76
77      RINOK(GetCodecs->GetProperty(i, NMethodPropID::kName, &prop));
78      if (prop.vt == VT_BSTR)
79        info.Name = prop.bstrVal;
80      else if (prop.vt != VT_EMPTY)
81        return E_INVALIDARG;
82
83      RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kInStreams, info.NumInStreams));
84      RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kOutStreams, info.NumOutStreams));
85      RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned));
86      RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned));
87
88      Codecs.Add(info);
89    }
90  }
91  if (GetHashers)
92  {
93    UInt32 num = GetHashers->GetNumHashers();
94    for (UInt32 i = 0; i < num; i++)
95    {
96      CHasherInfoEx info;
97      NWindows::NCOM::CPropVariant prop;
98      RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kID, &prop));
99      if (prop.vt != VT_UI8)
100        continue;
101      info.Id = prop.uhVal.QuadPart;
102      prop.Clear();
103
104      RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kName, &prop));
105      if (prop.vt == VT_BSTR)
106        info.Name = prop.bstrVal;
107      else if (prop.vt != VT_EMPTY)
108        return E_INVALIDARG;
109
110      Hashers.Add(info);
111    }
112  }
113  return S_OK;
114}
115
116#endif
117
118bool FindMethod(DECL_EXTERNAL_CODECS_LOC_VARS
119    const UString &name, CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams)
120{
121  UInt32 i;
122  for (i = 0; i < g_NumCodecs; i++)
123  {
124    const CCodecInfo &codec = *g_Codecs[i];
125    if (name.IsEqualToNoCase(codec.Name))
126    {
127      methodId = codec.Id;
128      numInStreams = codec.NumInStreams;
129      numOutStreams = 1;
130      return true;
131    }
132  }
133  #ifdef EXTERNAL_CODECS
134  if (__externalCodecs)
135    for (i = 0; i < (UInt32)__externalCodecs->Codecs.Size(); i++)
136    {
137      const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
138      if (codec.Name.IsEqualToNoCase(name))
139      {
140        methodId = codec.Id;
141        numInStreams = codec.NumInStreams;
142        numOutStreams = codec.NumOutStreams;
143        return true;
144      }
145    }
146  #endif
147  return false;
148}
149
150bool FindMethod(DECL_EXTERNAL_CODECS_LOC_VARS
151   CMethodId methodId, UString &name)
152{
153  UInt32 i;
154  for (i = 0; i < g_NumCodecs; i++)
155  {
156    const CCodecInfo &codec = *g_Codecs[i];
157    if (methodId == codec.Id)
158    {
159      name = codec.Name;
160      return true;
161    }
162  }
163  #ifdef EXTERNAL_CODECS
164  if (__externalCodecs)
165    for (i = 0; i < (UInt32)__externalCodecs->Codecs.Size(); i++)
166    {
167      const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
168      if (methodId == codec.Id)
169      {
170        name = codec.Name;
171        return true;
172      }
173    }
174  #endif
175  return false;
176}
177
178bool FindHashMethod(DECL_EXTERNAL_CODECS_LOC_VARS
179  const UString &name,
180  CMethodId &methodId)
181{
182  UInt32 i;
183  for (i = 0; i < g_NumHashers; i++)
184  {
185    const CHasherInfo &codec = *g_Hashers[i];
186    if (name.IsEqualToNoCase(codec.Name))
187    {
188      methodId = codec.Id;
189      return true;
190    }
191  }
192  #ifdef EXTERNAL_CODECS
193  if (__externalCodecs)
194    for (i = 0; i < (UInt32)__externalCodecs->Hashers.Size(); i++)
195    {
196      const CHasherInfoEx &codec = __externalCodecs->Hashers[i];
197      if (codec.Name.IsEqualToNoCase(name))
198      {
199        methodId = codec.Id;
200        return true;
201      }
202    }
203  #endif
204  return false;
205}
206
207void GetHashMethods(DECL_EXTERNAL_CODECS_LOC_VARS
208    CRecordVector<CMethodId> &methods)
209{
210  methods.ClearAndSetSize(g_NumHashers);
211  UInt32 i;
212  for (i = 0; i < g_NumHashers; i++)
213    methods[i] = (*g_Hashers[i]).Id;
214  #ifdef EXTERNAL_CODECS
215  if (__externalCodecs)
216    for (i = 0; i < (UInt32)__externalCodecs->Hashers.Size(); i++)
217      methods.Add(__externalCodecs->Hashers[i].Id);
218  #endif
219}
220
221HRESULT CreateCoder(
222  DECL_EXTERNAL_CODECS_LOC_VARS
223  CMethodId methodId,
224  CMyComPtr<ICompressFilter> &filter,
225  CMyComPtr<ICompressCoder> &coder,
226  CMyComPtr<ICompressCoder2> &coder2,
227  bool encode, bool onlyCoder)
228{
229  UInt32 i;
230  for (i = 0; i < g_NumCodecs; i++)
231  {
232    const CCodecInfo &codec = *g_Codecs[i];
233    if (codec.Id == methodId)
234    {
235      if (encode)
236      {
237        if (codec.CreateEncoder)
238        {
239          void *p = codec.CreateEncoder();
240          if (codec.IsFilter) filter = (ICompressFilter *)p;
241          else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p;
242          else coder2 = (ICompressCoder2 *)p;
243          break;
244        }
245      }
246      else
247        if (codec.CreateDecoder)
248        {
249          void *p = codec.CreateDecoder();
250          if (codec.IsFilter) filter = (ICompressFilter *)p;
251          else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p;
252          else coder2 = (ICompressCoder2 *)p;
253          break;
254        }
255    }
256  }
257
258  #ifdef EXTERNAL_CODECS
259  if (!filter && !coder && !coder2 && __externalCodecs)
260    for (i = 0; i < (UInt32)__externalCodecs->Codecs.Size(); i++)
261    {
262      const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
263      if (codec.Id == methodId)
264      {
265        if (encode)
266        {
267          if (codec.EncoderIsAssigned)
268          {
269            if (codec.IsSimpleCodec())
270            {
271              HRESULT result = __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder, (void **)&coder);
272              if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE)
273                return result;
274              if (!coder)
275              {
276                RINOK(__externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter));
277              }
278            }
279            else
280            {
281              RINOK(__externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder2, (void **)&coder2));
282            }
283            break;
284          }
285        }
286        else
287          if (codec.DecoderIsAssigned)
288          {
289            if (codec.IsSimpleCodec())
290            {
291              HRESULT result = __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder, (void **)&coder);
292              if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE)
293                return result;
294              if (!coder)
295              {
296                RINOK(__externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter));
297              }
298            }
299            else
300            {
301              RINOK(__externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder2, (void **)&coder2));
302            }
303            break;
304          }
305      }
306    }
307  #endif
308
309  if (onlyCoder && filter)
310  {
311    CFilterCoder *coderSpec = new CFilterCoder;
312    coder = coderSpec;
313    coderSpec->Filter = filter;
314  }
315  return S_OK;
316}
317
318HRESULT CreateCoder(
319  DECL_EXTERNAL_CODECS_LOC_VARS
320  CMethodId methodId,
321  CMyComPtr<ICompressCoder> &coder,
322  CMyComPtr<ICompressCoder2> &coder2,
323  bool encode)
324{
325  CMyComPtr<ICompressFilter> filter;
326  return CreateCoder(
327    EXTERNAL_CODECS_LOC_VARS
328    methodId,
329    filter, coder, coder2, encode, true);
330}
331
332HRESULT CreateCoder(
333  DECL_EXTERNAL_CODECS_LOC_VARS
334  CMethodId methodId,
335  CMyComPtr<ICompressCoder> &coder, bool encode)
336{
337  CMyComPtr<ICompressFilter> filter;
338  CMyComPtr<ICompressCoder2> coder2;
339  return CreateCoder(
340    EXTERNAL_CODECS_LOC_VARS
341    methodId,
342    coder, coder2, encode);
343}
344
345HRESULT CreateFilter(
346  DECL_EXTERNAL_CODECS_LOC_VARS
347  CMethodId methodId,
348  CMyComPtr<ICompressFilter> &filter,
349  bool encode)
350{
351  CMyComPtr<ICompressCoder> coder;
352  CMyComPtr<ICompressCoder2> coder2;
353  return CreateCoder(
354    EXTERNAL_CODECS_LOC_VARS
355    methodId,
356    filter, coder, coder2, encode, false);
357}
358
359HRESULT CreateHasher(
360  DECL_EXTERNAL_CODECS_LOC_VARS
361  CMethodId methodId,
362  UString &name,
363  CMyComPtr<IHasher> &hasher)
364{
365  UInt32 i;
366  for (i = 0; i < g_NumHashers; i++)
367  {
368    const CHasherInfo &codec = *g_Hashers[i];
369    if (codec.Id == methodId)
370    {
371      hasher = (IHasher *)codec.CreateHasher();
372      name = codec.Name;
373      break;
374    }
375  }
376
377  #ifdef EXTERNAL_CODECS
378  if (!hasher && __externalCodecs)
379    for (i = 0; i < (UInt32)__externalCodecs->Hashers.Size(); i++)
380    {
381      const CHasherInfoEx &codec = __externalCodecs->Hashers[i];
382      if (codec.Id == methodId)
383      {
384        name = codec.Name;
385        return __externalCodecs->GetHashers->CreateHasher(i, &hasher);
386      }
387    }
388  #endif
389
390  return S_OK;
391}
392