Home | History | Annotate | Download | only in Common
      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