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 Z7_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 Z7_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,bool & isFilter)160 int FindMethod_Index(
161 DECL_EXTERNAL_CODECS_LOC_VARS
162 const AString &name,
163 bool encode,
164 CMethodId &methodId,
165 UInt32 &numStreams,
166 bool &isFilter)
167 {
168 unsigned i;
169 for (i = 0; i < g_NumCodecs; i++)
170 {
171 const CCodecInfo &codec = *g_Codecs[i];
172 if ((encode ? codec.CreateEncoder : codec.CreateDecoder)
173 && StringsAreEqualNoCase_Ascii(name, codec.Name))
174 {
175 methodId = codec.Id;
176 numStreams = codec.NumStreams;
177 isFilter = codec.IsFilter;
178 return (int)i;
179 }
180 }
181
182 #ifdef Z7_EXTERNAL_CODECS
183
184 CHECK_GLOBAL_CODECS
185
186 if (_externalCodecs)
187 for (i = 0; i < _externalCodecs->Codecs.Size(); i++)
188 {
189 const CCodecInfoEx &codec = _externalCodecs->Codecs[i];
190 if ((encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned)
191 && StringsAreEqualNoCase_Ascii(name, codec.Name))
192 {
193 methodId = codec.Id;
194 numStreams = codec.NumStreams;
195 isFilter = codec.IsFilter;
196 return (int)(g_NumCodecs + i);
197 }
198 }
199
200 #endif
201
202 return -1;
203 }
204
205
FindMethod_Index(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,bool encode)206 static int FindMethod_Index(
207 DECL_EXTERNAL_CODECS_LOC_VARS
208 CMethodId methodId, bool encode)
209 {
210 unsigned i;
211 for (i = 0; i < g_NumCodecs; i++)
212 {
213 const CCodecInfo &codec = *g_Codecs[i];
214 if (codec.Id == methodId && (encode ? codec.CreateEncoder : codec.CreateDecoder))
215 return (int)i;
216 }
217
218 #ifdef Z7_EXTERNAL_CODECS
219
220 CHECK_GLOBAL_CODECS
221
222 if (_externalCodecs)
223 for (i = 0; i < _externalCodecs->Codecs.Size(); i++)
224 {
225 const CCodecInfoEx &codec = _externalCodecs->Codecs[i];
226 if (codec.Id == methodId && (encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned))
227 return (int)(g_NumCodecs + i);
228 }
229
230 #endif
231
232 return -1;
233 }
234
235
FindMethod(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,AString & name)236 bool FindMethod(
237 DECL_EXTERNAL_CODECS_LOC_VARS
238 CMethodId methodId,
239 AString &name)
240 {
241 name.Empty();
242
243 unsigned i;
244 for (i = 0; i < g_NumCodecs; i++)
245 {
246 const CCodecInfo &codec = *g_Codecs[i];
247 if (methodId == codec.Id)
248 {
249 name = codec.Name;
250 return true;
251 }
252 }
253
254 #ifdef Z7_EXTERNAL_CODECS
255
256 CHECK_GLOBAL_CODECS
257
258 if (_externalCodecs)
259 for (i = 0; i < _externalCodecs->Codecs.Size(); i++)
260 {
261 const CCodecInfoEx &codec = _externalCodecs->Codecs[i];
262 if (methodId == codec.Id)
263 {
264 name = codec.Name;
265 return true;
266 }
267 }
268
269 #endif
270
271 return false;
272 }
273
FindHashMethod(DECL_EXTERNAL_CODECS_LOC_VARS const AString & name,CMethodId & methodId)274 bool FindHashMethod(
275 DECL_EXTERNAL_CODECS_LOC_VARS
276 const AString &name,
277 CMethodId &methodId)
278 {
279 unsigned i;
280 for (i = 0; i < g_NumHashers; i++)
281 {
282 const CHasherInfo &codec = *g_Hashers[i];
283 if (StringsAreEqualNoCase_Ascii(name, codec.Name))
284 {
285 methodId = codec.Id;
286 return true;
287 }
288 }
289
290 #ifdef Z7_EXTERNAL_CODECS
291
292 CHECK_GLOBAL_CODECS
293
294 if (_externalCodecs)
295 for (i = 0; i < _externalCodecs->Hashers.Size(); i++)
296 {
297 const CHasherInfoEx &codec = _externalCodecs->Hashers[i];
298 if (StringsAreEqualNoCase_Ascii(name, codec.Name))
299 {
300 methodId = codec.Id;
301 return true;
302 }
303 }
304
305 #endif
306
307 return false;
308 }
309
GetHashMethods(DECL_EXTERNAL_CODECS_LOC_VARS CRecordVector<CMethodId> & methods)310 void GetHashMethods(
311 DECL_EXTERNAL_CODECS_LOC_VARS
312 CRecordVector<CMethodId> &methods)
313 {
314 methods.ClearAndSetSize(g_NumHashers);
315 unsigned i;
316 for (i = 0; i < g_NumHashers; i++)
317 methods[i] = (*g_Hashers[i]).Id;
318
319 #ifdef Z7_EXTERNAL_CODECS
320
321 CHECK_GLOBAL_CODECS
322
323 if (_externalCodecs)
324 for (i = 0; i < _externalCodecs->Hashers.Size(); i++)
325 methods.Add(_externalCodecs->Hashers[i].Id);
326
327 #endif
328 }
329
330
331
CreateCoder_Index(DECL_EXTERNAL_CODECS_LOC_VARS unsigned i,bool encode,CMyComPtr<ICompressFilter> & filter,CCreatedCoder & cod)332 HRESULT CreateCoder_Index(
333 DECL_EXTERNAL_CODECS_LOC_VARS
334 unsigned i, bool encode,
335 CMyComPtr<ICompressFilter> &filter,
336 CCreatedCoder &cod)
337 {
338 cod.IsExternal = false;
339 cod.IsFilter = false;
340 cod.NumStreams = 1;
341
342 if (i < g_NumCodecs)
343 {
344 const CCodecInfo &codec = *g_Codecs[i];
345 // if (codec.Id == methodId)
346 {
347 if (encode)
348 {
349 if (codec.CreateEncoder)
350 {
351 void *p = codec.CreateEncoder();
352 if (codec.IsFilter) filter = (ICompressFilter *)p;
353 else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p;
354 else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; }
355 return S_OK;
356 }
357 }
358 else
359 if (codec.CreateDecoder)
360 {
361 void *p = codec.CreateDecoder();
362 if (codec.IsFilter) filter = (ICompressFilter *)p;
363 else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p;
364 else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; }
365 return S_OK;
366 }
367 }
368 }
369
370 #ifdef Z7_EXTERNAL_CODECS
371
372 CHECK_GLOBAL_CODECS
373
374 if (_externalCodecs)
375 {
376 i -= g_NumCodecs;
377 cod.IsExternal = true;
378 if (i < _externalCodecs->Codecs.Size())
379 {
380 const CCodecInfoEx &codec = _externalCodecs->Codecs[i];
381 // if (codec.Id == methodId)
382 {
383 if (encode)
384 {
385 if (codec.EncoderIsAssigned)
386 {
387 if (codec.NumStreams == 1)
388 {
389 const HRESULT res = _externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder, (void **)&cod.Coder);
390 if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE)
391 return res;
392 if (cod.Coder)
393 return res;
394 return _externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter);
395 }
396 cod.NumStreams = codec.NumStreams;
397 return _externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2);
398 }
399 }
400 else
401 if (codec.DecoderIsAssigned)
402 {
403 if (codec.NumStreams == 1)
404 {
405 const HRESULT res = _externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder, (void **)&cod.Coder);
406 if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE)
407 return res;
408 if (cod.Coder)
409 return res;
410 return _externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter);
411 }
412 cod.NumStreams = codec.NumStreams;
413 return _externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2);
414 }
415 }
416 }
417 }
418 #endif
419
420 return S_OK;
421 }
422
423
CreateCoder_Index(DECL_EXTERNAL_CODECS_LOC_VARS unsigned index,bool encode,CCreatedCoder & cod)424 HRESULT CreateCoder_Index(
425 DECL_EXTERNAL_CODECS_LOC_VARS
426 unsigned index, bool encode,
427 CCreatedCoder &cod)
428 {
429 CMyComPtr<ICompressFilter> filter;
430 const HRESULT res = CreateCoder_Index(
431 EXTERNAL_CODECS_LOC_VARS
432 index, encode,
433 filter, cod);
434
435 if (filter)
436 {
437 cod.IsFilter = true;
438 CFilterCoder *coderSpec = new CFilterCoder(encode);
439 cod.Coder = coderSpec;
440 coderSpec->Filter = filter;
441 }
442
443 return res;
444 }
445
446
CreateCoder_Id(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,bool encode,CMyComPtr<ICompressFilter> & filter,CCreatedCoder & cod)447 HRESULT CreateCoder_Id(
448 DECL_EXTERNAL_CODECS_LOC_VARS
449 CMethodId methodId, bool encode,
450 CMyComPtr<ICompressFilter> &filter,
451 CCreatedCoder &cod)
452 {
453 const int index = FindMethod_Index(EXTERNAL_CODECS_LOC_VARS methodId, encode);
454 if (index < 0)
455 return S_OK;
456 return CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS (unsigned)index, encode, filter, cod);
457 }
458
459
CreateCoder_Id(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,bool encode,CCreatedCoder & cod)460 HRESULT CreateCoder_Id(
461 DECL_EXTERNAL_CODECS_LOC_VARS
462 CMethodId methodId, bool encode,
463 CCreatedCoder &cod)
464 {
465 CMyComPtr<ICompressFilter> filter;
466 const HRESULT res = CreateCoder_Id(
467 EXTERNAL_CODECS_LOC_VARS
468 methodId, encode,
469 filter, cod);
470
471 if (filter)
472 {
473 cod.IsFilter = true;
474 CFilterCoder *coderSpec = new CFilterCoder(encode);
475 cod.Coder = coderSpec;
476 coderSpec->Filter = filter;
477 }
478
479 return res;
480 }
481
482
CreateCoder_Id(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,bool encode,CMyComPtr<ICompressCoder> & coder)483 HRESULT CreateCoder_Id(
484 DECL_EXTERNAL_CODECS_LOC_VARS
485 CMethodId methodId, bool encode,
486 CMyComPtr<ICompressCoder> &coder)
487 {
488 CCreatedCoder cod;
489 const HRESULT res = CreateCoder_Id(
490 EXTERNAL_CODECS_LOC_VARS
491 methodId, encode,
492 cod);
493 coder = cod.Coder;
494 return res;
495 }
496
CreateFilter(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,bool encode,CMyComPtr<ICompressFilter> & filter)497 HRESULT CreateFilter(
498 DECL_EXTERNAL_CODECS_LOC_VARS
499 CMethodId methodId, bool encode,
500 CMyComPtr<ICompressFilter> &filter)
501 {
502 CCreatedCoder cod;
503 return CreateCoder_Id(
504 EXTERNAL_CODECS_LOC_VARS
505 methodId, encode,
506 filter, cod);
507 }
508
509
CreateHasher(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,AString & name,CMyComPtr<IHasher> & hasher)510 HRESULT CreateHasher(
511 DECL_EXTERNAL_CODECS_LOC_VARS
512 CMethodId methodId,
513 AString &name,
514 CMyComPtr<IHasher> &hasher)
515 {
516 name.Empty();
517
518 unsigned i;
519 for (i = 0; i < g_NumHashers; i++)
520 {
521 const CHasherInfo &codec = *g_Hashers[i];
522 if (codec.Id == methodId)
523 {
524 hasher = codec.CreateHasher();
525 name = codec.Name;
526 break;
527 }
528 }
529
530 #ifdef Z7_EXTERNAL_CODECS
531
532 CHECK_GLOBAL_CODECS
533
534 if (!hasher && _externalCodecs)
535 for (i = 0; i < _externalCodecs->Hashers.Size(); i++)
536 {
537 const CHasherInfoEx &codec = _externalCodecs->Hashers[i];
538 if (codec.Id == methodId)
539 {
540 name = codec.Name;
541 return _externalCodecs->GetHashers->CreateHasher((UInt32)i, &hasher);
542 }
543 }
544
545 #endif
546
547 return S_OK;
548 }
549