OPAL  Version 3.14.3
opalplugin.hpp
Go to the documentation of this file.
1 /*
2  * opalplugins.hpp
3  *
4  * OPAL codec plugins handler (C++ version)
5  *
6  * Open Phone Abstraction Library (OPAL)
7  * Formally known as the Open H323 project.
8  *
9  * Copyright (C) 2010 Vox Lucida
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * - Redistributions of source code must retain the above copyright
16  * notice, this list of conditions and the following disclaimer.
17 
18  * - Redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
26  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * $Revision: 32519 $
35  * $Author: rjongbloed $
36  * $Date: 2014-08-14 15:24:01 +1000 (Thu, 14 Aug 2014) $
37  */
38 
39 #ifndef OPAL_CODEC_OPALPLUGIN_HPP
40 #define OPAL_CODEC_OPALPLUGIN_HPP
41 
42 #include "opalplugin.h"
43 
44 #include <string.h>
45 #include <stdlib.h>
46 #include <limits.h>
47 
48 #include <map>
49 #include <string>
50 
51 
53 
54 #ifndef PLUGINCODEC_TRACING
55  #define PLUGINCODEC_TRACING 1
56 #endif
57 
58 #if PLUGINCODEC_TRACING
60  extern int PluginCodec_SetLogFunction(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len);
61 
62 #define PLUGINCODEC_CONTROL_LOG_FUNCTION_DEF \
63  PluginCodec_LogFunction PluginCodec_LogFunctionInstance; \
64  int PluginCodec_SetLogFunction(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len) \
65  { \
66  if (len == NULL || *len != sizeof(PluginCodec_LogFunction)) \
67  return false; \
68  \
69  PluginCodec_LogFunctionInstance = (PluginCodec_LogFunction)parm; \
70  if (PluginCodec_LogFunctionInstance != NULL) \
71  PluginCodec_LogFunctionInstance(4, __FILE__, __LINE__, "Plugin", "Started logging."); \
72  \
73  return true; \
74  } \
75 
76  #define PLUGINCODEC_CONTROL_LOG_FUNCTION_INC { PLUGINCODEC_CONTROL_SET_LOG_FUNCTION, PluginCodec_SetLogFunction },
77 #else
78  #define PLUGINCODEC_CONTROL_LOG_FUNCTION_DEF
79  #define PLUGINCODEC_CONTROL_LOG_FUNCTION_INC
80 #endif
81 
82 #if !defined(PTRACE)
83  #if PLUGINCODEC_TRACING
84  #include <sstream>
85  #define PTRACE_CHECK(level) \
86  (PluginCodec_LogFunctionInstance != NULL && PluginCodec_LogFunctionInstance(level, NULL, 0, NULL, NULL))
87  #define PTRACE(level, section, args) \
88  if (PTRACE_CHECK(level)) { \
89  std::ostringstream strm; strm << args; \
90  PluginCodec_LogFunctionInstance(level, __FILE__, __LINE__, section, strm.str().c_str()); \
91  } else (void)0
92  #else
93  #define PTRACE_CHECK(level)
94  #define PTRACE(level, section, expr)
95  #endif
96 #endif
97 
98 
100 
102 {
103  unsigned char * m_packet;
104  size_t m_maxSize;
105  size_t m_headerSize;
106  size_t m_payloadSize;
107 
108  public:
109  PluginCodec_RTP(const void * packet, unsigned size)
110  : m_packet((unsigned char *)packet)
111  , m_maxSize(size)
112  , m_headerSize(PluginCodec_RTP_GetHeaderLength(m_packet))
113  , m_payloadSize(size - m_headerSize)
114  {
115  }
116 
117  __inline size_t GetMaxSize() const { return m_maxSize; }
118  __inline size_t GetPacketSize() const { return m_headerSize+m_payloadSize; }
119  __inline size_t GetHeaderSize() const { return m_headerSize; }
120  __inline size_t GetPayloadSize() const { return m_payloadSize; }
121  __inline bool SetPayloadSize(size_t size)
122  {
123  if (m_headerSize+size > m_maxSize)
124  return false;
125  m_payloadSize = size;
126  return true;
127  }
128 
129  __inline unsigned GetPayloadType() const { return PluginCodec_RTP_GetPayloadType(m_packet); }
130  __inline void SetPayloadType(unsigned type) { PluginCodec_RTP_SetPayloadType(m_packet, type); }
131  __inline bool GetMarker() const { return PluginCodec_RTP_GetMarker(m_packet); }
132  __inline void SetMarker(bool mark) { PluginCodec_RTP_SetMarker(m_packet, mark); }
133  __inline unsigned GetTimestamp() const { return PluginCodec_RTP_GetTimestamp(m_packet); }
134  __inline void SetTimestamp(unsigned ts) { PluginCodec_RTP_SetTimestamp(m_packet, ts); }
135  __inline unsigned GetSequenceNumber() const { return PluginCodec_RTP_GetSequenceNumber(m_packet); }
136  __inline void SetSequenceNumber(unsigned sn) { PluginCodec_RTP_SetSequenceNumber(m_packet, sn); }
137  __inline unsigned GetSSRC() const { return PluginCodec_RTP_GetSSRC(m_packet); }
138  __inline void SetSSRC(unsigned ssrc) { PluginCodec_RTP_SetSSRC(m_packet, ssrc); }
139 
140  __inline unsigned char * SetExtended(unsigned id, unsigned len)
141  {
142  m_packet[0] |= 0x10;
143 
144  unsigned char * ptr = m_packet + PluginCodec_RTP_GetCSRCHdrLength(m_packet);
145  switch (id >> 16) {
146  case 0 :
147  PluginCodec_RTP_SetWORD(ptr, 0, id);
148  PluginCodec_RTP_SetWORD(ptr, 2, (len+3)/4);
149  ptr += 4;
150  break;
151 
152  case 1 :
153  *ptr++ = 0xbe;
154  *ptr++ = 0xde;
155  PluginCodec_RTP_SetWORD(ptr, 0, (len+7)/4); ptr += 2;
156  *ptr++ = (unsigned char)(((id&0xf) << 4)|(len-1));
157  break;
158 
159  case 2 :
160  *ptr++ = 0x10;
161  *ptr++ = 0x00;
162  PluginCodec_RTP_SetWORD(ptr, 0, (len+8)/4); ptr += 2;
163  *ptr++ = (unsigned char)(id&0xff);
164  *ptr++ = (unsigned char)(len&0xff);
165  }
166 
167  m_headerSize = PluginCodec_RTP_GetHeaderLength(m_packet);
168  return ptr;
169  }
170 
171  __inline unsigned char * GetExtendedHeader(unsigned & id, size_t & len) const
172  {
173  if ((m_packet[0]&0x10) == 0)
174  return NULL;
175 
176  unsigned char * ptr = m_packet + PluginCodec_RTP_GetCSRCHdrLength(m_packet);
177  id = PluginCodec_RTP_GetWORD(ptr, 0);
178 
179  if (id == 0xbede) {
180  id = (0x10000|(ptr[4] >> 4));
181  len = (ptr[4] & 0xf)+1;
182  return ptr + 5;
183  }
184 
185  if ((id&0xfff0) == 0x1000) {
186  id = 0x20000 | ptr[4];
187  len = ptr[5];
188  return ptr + 6;
189  }
190 
191  len = PluginCodec_RTP_GetWORD(ptr, 2)*4;
192  return ptr + 4;
193  }
194 
195  __inline unsigned char * GetPayloadPtr() const { return m_packet + m_headerSize; }
196  __inline unsigned char & operator[](size_t offset) { return m_packet[m_headerSize + offset]; }
197  __inline unsigned const char & operator[](size_t offset) const { return m_packet[m_headerSize + offset]; }
198  __inline bool CopyPayload(const void * data, size_t size, size_t offset = 0)
199  {
200  if (!SetPayloadSize(offset + size))
201  return false;
202  memcpy(GetPayloadPtr()+offset, data, size);
203  return true;
204  }
205 
207  __inline unsigned char * GetVideoFrameData() const { return m_packet + m_headerSize + sizeof(PluginCodec_Video_FrameHeader); }
208 };
209 
210 
212 
213 typedef std::map<std::string, std::string> PluginCodec_OptionMapBase;
214 
216 {
217  public:
218  static unsigned String2Unsigned(const std::string & str)
219  {
220  return strtoul(str.c_str(), NULL, 10);
221  }
222 
223 
224  static void AppendUnsigned2String(unsigned value, std::string & str)
225  {
226  // Not very efficient, but really, really simple
227  if (value > 9)
228  AppendUnsigned2String(value/10, str);
229  str += (char)(value%10 + '0');
230  }
231 
232 
233  static void Unsigned2String(unsigned value, std::string & str)
234  {
235  str.clear();
236  AppendUnsigned2String(value,str);
237  }
238 
239 
240  static void Change(const char * value,
241  PluginCodec_OptionMapBase & original,
242  PluginCodec_OptionMapBase & changed,
243  const char * option)
244  {
245  PluginCodec_OptionMapBase::iterator it = original.find(option);
246  if (it != original.end() && it->second != value)
247  changed[option] = value;
248  }
249 
250 
251  static void Change(unsigned value,
252  PluginCodec_OptionMapBase & original,
253  PluginCodec_OptionMapBase & changed,
254  const char * option)
255  {
256  if (String2Unsigned(original[option]) != value)
257  Unsigned2String(value, changed[option]);
258  }
259 
260 
261  static void ClampMax(unsigned maximum,
262  PluginCodec_OptionMapBase & original,
263  PluginCodec_OptionMapBase & changed,
264  const char * option,
265  bool forceIfZero = false)
266  {
267  unsigned value = String2Unsigned(original[option]);
268  if (value > maximum || (forceIfZero && value == 0))
269  Unsigned2String(maximum, changed[option]);
270  }
271 
272 
273  static void ClampMin(unsigned minimum,
274  PluginCodec_OptionMapBase & original,
275  PluginCodec_OptionMapBase & changed,
276  const char * option)
277  {
278  unsigned value = String2Unsigned(original[option]);
279  if (value < minimum)
280  Unsigned2String(minimum, changed[option]);
281  }
282 
283 
284  static unsigned GetMacroBlocks(unsigned width, unsigned height)
285  {
286  return ((width+15)/16) * ((height+15)/16);
287  }
288 
289 
290  static bool ClampResolution(
291  unsigned & width,
292  unsigned & height,
293  unsigned & maxFrameSize)
294  {
295  static struct {
296  unsigned m_width;
297  unsigned m_height;
298  unsigned m_macroblocks;
299  } MaxVideoResolutions[] = {
300  #define OPAL_PLUGIN_CLAMPED_RESOLUTION(width, height) { width, height, ((width+15)/16) * ((height+15)/16) }
301  OPAL_PLUGIN_CLAMPED_RESOLUTION(4096, 2304), // 36864 - Cinema 16:9 (H.264 Level 5.1 - 5.2)
302  OPAL_PLUGIN_CLAMPED_RESOLUTION(4096, 2160), // 34560 - DCI HD
303  OPAL_PLUGIN_CLAMPED_RESOLUTION(3840, 2160), // 32400 - 4k UHDTV
304  OPAL_PLUGIN_CLAMPED_RESOLUTION(3672, 1536), // 22080 - Cinema 2.39:1 (H.264 Level 5)
305  OPAL_PLUGIN_CLAMPED_RESOLUTION(2048, 1080), // 8704 - 2Kx1080 (H.264 Level 4.2)
306  OPAL_PLUGIN_CLAMPED_RESOLUTION(2048, 1024), // 8192 - 2Kx1K (H.264 Level 4 - 4.1)
307  OPAL_PLUGIN_CLAMPED_RESOLUTION(1920, 1080), // 8100 - 1080p HD
308  OPAL_PLUGIN_CLAMPED_RESOLUTION(1408, 1152), // 6336 - 16CIF
309  OPAL_PLUGIN_CLAMPED_RESOLUTION(1280, 1024), // 5120 - SXGA (H.264 Level 3.2)
310  OPAL_PLUGIN_CLAMPED_RESOLUTION(1280, 720), // 3600 - 720p HD (H.264 Level 3.1)
311  OPAL_PLUGIN_CLAMPED_RESOLUTION( 720, 576), // 1620 - 625 SD (H.264 Level 2.2 - 3)
312  OPAL_PLUGIN_CLAMPED_RESOLUTION( 704, 576), // 1584 - 4CIF
313  OPAL_PLUGIN_CLAMPED_RESOLUTION( 640, 480), // 1200 - VGA
314  OPAL_PLUGIN_CLAMPED_RESOLUTION( 352, 576), // 792 - 625 HHR (H.264 Level 2.1)
315  OPAL_PLUGIN_CLAMPED_RESOLUTION( 352, 288), // 396 - CIF (H.264 Level 1.1 - 2)
316  OPAL_PLUGIN_CLAMPED_RESOLUTION( 320, 240), // 300 - QVGA
317  OPAL_PLUGIN_CLAMPED_RESOLUTION( 176, 144), // 99 - QCIF (H.264 Level 1, 1b)
318  OPAL_PLUGIN_CLAMPED_RESOLUTION( 128, 96) // 48 - SQCIF
319  };
320  static size_t const LastMaxVideoResolutions = sizeof(MaxVideoResolutions)/sizeof(MaxVideoResolutions[0]) - 1;
321 
322  size_t index = 0;
323 
324  if (maxFrameSize > 0) {
325  static unsigned const MinWidth = 4*16; // Four macroblocks wide
326  static unsigned const MinHeight = 3*16; // Three macroblocks high
327 
328  unsigned maxWidth = maxFrameSize*16*16/MinHeight;
329  unsigned maxHeight = maxFrameSize*16*16/MinWidth;
330 
331  // Check if total frame size below threshold total of macroblocks.
332  unsigned macroBlocks = GetMacroBlocks(width, height);
333  if (macroBlocks <= maxFrameSize &&
334  width >= MinWidth && width <= maxWidth &&
335  height >= MinHeight && height <= maxHeight)
336  return false;
337 
338  while (index < LastMaxVideoResolutions &&
339  (MaxVideoResolutions[index].m_macroblocks > maxFrameSize ||
340  MaxVideoResolutions[index].m_width > maxWidth ||
341  MaxVideoResolutions[index].m_height > maxHeight))
342  ++index;
343  }
344 
345  PTRACE(4, "Plugin", "ClampResolution: idx=" << index << ' '
346  << width << 'x' << height << " > " << maxFrameSize << "mb reduced to "
347  << MaxVideoResolutions[index].m_width << 'x' << MaxVideoResolutions[index].m_height
348  << '=' << MaxVideoResolutions[index].m_macroblocks << "mb");
349  width = MaxVideoResolutions[index].m_width;
350  height = MaxVideoResolutions[index].m_height;
351  maxFrameSize = MaxVideoResolutions[index].m_macroblocks;
352  return true;
353  }
354 
355  static bool ClampResolution(
356  PluginCodec_OptionMapBase & original,
357  PluginCodec_OptionMapBase & changed,
358  unsigned maxWidth,
359  unsigned maxHeight,
360  unsigned & maxMacroBlocks,
361  const char * widthKey = PLUGINCODEC_OPTION_FRAME_WIDTH,
362  const char * heightKey = PLUGINCODEC_OPTION_FRAME_HEIGHT,
363  const char * maxWidthKey = PLUGINCODEC_OPTION_MAX_RX_FRAME_WIDTH,
364  const char * maxHeightKey = PLUGINCODEC_OPTION_MAX_RX_FRAME_HEIGHT,
365  const char * minWidthKey = PLUGINCODEC_OPTION_MIN_RX_FRAME_WIDTH,
366  const char * minHeightKey = PLUGINCODEC_OPTION_MIN_RX_FRAME_HEIGHT
367  )
368  {
369  if (!ClampResolution(maxWidth, maxHeight, maxMacroBlocks))
370  return false;
371 
372  ClampMax(maxWidth, original, changed, widthKey);
373  ClampMax(maxHeight, original, changed, heightKey);
374  ClampMax(maxWidth, original, changed, maxWidthKey);
375  ClampMax(maxHeight, original, changed, maxHeightKey);
376  ClampMax(maxWidth, original, changed, minWidthKey);
377  ClampMax(maxHeight, original, changed, minHeightKey);
378  return true;
379  }
380 };
381 
382 
384 {
385  public:
386  PluginCodec_OptionMap(const char * const * * options = NULL)
387  {
388  if (options != NULL) {
389  for (const char * const * option = *options; *option != NULL; option += 2)
390  insert(value_type(option[0], option[1]));
391  }
392  }
393 
394 
395  unsigned GetUnsigned(const char * key, unsigned dflt = 0) const
396  {
397  const_iterator it = find(key);
398  return it == end() ? dflt : String2Unsigned(it->second);
399  }
400 
401  void SetUnsigned(unsigned value, const char * key)
402  {
403  Unsigned2String(value, operator[](key));
404  }
405 
406 
407  char ** GetOptions() const
408  {
409  char ** options = (char **)calloc(size()*2+1, sizeof(char *));
410  if (options == NULL) {
411  PTRACE(1, "Plugin", "Could not allocate new option lists.");
412  return NULL;
413  }
414 
415  char ** opt = options;
416  for (const_iterator it = begin(); it != end(); ++it) {
417  *opt++ = strdup(it->first.c_str());
418  *opt++ = strdup(it->second.c_str());
419  }
420 
421  return options;
422  }
423 };
424 
425 
426 template<typename NAME>
428 {
429  public:
430  typedef struct PluginCodec_Option const * const * OptionsTable;
432 
433  protected:
434  const char * m_rawFormat;
435  const char * m_formatName;
436  const char * m_payloadName;
437  unsigned m_payloadType;
438  const char * m_description;
439  unsigned m_maxBandwidth;
441  const void * m_h323CapabilityData;
442  unsigned m_flags;
444 
445  protected:
447  const char * rawFormat,
448  const char * formatName,
449  const char * payloadName,
450  const char * description,
451  unsigned maxBandwidth,
452  OptionsTable options,
453  unsigned flags = PluginCodec_RTPTypeDynamic
454  ) : m_rawFormat(rawFormat)
455  , m_formatName(formatName)
456  , m_payloadName(payloadName)
457  , m_payloadType(0)
458  , m_description(description)
459  , m_maxBandwidth(maxBandwidth)
461  , m_h323CapabilityData(NULL)
462  , m_flags(flags)
463  , m_options(options)
464  {
465  }
466 
467  public:
469  {
470  }
471 
472 
473  __inline const char * GetRawFormat() const { return this->m_rawFormat; }
474  __inline const char * GetFormatName() const { return this->m_formatName; }
475  __inline const char * GetPayloadName() const { return this->m_payloadName; }
476  __inline unsigned char GetPayloadType() const { return (unsigned char)this->m_payloadType; }
477  __inline const char * GetDescription() const { return this->m_description; }
478  __inline unsigned GetMaxBandwidth() const { return this->m_maxBandwidth; }
479  __inline unsigned char GetH323CapabilityType() const { return (unsigned char)this->m_h323CapabilityType; }
480  __inline const void * GetH323CapabilityData() const { return this->m_h323CapabilityData; }
481  __inline unsigned GetFlags() const { return this->m_flags; }
482  __inline const void * GetOptionsTable() const { return this->m_options; }
483 
484  __inline void SetFlags(unsigned b, unsigned m = 0) { this->m_flags = (this->m_flags&~m) | b; }
485  __inline void SetPayloadType(unsigned p) { this->m_payloadType = p; this->m_flags |= PluginCodec_RTPTypeExplicit; }
486  __inline void SetH323Capability(unsigned type, const void * data = NULL) { this->m_h323CapabilityType = type; this->m_h323CapabilityData = data; }
487 
488 
490  virtual bool IsValidForProtocol(const char * /*protocol*/) const = 0;
491 
493  bool AdjustOptions(void * parm, unsigned * parmLen, bool (PluginCodec_MediaFormat:: * adjuster)(OptionMap & original, OptionMap & changed) const) const
494  {
495  if (parmLen == NULL || parm == NULL || *parmLen != sizeof(char ***)) {
496  PTRACE(1, "Plugin", "Invalid parameters to AdjustOptions.");
497  return false;
498  }
499 
500  OptionMap originalOptions((const char * const * *)parm);
501  OptionMap changedOptions;
502  if (!(this->*adjuster)(originalOptions, changedOptions)) {
503  PTRACE(1, "Plugin", "Could not normalise/customise options.");
504  return false;
505  }
506 
507  return (*(char ***)parm = changedOptions.GetOptions()) != NULL;
508  }
509 
510 
512  virtual bool ToNormalised(OptionMap & /*original*/, OptionMap & /*changed*/) const = 0;
513 
514  // Adjust codec specific options calculated from normalised options.
515  virtual bool ToCustomised(OptionMap & /*original*/, OptionMap & /*changed*/) const = 0;
516 
517  virtual void AdjustForVersion(unsigned version, const PluginCodec_Definition * /*definition*/) const
518  {
519  if (version < PLUGIN_CODEC_VERSION_INTERSECT) {
520  for (PluginCodec_Option ** options = (PluginCodec_Option **)m_options; *options != NULL; ++options) {
521  if (strcmp((*options)->m_name, PLUGINCODEC_MEDIA_PACKETIZATIONS) == 0) {
522  *options = NULL;
523  break;
524  }
525  }
526  }
527  }
528 
529 
530  static void AdjustAllForVersion(unsigned version, const PluginCodec_Definition * definitions, size_t size)
531  {
532  while (size-- > 0) {
534  if (info != NULL)
535  info->AdjustForVersion(version, definitions);
536  ++definitions;
537  }
538  }
539 };
540 
541 
542 template<typename NAME>
544 {
545  public:
548 
549  protected:
551  unsigned m_bytesPerFrame;
552  unsigned m_sampleRate;
555 
556 
558  const char * formatName,
559  const char * payloadName,
560  const char * description,
561  unsigned samplesPerFrame,
562  unsigned bytesPerFrame,
563  unsigned sampleRate = 8000,
564  OptionsTable options = NULL
565  ) : Parent(PLUGINCODEC_RAW_AUDIO, formatName, payloadName, description, bytesPerFrame*8 * samplesPerFrame*1000000/sampleRate, options)
566  , m_samplesPerFrame(samplesPerFrame)
567  , m_bytesPerFrame(bytesPerFrame)
568  , m_sampleRate(sampleRate)
569  , m_recommendedFramesPerPacket((50*sampleRate)/(1000*samplesPerFrame))
570  , m_maxFramesPerPacket((120*sampleRate)/(1000*samplesPerFrame))
571  {
572  this->m_flags = PluginCodec_MediaTypeAudio /* audio codec */
573  | PluginCodec_InputTypeRaw /* raw input data */
574  | PluginCodec_OutputTypeRaw; /* raw output data */
575 
576  }
577 
578  __inline PluginCodec_AudioFormat & SetFlags(unsigned b, unsigned m = 0) { this->Parent::SetFlags(b,m); return *this; }
579  __inline PluginCodec_AudioFormat & SetPayloadType(unsigned p) { this->Parent::SetPayloadType(p); return *this; }
580  __inline PluginCodec_AudioFormat & SetH323Capability(unsigned type, const void * data = NULL) { this->Parent::SetH323Capability(type, data); return *this; }
581  __inline PluginCodec_AudioFormat & SetMaxFramesPerPacket(unsigned p) { this->m_maxFramesPerPacket = p; return *this; }
582  __inline PluginCodec_AudioFormat & SetChannels(unsigned n) { this->m_flags |= PluginCodec_SetChannels(n); return *this; }
583 
584  public:
585  __inline unsigned GetSamplesPerFrame() const { return this->m_samplesPerFrame; }
586  __inline unsigned GetBytesPerFrame() const { return this->m_bytesPerFrame; }
587  __inline unsigned GetSampleRate() const { return this->m_sampleRate; }
588  __inline unsigned GetFrameTime() const { return this->m_samplesPerFrame*1000000/this->m_sampleRate; }
589  __inline unsigned GetRecommendedFramesPerPacket() const { return this->m_recommendedFramesPerPacket; }
590  __inline unsigned GetMaxFramesPerPacket() const { return this->m_maxFramesPerPacket; }
591 };
592 
593 
594 template<typename NAME>
596 {
597  public:
600 
601  protected:
602  unsigned m_maxWidth;
603  unsigned m_maxHeight;
604 
605 
607  const char * formatName,
608  const char * payloadName,
609  const char * description,
610  unsigned maxBandwidth,
611  OptionsTable options = NULL
612  ) : Parent(PLUGINCODEC_RAW_VIDEO, formatName, payloadName, description, maxBandwidth, options)
613  , m_maxWidth(1920)
614  , m_maxHeight(1200)
615  {
616  this->m_flags = PluginCodec_MediaTypeVideo /* audio codec */
617  | PluginCodec_InputTypeRTP /* raw input data */
618  | PluginCodec_OutputTypeRTP; /* raw output data */
619  }
620 
621  __inline PluginCodec_VideoFormat & SetFlags(unsigned b, unsigned m = 0) { this->Parent::SetFlags(b,m); return *this; }
622  __inline PluginCodec_VideoFormat & SetPayloadType(unsigned p) { this->Parent::SetPayloadType(p); return *this; }
623  __inline PluginCodec_VideoFormat & SetH323Capability(unsigned type, const void * data = NULL) { this->Parent::SetH323Capability(type, data); return *this; }
624 
625  public:
626  __inline unsigned GetMaxWidth() const { return this->m_maxWidth; }
627  __inline unsigned GetMaxHeight() const { return this->m_maxHeight; }
628 };
629 
630 
632 
633 template<typename NAME>
635 {
636  protected:
638  : m_definition(defn)
639  , m_optionsSame(false)
640  , m_maxBitRate(defn->bitsPerSec > 0 ? defn->bitsPerSec : 4*1024*1024)
641  , m_frameTime((defn->sampleRate/1000*defn->usPerFrame)/1000) // Odd way of calculation to avoid 32 bit integer overflow
642  {
643  PTRACE(3, "Plugin", "Codec created: \"" << defn->descr
644  << "\", \"" << defn->sourceFormat << "\" -> \"" << defn->destFormat << '"');
645  }
646 
647 
648  public:
649  virtual ~PluginCodec()
650  {
651  }
652 
653 
655  virtual bool Construct()
656  {
657  return true;
658  }
659 
660 
665  static bool Terminate()
666  {
667  return true;
668  }
669 
670 
672  virtual bool Transcode(const void * fromPtr,
673  unsigned & fromLen,
674  void * toPtr,
675  unsigned & toLen,
676  unsigned & flags) = 0;
677 
678 
680  virtual bool GetStatistics(char * /*bufferPtr*/, unsigned /*bufferSize*/)
681  {
682  return true;
683  }
684 
685 
687  virtual size_t GetOutputDataSize()
688  {
689  return 576-20-16; // Max safe MTU size (576 bytes as per RFC879) minus IP & UDP headers
690  }
691 
692 
699  virtual bool SetInstanceID(const char * /*idPtr*/, unsigned /*idLen*/)
700  {
701  return true;
702  }
703 
704 
706  virtual bool GetActiveOptions(PluginCodec_OptionMap & /*options*/)
707  {
708  return false;
709  }
710 
711 
713  virtual bool SetOptions(const char * const * options)
714  {
715  this->m_optionsSame = true;
716 
717  // get the media format options after adjustment from protocol negotiation
718  for (const char * const * option = options; *option != NULL; option += 2) {
719  if (!this->SetOption(option[0], option[1])) {
720  PTRACE(1, "Plugin", "Could not set option \"" << option[0] << "\" to \"" << option[1] << '"');
721  return false;
722  }
723  }
724 
725  if (this->m_optionsSame)
726  return true;
727 
728  return this->OnChangedOptions();
729  }
730 
731 
733  virtual bool OnChangedOptions()
734  {
735  return true;
736  }
737 
738 
740  virtual bool SetOption(const char * optionName, const char * optionValue)
741  {
742  if (strcasecmp(optionName, PLUGINCODEC_OPTION_TARGET_BIT_RATE) == 0)
743  return this->SetOptionUnsigned(this->m_maxBitRate, optionValue, 1);
744 
745  if (strcasecmp(optionName, PLUGINCODEC_OPTION_MAX_BIT_RATE) == 0) {
746  unsigned bitRate = this->m_maxBitRate;
747  if (!this->SetOptionUnsigned(bitRate, optionValue, 1))
748  return false;
749  if (m_maxBitRate > bitRate)
750  m_maxBitRate = bitRate;
751  return true;
752  }
753 
754  if (strcasecmp(optionName, PLUGINCODEC_OPTION_FRAME_TIME) == 0)
755  return this->SetOptionUnsigned(this->m_frameTime, optionValue, 1);
756 
757  return true;
758  }
759 
760 
761  template <typename T>
762  bool SetOptionUnsigned(T & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX)
763  {
764  unsigned newValue = oldValue;
765  if (!this->SetOptionUnsigned(newValue, optionValue, minimum, maximum))
766  return false;
767  oldValue = (T)newValue;
768  return true;
769  }
770 
771 
772  bool SetOptionUnsigned(unsigned & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX)
773  {
774  char * end;
775  unsigned newValue = strtoul(optionValue, &end, 10);
776  if (*end != '\0')
777  return false;
778 
779  if (newValue < minimum)
780  newValue = minimum;
781  else if (newValue > maximum)
782  newValue = maximum;
783 
784  if (oldValue != newValue) {
785  oldValue = newValue;
786  this->m_optionsSame = false;
787  }
788 
789  return true;
790  }
791 
792 
793  template <typename T>
794  bool SetOptionBoolean(T & oldValue, const char * optionValue)
795  {
796  bool opt = oldValue != 0;
797  if (!this->SetOptionBoolean(opt, optionValue))
798  return false;
799  oldValue = (T)opt;
800  return true;
801  }
802 
803 
804  bool SetOptionBoolean(bool & oldValue, const char * optionValue)
805  {
806  bool newValue;
807  if ( strcasecmp(optionValue, "0") == 0 ||
808  strcasecmp(optionValue, "n") == 0 ||
809  strcasecmp(optionValue, "f") == 0 ||
810  strcasecmp(optionValue, "no") == 0 ||
811  strcasecmp(optionValue, "false") == 0)
812  newValue = false;
813  else if (strcasecmp(optionValue, "1") == 0 ||
814  strcasecmp(optionValue, "y") == 0 ||
815  strcasecmp(optionValue, "t") == 0 ||
816  strcasecmp(optionValue, "yes") == 0 ||
817  strcasecmp(optionValue, "true") == 0)
818  newValue = true;
819  else
820  return false;
821 
822  if (oldValue != newValue) {
823  oldValue = newValue;
824  this->m_optionsSame = false;
825  }
826 
827  return true;
828  }
829 
830 
831  bool SetOptionBit(int & oldValue, unsigned bit, const char * optionValue)
832  {
833  return this->SetOptionBit((unsigned &)oldValue, bit, optionValue);
834  }
835 
836 
837  bool SetOptionBit(unsigned & oldValue, unsigned bit, const char * optionValue)
838  {
839  bool newValue;
840  if (strcmp(optionValue, "0") == 0)
841  newValue = false;
842  else if (strcmp(optionValue, "1") == 0)
843  newValue = true;
844  else
845  return false;
846 
847  if (((oldValue&bit) != 0) != newValue) {
848  if (newValue)
849  oldValue |= bit;
850  else
851  oldValue &= ~bit;
852  this->m_optionsSame = false;
853  }
854 
855  return true;
856  }
857 
858 
859  template <class CodecClass> static void * Create_s(const PluginCodec_Definition * defn)
860  {
861  CodecClass * codec = new CodecClass(defn);
862  if (codec != NULL && codec->Construct())
863  return codec;
864 
865  PTRACE(1, "Plugin", "Could not open codec, no context being returned.");
866  delete codec;
867  return NULL;
868  }
869 
870 
871  static void Destroy_s(const PluginCodec_Definition * /*defn*/, void * context)
872  {
873  delete (PluginCodec *)context;
874  }
875 
876 
877  static int Transcode_s(const PluginCodec_Definition * /*defn*/,
878  void * context,
879  const void * fromPtr,
880  unsigned * fromLen,
881  void * toPtr,
882  unsigned * toLen,
883  unsigned int * flags)
884  {
885  if (context != NULL && fromPtr != NULL && fromLen != NULL && toPtr != NULL && toLen != NULL && flags != NULL)
886  return ((PluginCodec *)context)->Transcode(fromPtr, *fromLen, toPtr, *toLen, *flags);
887 
888  PTRACE(1, "Plugin", "Invalid parameter to Transcode.");
889  return false;
890  }
891 
892 
893  static int GetOutputDataSize_s(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *)
894  {
895  return context != NULL ? (int)((PluginCodec *)context)->GetOutputDataSize() : 0;
896  }
897 
899 
900  static int ToNormalised_s(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
901  {
902  return defn->userData != NULL ? ((MediaFormat *)defn->userData)->AdjustOptions(parm, len, &MediaFormat::ToNormalised) : -1;
903  }
904 
905 
906  static int ToCustomised_s(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
907  {
908  return defn->userData != NULL ? ((MediaFormat *)defn->userData)->AdjustOptions(parm, len, &MediaFormat::ToCustomised) : -1;
909  }
910 
911 
912  static int GetActiveOptions_s(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * parmLen)
913  {
914  if (context == NULL || parmLen == NULL || parm == NULL || *parmLen != sizeof(char ***)) {
915  PTRACE(1, "Plugin", "Invalid parameters to GetActiveOptions.");
916  return false;
917  }
918 
919  PluginCodec_OptionMap activeOptions;
920  if (!((PluginCodec *)context)->GetActiveOptions(activeOptions))
921  return false;
922 
923  return (*(char ***)parm = activeOptions.GetOptions()) != NULL;
924  }
925 
926 
927  static int FreeOptions_s(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len)
928  {
929  if (parm == NULL || len == NULL || *len != sizeof(char ***))
930  return false;
931 
932  char ** strings = (char **)parm;
933  for (char ** string = strings; *string != NULL; string++)
934  free(*string);
935  free(strings);
936  return true;
937  }
938 
939 
940  static int GetOptions_s(const struct PluginCodec_Definition * codec, void *, const char *, void * parm, unsigned * len)
941  {
942  if (parm == NULL || len == NULL || *len != sizeof(struct PluginCodec_Option **))
943  return false;
944 
945  *(const void **)parm = codec->userData != NULL ? ((MediaFormat *)codec->userData)->GetOptionsTable() : NULL;
946  *len = 0;
947  return true;
948  }
949 
950 
951  static int SetOptions_s(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
952  {
953  PluginCodec * codec = (PluginCodec *)context;
954  return len != NULL && *len == sizeof(const char **) && parm != NULL &&
955  codec != NULL && codec->SetOptions((const char * const *)parm);
956  }
957 
958  static int ValidForProtocol_s(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
959  {
960  return len != NULL && *len == sizeof(const char *) && parm != NULL && defn->userData != NULL &&
961  ((MediaFormat *)defn->userData)->IsValidForProtocol((const char *)parm);
962  }
963 
964  static int SetInstanceID_s(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
965  {
966  PluginCodec * codec = (PluginCodec *)context;
967  return len != NULL && parm != NULL &&
968  codec != NULL && codec->SetInstanceID((const char *)parm, *len);
969  }
970 
971  static int GetStatistics_s(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
972  {
973  PluginCodec * codec = (PluginCodec *)context;
974  return len != NULL && parm != NULL &&
975  codec != NULL && codec->GetStatistics((char *)parm, *len);
976  }
977 
978  static int Terminate_s(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *)
979  {
980  PluginCodec * codec = (PluginCodec *)context;
981  return codec != NULL && codec->Terminate();
982  }
983 
985  {
986  static PluginCodec_ControlDefn ControlsTable[] = {
999  { NULL }
1000  };
1001  return ControlsTable;
1002  }
1003 
1004  protected:
1006 
1008  unsigned m_maxBitRate;
1009  unsigned m_frameTime;
1010 };
1011 
1012 
1014 
1015 template<typename NAME>
1016 class PluginVideoCodec : public PluginCodec<NAME>
1017 {
1018  typedef PluginCodec<NAME> BaseClass;
1019 
1020  protected:
1021  unsigned m_maxWidth;
1022  unsigned m_maxHeight;
1023  unsigned m_width;
1024  unsigned m_height;
1025 
1026  public:
1027  enum {
1028  DefaultWidth = 352, // CIF size
1030  };
1031 
1032 
1034  : BaseClass(defn)
1039  {
1040  }
1041 
1042 
1043  virtual size_t GetRawFrameSize(unsigned width, unsigned height)
1044  {
1045  return width*height*3/2; // YUV420P
1046  }
1047 
1048 
1049  __inline unsigned GetMaxWidth() const { return m_maxWidth; }
1050  __inline unsigned GetMaxHeight() const { return m_maxHeight; }
1051  __inline unsigned GetWidth() const { return m_width; }
1052  __inline unsigned GetHeight() const { return m_height; }
1053 };
1054 
1055 
1057 
1058 template<typename NAME>
1060 {
1062 
1063  protected:
1064  unsigned m_maxRTPSize;
1065  unsigned m_tsto;
1067 
1068  public:
1070  : BaseClass(defn)
1072  , m_tsto(31)
1073  , m_keyFramePeriod(0) // Indicates auto/default
1074  {
1075  }
1076 
1077 
1078  virtual bool SetOption(const char * optionName, const char * optionValue)
1079  {
1080  if (strcasecmp(optionName, PLUGINCODEC_OPTION_FRAME_WIDTH) == 0)
1081  return this->SetOptionUnsigned(this->m_width, optionValue, 16, this->m_maxWidth);
1082 
1083  if (strcasecmp(optionName, PLUGINCODEC_OPTION_FRAME_HEIGHT) == 0)
1084  return this->SetOptionUnsigned(this->m_height, optionValue, 16, this->m_maxHeight);
1085 
1086  if (strcasecmp(optionName, PLUGINCODEC_OPTION_MAX_TX_PACKET_SIZE) == 0)
1087  return this->SetOptionUnsigned(this->m_maxRTPSize, optionValue, 256, 8192);
1088 
1089  if (strcasecmp(optionName, PLUGINCODEC_OPTION_TEMPORAL_SPATIAL_TRADE_OFF) == 0)
1090  return this->SetOptionUnsigned(this->m_tsto, optionValue, 1, 31);
1091 
1092  if (strcasecmp(optionName, PLUGINCODEC_OPTION_TX_KEY_FRAME_PERIOD) == 0)
1093  return this->SetOptionUnsigned(this->m_keyFramePeriod, optionValue, 0);
1094 
1095  // Base class sets bit rate and frame time
1096  return BaseClass::SetOption(optionName, optionValue);
1097  }
1098 
1099 
1101  virtual bool GetActiveOptions(PluginCodec_OptionMap & options)
1102  {
1104  return true;
1105  }
1106 
1107 
1108  virtual size_t GetPacketSpace(const PluginCodec_RTP & rtp, size_t total)
1109  {
1110  size_t space = rtp.GetMaxSize();
1111  if (space > this->m_maxRTPSize)
1112  space = this->m_maxRTPSize;
1113  space -= rtp.GetHeaderSize();
1114  if (space > total)
1115  space = total;
1116  return space;
1117  }
1118 };
1119 
1120 
1122 
1123 template<typename NAME>
1125 {
1127 
1128  protected:
1130 
1131  public:
1133  : BaseClass(defn)
1135  {
1136  }
1137 
1138 
1139  virtual bool SetOption(const char * optionName, const char * optionValue)
1140  {
1141  if (strcasecmp(optionName, PLUGINCODEC_OPTION_MAX_RX_FRAME_WIDTH) == 0)
1142  return this->SetOptionUnsigned(this->m_width, optionValue, 16, this->m_maxWidth);
1143 
1144  if (strcasecmp(optionName, PLUGINCODEC_OPTION_MAX_RX_FRAME_HEIGHT) == 0)
1145  return this->SetOptionUnsigned(this->m_height, optionValue, 16, this->m_maxHeight);
1146 
1147  // Base class sets bit rate and frame time
1148  return BaseClass::SetOption(optionName, optionValue);
1149  }
1150 
1151 
1152  virtual size_t GetOutputDataSize()
1153  {
1154  return this->m_outputSize;
1155  }
1156 
1157 
1158  virtual bool CanOutputImage(unsigned width, unsigned height, PluginCodec_RTP & rtp, unsigned & flags)
1159  {
1160  if (width == 0 || height == 0)
1161  return false;
1162 
1163  size_t newSize = this->GetRawFrameSize(width, height) + sizeof(PluginCodec_Video_FrameHeader);
1164  if (!rtp.SetPayloadSize(newSize)) {
1165  m_outputSize = newSize + rtp.GetHeaderSize();
1167  return false;
1168  }
1169 
1170  PluginCodec_Video_FrameHeader * videoHeader = rtp.GetVideoHeader();
1171  videoHeader->x = 0;
1172  videoHeader->y = 0;
1173  videoHeader->width = width;
1174  videoHeader->height = height;
1175 
1177  rtp.SetMarker(true);
1178  return true;
1179  }
1180 
1181 
1183  {
1184  unsigned m_width;
1185  unsigned m_height;
1186  unsigned m_raster;
1187  unsigned char * m_source;
1188  unsigned char * m_destination;
1189 
1190  void Copy()
1191  {
1192  for (unsigned y = 0; y < m_height; ++y) {
1193  memcpy(m_destination, m_source, m_width);
1194  this->m_source += m_raster;
1195  this->m_destination += m_width;
1196  }
1197  }
1198  };
1199 
1200  virtual unsigned OutputImage(unsigned char * planes[3], int raster[3],
1201  unsigned width, unsigned height, PluginCodec_RTP & rtp, unsigned & flags)
1202  {
1203  if (!CanOutputImage(width, height, rtp, flags))
1204  return 0;
1205 
1206  size_t ySize = width*height;
1207  size_t uvSize = ySize/4;
1208  if (planes[1] == planes[0]+ySize && planes[2] == planes[1]+uvSize)
1209  memcpy(rtp.GetVideoFrameData(), planes[0], ySize+uvSize*2);
1210  else {
1211  OutputImagePlaneInfo planeInfo[3] = {
1212  { width, height, raster[0], planes[0], rtp.GetVideoFrameData() },
1213  { width/2, height/2, raster[1], planes[1], planeInfo[0].m_destination + ySize },
1214  { width/2, height/2, raster[2], planes[2], planeInfo[1].m_destination + uvSize }
1215  };
1216 
1217  for (unsigned plane = 0; plane < 3; ++plane)
1218  planeInfo[plane].Copy();
1219  }
1220 
1221  return (unsigned)rtp.GetPacketSize();
1222  }
1223 };
1224 
1225 
1227 
1229 #define PLUGINCODEC_KNOWN_CODEC_CXX(MediaType, \
1230  Name, \
1231  Description, \
1232  EncoderClass, \
1233  DecoderClass \
1234  ) \
1235  PLUGINCODEC_CODEC_PAIR(Name, \
1236  NULL, \
1237  Description, \
1238  0, \
1239  0, \
1240  0, \
1241  0, \
1242  0, \
1243  0, \
1244  0, \
1245  0, \
1246  0, \
1247  0, \
1248  EncoderClass::Create_s<EncoderClass>, \
1249  EncoderClass::Destroy_s, \
1250  EncoderClass::Transcode_s, \
1251  DecoderClass::Create_s<DecoderClass>, \
1252  DecoderClass::Destroy_s, \
1253  DecoderClass::Transcode_s, \
1254  DecoderClass::GetControls(), /* Note doesn't matter if encoder or decoder */ \
1255  PluginCodec_MediaTypeKnown, \
1256  PLUGINCODEC_RAW_##MediaType, \
1257  NULL)
1258 
1260 #define PLUGINCODEC_AUDIO_CODEC_CXX(MediaFormat, \
1261  EncoderClass, \
1262  DecoderClass \
1263  ) \
1264  PLUGINCODEC_CODEC_PAIR(MediaFormat.GetFormatName(), \
1265  MediaFormat.GetPayloadName(), \
1266  MediaFormat.GetDescription(), \
1267  MediaFormat.GetSampleRate(), \
1268  MediaFormat.GetMaxBandwidth(), \
1269  MediaFormat.GetFrameTime(), \
1270  MediaFormat.GetSamplesPerFrame(), \
1271  MediaFormat.GetBytesPerFrame(), \
1272  MediaFormat.GetRecommendedFramesPerPacket(), \
1273  MediaFormat.GetMaxFramesPerPacket(), \
1274  MediaFormat.GetPayloadType(), \
1275  MediaFormat.GetH323CapabilityType(), \
1276  MediaFormat.GetH323CapabilityData(), \
1277  EncoderClass::Create_s<EncoderClass>, \
1278  EncoderClass::Destroy_s, \
1279  EncoderClass::Transcode_s, \
1280  DecoderClass::Create_s<DecoderClass>, \
1281  DecoderClass::Destroy_s, \
1282  DecoderClass::Transcode_s, \
1283  DecoderClass::GetControls(), /* Note doesn't matter if encoder or decoder */ \
1284  MediaFormat.GetFlags(), \
1285  MediaFormat.GetRawFormat(), \
1286  &MediaFormat)
1287 
1289 #define PLUGINCODEC_VIDEO_CODEC_CXX(MediaFormat, \
1290  EncoderClass, \
1291  DecoderClass \
1292  ) \
1293  PLUGINCODEC_CODEC_PAIR(MediaFormat.GetFormatName(), \
1294  MediaFormat.GetPayloadName(), \
1295  MediaFormat.GetDescription(), \
1296  PLUGINCODEC_VIDEO_CLOCK, \
1297  MediaFormat.GetMaxBandwidth(), \
1298  1000000/PLUGINCODEC_MAX_FRAME_RATE, \
1299  MediaFormat.GetMaxWidth(), \
1300  MediaFormat.GetMaxHeight(), \
1301  0,PLUGINCODEC_MAX_FRAME_RATE, \
1302  MediaFormat.GetPayloadType(), \
1303  MediaFormat.GetH323CapabilityType(), \
1304  MediaFormat.GetH323CapabilityData(), \
1305  EncoderClass::Create_s<EncoderClass>, \
1306  EncoderClass::Destroy_s, \
1307  EncoderClass::Transcode_s, \
1308  DecoderClass::Create_s<DecoderClass>, \
1309  DecoderClass::Destroy_s, \
1310  DecoderClass::Transcode_s, \
1311  DecoderClass::GetControls(), /* Note doesn't matter if encoder or decoder */ \
1312  MediaFormat.GetFlags(), \
1313  MediaFormat.GetRawFormat(), \
1314  &MediaFormat)
1315 
1316 
1317 #define PLUGIN_CODEC_IMPLEMENT_CXX(NAME, table) \
1318  extern "C" { \
1319  PLUGIN_CODEC_IMPLEMENT(NAME) \
1320  PLUGIN_CODEC_DLL_API struct PluginCodec_Definition * PLUGIN_CODEC_GET_CODEC_FN(unsigned * count, unsigned version) { \
1321  if (version < PLUGIN_CODEC_VERSION_OPTIONS) return NULL; \
1322  *count = sizeof(table)/sizeof(struct PluginCodec_Definition); \
1323  PluginCodec_MediaFormat<NAME>::AdjustAllForVersion(version, table, *count); \
1324  return table; \
1325  } \
1326  }
1327 
1328 
1329 #endif // OPAL_CODEC_OPALPLUGIN_HPP