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