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