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