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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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