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