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
13static const unsigned int kNumCodecsMax = 64;
14unsigned int g_NumCodecs = 0;
15const CCodecInfo *g_Codecs[kNumCodecsMax];
16void RegisterCodec(const CCodecInfo *codecInfo)
17{
18  if (g_NumCodecs < kNumCodecsMax)
19    g_Codecs[g_NumCodecs++] = codecInfo;
20}
21
22#ifdef EXTERNAL_CODECS
23static 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
36static 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
49HRESULT 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
87bool 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
123bool 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
154HRESULT 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
254HRESULT 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
268HRESULT 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
281HRESULT 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