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 int kNumCodecsMax = 64;
14 unsigned int g_NumCodecs = 0;
15 const CCodecInfo *g_Codecs[kNumCodecsMax];
RegisterCodec(const CCodecInfo * codecInfo)16 void RegisterCodec(const CCodecInfo *codecInfo) throw()
17 {
18   if (g_NumCodecs < kNumCodecsMax)
19     g_Codecs[g_NumCodecs++] = codecInfo;
20 }
21 
22 static const unsigned int kNumHashersMax = 16;
23 unsigned int g_NumHashers = 0;
24 const CHasherInfo *g_Hashers[kNumHashersMax];
RegisterHasher(const CHasherInfo * hashInfo)25 void RegisterHasher(const CHasherInfo *hashInfo) throw()
26 {
27   if (g_NumHashers < kNumHashersMax)
28     g_Hashers[g_NumHashers++] = hashInfo;
29 }
30 
31 #ifdef EXTERNAL_CODECS
ReadNumberOfStreams(ICompressCodecsInfo * codecsInfo,UInt32 index,PROPID propID,UInt32 & res)32 static 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 
ReadIsAssignedProp(ICompressCodecsInfo * codecsInfo,UInt32 index,PROPID propID,bool & res)45 static 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 
LoadCodecs()58 HRESULT 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 
FindMethod(DECL_EXTERNAL_CODECS_LOC_VARS const UString & name,CMethodId & methodId,UInt32 & numInStreams,UInt32 & numOutStreams)118 bool 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 
FindMethod(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,UString & name)150 bool 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 
FindHashMethod(DECL_EXTERNAL_CODECS_LOC_VARS const UString & name,CMethodId & methodId)178 bool 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 
GetHashMethods(DECL_EXTERNAL_CODECS_LOC_VARS CRecordVector<CMethodId> & methods)207 void 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 
CreateCoder(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,CMyComPtr<ICompressFilter> & filter,CMyComPtr<ICompressCoder> & coder,CMyComPtr<ICompressCoder2> & coder2,bool encode,bool onlyCoder)221 HRESULT 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 
CreateCoder(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,CMyComPtr<ICompressCoder> & coder,CMyComPtr<ICompressCoder2> & coder2,bool encode)318 HRESULT 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 
CreateCoder(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,CMyComPtr<ICompressCoder> & coder,bool encode)332 HRESULT 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 
CreateFilter(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,CMyComPtr<ICompressFilter> & filter,bool encode)345 HRESULT 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 
CreateHasher(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,UString & name,CMyComPtr<IHasher> & hasher)359 HRESULT 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