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