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 
13 static const unsigned kNumCodecsMax = 64;
14 unsigned g_NumCodecs = 0;
15 const CCodecInfo *g_Codecs[kNumCodecsMax];
16 
17 // We use g_ExternalCodecs in other stages.
18 /*
19 #ifdef EXTERNAL_CODECS
20 extern CExternalCodecs g_ExternalCodecs;
21 #define CHECK_GLOBAL_CODECS \
22     if (!__externalCodecs || !__externalCodecs->IsSet()) __externalCodecs = &g_ExternalCodecs;
23 #endif
24 */
25 
26 #define CHECK_GLOBAL_CODECS
27 
RegisterCodec(const CCodecInfo * codecInfo)28 void RegisterCodec(const CCodecInfo *codecInfo) throw()
29 {
30   if (g_NumCodecs < kNumCodecsMax)
31     g_Codecs[g_NumCodecs++] = codecInfo;
32 }
33 
34 static const unsigned kNumHashersMax = 16;
35 unsigned g_NumHashers = 0;
36 const CHasherInfo *g_Hashers[kNumHashersMax];
37 
RegisterHasher(const CHasherInfo * hashInfo)38 void RegisterHasher(const CHasherInfo *hashInfo) throw()
39 {
40   if (g_NumHashers < kNumHashersMax)
41     g_Hashers[g_NumHashers++] = hashInfo;
42 }
43 
44 
45 #ifdef EXTERNAL_CODECS
46 
ReadNumberOfStreams(ICompressCodecsInfo * codecsInfo,UInt32 index,PROPID propID,UInt32 & res)47 static HRESULT ReadNumberOfStreams(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, UInt32 &res)
48 {
49   NWindows::NCOM::CPropVariant prop;
50   RINOK(codecsInfo->GetProperty(index, propID, &prop));
51   if (prop.vt == VT_EMPTY)
52     res = 1;
53   else if (prop.vt == VT_UI4)
54     res = prop.ulVal;
55   else
56     return E_INVALIDARG;
57   return S_OK;
58 }
59 
ReadIsAssignedProp(ICompressCodecsInfo * codecsInfo,UInt32 index,PROPID propID,bool & res)60 static HRESULT ReadIsAssignedProp(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, bool &res)
61 {
62   NWindows::NCOM::CPropVariant prop;
63   RINOK(codecsInfo->GetProperty(index, propID, &prop));
64   if (prop.vt == VT_EMPTY)
65     res = true;
66   else if (prop.vt == VT_BOOL)
67     res = VARIANT_BOOLToBool(prop.boolVal);
68   else
69     return E_INVALIDARG;
70   return S_OK;
71 }
72 
Load()73 HRESULT CExternalCodecs::Load()
74 {
75   Codecs.Clear();
76   Hashers.Clear();
77 
78   if (GetCodecs)
79   {
80     CCodecInfoEx info;
81 
82     UString s;
83     UInt32 num;
84     RINOK(GetCodecs->GetNumMethods(&num));
85 
86     for (UInt32 i = 0; i < num; i++)
87     {
88       NWindows::NCOM::CPropVariant prop;
89 
90       RINOK(GetCodecs->GetProperty(i, NMethodPropID::kID, &prop));
91       if (prop.vt != VT_UI8)
92         continue; // old Interface
93       info.Id = prop.uhVal.QuadPart;
94 
95       prop.Clear();
96 
97       info.Name.Empty();
98       RINOK(GetCodecs->GetProperty(i, NMethodPropID::kName, &prop));
99       if (prop.vt == VT_BSTR)
100         info.Name.SetFromWStr_if_Ascii(prop.bstrVal);
101       else if (prop.vt != VT_EMPTY)
102         continue;
103 
104       RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kPackStreams, info.NumStreams));
105       {
106         UInt32 numUnpackStreams = 1;
107         RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kUnpackStreams, numUnpackStreams));
108         if (numUnpackStreams != 1)
109           continue;
110       }
111       RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned));
112       RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned));
113 
114       Codecs.Add(info);
115     }
116   }
117 
118   if (GetHashers)
119   {
120     UInt32 num = GetHashers->GetNumHashers();
121     CHasherInfoEx info;
122 
123     for (UInt32 i = 0; i < num; i++)
124     {
125       NWindows::NCOM::CPropVariant prop;
126 
127       RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kID, &prop));
128       if (prop.vt != VT_UI8)
129         continue;
130       info.Id = prop.uhVal.QuadPart;
131 
132       prop.Clear();
133 
134       info.Name.Empty();
135       RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kName, &prop));
136       if (prop.vt == VT_BSTR)
137         info.Name.SetFromWStr_if_Ascii(prop.bstrVal);
138       else if (prop.vt != VT_EMPTY)
139         continue;
140 
141       Hashers.Add(info);
142     }
143   }
144 
145   return S_OK;
146 }
147 
148 #endif
149 
150 
FindMethod_Index(DECL_EXTERNAL_CODECS_LOC_VARS const AString & name,bool encode,CMethodId & methodId,UInt32 & numStreams)151 int FindMethod_Index(
152     DECL_EXTERNAL_CODECS_LOC_VARS
153     const AString &name,
154     bool encode,
155     CMethodId &methodId,
156     UInt32 &numStreams)
157 {
158   unsigned i;
159   for (i = 0; i < g_NumCodecs; i++)
160   {
161     const CCodecInfo &codec = *g_Codecs[i];
162     if ((encode ? codec.CreateEncoder : codec.CreateDecoder)
163         && StringsAreEqualNoCase_Ascii(name, codec.Name))
164     {
165       methodId = codec.Id;
166       numStreams = codec.NumStreams;
167       return i;
168     }
169   }
170 
171   #ifdef EXTERNAL_CODECS
172 
173   CHECK_GLOBAL_CODECS
174 
175   if (__externalCodecs)
176     for (i = 0; i < __externalCodecs->Codecs.Size(); i++)
177     {
178       const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
179       if ((encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned)
180           && StringsAreEqualNoCase_Ascii(name, codec.Name))
181       {
182         methodId = codec.Id;
183         numStreams = codec.NumStreams;
184         return g_NumCodecs + i;
185       }
186     }
187 
188   #endif
189 
190   return -1;
191 }
192 
193 
FindMethod_Index(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,bool encode)194 static int FindMethod_Index(
195     DECL_EXTERNAL_CODECS_LOC_VARS
196     CMethodId methodId, bool encode)
197 {
198   unsigned i;
199   for (i = 0; i < g_NumCodecs; i++)
200   {
201     const CCodecInfo &codec = *g_Codecs[i];
202     if (codec.Id == methodId && (encode ? codec.CreateEncoder : codec.CreateDecoder))
203       return i;
204   }
205 
206   #ifdef EXTERNAL_CODECS
207 
208   CHECK_GLOBAL_CODECS
209 
210   if (__externalCodecs)
211     for (i = 0; i < __externalCodecs->Codecs.Size(); i++)
212     {
213       const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
214       if (codec.Id == methodId && (encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned))
215         return g_NumCodecs + i;
216     }
217 
218   #endif
219 
220   return -1;
221 }
222 
223 
FindMethod(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,AString & name)224 bool FindMethod(
225     DECL_EXTERNAL_CODECS_LOC_VARS
226     CMethodId methodId,
227     AString &name)
228 {
229   name.Empty();
230 
231   unsigned i;
232   for (i = 0; i < g_NumCodecs; i++)
233   {
234     const CCodecInfo &codec = *g_Codecs[i];
235     if (methodId == codec.Id)
236     {
237       name = codec.Name;
238       return true;
239     }
240   }
241 
242   #ifdef EXTERNAL_CODECS
243 
244   CHECK_GLOBAL_CODECS
245 
246   if (__externalCodecs)
247     for (i = 0; i < __externalCodecs->Codecs.Size(); i++)
248     {
249       const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
250       if (methodId == codec.Id)
251       {
252         name = codec.Name;
253         return true;
254       }
255     }
256 
257   #endif
258 
259   return false;
260 }
261 
FindHashMethod(DECL_EXTERNAL_CODECS_LOC_VARS const AString & name,CMethodId & methodId)262 bool FindHashMethod(
263     DECL_EXTERNAL_CODECS_LOC_VARS
264     const AString &name,
265     CMethodId &methodId)
266 {
267   unsigned i;
268   for (i = 0; i < g_NumHashers; i++)
269   {
270     const CHasherInfo &codec = *g_Hashers[i];
271     if (StringsAreEqualNoCase_Ascii(name, codec.Name))
272     {
273       methodId = codec.Id;
274       return true;
275     }
276   }
277 
278   #ifdef EXTERNAL_CODECS
279 
280   CHECK_GLOBAL_CODECS
281 
282   if (__externalCodecs)
283     for (i = 0; i < __externalCodecs->Hashers.Size(); i++)
284     {
285       const CHasherInfoEx &codec = __externalCodecs->Hashers[i];
286       if (StringsAreEqualNoCase_Ascii(name, codec.Name))
287       {
288         methodId = codec.Id;
289         return true;
290       }
291     }
292 
293   #endif
294 
295   return false;
296 }
297 
GetHashMethods(DECL_EXTERNAL_CODECS_LOC_VARS CRecordVector<CMethodId> & methods)298 void GetHashMethods(
299     DECL_EXTERNAL_CODECS_LOC_VARS
300     CRecordVector<CMethodId> &methods)
301 {
302   methods.ClearAndSetSize(g_NumHashers);
303   unsigned i;
304   for (i = 0; i < g_NumHashers; i++)
305     methods[i] = (*g_Hashers[i]).Id;
306 
307   #ifdef EXTERNAL_CODECS
308 
309   CHECK_GLOBAL_CODECS
310 
311   if (__externalCodecs)
312     for (i = 0; i < __externalCodecs->Hashers.Size(); i++)
313       methods.Add(__externalCodecs->Hashers[i].Id);
314 
315   #endif
316 }
317 
318 
319 
CreateCoder_Index(DECL_EXTERNAL_CODECS_LOC_VARS unsigned i,bool encode,CMyComPtr<ICompressFilter> & filter,CCreatedCoder & cod)320 HRESULT CreateCoder_Index(
321     DECL_EXTERNAL_CODECS_LOC_VARS
322     unsigned i, bool encode,
323     CMyComPtr<ICompressFilter> &filter,
324     CCreatedCoder &cod)
325 {
326   cod.IsExternal = false;
327   cod.IsFilter = false;
328   cod.NumStreams = 1;
329 
330   if (i < g_NumCodecs)
331   {
332     const CCodecInfo &codec = *g_Codecs[i];
333     // if (codec.Id == methodId)
334     {
335       if (encode)
336       {
337         if (codec.CreateEncoder)
338         {
339           void *p = codec.CreateEncoder();
340           if (codec.IsFilter) filter = (ICompressFilter *)p;
341           else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p;
342           else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; }
343           return S_OK;
344         }
345       }
346       else
347         if (codec.CreateDecoder)
348         {
349           void *p = codec.CreateDecoder();
350           if (codec.IsFilter) filter = (ICompressFilter *)p;
351           else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p;
352           else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; }
353           return S_OK;
354         }
355     }
356   }
357 
358   #ifdef EXTERNAL_CODECS
359 
360   CHECK_GLOBAL_CODECS
361 
362   if (__externalCodecs)
363   {
364     i -= g_NumCodecs;
365     cod.IsExternal = true;
366     if (i < __externalCodecs->Codecs.Size())
367     {
368       const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
369       // if (codec.Id == methodId)
370       {
371         if (encode)
372         {
373           if (codec.EncoderIsAssigned)
374           {
375             if (codec.NumStreams == 1)
376             {
377               HRESULT res = __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder, (void **)&cod.Coder);
378               if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE)
379                 return res;
380               if (cod.Coder)
381                 return res;
382               return __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter);
383             }
384             cod.NumStreams = codec.NumStreams;
385             return __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2);
386           }
387         }
388         else
389           if (codec.DecoderIsAssigned)
390           {
391             if (codec.NumStreams == 1)
392             {
393               HRESULT res = __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder, (void **)&cod.Coder);
394               if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE)
395                 return res;
396               if (cod.Coder)
397                 return res;
398               return __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter);
399             }
400             cod.NumStreams = codec.NumStreams;
401             return __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2);
402           }
403       }
404     }
405   }
406   #endif
407 
408   return S_OK;
409 }
410 
411 
CreateCoder_Index(DECL_EXTERNAL_CODECS_LOC_VARS unsigned index,bool encode,CCreatedCoder & cod)412 HRESULT CreateCoder_Index(
413     DECL_EXTERNAL_CODECS_LOC_VARS
414     unsigned index, bool encode,
415     CCreatedCoder &cod)
416 {
417   CMyComPtr<ICompressFilter> filter;
418   HRESULT res = CreateCoder_Index(
419       EXTERNAL_CODECS_LOC_VARS
420       index, encode,
421       filter, cod);
422 
423   if (filter)
424   {
425     cod.IsFilter = true;
426     CFilterCoder *coderSpec = new CFilterCoder(encode);
427     cod.Coder = coderSpec;
428     coderSpec->Filter = filter;
429   }
430 
431   return res;
432 }
433 
434 
CreateCoder_Id(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,bool encode,CMyComPtr<ICompressFilter> & filter,CCreatedCoder & cod)435 HRESULT CreateCoder_Id(
436     DECL_EXTERNAL_CODECS_LOC_VARS
437     CMethodId methodId, bool encode,
438     CMyComPtr<ICompressFilter> &filter,
439     CCreatedCoder &cod)
440 {
441   int index = FindMethod_Index(EXTERNAL_CODECS_LOC_VARS methodId, encode);
442   if (index < 0)
443     return S_OK;
444   return CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS index, encode, filter, cod);
445 }
446 
447 
CreateCoder_Id(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,bool encode,CCreatedCoder & cod)448 HRESULT CreateCoder_Id(
449     DECL_EXTERNAL_CODECS_LOC_VARS
450     CMethodId methodId, bool encode,
451     CCreatedCoder &cod)
452 {
453   CMyComPtr<ICompressFilter> filter;
454   HRESULT res = CreateCoder_Id(
455       EXTERNAL_CODECS_LOC_VARS
456       methodId, encode,
457       filter, cod);
458 
459   if (filter)
460   {
461     cod.IsFilter = true;
462     CFilterCoder *coderSpec = new CFilterCoder(encode);
463     cod.Coder = coderSpec;
464     coderSpec->Filter = filter;
465   }
466 
467   return res;
468 }
469 
470 
CreateCoder_Id(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,bool encode,CMyComPtr<ICompressCoder> & coder)471 HRESULT CreateCoder_Id(
472     DECL_EXTERNAL_CODECS_LOC_VARS
473     CMethodId methodId, bool encode,
474     CMyComPtr<ICompressCoder> &coder)
475 {
476   CCreatedCoder cod;
477   HRESULT res = CreateCoder_Id(
478       EXTERNAL_CODECS_LOC_VARS
479       methodId, encode,
480       cod);
481   coder = cod.Coder;
482   return res;
483 }
484 
CreateFilter(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,bool encode,CMyComPtr<ICompressFilter> & filter)485 HRESULT CreateFilter(
486     DECL_EXTERNAL_CODECS_LOC_VARS
487     CMethodId methodId, bool encode,
488     CMyComPtr<ICompressFilter> &filter)
489 {
490   CCreatedCoder cod;
491   return CreateCoder_Id(
492       EXTERNAL_CODECS_LOC_VARS
493       methodId, encode,
494       filter, cod);
495 }
496 
497 
CreateHasher(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,AString & name,CMyComPtr<IHasher> & hasher)498 HRESULT CreateHasher(
499     DECL_EXTERNAL_CODECS_LOC_VARS
500     CMethodId methodId,
501     AString &name,
502     CMyComPtr<IHasher> &hasher)
503 {
504   name.Empty();
505 
506   unsigned i;
507   for (i = 0; i < g_NumHashers; i++)
508   {
509     const CHasherInfo &codec = *g_Hashers[i];
510     if (codec.Id == methodId)
511     {
512       hasher = codec.CreateHasher();
513       name = codec.Name;
514       break;
515     }
516   }
517 
518   #ifdef EXTERNAL_CODECS
519 
520   CHECK_GLOBAL_CODECS
521 
522   if (!hasher && __externalCodecs)
523     for (i = 0; i < __externalCodecs->Hashers.Size(); i++)
524     {
525       const CHasherInfoEx &codec = __externalCodecs->Hashers[i];
526       if (codec.Id == methodId)
527       {
528         name = codec.Name;
529         return __externalCodecs->GetHashers->CreateHasher((UInt32)i, &hasher);
530       }
531     }
532 
533   #endif
534 
535   return S_OK;
536 }
537