OPAL
Version 3.10.4
|
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: 26787 $ 00035 * $Author: rjongbloed $ 00036 * $Date: 2011-12-08 18:49:50 -0600 (Thu, 08 Dec 2011) $ 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_MediaFormat 00102 { 00103 public: 00104 typedef struct PluginCodec_Option const * const * OptionsTable; 00105 typedef std::map<std::string, std::string> OptionMap; 00106 00107 protected: 00108 OptionsTable m_options; 00109 00110 protected: 00111 PluginCodec_MediaFormat(OptionsTable options) 00112 : m_options(options) 00113 { 00114 } 00115 00116 public: 00117 virtual ~PluginCodec_MediaFormat() 00118 { 00119 } 00120 00121 00122 const void * GetOptionsTable() const { return m_options; } 00123 00125 virtual bool IsValidForProtocol(const char * /*protocol*/) 00126 { 00127 return true; 00128 } 00129 00130 00132 bool AdjustOptions(void * parm, unsigned * parmLen, bool (PluginCodec_MediaFormat:: * adjuster)(OptionMap & original, OptionMap & changed)) 00133 { 00134 if (parmLen == NULL || parm == NULL || *parmLen != sizeof(char ***)) { 00135 PTRACE(1, "Plugin", "Invalid parameters to AdjustOptions."); 00136 return false; 00137 } 00138 00139 OptionMap originalOptions; 00140 for (const char * const * option = *(const char * const * *)parm; *option != NULL; option += 2) 00141 originalOptions[option[0]] = option[1]; 00142 00143 OptionMap changedOptions; 00144 if (!(this->*adjuster)(originalOptions, changedOptions)) { 00145 PTRACE(1, "Plugin", "Could not normalise/customise options."); 00146 return false; 00147 } 00148 00149 char ** options = (char **)calloc(changedOptions.size()*2+1, sizeof(char *)); 00150 *(char ***)parm = options; 00151 if (options == NULL) { 00152 PTRACE(1, "Plugin", "Could not allocate new option lists."); 00153 return false; 00154 } 00155 00156 for (OptionMap::iterator i = changedOptions.begin(); i != changedOptions.end(); ++i) { 00157 *options++ = strdup(i->first.c_str()); 00158 *options++ = strdup(i->second.c_str()); 00159 } 00160 00161 return true; 00162 } 00163 00164 00166 virtual bool ToNormalised(OptionMap & original, OptionMap & changed) = 0; 00167 00168 00169 // Adjust codec specific options calculated from normalised options. 00170 virtual bool ToCustomised(OptionMap & original, OptionMap & changed) = 0; 00171 00172 00173 static void Change(const char * value, 00174 OptionMap & original, 00175 OptionMap & changed, 00176 const char * option) 00177 { 00178 if (original[option] != value) 00179 changed[option] = value; 00180 } 00181 00182 00183 static unsigned String2Unsigned(const std::string & str) 00184 { 00185 return strtoul(str.c_str(), NULL, 10); 00186 } 00187 00188 00189 static void AppendUnsigned2String(unsigned value, std::string & str) 00190 { 00191 // Not very efficient, but really, really simple 00192 if (value > 9) 00193 AppendUnsigned2String(value/10, str); 00194 str += (char)(value%10 + '0'); 00195 } 00196 00197 00198 static void Unsigned2String(unsigned value, std::string & str) 00199 { 00200 str.clear(); 00201 AppendUnsigned2String(value,str); 00202 } 00203 00204 00205 static void Change(unsigned value, 00206 OptionMap & original, 00207 OptionMap & changed, 00208 const char * option) 00209 { 00210 if (String2Unsigned(original[option]) != value) 00211 Unsigned2String(value, changed[option]); 00212 } 00213 00214 00215 static void ClampMax(unsigned maximum, 00216 OptionMap & original, 00217 OptionMap & changed, 00218 const char * option) 00219 { 00220 unsigned value = String2Unsigned(original[option]); 00221 if (value > maximum) 00222 Unsigned2String(maximum, changed[option]); 00223 } 00224 00225 00226 static void ClampMin(unsigned minimum, 00227 OptionMap & original, 00228 OptionMap & changed, 00229 const char * option) 00230 { 00231 unsigned value = String2Unsigned(original[option]); 00232 if (value < minimum) 00233 Unsigned2String(minimum, changed[option]); 00234 } 00235 00236 virtual void AdjustForVersion(unsigned version, const PluginCodec_Definition * /*definition*/) 00237 { 00238 if (version < PLUGIN_CODEC_VERSION_INTERSECT) { 00239 for (PluginCodec_Option ** options = (PluginCodec_Option **)m_options; *options != NULL; ++options) { 00240 if (strcmp((*options)->m_name, PLUGINCODEC_MEDIA_PACKETIZATIONS) == 0) { 00241 *options = NULL; 00242 break; 00243 } 00244 } 00245 } 00246 } 00247 00248 static void AdjustAllForVersion(unsigned version, const PluginCodec_Definition * definitions, size_t size) 00249 { 00250 while (size-- > 0) { 00251 PluginCodec_MediaFormat * info = (PluginCodec_MediaFormat *)definitions->userData; 00252 if (info != NULL) 00253 info->AdjustForVersion(version, definitions); 00254 ++definitions; 00255 } 00256 } 00257 }; 00258 00259 00261 00262 template<typename NAME> 00263 class PluginCodec 00264 { 00265 protected: 00266 PluginCodec(const PluginCodec_Definition * defn) 00267 : m_definition(defn) 00268 , m_optionsSame(false) 00269 , m_maxBitRate(defn->bitsPerSec) 00270 , m_frameTime((defn->sampleRate/1000*defn->usPerFrame)/1000) // Odd way of calculation to avoid 32 bit integer overflow 00271 { 00272 PTRACE(3, "Plugin", "Codec created: \"" << defn->descr 00273 << "\", \"" << defn->sourceFormat << "\" -> \"" << defn->destFormat << '"'); 00274 } 00275 00276 00277 public: 00278 virtual ~PluginCodec() 00279 { 00280 } 00281 00282 00284 virtual bool Construct() 00285 { 00286 return true; 00287 } 00288 00289 00294 static bool Terminate() 00295 { 00296 return true; 00297 } 00298 00299 00301 virtual bool Transcode(const void * fromPtr, 00302 unsigned & fromLen, 00303 void * toPtr, 00304 unsigned & toLen, 00305 unsigned & flags) = 0; 00306 00307 00309 virtual bool GetStatistics(char * /*bufferPtr*/, unsigned /*bufferSize*/) 00310 { 00311 return true; 00312 } 00313 00314 00316 virtual size_t GetOutputDataSize() 00317 { 00318 return 576-20-16; // Max safe MTU size (576 bytes as per RFC879) minus IP & UDP headers 00319 } 00320 00321 00328 virtual bool SetInstanceID(const char * /*idPtr*/, unsigned /*idLen*/) 00329 { 00330 return true; 00331 } 00332 00333 00335 virtual bool SetOptions(const char * const * options) 00336 { 00337 m_optionsSame = true; 00338 00339 // get the media format options after adjustment from protocol negotiation 00340 for (const char * const * option = options; *option != NULL; option += 2) { 00341 if (!SetOption(option[0], option[1])) { 00342 PTRACE(1, "Plugin", "Could not set option \"" << option[0] << "\" to \"" << option[1] << '"'); 00343 return false; 00344 } 00345 } 00346 00347 if (m_optionsSame) 00348 return true; 00349 00350 return OnChangedOptions(); 00351 } 00352 00353 00355 virtual bool OnChangedOptions() 00356 { 00357 return true; 00358 } 00359 00360 00362 virtual bool SetOption(const char * optionName, const char * optionValue) 00363 { 00364 if (strcasecmp(optionName, PLUGINCODEC_OPTION_TARGET_BIT_RATE) == 0) 00365 return SetOptionUnsigned(m_maxBitRate, optionValue, 1, m_definition->bitsPerSec); 00366 00367 if (strcasecmp(optionName, PLUGINCODEC_OPTION_FRAME_TIME) == 0) 00368 return SetOptionUnsigned(m_frameTime, optionValue, m_definition->sampleRate/1000, m_definition->sampleRate); // 1ms to 1 second 00369 00370 return true; 00371 } 00372 00373 00374 template <typename T> 00375 bool SetOptionUnsigned(T & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX) 00376 { 00377 unsigned newValue = oldValue; 00378 if (!SetOptionUnsigned(newValue, optionValue, minimum, maximum)) 00379 return false; 00380 oldValue = (T)newValue; 00381 return true; 00382 } 00383 00384 00385 bool SetOptionUnsigned(unsigned & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX) 00386 { 00387 char * end; 00388 unsigned newValue = strtoul(optionValue, &end, 10); 00389 if (*end != '\0') 00390 return false; 00391 00392 if (newValue < minimum) 00393 newValue = minimum; 00394 else if (newValue > maximum) 00395 newValue = maximum; 00396 00397 if (oldValue != newValue) { 00398 oldValue = newValue; 00399 m_optionsSame = false; 00400 } 00401 00402 return true; 00403 } 00404 00405 00406 template <typename T> 00407 bool SetOptionBoolean(T & oldValue, const char * optionValue) 00408 { 00409 bool opt = oldValue != 0; 00410 if (!SetOptionBoolean(opt, optionValue)) 00411 return false; 00412 oldValue = (T)opt; 00413 return true; 00414 } 00415 00416 00417 bool SetOptionBoolean(bool & oldValue, const char * optionValue) 00418 { 00419 bool newValue; 00420 if ( strcasecmp(optionValue, "0") == 0 || 00421 strcasecmp(optionValue, "n") == 0 || 00422 strcasecmp(optionValue, "f") == 0 || 00423 strcasecmp(optionValue, "no") == 0 || 00424 strcasecmp(optionValue, "false") == 0) 00425 newValue = false; 00426 else if (strcasecmp(optionValue, "1") == 0 || 00427 strcasecmp(optionValue, "y") == 0 || 00428 strcasecmp(optionValue, "t") == 0 || 00429 strcasecmp(optionValue, "yes") == 0 || 00430 strcasecmp(optionValue, "true") == 0) 00431 newValue = true; 00432 else 00433 return false; 00434 00435 if (oldValue != newValue) { 00436 oldValue = newValue; 00437 m_optionsSame = false; 00438 } 00439 00440 return true; 00441 } 00442 00443 00444 bool SetOptionBit(int & oldValue, unsigned bit, const char * optionValue) 00445 { 00446 return SetOptionBit((unsigned &)oldValue, bit, optionValue); 00447 } 00448 00449 00450 bool SetOptionBit(unsigned & oldValue, unsigned bit, const char * optionValue) 00451 { 00452 bool newValue; 00453 if (strcmp(optionValue, "0") == 0) 00454 newValue = false; 00455 else if (strcmp(optionValue, "1") == 0) 00456 newValue = true; 00457 else 00458 return false; 00459 00460 if (((oldValue&bit) != 0) != newValue) { 00461 if (newValue) 00462 oldValue |= bit; 00463 else 00464 oldValue &= ~bit; 00465 m_optionsSame = false; 00466 } 00467 00468 return true; 00469 } 00470 00471 00472 template <class CodecClass> static void * Create(const PluginCodec_Definition * defn) 00473 { 00474 CodecClass * codec = new CodecClass(defn); 00475 if (codec != NULL && codec->Construct()) 00476 return codec; 00477 00478 PTRACE(1, "Plugin", "Could not open codec, no context being returned."); 00479 delete codec; 00480 return NULL; 00481 } 00482 00483 00484 static void Destroy(const PluginCodec_Definition * /*defn*/, void * context) 00485 { 00486 delete (PluginCodec *)context; 00487 } 00488 00489 00490 static int Transcode(const PluginCodec_Definition * /*defn*/, 00491 void * context, 00492 const void * fromPtr, 00493 unsigned * fromLen, 00494 void * toPtr, 00495 unsigned * toLen, 00496 unsigned int * flags) 00497 { 00498 if (context != NULL && fromPtr != NULL && fromLen != NULL && toPtr != NULL && toLen != NULL && flags != NULL) 00499 return ((PluginCodec *)context)->Transcode(fromPtr, *fromLen, toPtr, *toLen, *flags); 00500 00501 PTRACE(1, "Plugin", "Invalid parameter to Transcode."); 00502 return false; 00503 } 00504 00505 00506 static int GetOutputDataSize(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *) 00507 { 00508 return context != NULL ? ((PluginCodec *)context)->GetOutputDataSize() : 0; 00509 } 00510 00511 00512 static int ToNormalised(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len) 00513 { 00514 return defn->userData != NULL ? ((PluginCodec_MediaFormat *)defn->userData)->AdjustOptions(parm, len, &PluginCodec_MediaFormat::ToNormalised) : -1; 00515 } 00516 00517 00518 static int ToCustomised(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len) 00519 { 00520 return defn->userData != NULL ? ((PluginCodec_MediaFormat *)defn->userData)->AdjustOptions(parm, len, &PluginCodec_MediaFormat::ToCustomised) : -1; 00521 } 00522 00523 00524 static int FreeOptions(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len) 00525 { 00526 if (parm == NULL || len == NULL || *len != sizeof(char ***)) 00527 return false; 00528 00529 char ** strings = (char **)parm; 00530 for (char ** string = strings; *string != NULL; string++) 00531 free(*string); 00532 free(strings); 00533 return true; 00534 } 00535 00536 00537 static int GetOptions(const struct PluginCodec_Definition * codec, void *, const char *, void * parm, unsigned * len) 00538 { 00539 if (parm == NULL || len == NULL || *len != sizeof(struct PluginCodec_Option **)) 00540 return false; 00541 00542 *(const void **)parm = codec->userData != NULL ? ((PluginCodec_MediaFormat *)codec->userData)->GetOptionsTable() : NULL; 00543 *len = 0; 00544 return true; 00545 } 00546 00547 00548 static int SetOptions(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len) 00549 { 00550 PluginCodec * codec = (PluginCodec *)context; 00551 return len != NULL && *len == sizeof(const char **) && parm != NULL && 00552 codec != NULL && codec->SetOptions((const char * const *)parm); 00553 } 00554 00555 static int ValidForProtocol(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len) 00556 { 00557 return len != NULL && *len == sizeof(const char *) && parm != NULL && defn->userData != NULL && 00558 ((PluginCodec_MediaFormat *)defn->userData)->IsValidForProtocol((const char *)parm); 00559 } 00560 00561 static int SetInstanceID(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len) 00562 { 00563 PluginCodec * codec = (PluginCodec *)context; 00564 return len != NULL && parm != NULL && 00565 codec != NULL && codec->SetInstanceID((const char *)parm, *len); 00566 } 00567 00568 static int GetStatistics(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len) 00569 { 00570 PluginCodec * codec = (PluginCodec *)context; 00571 return len != NULL && parm != NULL && 00572 codec != NULL && codec->GetStatistics((char *)parm, *len); 00573 } 00574 00575 static int Terminate(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *) 00576 { 00577 PluginCodec * codec = (PluginCodec *)context; 00578 return codec != NULL && codec->Terminate(); 00579 } 00580 00581 static struct PluginCodec_ControlDefn * GetControls() 00582 { 00583 static PluginCodec_ControlDefn ControlsTable[] = { 00584 { PLUGINCODEC_CONTROL_GET_OUTPUT_DATA_SIZE, PluginCodec::GetOutputDataSize }, 00585 { PLUGINCODEC_CONTROL_TO_NORMALISED_OPTIONS, PluginCodec::ToNormalised }, 00586 { PLUGINCODEC_CONTROL_TO_CUSTOMISED_OPTIONS, PluginCodec::ToCustomised }, 00587 { PLUGINCODEC_CONTROL_SET_CODEC_OPTIONS, PluginCodec::SetOptions }, 00588 { PLUGINCODEC_CONTROL_GET_CODEC_OPTIONS, PluginCodec::GetOptions }, 00589 { PLUGINCODEC_CONTROL_FREE_CODEC_OPTIONS, PluginCodec::FreeOptions }, 00590 { PLUGINCODEC_CONTROL_VALID_FOR_PROTOCOL, PluginCodec::ValidForProtocol }, 00591 { PLUGINCODEC_CONTROL_SET_INSTANCE_ID, PluginCodec::SetInstanceID }, 00592 { PLUGINCODEC_CONTROL_GET_STATISTICS, PluginCodec::GetStatistics }, 00593 { PLUGINCODEC_CONTROL_TERMINATE_CODEC, PluginCodec::Terminate }, 00594 PLUGINCODEC_CONTROL_LOG_FUNCTION_INC 00595 { NULL } 00596 }; 00597 return ControlsTable; 00598 } 00599 00600 protected: 00601 const PluginCodec_Definition * m_definition; 00602 00603 bool m_optionsSame; 00604 unsigned m_maxBitRate; 00605 unsigned m_frameTime; 00606 }; 00607 00608 00609 #endif // OPAL_CODEC_OPALPLUGIN_HPP