opalplugin.hpp

Go to the documentation of this file.
00001 /*
00002  * opalplugins.hpp
00003  *
00004  * OPAL codec plugins handler (C++ version)
00005  *
00006  * Open Phone Abstraction Library (OPAL)
00007  * Formally known as the Open H323 project.
00008  *
00009  * Copyright (C) 2010 Vox Lucida
00010  *
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions
00013  * are met:
00014  *
00015  * - Redistributions of source code must retain the above copyright
00016  *   notice, this list of conditions and the following disclaimer.
00017 
00018  * - Redistributions in binary form must reproduce the above copyright
00019  *   notice, this list of conditions and the following disclaimer in the
00020  *   documentation and/or other materials provided with the distribution.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00025  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
00026  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00027  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00028  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00029  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00030  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00031  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00032  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  * $Revision: 29223 $
00035  * $Author: rjongbloed $
00036  * $Date: 2013-03-07 18:00:29 -0600 (Thu, 07 Mar 2013) $
00037  */
00038 
00039 #ifndef OPAL_CODEC_OPALPLUGIN_HPP
00040 #define OPAL_CODEC_OPALPLUGIN_HPP
00041 
00042 #include "opalplugin.h"
00043 
00044 #include <string.h>
00045 #include <stdlib.h>
00046 #include <limits.h>
00047 
00048 #include <map>
00049 #include <string>
00050 
00051 
00053 
00054 #ifndef PLUGINCODEC_TRACING
00055   #define PLUGINCODEC_TRACING 1
00056 #endif
00057 
00058 #if PLUGINCODEC_TRACING
00059   extern PluginCodec_LogFunction PluginCodec_LogFunctionInstance;
00060   extern int PluginCodec_SetLogFunction(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len);
00061 
00062 #define PLUGINCODEC_CONTROL_LOG_FUNCTION_DEF \
00063   PluginCodec_LogFunction PluginCodec_LogFunctionInstance; \
00064   int PluginCodec_SetLogFunction(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len) \
00065   { \
00066     if (len == NULL || *len != sizeof(PluginCodec_LogFunction)) \
00067       return false; \
00068  \
00069     PluginCodec_LogFunctionInstance = (PluginCodec_LogFunction)parm; \
00070     if (PluginCodec_LogFunctionInstance != NULL) \
00071       PluginCodec_LogFunctionInstance(4, __FILE__, __LINE__, "Plugin", "Started logging."); \
00072  \
00073     return true; \
00074   } \
00075 
00076   #define PLUGINCODEC_CONTROL_LOG_FUNCTION_INC { PLUGINCODEC_CONTROL_SET_LOG_FUNCTION, PluginCodec_SetLogFunction },
00077 #else
00078   #define PLUGINCODEC_CONTROL_LOG_FUNCTION_DEF
00079   #define PLUGINCODEC_CONTROL_LOG_FUNCTION_INC
00080 #endif
00081 
00082 #if !defined(PTRACE)
00083   #if PLUGINCODEC_TRACING
00084     #include <sstream>
00085     #define PTRACE_CHECK(level) \
00086         (PluginCodec_LogFunctionInstance != NULL && PluginCodec_LogFunctionInstance(level, NULL, 0, NULL, NULL))
00087     #define PTRACE(level, section, args) \
00088       if (PTRACE_CHECK(level)) { \
00089         std::ostringstream strm; strm << args; \
00090         PluginCodec_LogFunctionInstance(level, __FILE__, __LINE__, section, strm.str().c_str()); \
00091       } else (void)0
00092   #else
00093     #define PTRACE_CHECK(level)
00094     #define PTRACE(level, section, expr)
00095   #endif
00096 #endif
00097 
00098 
00100 
00101 class PluginCodec_RTP
00102 {
00103     unsigned char * m_packet;
00104     unsigned        m_maxSize;
00105     unsigned        m_headerSize;
00106     unsigned        m_payloadSize;
00107 
00108   public:
00109     PluginCodec_RTP(const void * packet, unsigned size)
00110       : m_packet((unsigned char *)packet)
00111       , m_maxSize(size)
00112       , m_headerSize(PluginCodec_RTP_GetHeaderLength(m_packet))
00113       , m_payloadSize(size - m_headerSize)
00114     {
00115     }
00116 
00117     __inline unsigned GetMaxSize() const           { return m_maxSize; }
00118     __inline unsigned GetPacketSize() const        { return m_headerSize+m_payloadSize; }
00119     __inline unsigned GetHeaderSize() const        { return m_headerSize; }
00120     __inline unsigned GetPayloadSize() const       { return m_payloadSize; }
00121     __inline bool     SetPayloadSize(unsigned size)
00122     {
00123       if (m_headerSize+size > m_maxSize)
00124         return false;
00125       m_payloadSize = size;
00126       return true;
00127     }
00128 
00129     __inline unsigned GetPayloadType() const         { return PluginCodec_RTP_GetPayloadType(m_packet);        }
00130     __inline void     SetPayloadType(unsigned type)  {        PluginCodec_RTP_SetPayloadType(m_packet, type);  }
00131     __inline bool     GetMarker() const              { return PluginCodec_RTP_GetMarker(m_packet);             }
00132     __inline void     SetMarker(bool mark)           {        PluginCodec_RTP_SetMarker(m_packet, mark);       }
00133     __inline unsigned GetTimestamp() const           { return PluginCodec_RTP_GetTimestamp(m_packet);          }
00134     __inline void     SetTimestamp(unsigned ts)      {        PluginCodec_RTP_SetTimestamp(m_packet, ts);      }
00135     __inline unsigned GetSequenceNumber() const      { return PluginCodec_RTP_GetSequenceNumber(m_packet);     }
00136     __inline void     SetSequenceNumber(unsigned sn) {        PluginCodec_RTP_SetSequenceNumber(m_packet, sn); }
00137     __inline unsigned GetSSRC() const                { return PluginCodec_RTP_GetSSRC(m_packet);               }
00138     __inline void     SetSSRC(unsigned ssrc)         {        PluginCodec_RTP_SetSSRC(m_packet, ssrc);         }
00139 
00140     __inline unsigned char * SetExtended(unsigned id, unsigned len)
00141     {
00142       m_packet[0] |= 0x10;
00143 
00144       unsigned char * ptr = m_packet + PluginCodec_RTP_GetCSRCHdrLength(m_packet);
00145       switch (id >> 16) {
00146         case 0 :
00147           PluginCodec_RTP_SetWORD(ptr, 0, id);
00148           PluginCodec_RTP_SetWORD(ptr, 2, (len+3)/4);
00149           ptr += 4;
00150           break;
00151 
00152         case 1 :
00153           *ptr++ = 0xbe;
00154           *ptr++ = 0xde;
00155           PluginCodec_RTP_SetWORD(ptr, 0, (len+7)/4); ptr += 2;
00156           *ptr++ = (unsigned char)(((id&0xf) << 4)|(len-1));
00157           break;
00158 
00159         case 2 :
00160           *ptr++ = 0x10;
00161           *ptr++ = 0x00;
00162           PluginCodec_RTP_SetWORD(ptr, 0, (len+8)/4); ptr += 2;
00163           *ptr++ = (unsigned char)(id&0xff);
00164           *ptr++ = (unsigned char)(len&0xff);
00165       }
00166 
00167       m_headerSize = PluginCodec_RTP_GetHeaderLength(m_packet);
00168       return ptr;
00169     }
00170 
00171     __inline unsigned char * GetExtendedHeader(unsigned & id, size_t & len) const
00172     {
00173       if ((m_packet[0]&0x10) == 0)
00174         return NULL;
00175 
00176       unsigned char * ptr = m_packet + PluginCodec_RTP_GetCSRCHdrLength(m_packet);
00177       id = PluginCodec_RTP_GetWORD(ptr, 0);
00178 
00179       if (id == 0xbede) {
00180         id = (0x10000|(ptr[4] >> 4));
00181         len = (ptr[4] & 0xf)+1;
00182         return ptr + 5;
00183       }
00184 
00185       if ((id&0xfff0) == 0x1000) {
00186         id = 0x20000 | ptr[4];
00187         len = ptr[5];
00188         return ptr + 6;
00189       }
00190 
00191       len = PluginCodec_RTP_GetWORD(ptr, 2)*4;
00192       return ptr + 4;
00193     }
00194 
00195     __inline unsigned char * GetPayloadPtr() const   { return m_packet + m_headerSize; }
00196     __inline unsigned char & operator[](size_t offset) { return m_packet[m_headerSize + offset]; }
00197     __inline unsigned const char & operator[](size_t offset) const { return m_packet[m_headerSize + offset]; }
00198     __inline bool CopyPayload(const void * data, size_t size, size_t offset = 0)
00199     {
00200       if (!SetPayloadSize(offset + size))
00201         return false;
00202       memcpy(GetPayloadPtr()+offset, data, size);
00203       return true;
00204     }
00205 
00206     __inline PluginCodec_Video_FrameHeader * GetVideoHeader() const { return (PluginCodec_Video_FrameHeader *)GetPayloadPtr(); }
00207     __inline unsigned char * GetVideoFrameData() const { return m_packet + m_headerSize + sizeof(PluginCodec_Video_FrameHeader); }
00208 };
00209 
00210 
00212 
00213 typedef std::map<std::string, std::string> PluginCodec_OptionMapBase;
00214 
00215 class PluginCodec_Utilities
00216 {
00217   public:
00218    static unsigned String2Unsigned(const std::string & str)
00219     {
00220       return strtoul(str.c_str(), NULL, 10);
00221     }
00222 
00223 
00224     static void AppendUnsigned2String(unsigned value, std::string & str)
00225     {
00226       // Not very efficient, but really, really simple
00227       if (value > 9)
00228         AppendUnsigned2String(value/10, str);
00229       str += (char)(value%10 + '0');
00230     }
00231 
00232 
00233     static void Unsigned2String(unsigned value, std::string & str)
00234     {
00235       str.clear();
00236       AppendUnsigned2String(value,str);
00237     }
00238 
00239 
00240     static void Change(const char * value,
00241                        PluginCodec_OptionMapBase & original,
00242                        PluginCodec_OptionMapBase & changed,
00243                        const char * option)
00244     {
00245       PluginCodec_OptionMapBase::iterator it = original.find(option);
00246       if (it != original.end() && it->second != value)
00247         changed[option] = value;
00248     }
00249 
00250 
00251     static void Change(unsigned     value,
00252                        PluginCodec_OptionMapBase  & original,
00253                        PluginCodec_OptionMapBase  & changed,
00254                        const char * option)
00255     {
00256       if (String2Unsigned(original[option]) != value)
00257         Unsigned2String(value, changed[option]);
00258     }
00259 
00260 
00261     static void ClampMax(unsigned     maximum,
00262                          PluginCodec_OptionMapBase  & original,
00263                          PluginCodec_OptionMapBase  & changed,
00264                          const char * option,
00265                          bool forceIfZero = false)
00266     {
00267       unsigned value = String2Unsigned(original[option]);
00268       if (value > maximum || (forceIfZero && value == 0))
00269         Unsigned2String(maximum, changed[option]);
00270     }
00271 
00272 
00273     static void ClampMin(unsigned     minimum,
00274                          PluginCodec_OptionMapBase  & original,
00275                          PluginCodec_OptionMapBase  & changed,
00276                          const char * option)
00277     {
00278       unsigned value = String2Unsigned(original[option]);
00279       if (value < minimum)
00280         Unsigned2String(minimum, changed[option]);
00281     }
00282 
00283 
00284     static unsigned GetMacroBlocks(unsigned width, unsigned height)
00285     {
00286       return ((width+15)/16) * ((height+15)/16);
00287     }
00288 
00289 
00290     static bool ClampResolution(
00291       unsigned & width,
00292       unsigned & height,
00293       unsigned & maxFrameSize)
00294     {
00295       static struct {
00296         unsigned m_width;
00297         unsigned m_height;
00298         unsigned m_macroblocks;
00299       } MaxVideoResolutions[] = {
00300         #define OPAL_PLUGIN_CLAMPED_RESOLUTION(width, height) { width, height, ((width+15)/16) * ((height+15)/16) }
00301         OPAL_PLUGIN_CLAMPED_RESOLUTION(2816, 2304),
00302         OPAL_PLUGIN_CLAMPED_RESOLUTION(1920, 1080),
00303         OPAL_PLUGIN_CLAMPED_RESOLUTION(1408, 1152),
00304         OPAL_PLUGIN_CLAMPED_RESOLUTION(1280,  720),
00305         OPAL_PLUGIN_CLAMPED_RESOLUTION( 704,  576),
00306         OPAL_PLUGIN_CLAMPED_RESOLUTION( 640,  480),
00307         OPAL_PLUGIN_CLAMPED_RESOLUTION( 352,  288),
00308         OPAL_PLUGIN_CLAMPED_RESOLUTION( 320,  240),
00309         OPAL_PLUGIN_CLAMPED_RESOLUTION( 176,  144),
00310         OPAL_PLUGIN_CLAMPED_RESOLUTION( 128,   96)
00311       };
00312       static size_t const LastMaxVideoResolutions = sizeof(MaxVideoResolutions)/sizeof(MaxVideoResolutions[0]) - 1;
00313 
00314       size_t index = 0;
00315 
00316       if (maxFrameSize > 0) {
00317         static unsigned const MinWidth = 4*16;  // Four macroblocks wide
00318         static unsigned const MinHeight = 3*16; // Three macroblocks high
00319 
00320         unsigned maxWidth  = maxFrameSize*16*16/MinHeight;
00321         unsigned maxHeight = maxFrameSize*16*16/MinWidth;
00322 
00323         // Check if total frame size below threshold total of macroblocks.
00324         unsigned macroBlocks = GetMacroBlocks(width, height);
00325         if (macroBlocks <= maxFrameSize &&
00326             width  >= MinWidth  && width  <= maxWidth &&
00327             height >= MinHeight && height <= maxHeight)
00328           return false;
00329 
00330         while (index < LastMaxVideoResolutions &&
00331                 (MaxVideoResolutions[index].m_macroblocks > maxFrameSize ||
00332                 MaxVideoResolutions[index].m_width > maxWidth ||
00333                 MaxVideoResolutions[index].m_height > maxHeight))
00334           ++index;
00335       }
00336 
00337       width = MaxVideoResolutions[index].m_width;
00338       height = MaxVideoResolutions[index].m_height;
00339       maxFrameSize = MaxVideoResolutions[index].m_macroblocks;
00340       return true;
00341     }
00342 };
00343 
00344 
00345 class PluginCodec_OptionMap : public PluginCodec_OptionMapBase, public PluginCodec_Utilities
00346 {
00347   public:
00348     PluginCodec_OptionMap(const char * const * * options = NULL)
00349     {
00350       if (options != NULL) {
00351         for (const char * const * option = *options; *option != NULL; option += 2)
00352           insert(value_type(option[0], option[1]));
00353       }
00354     }
00355 
00356 
00357     unsigned GetUnsigned(const char * key, unsigned dflt = 0) const
00358     {
00359       const_iterator it = find(key);
00360       return it == end() ? dflt : String2Unsigned(it->second);
00361     }
00362 
00363     void SetUnsigned(unsigned value, const char * key)
00364     {
00365       Unsigned2String(value, operator[](key));
00366     }
00367 
00368 
00369     char ** GetOptions() const
00370     {
00371       char ** options = (char **)calloc(size()*2+1, sizeof(char *));
00372       if (options == NULL) {
00373         PTRACE(1, "Plugin", "Could not allocate new option lists.");
00374         return NULL;
00375       }
00376 
00377       char ** opt = options;
00378       for (const_iterator it = begin(); it != end(); ++it) {
00379         *opt++ = strdup(it->first.c_str());
00380         *opt++ = strdup(it->second.c_str());
00381       }
00382 
00383       return options;
00384     }
00385 };
00386 
00387 
00388 template<typename NAME>
00389 class PluginCodec_MediaFormat : public PluginCodec_Utilities
00390 {
00391   public:
00392     typedef struct PluginCodec_Option const * const * OptionsTable;
00393     typedef PluginCodec_OptionMap OptionMap;
00394 
00395   protected:
00396     const char * m_formatName;
00397     const char * m_payloadName;
00398     unsigned     m_payloadType;
00399     const char * m_description;
00400     unsigned     m_maxBandwidth;
00401     unsigned     m_h323CapabilityType;
00402     const void * m_h323CapabilityData;
00403     unsigned     m_flags;
00404     OptionsTable m_options;
00405 
00406   protected:
00407     PluginCodec_MediaFormat(
00408         const char * formatName,
00409         const char * payloadName,
00410         const char * description,
00411         unsigned     maxBandwidth,
00412         OptionsTable options)
00413       : m_formatName(formatName)
00414       , m_payloadName(payloadName)
00415       , m_payloadType(0)
00416       , m_description(description)
00417       , m_maxBandwidth(maxBandwidth)
00418       , m_h323CapabilityType(PluginCodec_H323Codec_NoH323)
00419       , m_h323CapabilityData(NULL)
00420       , m_flags(PluginCodec_RTPTypeDynamic)
00421       , m_options(options)
00422     {
00423     }
00424 
00425   public:
00426     virtual ~PluginCodec_MediaFormat()
00427     {
00428     }
00429 
00430 
00431     __inline const char *  GetFormatName() const   { return this->m_formatName; }
00432     __inline const char *  GetPayloadName() const  { return this->m_payloadName; }
00433     __inline unsigned char GetPayloadType() const  { return (unsigned char)this->m_payloadType; }
00434     __inline const char *  GetDescription() const  { return this->m_description; }
00435     __inline unsigned      GetMaxBandwidth() const { return this->m_maxBandwidth; }
00436     __inline unsigned char GetH323CapabilityType() const { return (unsigned char)this->m_h323CapabilityType; }
00437     __inline const void *  GetH323CapabilityData() const { return this->m_h323CapabilityData; }
00438     __inline unsigned      GetFlags() const { return this->m_flags; }
00439     __inline const void *  GetOptionsTable() const { return this->m_options; }
00440 
00441 
00443     virtual bool IsValidForProtocol(const char * /*protocol*/)
00444     {
00445       return true;
00446     }
00447 
00448 
00450     bool AdjustOptions(void * parm, unsigned * parmLen, bool (PluginCodec_MediaFormat:: * adjuster)(OptionMap & original, OptionMap & changed))
00451     {
00452       if (parmLen == NULL || parm == NULL || *parmLen != sizeof(char ***)) {
00453         PTRACE(1, "Plugin", "Invalid parameters to AdjustOptions.");
00454         return false;
00455       }
00456 
00457       OptionMap originalOptions((const char * const * *)parm);
00458       OptionMap changedOptions;
00459       if (!(this->*adjuster)(originalOptions, changedOptions)) {
00460         PTRACE(1, "Plugin", "Could not normalise/customise options.");
00461         return false;
00462       }
00463 
00464       return (*(char ***)parm = changedOptions.GetOptions()) != NULL;
00465     }
00466 
00467 
00469     virtual bool ToNormalised(OptionMap & /*original*/, OptionMap & /*changed*/)
00470     {
00471       return true;
00472     }
00473 
00474 
00475     // Adjust codec specific options calculated from normalised options.
00476     virtual bool ToCustomised(OptionMap & /*original*/, OptionMap & /*changed*/)
00477     {
00478       return true;
00479     }
00480 
00481 
00482     virtual void AdjustForVersion(unsigned version, const PluginCodec_Definition * /*definition*/)
00483     {
00484       if (version < PLUGIN_CODEC_VERSION_INTERSECT) {
00485         for (PluginCodec_Option ** options = (PluginCodec_Option **)m_options; *options != NULL; ++options) {
00486           if (strcmp((*options)->m_name, PLUGINCODEC_MEDIA_PACKETIZATIONS) == 0) {
00487             *options = NULL;
00488             break;
00489           }
00490         }
00491       }
00492     }
00493 
00494 
00495     static void AdjustAllForVersion(unsigned version, const PluginCodec_Definition * definitions, size_t size)
00496     {
00497       while (size-- > 0) {
00498         PluginCodec_MediaFormat * info = (PluginCodec_MediaFormat *)definitions->userData;
00499         if (info != NULL)
00500           info->AdjustForVersion(version, definitions);
00501         ++definitions;
00502       }
00503     }
00504 };
00505 
00506 
00507 template<typename NAME>
00508 class PluginCodec_AudioFormat : public PluginCodec_MediaFormat<NAME>
00509 {
00510   protected:
00511     unsigned m_samplesPerFrame;
00512     unsigned m_bytesPerFrame;
00513     unsigned m_sampleRate;
00514     unsigned m_recommendedFramesPerPacket;
00515     unsigned m_maxFramesPerPacket;
00516 
00517   public:
00518     typedef PluginCodec_MediaFormat<NAME> Parent;
00519     typedef typename Parent::OptionsTable OptionsTable;
00520 
00521     PluginCodec_AudioFormat(
00522       const char * formatName,
00523       const char * payloadName,
00524       const char * description,
00525       unsigned     samplesPerFrame,
00526       unsigned     bytesPerFrame,
00527       unsigned     sampleRate,
00528       OptionsTable options
00529     ) : Parent(formatName, payloadName, description, bytesPerFrame*8 * samplesPerFrame*1000000/sampleRate, options)
00530       , m_samplesPerFrame(samplesPerFrame)
00531       , m_bytesPerFrame(bytesPerFrame)
00532       , m_sampleRate(sampleRate)
00533       , m_recommendedFramesPerPacket((50*sampleRate)/(1000*samplesPerFrame))
00534       , m_maxFramesPerPacket((120*sampleRate)/(1000*samplesPerFrame))
00535     {
00536       this->m_flags = PluginCodec_MediaTypeAudio /* audio codec */
00537                     | PluginCodec_InputTypeRaw   /* raw input data */
00538                     | PluginCodec_OutputTypeRaw; /* raw output data */
00539 
00540     }
00541 
00542 
00543     __inline unsigned GetSamplesPerFrame() const { return this->m_samplesPerFrame; }
00544     __inline unsigned GetBytesPerFrame() const { return this->m_bytesPerFrame; }
00545     __inline unsigned GetSampleRate() const { return this->m_sampleRate; }
00546     __inline unsigned GetFrameTime() const { return this->m_samplesPerFrame*1000000/this->m_sampleRate; }
00547     __inline unsigned GetRecommendedFramesPerPacket() const { return this->m_recommendedFramesPerPacket; }
00548     __inline unsigned GetMaxFramesPerPacket() const { return this->m_maxFramesPerPacket; }
00549 };
00550 
00551 
00552 template<typename NAME>
00553 class PluginCodec_VideoFormat : public PluginCodec_MediaFormat<NAME>
00554 {
00555   protected:
00556     unsigned m_maxWidth;
00557     unsigned m_maxHeight;
00558 
00559   public:
00560     typedef PluginCodec_MediaFormat<NAME> Parent;
00561     typedef typename Parent::OptionsTable OptionsTable;
00562 
00563     PluginCodec_VideoFormat(
00564       const char * formatName,
00565       const char * payloadName,
00566       const char * description,
00567       unsigned     maxBandwidth,
00568       OptionsTable options
00569     ) : Parent(formatName, payloadName, description, maxBandwidth, options)
00570       , m_maxWidth(1920)
00571       , m_maxHeight(1200)
00572     {
00573       this->m_flags = PluginCodec_MediaTypeVideo /* audio codec */
00574                     | PluginCodec_InputTypeRTP   /* raw input data */
00575                     | PluginCodec_OutputTypeRTP; /* raw output data */
00576     }
00577 
00578 
00579     __inline unsigned GetMaxWidth() const { return this->m_maxWidth; }
00580     __inline unsigned GetMaxHeight() const { return this->m_maxHeight; }
00581 };
00582 
00583 
00585 
00586 template<typename NAME>
00587 class PluginCodec : public PluginCodec_Utilities
00588 {
00589   protected:
00590     PluginCodec(const PluginCodec_Definition * defn)
00591       : m_definition(defn)
00592       , m_optionsSame(false)
00593       , m_maxBitRate(defn->bitsPerSec)
00594       , m_frameTime((defn->sampleRate/1000*defn->usPerFrame)/1000) // Odd way of calculation to avoid 32 bit integer overflow
00595     {
00596       PTRACE(3, "Plugin", "Codec created: \"" << defn->descr
00597              << "\", \"" << defn->sourceFormat << "\" -> \"" << defn->destFormat << '"');
00598     }
00599 
00600 
00601   public:
00602     virtual ~PluginCodec()
00603     {
00604     }
00605 
00606 
00608     virtual bool Construct()
00609     {
00610       return true;
00611     }
00612 
00613 
00618     static bool Terminate()
00619     {
00620       return true;
00621     }
00622 
00623 
00625     virtual bool Transcode(const void * fromPtr,
00626                              unsigned & fromLen,
00627                                  void * toPtr,
00628                              unsigned & toLen,
00629                              unsigned & flags) = 0;
00630 
00631 
00633     virtual bool GetStatistics(char * /*bufferPtr*/, unsigned /*bufferSize*/)
00634     {
00635       return true;
00636     }
00637 
00638 
00640     virtual size_t GetOutputDataSize()
00641     {
00642       return 576-20-16; // Max safe MTU size (576 bytes as per RFC879) minus IP & UDP headers
00643     }
00644 
00645 
00652     virtual bool SetInstanceID(const char * /*idPtr*/, unsigned /*idLen*/)
00653     {
00654       return true;
00655     }
00656 
00657 
00659     virtual bool GetActiveOptions(PluginCodec_OptionMap & /*options*/)
00660     {
00661       return false;
00662     }
00663 
00664 
00666     virtual bool SetOptions(const char * const * options)
00667     {
00668       this->m_optionsSame = true;
00669 
00670       // get the media format options after adjustment from protocol negotiation
00671       for (const char * const * option = options; *option != NULL; option += 2) {
00672         if (!this->SetOption(option[0], option[1])) {
00673           PTRACE(1, "Plugin", "Could not set option \"" << option[0] << "\" to \"" << option[1] << '"');
00674           return false;
00675         }
00676       }
00677 
00678       if (this->m_optionsSame)
00679         return true;
00680 
00681       return this->OnChangedOptions();
00682     }
00683 
00684 
00686     virtual bool OnChangedOptions()
00687     {
00688       return true;
00689     }
00690 
00691 
00693     virtual bool SetOption(const char * optionName, const char * optionValue)
00694     {
00695       if (strcasecmp(optionName, PLUGINCODEC_OPTION_TARGET_BIT_RATE) == 0)
00696         return this->SetOptionUnsigned(this->m_maxBitRate, optionValue, 1, this->m_definition->bitsPerSec);
00697 
00698       if (strcasecmp(optionName, PLUGINCODEC_OPTION_FRAME_TIME) == 0)
00699         return this->SetOptionUnsigned(this->m_frameTime, optionValue,
00700                                        this->m_definition->sampleRate/1000, this->m_definition->sampleRate); // 1ms to 1 second
00701 
00702       return true;
00703     }
00704 
00705 
00706     template <typename T>
00707     bool SetOptionUnsigned(T & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX)
00708     {
00709       unsigned newValue = oldValue;
00710       if (!this->SetOptionUnsigned(newValue, optionValue, minimum, maximum))
00711         return false;
00712       oldValue = (T)newValue;
00713       return true;
00714     }
00715 
00716 
00717     bool SetOptionUnsigned(unsigned & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX)
00718     {
00719       char * end;
00720       unsigned newValue = strtoul(optionValue, &end, 10);
00721       if (*end != '\0')
00722         return false;
00723 
00724       if (newValue < minimum)
00725         newValue = minimum;
00726       else if (newValue > maximum)
00727         newValue = maximum;
00728 
00729       if (oldValue != newValue) {
00730         oldValue = newValue;
00731         this->m_optionsSame = false;
00732       }
00733 
00734       return true;
00735     }
00736 
00737 
00738     template <typename T>
00739     bool SetOptionBoolean(T & oldValue, const char * optionValue)
00740     {
00741       bool opt = oldValue != 0;
00742       if (!this->SetOptionBoolean(opt, optionValue))
00743         return false;
00744       oldValue = (T)opt;
00745       return true;
00746     }
00747 
00748 
00749     bool SetOptionBoolean(bool & oldValue, const char * optionValue)
00750     {
00751       bool newValue;
00752       if (     strcasecmp(optionValue, "0") == 0 ||
00753                strcasecmp(optionValue, "n") == 0 ||
00754                strcasecmp(optionValue, "f") == 0 ||
00755                strcasecmp(optionValue, "no") == 0 ||
00756                strcasecmp(optionValue, "false") == 0)
00757         newValue = false;
00758       else if (strcasecmp(optionValue, "1") == 0 ||
00759                strcasecmp(optionValue, "y") == 0 ||
00760                strcasecmp(optionValue, "t") == 0 ||
00761                strcasecmp(optionValue, "yes") == 0 ||
00762                strcasecmp(optionValue, "true") == 0)
00763         newValue = true;
00764       else
00765         return false;
00766 
00767       if (oldValue != newValue) {
00768         oldValue = newValue;
00769         this->m_optionsSame = false;
00770       }
00771 
00772       return true;
00773     }
00774 
00775 
00776     bool SetOptionBit(int & oldValue, unsigned bit, const char * optionValue)
00777     {
00778       return this->SetOptionBit((unsigned &)oldValue, bit, optionValue);
00779     }
00780 
00781 
00782     bool SetOptionBit(unsigned & oldValue, unsigned bit, const char * optionValue)
00783     {
00784       bool newValue;
00785       if (strcmp(optionValue, "0") == 0)
00786         newValue = false;
00787       else if (strcmp(optionValue, "1") == 0)
00788         newValue = true;
00789       else
00790         return false;
00791 
00792       if (((oldValue&bit) != 0) != newValue) {
00793         if (newValue)
00794           oldValue |= bit;
00795         else
00796           oldValue &= ~bit;
00797         this->m_optionsSame = false;
00798       }
00799 
00800       return true;
00801     }
00802 
00803 
00804     template <class CodecClass> static void * Create_s(const PluginCodec_Definition * defn)
00805     {
00806       CodecClass * codec = new CodecClass(defn);
00807       if (codec != NULL && codec->Construct())
00808         return codec;
00809 
00810       PTRACE(1, "Plugin", "Could not open codec, no context being returned.");
00811       delete codec;
00812       return NULL;
00813     }
00814 
00815 
00816     static void Destroy_s(const PluginCodec_Definition * /*defn*/, void * context)
00817     {
00818       delete (PluginCodec *)context;
00819     }
00820 
00821 
00822     static int Transcode_s(const PluginCodec_Definition * /*defn*/,
00823                                                    void * context,
00824                                              const void * fromPtr,
00825                                                unsigned * fromLen,
00826                                                    void * toPtr,
00827                                                unsigned * toLen,
00828                                            unsigned int * flags)
00829     {
00830       if (context != NULL && fromPtr != NULL && fromLen != NULL && toPtr != NULL && toLen != NULL && flags != NULL)
00831         return ((PluginCodec *)context)->Transcode(fromPtr, *fromLen, toPtr, *toLen, *flags);
00832 
00833       PTRACE(1, "Plugin", "Invalid parameter to Transcode.");
00834       return false;
00835     }
00836 
00837 
00838     static int GetOutputDataSize_s(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *)
00839     {
00840       return context != NULL ? ((PluginCodec *)context)->GetOutputDataSize() : 0;
00841     }
00842 
00843     typedef PluginCodec_MediaFormat<NAME> MediaFormat;
00844 
00845     static int ToNormalised_s(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
00846     {
00847       return defn->userData != NULL ? ((MediaFormat *)defn->userData)->AdjustOptions(parm, len, &MediaFormat::ToNormalised) : -1;
00848     }
00849 
00850 
00851     static int ToCustomised_s(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
00852     {
00853       return defn->userData != NULL ? ((MediaFormat *)defn->userData)->AdjustOptions(parm, len, &MediaFormat::ToCustomised) : -1;
00854     }
00855 
00856 
00857     static int GetActiveOptions_s(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * parmLen)
00858     {
00859       if (context == NULL || parmLen == NULL || parm == NULL || *parmLen != sizeof(char ***)) {
00860         PTRACE(1, "Plugin", "Invalid parameters to GetActiveOptions.");
00861         return false;
00862       }
00863 
00864       PluginCodec_OptionMap activeOptions;
00865       if (!((PluginCodec *)context)->GetActiveOptions(activeOptions))
00866         return false;
00867 
00868       return (*(char ***)parm = activeOptions.GetOptions()) != NULL;
00869     }
00870 
00871 
00872     static int FreeOptions_s(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len)
00873     {
00874       if (parm == NULL || len == NULL || *len != sizeof(char ***))
00875         return false;
00876 
00877       char ** strings = (char **)parm;
00878       for (char ** string = strings; *string != NULL; string++)
00879         free(*string);
00880       free(strings);
00881       return true;
00882     }
00883 
00884 
00885     static int GetOptions_s(const struct PluginCodec_Definition * codec, void *, const char *, void * parm, unsigned * len)
00886     {
00887       if (parm == NULL || len == NULL || *len != sizeof(struct PluginCodec_Option **))
00888         return false;
00889 
00890       *(const void **)parm = codec->userData != NULL ? ((MediaFormat *)codec->userData)->GetOptionsTable() : NULL;
00891       *len = 0;
00892       return true;
00893     }
00894 
00895 
00896     static int SetOptions_s(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
00897     {
00898       PluginCodec * codec = (PluginCodec *)context;
00899       return len != NULL && *len == sizeof(const char **) && parm != NULL &&
00900              codec != NULL && codec->SetOptions((const char * const *)parm);
00901     }
00902 
00903     static int ValidForProtocol_s(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
00904     {
00905       return len != NULL && *len == sizeof(const char *) && parm != NULL && defn->userData != NULL &&
00906                               ((MediaFormat *)defn->userData)->IsValidForProtocol((const char *)parm);
00907     }
00908 
00909     static int SetInstanceID_s(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
00910     {
00911       PluginCodec * codec = (PluginCodec *)context;
00912       return len != NULL && parm != NULL &&
00913              codec != NULL && codec->SetInstanceID((const char *)parm, *len);
00914     }
00915 
00916     static int GetStatistics_s(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
00917     {
00918       PluginCodec * codec = (PluginCodec *)context;
00919       return len != NULL && parm != NULL &&
00920              codec != NULL && codec->GetStatistics((char *)parm, *len);
00921     }
00922 
00923     static int Terminate_s(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *)
00924     {
00925       PluginCodec * codec = (PluginCodec *)context;
00926       return codec != NULL && codec->Terminate();
00927     }
00928 
00929     static struct PluginCodec_ControlDefn * GetControls()
00930     {
00931       static PluginCodec_ControlDefn ControlsTable[] = {
00932         { PLUGINCODEC_CONTROL_GET_OUTPUT_DATA_SIZE,  PluginCodec::GetOutputDataSize_s },
00933         { PLUGINCODEC_CONTROL_TO_NORMALISED_OPTIONS, PluginCodec::ToNormalised_s },
00934         { PLUGINCODEC_CONTROL_TO_CUSTOMISED_OPTIONS, PluginCodec::ToCustomised_s },
00935         { PLUGINCODEC_CONTROL_SET_CODEC_OPTIONS,     PluginCodec::SetOptions_s },
00936         { PLUGINCODEC_CONTROL_GET_ACTIVE_OPTIONS,    PluginCodec::GetActiveOptions_s },
00937         { PLUGINCODEC_CONTROL_GET_CODEC_OPTIONS,     PluginCodec::GetOptions_s },
00938         { PLUGINCODEC_CONTROL_FREE_CODEC_OPTIONS,    PluginCodec::FreeOptions_s },
00939         { PLUGINCODEC_CONTROL_VALID_FOR_PROTOCOL,    PluginCodec::ValidForProtocol_s },
00940         { PLUGINCODEC_CONTROL_SET_INSTANCE_ID,       PluginCodec::SetInstanceID_s },
00941         { PLUGINCODEC_CONTROL_GET_STATISTICS,        PluginCodec::GetStatistics_s },
00942         { PLUGINCODEC_CONTROL_TERMINATE_CODEC,       PluginCodec::Terminate_s },
00943         PLUGINCODEC_CONTROL_LOG_FUNCTION_INC
00944         { NULL }
00945       };
00946       return ControlsTable;
00947     }
00948 
00949   protected:
00950     const PluginCodec_Definition * m_definition;
00951 
00952     bool     m_optionsSame;
00953     unsigned m_maxBitRate;
00954     unsigned m_frameTime;
00955 };
00956 
00957 
00959 
00960 template<typename NAME>
00961 class PluginVideoCodec : public PluginCodec<NAME>
00962 {
00963     typedef PluginCodec<NAME> BaseClass;
00964 
00965   public:
00966     enum {
00967       DefaultWidth = 352, // CIF size
00968       DefaultHeight = 288,
00969       MaxWidth = DefaultWidth*8,
00970       MaxHeight = DefaultHeight*8
00971     };
00972 
00973 
00974     PluginVideoCodec(const PluginCodec_Definition * defn)
00975       : BaseClass(defn)
00976     {
00977     }
00978 
00979 
00980     virtual size_t GetRawFrameSize(unsigned width, unsigned height)
00981     {
00982       return width*height*3/2; // YUV420P
00983     }
00984 };
00985 
00986 
00988 
00989 template<typename NAME>
00990 class PluginVideoEncoder : public PluginVideoCodec<NAME>
00991 {
00992     typedef PluginVideoCodec<NAME> BaseClass;
00993 
00994   protected:
00995     unsigned m_width;
00996     unsigned m_height;
00997     unsigned m_maxRTPSize;
00998     unsigned m_tsto;
00999     unsigned m_keyFramePeriod;
01000 
01001   public:
01002     PluginVideoEncoder(const PluginCodec_Definition * defn)
01003       : BaseClass(defn)
01004       , m_width(BaseClass::DefaultWidth)
01005       , m_height(BaseClass::DefaultHeight)
01006       , m_maxRTPSize(PluginCodec_RTP_MaxPacketSize)
01007       , m_tsto(31)
01008       , m_keyFramePeriod(0) // Indicates auto/default
01009     {
01010     }
01011 
01012 
01013     virtual bool SetOption(const char * optionName, const char * optionValue)
01014     {
01015       if (strcasecmp(optionName, PLUGINCODEC_OPTION_FRAME_WIDTH) == 0)
01016         return this->SetOptionUnsigned(this->m_width, optionValue, 16, BaseClass::MaxWidth);
01017 
01018       if (strcasecmp(optionName, PLUGINCODEC_OPTION_FRAME_HEIGHT) == 0)
01019         return this->SetOptionUnsigned(this->m_height, optionValue, 16, BaseClass::MaxHeight);
01020 
01021       if (strcasecmp(optionName, PLUGINCODEC_OPTION_MAX_TX_PACKET_SIZE) == 0)
01022         return this->SetOptionUnsigned(this->m_maxRTPSize, optionValue, 256, 8192);
01023 
01024       if (strcasecmp(optionName, PLUGINCODEC_OPTION_TEMPORAL_SPATIAL_TRADE_OFF) == 0)
01025         return this->SetOptionUnsigned(this->m_tsto, optionValue, 1, 31);
01026 
01027       if (strcasecmp(optionName, PLUGINCODEC_OPTION_TX_KEY_FRAME_PERIOD) == 0)
01028         return this->SetOptionUnsigned(this->m_keyFramePeriod, optionValue, 0);
01029 
01030       // Base class sets bit rate and frame time
01031       return BaseClass::SetOption(optionName, optionValue);
01032     }
01033 
01034 
01036     virtual bool GetActiveOptions(PluginCodec_OptionMap & options)
01037     {
01038       options.SetUnsigned(this->m_frameTime, PLUGINCODEC_OPTION_FRAME_TIME);
01039       return true;
01040     }
01041 
01042 
01043     virtual size_t GetPacketSpace(const PluginCodec_RTP & rtp, size_t total)
01044     {
01045       size_t space = rtp.GetMaxSize();
01046       if (space > this->m_maxRTPSize)
01047         space = this->m_maxRTPSize;
01048       space -= rtp.GetHeaderSize();
01049       if (space > total)
01050         space = total;
01051       return space;
01052     }
01053 };
01054 
01055 
01057 
01058 template<typename NAME>
01059 class PluginVideoDecoder : public PluginVideoCodec<NAME>
01060 {
01061     typedef PluginVideoCodec<NAME> BaseClass;
01062 
01063   protected:
01064     size_t m_outputSize;
01065 
01066   public:
01067     PluginVideoDecoder(const PluginCodec_Definition * defn)
01068       : BaseClass(defn)
01069       , m_outputSize(BaseClass::DefaultWidth*BaseClass::DefaultHeight*3/2 + sizeof(PluginCodec_Video_FrameHeader) + PluginCodec_RTP_MinHeaderSize)
01070     {
01071     }
01072 
01073 
01074     virtual size_t GetOutputDataSize()
01075     {
01076       return this->m_outputSize;
01077     }
01078 
01079 
01080     virtual bool CanOutputImage(unsigned width, unsigned height, PluginCodec_RTP & rtp, unsigned & flags)
01081     {
01082       size_t newSize = this->GetRawFrameSize(width, height) + sizeof(PluginCodec_Video_FrameHeader) + rtp.GetHeaderSize();
01083       if (newSize > rtp.GetMaxSize() || !rtp.SetPayloadSize(newSize)) {
01084         m_outputSize = newSize;
01085         flags |= PluginCodec_ReturnCoderBufferTooSmall;
01086         return false;
01087       }
01088 
01089       PluginCodec_Video_FrameHeader * videoHeader = rtp.GetVideoHeader();
01090       videoHeader->x = 0;
01091       videoHeader->y = 0;
01092       videoHeader->width = width;
01093       videoHeader->height = height;
01094 
01095       flags |= PluginCodec_ReturnCoderLastFrame;
01096       rtp.SetMarker(true);
01097       return true;
01098     }
01099 
01100 
01101     struct OutputImagePlaneInfo
01102     {
01103       unsigned        m_width;
01104       unsigned        m_height;
01105       unsigned        m_raster;
01106       unsigned char * m_source;
01107       unsigned char * m_destination;
01108 
01109       void Copy()
01110       {
01111         for (unsigned y = 0; y < m_height; ++y) {
01112           memcpy(m_destination, m_source, m_width);
01113           this->m_source += m_raster;
01114           this->m_destination += m_width;
01115         }
01116       }
01117     };
01118 
01119     virtual unsigned OutputImage(unsigned char * planes[3], int raster[3],
01120                                  unsigned width, unsigned height, PluginCodec_RTP & rtp, unsigned & flags)
01121     {
01122       if (!CanOutputImage(width, height, rtp, flags))
01123         return 0;
01124 
01125       size_t ySize = width*height;
01126       size_t uvSize = ySize/4;
01127       if (planes[1] == planes[0]+ySize && planes[2] == planes[1]+uvSize)
01128         memcpy(rtp.GetVideoFrameData(), planes[0], ySize+uvSize*2);
01129       else {
01130         OutputImagePlaneInfo planeInfo[3] = {
01131           { width,   height,   raster[0], planes[0], rtp.GetVideoFrameData()     },
01132           { width/2, height/2, raster[1], planes[1], planeInfo[0].m_destination + ySize  },
01133           { width/2, height/2, raster[2], planes[2], planeInfo[1].m_destination + uvSize }
01134         };
01135 
01136         for (unsigned plane = 0; plane < 3; ++plane)
01137           planeInfo[plane].Copy();
01138       }
01139 
01140       return rtp.GetPacketSize();
01141     }
01142 };
01143 
01144 
01146 
01148 #define PLUGINCODEC_AUDIO_CODEC_CXX(MediaFormat,      \
01149                                     EncoderClass,     \
01150                                     DecoderClass      \
01151                                     ) \
01152              PLUGINCODEC_CODEC_PAIR(MediaFormat.GetFormatName(), \
01153                                     MediaFormat.GetPayloadName(), \
01154                                     MediaFormat.GetDescription(), \
01155                                     MediaFormat.GetSampleRate(), \
01156                                     MediaFormat.GetMaxBandwidth(), \
01157                                     MediaFormat.GetFrameTime(), \
01158                                     MediaFormat.GetSamplesPerFrame(), \
01159                                     MediaFormat.GetBytesPerFrame(), \
01160                                     MediaFormat.GetRecommendedFramesPerPacket(), \
01161                                     MediaFormat.GetMaxFramesPerPacket(), \
01162                                     MediaFormat.GetPayloadType(), \
01163                                     MediaFormat.GetH323CapabilityType(), \
01164                                     MediaFormat.GetH323CapabilityData(), \
01165                                     EncoderClass::Create_s<EncoderClass>, \
01166                                     EncoderClass::Destroy_s, \
01167                                     EncoderClass::Transcode_s, \
01168                                     DecoderClass::Create_s<DecoderClass>, \
01169                                     DecoderClass::Destroy_s, \
01170                                     DecoderClass::Transcode_s, \
01171                                     DecoderClass::GetControls(), /* Note doesn't matter if encoder or decoder */ \
01172                                     MediaFormat.GetFlags(), \
01173                                     PLUGINCODEC_RAW_AUDIO, \
01174                                     &MediaFormat)
01175 
01177 #define PLUGINCODEC_VIDEO_CODEC_CXX(MediaFormat,      \
01178                                     EncoderClass,     \
01179                                     DecoderClass      \
01180                                     ) \
01181              PLUGINCODEC_CODEC_PAIR(MediaFormat.GetFormatName(), \
01182                                     MediaFormat.GetPayloadName(), \
01183                                     MediaFormat.GetDescription(), \
01184                                     PLUGINCODEC_VIDEO_CLOCK, \
01185                                     MediaFormat.GetMaxBandwidth(), \
01186                                     1000000/PLUGINCODEC_MAX_FRAME_RATE, \
01187                                     MediaFormat.GetMaxWidth(), \
01188                                     MediaFormat.GetMaxHeight(), \
01189                                     0,PLUGINCODEC_MAX_FRAME_RATE, \
01190                                     MediaFormat.GetPayloadType(), \
01191                                     MediaFormat.GetH323CapabilityType(), \
01192                                     MediaFormat.GetH323CapabilityData(), \
01193                                     EncoderClass::Create_s<EncoderClass>, \
01194                                     EncoderClass::Destroy_s, \
01195                                     EncoderClass::Transcode_s, \
01196                                     DecoderClass::Create_s<DecoderClass>, \
01197                                     DecoderClass::Destroy_s, \
01198                                     DecoderClass::Transcode_s, \
01199                                     DecoderClass::GetControls(), /* Note doesn't matter if encoder or decoder */ \
01200                                     MediaFormat.GetFlags(), \
01201                                     PLUGINCODEC_RAW_VIDEO, \
01202                                     &MediaFormat)
01203 
01204 
01205 #define PLUGIN_CODEC_IMPLEMENT_CXX(NAME, table) \
01206   extern "C" { \
01207     PLUGIN_CODEC_IMPLEMENT(NAME) \
01208     PLUGIN_CODEC_DLL_API struct PluginCodec_Definition * PLUGIN_CODEC_GET_CODEC_FN(unsigned * count, unsigned version) { \
01209       if (version < PLUGIN_CODEC_VERSION_OPTIONS) return NULL; \
01210       *count = sizeof(table)/sizeof(struct PluginCodec_Definition); \
01211       PluginCodec_MediaFormat<NAME>::AdjustAllForVersion(version, table, *count); \
01212       return table; \
01213     } \
01214   }
01215 
01216 
01217 #endif // OPAL_CODEC_OPALPLUGIN_HPP

Generated on 21 Jun 2013 for OPAL by  doxygen 1.4.7