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  * The contents of this file are subject to the Mozilla Public License
00012  * Version 1.0 (the "License"); you may not use this file except in
00013  * compliance with the License. You may obtain a copy of the License at
00014  * http://www.mozilla.org/MPL/
00015  *
00016  * Software distributed under the License is distributed on an "AS IS"
00017  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
00018  * the License for the specific language governing rights and limitations
00019  * under the License.
00020  *
00021  * The Original Code is Open Phone Abstraction Library.
00022  *
00023  * The Initial Developer of the Original Code is Vox Lucida
00024  *
00025  * Contributor(s): ______________________________________.
00026  *
00027  * $Revision: 24116 $
00028  * $Author: rjongbloed $
00029  * $Date: 2010-03-11 20:33:30 -0600 (Thu, 11 Mar 2010) $
00030  */
00031 
00032 #ifndef OPAL_CODEC_OPALPLUGIN_HPP
00033 #define OPAL_CODEC_OPALPLUGIN_HPP
00034 
00035 #include "opalplugin.h"
00036 
00037 #include <map>
00038 #include <string>
00039 #include <string.h>
00040 #include <stdlib.h>
00041 #include <malloc.h>
00042 #include <limits.h>
00043 
00044 
00046 
00047 #ifndef PLUGINCODEC_TRACING
00048   #define PLUGINCODEC_TRACING 1
00049 #endif
00050 
00051 #if PLUGINCODEC_TRACING
00052   static PluginCodec_LogFunction PluginCodec_LogFunctionInstance;
00053 
00054   static int PluginCodec_SetLogFunction(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len)
00055   {
00056     if (len == NULL || *len != sizeof(PluginCodec_LogFunction))
00057       return false;
00058 
00059     PluginCodec_LogFunctionInstance = (PluginCodec_LogFunction)parm;
00060     if (PluginCodec_LogFunctionInstance != NULL)
00061       PluginCodec_LogFunctionInstance(4, __FILE__, __LINE__, "Plugin", "Started logging.");
00062 
00063     return true;
00064   }
00065 
00066   #define PLUGINCODEC_CONTROL_LOG_FUNCTION { PLUGINCODEC_CONTROL_SET_LOG_FUNCTION, PluginCodec_SetLogFunction },
00067 #else
00068   #define PLUGINCODEC_CONTROL_LOG_FUNCTION
00069 #endif
00070 
00071 #if !defined(PTRACE)
00072   #if PLUGINCODEC_TRACING
00073     #include <sstream>
00074     #define PTRACE(level, section, args) \
00075       if (PluginCodec_LogFunctionInstance != NULL && PluginCodec_LogFunctionInstance(level, NULL, 0, NULL, NULL)) { \
00076         std::ostringstream strm; strm << args; \
00077         PluginCodec_LogFunctionInstance(level, __FILE__, __LINE__, section, strm.str().c_str()); \
00078       } else (void)0
00079   #else
00080     #define PTRACE(level, section, expr)
00081   #endif
00082 #endif
00083 
00084 
00086 
00087 class PluginCodec_MediaFormat
00088 {
00089     friend class PluginCodec;
00090 
00091   public:
00092     typedef struct PluginCodec_Option const * const * OptionsTable;
00093     typedef std::map<std::string, std::string> OptionMap;
00094 
00095   protected:
00096     OptionsTable m_options;
00097 
00098   public:
00099     PluginCodec_MediaFormat(OptionsTable options)
00100       : m_options(options)
00101     {
00102     }
00103 
00104 
00105     virtual ~PluginCodec_MediaFormat()
00106     {
00107     }
00108 
00109 
00110     bool AdjustOptions(void * parm, unsigned * parmLen, bool (PluginCodec_MediaFormat:: * adjuster)(OptionMap & original, OptionMap & changed))
00111     {
00112       if (parmLen == NULL || parm == NULL || *parmLen != sizeof(char ***))
00113         return false;
00114 
00115       OptionMap originalOptions;
00116       for (const char * const * option = *(const char * const * *)parm; *option != NULL; option += 2)
00117         originalOptions[option[0]] = option[1];
00118 
00119       OptionMap changedOptions;
00120       if (!(this->*adjuster)(originalOptions, changedOptions))
00121         return false;
00122 
00123       char ** options = (char **)calloc(changedOptions.size()*2+1, sizeof(char *));
00124       *(char ***)parm = options;
00125       if (options == NULL)
00126         return false;
00127 
00128       for (OptionMap::iterator i = changedOptions.begin(); i != changedOptions.end(); ++i) {
00129         *options++ = strdup(i->first.c_str());
00130         *options++ = strdup(i->second.c_str());
00131       }
00132 
00133       return true;
00134     }
00135 
00136 
00137     virtual bool ToNormalised(OptionMap & original, OptionMap & changed) = 0;
00138 
00139 
00140     virtual bool ToCustomised(OptionMap & original, OptionMap & changed) = 0;
00141 
00142 
00143     static void Change(const char * value,
00144                        OptionMap  & original,
00145                        OptionMap  & changed,
00146                        const char * option)
00147     {
00148       if (original[option] != value)
00149         changed[option] = value;
00150     }
00151 
00152 
00153     static unsigned String2Unsigned(const std::string & str)
00154     {
00155       return strtoul(str.c_str(), NULL, 10);
00156     }
00157 
00158 
00159     static void Unsigned2String(unsigned value, std::string & str)
00160     {
00161       // Not very efficient, but really, really simple
00162       if (value > 9)
00163         Unsigned2String(value/10, str);
00164       str += (char)(value%10 + '0');
00165     }
00166 
00167 
00168     static void Change(unsigned     value,
00169                        OptionMap  & original,
00170                        OptionMap  & changed,
00171                        const char * option)
00172     {
00173       if (String2Unsigned(original[option]) != value)
00174         Unsigned2String(value, changed[option]);
00175     }
00176 
00177 
00178     static void ClampMax(unsigned     maximum,
00179                          OptionMap  & original,
00180                          OptionMap  & changed,
00181                          const char * option)
00182     {
00183       unsigned value = String2Unsigned(original[option]);
00184       if (value > maximum)
00185         Unsigned2String(maximum, changed[option]);
00186     }
00187 
00188 
00189     static void ClampMin(unsigned     minimum,
00190                          OptionMap  & original,
00191                          OptionMap  & changed,
00192                          const char * option)
00193     {
00194       unsigned value = String2Unsigned(original[option]);
00195       if (value < minimum)
00196         Unsigned2String(minimum, changed[option]);
00197     }
00198 };
00199 
00200 
00202 
00203 class PluginCodec
00204 {
00205   protected:
00206     PluginCodec(const PluginCodec_Definition * defn)
00207       : m_definition(defn)
00208       , m_optionsSame(false)
00209       , m_maxBitRate(defn->bitsPerSec)
00210       , m_frameTime((defn->sampleRate/1000*defn->usPerFrame)/1000) // Odd way of calculation to avoid 32 bit integer overflow
00211     {
00212       PTRACE(3, "Plugin", "Codec created: \"" << defn->descr
00213              << "\", \"" << defn->sourceFormat << "\" -> \"" << defn->destFormat << '"');
00214     }
00215 
00216 
00217   public:
00218     virtual ~PluginCodec()
00219     {
00220     }
00221 
00222 
00223     virtual bool Construct()
00224     {
00225       return true;
00226     }
00227 
00228 
00229     virtual bool Transcode(const void * fromPtr,
00230                              unsigned & fromLen,
00231                                  void * toPtr,
00232                              unsigned & toLen,
00233                              unsigned & flags) = 0;
00234 
00235 
00236     virtual size_t GetOutputDataSize()
00237     {
00238       return 576-20-16; // Max safe MTU size (576 bytes as per RFC879) minus IP & UDP headers
00239     }
00240 
00241 
00242     virtual bool SetOptions(const char * const * options)
00243     {
00244       m_optionsSame = true;
00245 
00246       // get the media format options after adjustment from protocol negotiation
00247       for (const char * const * option = options; *option != NULL; option += 2) {
00248         if (!SetOption(option[0], option[1]))
00249           return false;
00250       }
00251 
00252       if (m_optionsSame)
00253         return true;
00254 
00255       return OnChangedOptions();
00256     }
00257 
00258 
00259     virtual bool OnChangedOptions()
00260     {
00261       return true;
00262     }
00263 
00264 
00265     virtual bool SetOption(const char * optionName, const char * optionValue)
00266     {
00267       if (strcasecmp(optionName, PLUGINCODEC_OPTION_TARGET_BIT_RATE) == 0)
00268         return SetOptionUnsigned(m_maxBitRate, optionValue, 1, m_definition->bitsPerSec);
00269 
00270       if (strcasecmp(optionName, PLUGINCODEC_OPTION_FRAME_TIME) == 0)
00271         return SetOptionUnsigned(m_frameTime, optionValue, m_definition->sampleRate/1000, m_definition->sampleRate); // 1ms to 1 second
00272 
00273       return true;
00274     }
00275 
00276 
00277     bool SetOptionUnsigned(unsigned & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX)
00278     {
00279       char * end;
00280       unsigned newValue = strtoul(optionValue, &end, 10);
00281       if (*end != '\0')
00282         return false;
00283 
00284       if (newValue < minimum)
00285         newValue = minimum;
00286       else if (newValue > maximum)
00287         newValue = maximum;
00288 
00289       if (oldValue != newValue) {
00290         oldValue = newValue;
00291         m_optionsSame = false;
00292       }
00293 
00294       return true;
00295     }
00296 
00297 
00298     bool SetOptionBoolean(bool & oldValue, const char * optionValue)
00299     {
00300       bool newValue;
00301       if (strcmp(optionValue, "0") == 0)
00302         newValue = false;
00303       else if (strcmp(optionValue, "1") == 0)
00304         newValue = true;
00305       else
00306         return false;
00307 
00308       if (oldValue != newValue) {
00309         oldValue = newValue;
00310         m_optionsSame = false;
00311       }
00312 
00313       return true;
00314     }
00315 
00316 
00317     bool SetOptionBit(unsigned & oldValue, unsigned bit, const char * optionValue)
00318     {
00319       bool newValue;
00320       if (strcmp(optionValue, "0") == 0)
00321         newValue = false;
00322       else if (strcmp(optionValue, "1") == 0)
00323         newValue = true;
00324       else
00325         return false;
00326 
00327       if (((oldValue&bit) != 0) != newValue) {
00328         if (newValue)
00329           oldValue |= bit;
00330         else
00331           oldValue &= ~bit;
00332         m_optionsSame = false;
00333       }
00334 
00335       return true;
00336     }
00337 
00338 
00339     template <class CodecClass> static void * Create(const PluginCodec_Definition * defn)
00340     {
00341       CodecClass * codec = new CodecClass(defn);
00342       if (codec != NULL && codec->Construct())
00343         return codec;
00344 
00345       PTRACE(1, "Plugin", "Could not open codec, no context being returned.");
00346       delete codec;
00347       return NULL;
00348     }
00349 
00350 
00351     static void Destroy(const PluginCodec_Definition * /*defn*/, void * context)
00352     {
00353       delete (PluginCodec *)context;
00354     }
00355 
00356 
00357     static int Transcode(const PluginCodec_Definition * /*defn*/,
00358                                                  void * context,
00359                                            const void * fromPtr,
00360                                              unsigned * fromLen,
00361                                                  void * toPtr,
00362                                              unsigned * toLen,
00363                                          unsigned int * flags)
00364     {
00365       if (context != NULL && fromPtr != NULL && fromLen != NULL && toPtr != NULL && toLen != NULL && flags != NULL)
00366         return ((PluginCodec *)context)->Transcode(fromPtr, *fromLen, toPtr, *toLen, *flags);
00367 
00368       PTRACE(1, "Plugin", "Invalid parameter to Transcode.");
00369       return false;
00370     }
00371 
00372 
00373     static int GetOutputDataSize(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *)
00374     {
00375       return context != NULL ? ((PluginCodec *)context)->GetOutputDataSize() : 0;
00376     }
00377 
00378 
00379     static int ToNormalised(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
00380     {
00381       return defn->userData != NULL ? ((PluginCodec_MediaFormat *)defn->userData)->AdjustOptions(parm, len, &PluginCodec_MediaFormat::ToNormalised) : -1;
00382     }
00383 
00384 
00385     static int ToCustomised(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
00386     {
00387       return defn->userData != NULL ? ((PluginCodec_MediaFormat *)defn->userData)->AdjustOptions(parm, len, &PluginCodec_MediaFormat::ToCustomised) : -1;
00388     }
00389 
00390 
00391     static int FreeOptions(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len)
00392     {
00393       if (parm == NULL || len == NULL || *len != sizeof(char ***))
00394         return false;
00395 
00396       char ** strings = (char **)parm;
00397       for (char ** string = strings; *string != NULL; string++)
00398         free(*string);
00399       free(strings);
00400       return true;
00401     }
00402 
00403 
00404     static int GetOptions(const struct PluginCodec_Definition * codec, void *, const char *, void * parm, unsigned * len)
00405     {
00406       if (parm == NULL || len == NULL || *len != sizeof(struct PluginCodec_Option **))
00407         return false;
00408 
00409       *(const void **)parm = codec->userData != NULL ? ((PluginCodec_MediaFormat *)codec->userData)->m_options : NULL;
00410       *len = 0;
00411       return true;
00412     }
00413 
00414 
00415     static int SetOptions(const PluginCodec_Definition *, 
00416                                  void * context,
00417                                  const char * , 
00418                                  void * parm, 
00419                                  unsigned * len)
00420     {
00421       PluginCodec * codec = (PluginCodec *)context;
00422       return len != NULL && *len == sizeof(const char **) && parm != NULL &&
00423              codec != NULL && codec->SetOptions((const char * const *)parm);
00424     }
00425 
00426   protected:
00427     const PluginCodec_Definition * m_definition;
00428 
00429     bool     m_optionsSame;
00430     unsigned m_maxBitRate;
00431     unsigned m_frameTime;
00432 };
00433 
00434 
00435 #define PLUGINCODEC_DEFINE_CONTROL_TABLE(name) \
00436   static PluginCodec_ControlDefn name[] = { \
00437     { PLUGINCODEC_CONTROL_GET_OUTPUT_DATA_SIZE,  PluginCodec::GetOutputDataSize }, \
00438     { PLUGINCODEC_CONTROL_TO_NORMALISED_OPTIONS, PluginCodec::ToNormalised }, \
00439     { PLUGINCODEC_CONTROL_TO_CUSTOMISED_OPTIONS, PluginCodec::ToCustomised }, \
00440     { PLUGINCODEC_CONTROL_FREE_CODEC_OPTIONS,    PluginCodec::FreeOptions }, \
00441     { PLUGINCODEC_CONTROL_SET_CODEC_OPTIONS,     PluginCodec::SetOptions }, \
00442     { PLUGINCODEC_CONTROL_GET_CODEC_OPTIONS,     PluginCodec::GetOptions }, \
00443     PLUGINCODEC_CONTROL_LOG_FUNCTION \
00444     { NULL } \
00445   }
00446 
00447 
00448 
00449 #endif // OPAL_CODEC_OPALPLUGIN_HPP

Generated on Mon Feb 21 20:19:21 2011 for OPAL by  doxygen 1.4.7