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 int kNumCodecsMax = 64;
14 unsigned int g_NumCodecs = 0;
15 const CCodecInfo *g_Codecs[kNumCodecsMax];
RegisterCodec(const CCodecInfo * codecInfo)16 void RegisterCodec(const CCodecInfo *codecInfo)
17 {
18   if (g_NumCodecs < kNumCodecsMax)
19     g_Codecs[g_NumCodecs++] = codecInfo;
20 }
21 
22 #ifdef EXTERNAL_CODECS
ReadNumberOfStreams(ICompressCodecsInfo * codecsInfo,UInt32 index,PROPID propID,UInt32 & res)23 static HRESULT ReadNumberOfStreams(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, UInt32 &res)
24 {
25   NWindows::NCOM::CPropVariant prop;
26   RINOK(codecsInfo->GetProperty(index, propID, &prop));
27   if (prop.vt == VT_EMPTY)
28     res = 1;
29   else if (prop.vt == VT_UI4)
30     res = prop.ulVal;
31   else
32     return E_INVALIDARG;
33   return S_OK;
34 }
35 
ReadIsAssignedProp(ICompressCodecsInfo * codecsInfo,UInt32 index,PROPID propID,bool & res)36 static HRESULT ReadIsAssignedProp(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, bool &res)
37 {
38   NWindows::NCOM::CPropVariant prop;
39   RINOK(codecsInfo->GetProperty(index, propID, &prop));
40   if (prop.vt == VT_EMPTY)
41     res = true;
42   else if (prop.vt == VT_BOOL)
43     res = VARIANT_BOOLToBool(prop.boolVal);
44   else
45     return E_INVALIDARG;
46   return S_OK;
47 }
48 
LoadExternalCodecs(ICompressCodecsInfo * codecsInfo,CObjectVector<CCodecInfoEx> & externalCodecs)49 HRESULT LoadExternalCodecs(ICompressCodecsInfo *codecsInfo, CObjectVector<CCodecInfoEx> &externalCodecs)
50 {
51   UInt32 num;
52   RINOK(codecsInfo->GetNumberOfMethods(&num));
53   for (UInt32 i = 0; i < num; i++)
54   {
55     CCodecInfoEx info;
56     NWindows::NCOM::CPropVariant prop;
57     RINOK(codecsInfo->GetProperty(i, NMethodPropID::kID, &prop));
58     // if (prop.vt != VT_BSTR)
59     // info.Id.IDSize = (Byte)SysStringByteLen(prop.bstrVal);
60     // memmove(info.Id.ID, prop.bstrVal, info.Id.IDSize);
61     if (prop.vt != VT_UI8)
62     {
63       continue; // old Interface
64       // return E_INVALIDARG;
65     }
66     info.Id = prop.uhVal.QuadPart;
67     prop.Clear();
68 
69     RINOK(codecsInfo->GetProperty(i, NMethodPropID::kName, &prop));
70     if (prop.vt == VT_BSTR)
71       info.Name = prop.bstrVal;
72     else if (prop.vt != VT_EMPTY)
73       return E_INVALIDARG;;
74 
75     RINOK(ReadNumberOfStreams(codecsInfo, i, NMethodPropID::kInStreams, info.NumInStreams));
76     RINOK(ReadNumberOfStreams(codecsInfo, i, NMethodPropID::kOutStreams, info.NumOutStreams));
77     RINOK(ReadIsAssignedProp(codecsInfo, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned));
78     RINOK(ReadIsAssignedProp(codecsInfo, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned));
79 
80     externalCodecs.Add(info);
81   }
82   return S_OK;
83 }
84 
85 #endif
86 
FindMethod(ICompressCodecsInfo *,const CObjectVector<CCodecInfoEx> * externalCodecs,const UString & name,CMethodId & methodId,UInt32 & numInStreams,UInt32 & numOutStreams)87 bool FindMethod(
88   #ifdef EXTERNAL_CODECS
89   ICompressCodecsInfo * /* codecsInfo */, const CObjectVector<CCodecInfoEx> *externalCodecs,
90   #endif
91   const UString &name,
92   CMethodId &methodId, UInt32 &numInStreams, UInt32 &numOutStreams)
93 {
94   UInt32 i;
95   for (i = 0; i < g_NumCodecs; i++)
96   {
97     const CCodecInfo &codec = *g_Codecs[i];
98     if (name.CompareNoCase(codec.Name) == 0)
99     {
100       methodId = codec.Id;
101       numInStreams = codec.NumInStreams;
102       numOutStreams = 1;
103       return true;
104     }
105   }
106   #ifdef EXTERNAL_CODECS
107   if (externalCodecs)
108     for (i = 0; i < (UInt32)externalCodecs->Size(); i++)
109     {
110       const CCodecInfoEx &codec = (*externalCodecs)[i];
111       if (codec.Name.CompareNoCase(name) == 0)
112       {
113         methodId = codec.Id;
114         numInStreams = codec.NumInStreams;
115         numOutStreams = codec.NumOutStreams;
116         return true;
117       }
118     }
119   #endif
120   return false;
121 }
122 
FindMethod(ICompressCodecsInfo *,const CObjectVector<CCodecInfoEx> * externalCodecs,CMethodId methodId,UString & name)123 bool FindMethod(
124   #ifdef EXTERNAL_CODECS
125   ICompressCodecsInfo * /* codecsInfo */, const CObjectVector<CCodecInfoEx> *externalCodecs,
126   #endif
127   CMethodId methodId, UString &name)
128 {
129   UInt32 i;
130   for (i = 0; i < g_NumCodecs; i++)
131   {
132     const CCodecInfo &codec = *g_Codecs[i];
133     if (methodId == codec.Id)
134     {
135       name = codec.Name;
136       return true;
137     }
138   }
139   #ifdef EXTERNAL_CODECS
140   if (externalCodecs)
141     for (i = 0; i < (UInt32)externalCodecs->Size(); i++)
142     {
143       const CCodecInfoEx &codec = (*externalCodecs)[i];
144       if (methodId == codec.Id)
145       {
146         name = codec.Name;
147         return true;
148       }
149     }
150   #endif
151   return false;
152 }
153 
CreateCoder(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,CMyComPtr<ICompressFilter> & filter,CMyComPtr<ICompressCoder> & coder,CMyComPtr<ICompressCoder2> & coder2,bool encode,bool onlyCoder)154 HRESULT CreateCoder(
155   DECL_EXTERNAL_CODECS_LOC_VARS
156   CMethodId methodId,
157   CMyComPtr<ICompressFilter> &filter,
158   CMyComPtr<ICompressCoder> &coder,
159   CMyComPtr<ICompressCoder2> &coder2,
160   bool encode, bool onlyCoder)
161 {
162   bool created = false;
163   UInt32 i;
164   for (i = 0; i < g_NumCodecs; i++)
165   {
166     const CCodecInfo &codec = *g_Codecs[i];
167     if (codec.Id == methodId)
168     {
169       if (encode)
170       {
171         if (codec.CreateEncoder)
172         {
173           void *p = codec.CreateEncoder();
174           if (codec.IsFilter) filter = (ICompressFilter *)p;
175           else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p;
176           else coder2 = (ICompressCoder2 *)p;
177           created = (p != 0);
178           break;
179         }
180       }
181       else
182         if (codec.CreateDecoder)
183         {
184           void *p = codec.CreateDecoder();
185           if (codec.IsFilter) filter = (ICompressFilter *)p;
186           else if (codec.NumInStreams == 1) coder = (ICompressCoder *)p;
187           else coder2 = (ICompressCoder2 *)p;
188           created = (p != 0);
189           break;
190         }
191     }
192   }
193 
194   #ifdef EXTERNAL_CODECS
195   if (!created && externalCodecs)
196     for (i = 0; i < (UInt32)externalCodecs->Size(); i++)
197     {
198       const CCodecInfoEx &codec = (*externalCodecs)[i];
199       if (codec.Id == methodId)
200       {
201         if (encode)
202         {
203           if (codec.EncoderIsAssigned)
204           {
205             if (codec.IsSimpleCodec())
206             {
207               HRESULT result = codecsInfo->CreateEncoder(i, &IID_ICompressCoder, (void **)&coder);
208               if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE)
209                 return result;
210               if (!coder)
211               {
212                 RINOK(codecsInfo->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter));
213               }
214             }
215             else
216             {
217               RINOK(codecsInfo->CreateEncoder(i, &IID_ICompressCoder2, (void **)&coder2));
218             }
219             break;
220           }
221         }
222         else
223           if (codec.DecoderIsAssigned)
224           {
225             if (codec.IsSimpleCodec())
226             {
227               HRESULT result = codecsInfo->CreateDecoder(i, &IID_ICompressCoder, (void **)&coder);
228               if (result != S_OK && result != E_NOINTERFACE && result != CLASS_E_CLASSNOTAVAILABLE)
229                 return result;
230               if (!coder)
231               {
232                 RINOK(codecsInfo->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter));
233               }
234             }
235             else
236             {
237               RINOK(codecsInfo->CreateDecoder(i, &IID_ICompressCoder2, (void **)&coder2));
238             }
239             break;
240           }
241       }
242     }
243   #endif
244 
245   if (onlyCoder && filter)
246   {
247     CFilterCoder *coderSpec = new CFilterCoder;
248     coder = coderSpec;
249     coderSpec->Filter = filter;
250   }
251   return S_OK;
252 }
253 
CreateCoder(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,CMyComPtr<ICompressCoder> & coder,CMyComPtr<ICompressCoder2> & coder2,bool encode)254 HRESULT CreateCoder(
255   DECL_EXTERNAL_CODECS_LOC_VARS
256   CMethodId methodId,
257   CMyComPtr<ICompressCoder> &coder,
258   CMyComPtr<ICompressCoder2> &coder2,
259   bool encode)
260 {
261   CMyComPtr<ICompressFilter> filter;
262   return CreateCoder(
263     EXTERNAL_CODECS_LOC_VARS
264     methodId,
265     filter, coder, coder2, encode, true);
266 }
267 
CreateCoder(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,CMyComPtr<ICompressCoder> & coder,bool encode)268 HRESULT CreateCoder(
269   DECL_EXTERNAL_CODECS_LOC_VARS
270   CMethodId methodId,
271   CMyComPtr<ICompressCoder> &coder, bool encode)
272 {
273   CMyComPtr<ICompressFilter> filter;
274   CMyComPtr<ICompressCoder2> coder2;
275   return CreateCoder(
276     EXTERNAL_CODECS_LOC_VARS
277     methodId,
278     coder, coder2, encode);
279 }
280 
CreateFilter(DECL_EXTERNAL_CODECS_LOC_VARS CMethodId methodId,CMyComPtr<ICompressFilter> & filter,bool encode)281 HRESULT CreateFilter(
282   DECL_EXTERNAL_CODECS_LOC_VARS
283   CMethodId methodId,
284   CMyComPtr<ICompressFilter> &filter,
285   bool encode)
286 {
287   CMyComPtr<ICompressCoder> coder;
288   CMyComPtr<ICompressCoder2> coder2;
289   return CreateCoder(
290     EXTERNAL_CODECS_LOC_VARS
291     methodId,
292     filter, coder, coder2, encode, false);
293 }
294