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