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