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(DECL_EXTERNAL_CODECS_LOC_VARS const AString & name,CMethodId & methodId,UInt32 & numStreams)151 bool FindMethod(
152     DECL_EXTERNAL_CODECS_LOC_VARS
153     const AString &name,
154     CMethodId &methodId, UInt32 &numStreams)
155 {
156   unsigned i;
157   for (i = 0; i < g_NumCodecs; i++)
158   {
159     const CCodecInfo &codec = *g_Codecs[i];
160     if (StringsAreEqualNoCase_Ascii(name, codec.Name))
161     {
162       methodId = codec.Id;
163       numStreams = codec.NumStreams;
164       return true;
165     }
166   }
167 
168   #ifdef EXTERNAL_CODECS
169 
170   CHECK_GLOBAL_CODECS
171 
172   if (__externalCodecs)
173     for (i = 0; i < __externalCodecs->Codecs.Size(); i++)
174     {
175       const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
176       if (StringsAreEqualNoCase_Ascii(name, codec.Name))
177       {
178         methodId = codec.Id;
179         numStreams = codec.NumStreams;
180         return true;
181       }
182     }
183 
184   #endif
185 
186   return false;
187 }
188 
FindMethod(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,AString & name)189 bool FindMethod(
190     DECL_EXTERNAL_CODECS_LOC_VARS
191     CMethodId methodId,
192     AString &name)
193 {
194   name.Empty();
195 
196   unsigned i;
197   for (i = 0; i < g_NumCodecs; i++)
198   {
199     const CCodecInfo &codec = *g_Codecs[i];
200     if (methodId == codec.Id)
201     {
202       name = codec.Name;
203       return true;
204     }
205   }
206 
207   #ifdef EXTERNAL_CODECS
208 
209   CHECK_GLOBAL_CODECS
210 
211   if (__externalCodecs)
212     for (i = 0; i < __externalCodecs->Codecs.Size(); i++)
213     {
214       const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
215       if (methodId == codec.Id)
216       {
217         name = codec.Name;
218         return true;
219       }
220     }
221 
222   #endif
223 
224   return false;
225 }
226 
FindHashMethod(DECL_EXTERNAL_CODECS_LOC_VARS const AString & name,CMethodId & methodId)227 bool FindHashMethod(
228     DECL_EXTERNAL_CODECS_LOC_VARS
229     const AString &name,
230     CMethodId &methodId)
231 {
232   unsigned i;
233   for (i = 0; i < g_NumHashers; i++)
234   {
235     const CHasherInfo &codec = *g_Hashers[i];
236     if (StringsAreEqualNoCase_Ascii(name, codec.Name))
237     {
238       methodId = codec.Id;
239       return true;
240     }
241   }
242 
243   #ifdef EXTERNAL_CODECS
244 
245   CHECK_GLOBAL_CODECS
246 
247   if (__externalCodecs)
248     for (i = 0; i < __externalCodecs->Hashers.Size(); i++)
249     {
250       const CHasherInfoEx &codec = __externalCodecs->Hashers[i];
251       if (StringsAreEqualNoCase_Ascii(name, codec.Name))
252       {
253         methodId = codec.Id;
254         return true;
255       }
256     }
257 
258   #endif
259 
260   return false;
261 }
262 
GetHashMethods(DECL_EXTERNAL_CODECS_LOC_VARS CRecordVector<CMethodId> & methods)263 void GetHashMethods(
264     DECL_EXTERNAL_CODECS_LOC_VARS
265     CRecordVector<CMethodId> &methods)
266 {
267   methods.ClearAndSetSize(g_NumHashers);
268   unsigned i;
269   for (i = 0; i < g_NumHashers; i++)
270     methods[i] = (*g_Hashers[i]).Id;
271 
272   #ifdef EXTERNAL_CODECS
273 
274   CHECK_GLOBAL_CODECS
275 
276   if (__externalCodecs)
277     for (i = 0; i < __externalCodecs->Hashers.Size(); i++)
278       methods.Add(__externalCodecs->Hashers[i].Id);
279 
280   #endif
281 }
282 
CreateCoder(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,bool encode,CMyComPtr<ICompressFilter> & filter,CCreatedCoder & cod)283 HRESULT CreateCoder(
284     DECL_EXTERNAL_CODECS_LOC_VARS
285     CMethodId methodId, bool encode,
286     CMyComPtr<ICompressFilter> &filter,
287     CCreatedCoder &cod)
288 {
289   cod.IsExternal = false;
290   cod.IsFilter = false;
291   cod.NumStreams = 1;
292 
293   unsigned i;
294   for (i = 0; i < g_NumCodecs; i++)
295   {
296     const CCodecInfo &codec = *g_Codecs[i];
297     if (codec.Id == methodId)
298     {
299       if (encode)
300       {
301         if (codec.CreateEncoder)
302         {
303           void *p = codec.CreateEncoder();
304           if (codec.IsFilter) filter = (ICompressFilter *)p;
305           else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p;
306           else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; }
307           return S_OK;
308         }
309       }
310       else
311         if (codec.CreateDecoder)
312         {
313           void *p = codec.CreateDecoder();
314           if (codec.IsFilter) filter = (ICompressFilter *)p;
315           else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p;
316           else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; }
317           return S_OK;
318         }
319     }
320   }
321 
322   #ifdef EXTERNAL_CODECS
323 
324   CHECK_GLOBAL_CODECS
325 
326   if (__externalCodecs)
327   {
328     cod.IsExternal = true;
329     for (i = 0; i < __externalCodecs->Codecs.Size(); i++)
330     {
331       const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
332       if (codec.Id == methodId)
333       {
334         if (encode)
335         {
336           if (codec.EncoderIsAssigned)
337           {
338             if (codec.NumStreams == 1)
339             {
340               HRESULT res = __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder, (void **)&cod.Coder);
341               if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE)
342                 return res;
343               if (cod.Coder)
344                 return res;
345               return __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter);
346             }
347             cod.NumStreams = codec.NumStreams;
348             return __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2);
349           }
350         }
351         else
352           if (codec.DecoderIsAssigned)
353           {
354             if (codec.NumStreams == 1)
355             {
356               HRESULT res = __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder, (void **)&cod.Coder);
357               if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE)
358                 return res;
359               if (cod.Coder)
360                 return res;
361               return __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter);
362             }
363             cod.NumStreams = codec.NumStreams;
364             return __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2);
365           }
366       }
367     }
368   }
369   #endif
370 
371   return S_OK;
372 }
373 
CreateCoder(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,bool encode,CCreatedCoder & cod)374 HRESULT CreateCoder(
375     DECL_EXTERNAL_CODECS_LOC_VARS
376     CMethodId methodId, bool encode,
377     CCreatedCoder &cod)
378 {
379   CMyComPtr<ICompressFilter> filter;
380   HRESULT res = CreateCoder(
381       EXTERNAL_CODECS_LOC_VARS
382       methodId, encode,
383       filter, cod);
384 
385   if (filter)
386   {
387     cod.IsFilter = true;
388     CFilterCoder *coderSpec = new CFilterCoder(encode);
389     cod.Coder = coderSpec;
390     coderSpec->Filter = filter;
391   }
392 
393   return res;
394 }
395 
CreateCoder(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,bool encode,CMyComPtr<ICompressCoder> & coder)396 HRESULT CreateCoder(
397     DECL_EXTERNAL_CODECS_LOC_VARS
398     CMethodId methodId, bool encode,
399     CMyComPtr<ICompressCoder> &coder)
400 {
401   CCreatedCoder cod;
402   HRESULT res = CreateCoder(
403       EXTERNAL_CODECS_LOC_VARS
404       methodId, encode,
405       cod);
406   coder = cod.Coder;
407   return res;
408 }
409 
CreateFilter(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,bool encode,CMyComPtr<ICompressFilter> & filter)410 HRESULT CreateFilter(
411     DECL_EXTERNAL_CODECS_LOC_VARS
412     CMethodId methodId, bool encode,
413     CMyComPtr<ICompressFilter> &filter)
414 {
415   CCreatedCoder cod;
416   return CreateCoder(
417       EXTERNAL_CODECS_LOC_VARS
418       methodId, encode,
419       filter, cod);
420 }
421 
422 
CreateHasher(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,AString & name,CMyComPtr<IHasher> & hasher)423 HRESULT CreateHasher(
424     DECL_EXTERNAL_CODECS_LOC_VARS
425     CMethodId methodId,
426     AString &name,
427     CMyComPtr<IHasher> &hasher)
428 {
429   name.Empty();
430 
431   unsigned i;
432   for (i = 0; i < g_NumHashers; i++)
433   {
434     const CHasherInfo &codec = *g_Hashers[i];
435     if (codec.Id == methodId)
436     {
437       hasher = codec.CreateHasher();
438       name = codec.Name;
439       break;
440     }
441   }
442 
443   #ifdef EXTERNAL_CODECS
444 
445   CHECK_GLOBAL_CODECS
446 
447   if (!hasher && __externalCodecs)
448     for (i = 0; i < __externalCodecs->Hashers.Size(); i++)
449     {
450       const CHasherInfoEx &codec = __externalCodecs->Hashers[i];
451       if (codec.Id == methodId)
452       {
453         name = codec.Name;
454         return __externalCodecs->GetHashers->CreateHasher((UInt32)i, &hasher);
455       }
456     }
457 
458   #endif
459 
460   return S_OK;
461 }
462