OPAL Version 3.10.2
|
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: 25799 $ 00028 * $Author: rjongbloed $ 00029 * $Date: 2011-05-17 21:22:40 -0500 (Tue, 17 May 2011) $ 00030 */ 00031 00032 #ifndef OPAL_CODEC_OPALPLUGIN_HPP 00033 #define OPAL_CODEC_OPALPLUGIN_HPP 00034 00035 #include "opalplugin.h" 00036 00037 #include <string.h> 00038 #include <stdlib.h> 00039 #include <limits.h> 00040 00041 #include <map> 00042 #include <string> 00043 00044 00046 00047 #ifndef PLUGINCODEC_TRACING 00048 #define PLUGINCODEC_TRACING 1 00049 #endif 00050 00051 #if PLUGINCODEC_TRACING 00052 extern PluginCodec_LogFunction PluginCodec_LogFunctionInstance; 00053 extern int PluginCodec_SetLogFunction(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len); 00054 00055 #define PLUGINCODEC_CONTROL_LOG_FUNCTION_DEF \ 00056 PluginCodec_LogFunction PluginCodec_LogFunctionInstance; \ 00057 int PluginCodec_SetLogFunction(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len) \ 00058 { \ 00059 if (len == NULL || *len != sizeof(PluginCodec_LogFunction)) \ 00060 return false; \ 00061 \ 00062 PluginCodec_LogFunctionInstance = (PluginCodec_LogFunction)parm; \ 00063 if (PluginCodec_LogFunctionInstance != NULL) \ 00064 PluginCodec_LogFunctionInstance(4, __FILE__, __LINE__, "Plugin", "Started logging."); \ 00065 \ 00066 return true; \ 00067 } \ 00068 00069 #define PLUGINCODEC_CONTROL_LOG_FUNCTION_INC { PLUGINCODEC_CONTROL_SET_LOG_FUNCTION, PluginCodec_SetLogFunction }, 00070 #else 00071 #define PLUGINCODEC_CONTROL_LOG_FUNCTION_DEF 00072 #define PLUGINCODEC_CONTROL_LOG_FUNCTION_INC 00073 #endif 00074 00075 #if !defined(PTRACE) 00076 #if PLUGINCODEC_TRACING 00077 #include <sstream> 00078 #define PTRACE_CHECK(level) \ 00079 (PluginCodec_LogFunctionInstance != NULL && PluginCodec_LogFunctionInstance(level, NULL, 0, NULL, NULL)) 00080 #define PTRACE(level, section, args) \ 00081 if (PTRACE_CHECK(level)) { \ 00082 std::ostringstream strm; strm << args; \ 00083 PluginCodec_LogFunctionInstance(level, __FILE__, __LINE__, section, strm.str().c_str()); \ 00084 } else (void)0 00085 #else 00086 #define PTRACE_CHECK(level) 00087 #define PTRACE(level, section, expr) 00088 #endif 00089 #endif 00090 00091 00093 00094 class PluginCodec_MediaFormat 00095 { 00096 public: 00097 typedef struct PluginCodec_Option const * const * OptionsTable; 00098 typedef std::map<std::string, std::string> OptionMap; 00099 00100 protected: 00101 OptionsTable m_options; 00102 00103 protected: 00104 PluginCodec_MediaFormat(OptionsTable options) 00105 : m_options(options) 00106 { 00107 } 00108 00109 public: 00110 virtual ~PluginCodec_MediaFormat() 00111 { 00112 } 00113 00114 00115 const void * GetOptionsTable() const { return m_options; } 00116 00118 virtual bool IsValidForProtocol(const char * /*protocol*/) 00119 { 00120 return true; 00121 } 00122 00123 00125 bool AdjustOptions(void * parm, unsigned * parmLen, bool (PluginCodec_MediaFormat:: * adjuster)(OptionMap & original, OptionMap & changed)) 00126 { 00127 if (parmLen == NULL || parm == NULL || *parmLen != sizeof(char ***)) 00128 return false; 00129 00130 OptionMap originalOptions; 00131 for (const char * const * option = *(const char * const * *)parm; *option != NULL; option += 2) 00132 originalOptions[option[0]] = option[1]; 00133 00134 OptionMap changedOptions; 00135 if (!(this->*adjuster)(originalOptions, changedOptions)) 00136 return false; 00137 00138 char ** options = (char **)calloc(changedOptions.size()*2+1, sizeof(char *)); 00139 *(char ***)parm = options; 00140 if (options == NULL) 00141 return false; 00142 00143 for (OptionMap::iterator i = changedOptions.begin(); i != changedOptions.end(); ++i) { 00144 *options++ = strdup(i->first.c_str()); 00145 *options++ = strdup(i->second.c_str()); 00146 } 00147 00148 return true; 00149 } 00150 00151 00153 virtual bool ToNormalised(OptionMap & original, OptionMap & changed) = 0; 00154 00155 00156 // Adjust codec specific options calculated from normalised options. 00157 virtual bool ToCustomised(OptionMap & original, OptionMap & changed) = 0; 00158 00159 00160 static void Change(const char * value, 00161 OptionMap & original, 00162 OptionMap & changed, 00163 const char * option) 00164 { 00165 if (original[option] != value) 00166 changed[option] = value; 00167 } 00168 00169 00170 static unsigned String2Unsigned(const std::string & str) 00171 { 00172 return strtoul(str.c_str(), NULL, 10); 00173 } 00174 00175 00176 static void Unsigned2String(unsigned value, std::string & str) 00177 { 00178 // Not very efficient, but really, really simple 00179 if (value > 9) 00180 Unsigned2String(value/10, str); 00181 str += (char)(value%10 + '0'); 00182 } 00183 00184 00185 static void Change(unsigned value, 00186 OptionMap & original, 00187 OptionMap & changed, 00188 const char * option) 00189 { 00190 if (String2Unsigned(original[option]) != value) 00191 Unsigned2String(value, changed[option]); 00192 } 00193 00194 00195 static void ClampMax(unsigned maximum, 00196 OptionMap & original, 00197 OptionMap & changed, 00198 const char * option) 00199 { 00200 unsigned value = String2Unsigned(original[option]); 00201 if (value > maximum) 00202 Unsigned2String(maximum, changed[option]); 00203 } 00204 00205 00206 static void ClampMin(unsigned minimum, 00207 OptionMap & original, 00208 OptionMap & changed, 00209 const char * option) 00210 { 00211 unsigned value = String2Unsigned(original[option]); 00212 if (value < minimum) 00213 Unsigned2String(minimum, changed[option]); 00214 } 00215 }; 00216 00217 00219 00220 template<typename NAME> 00221 class PluginCodec 00222 { 00223 protected: 00224 PluginCodec(const PluginCodec_Definition * defn) 00225 : m_definition(defn) 00226 , m_optionsSame(false) 00227 , m_maxBitRate(defn->bitsPerSec) 00228 , m_frameTime((defn->sampleRate/1000*defn->usPerFrame)/1000) // Odd way of calculation to avoid 32 bit integer overflow 00229 { 00230 PTRACE(3, "Plugin", "Codec created: \"" << defn->descr 00231 << "\", \"" << defn->sourceFormat << "\" -> \"" << defn->destFormat << '"'); 00232 } 00233 00234 00235 public: 00236 virtual ~PluginCodec() 00237 { 00238 } 00239 00240 00242 virtual bool Construct() 00243 { 00244 return true; 00245 } 00246 00247 00252 static bool Terminate() 00253 { 00254 return true; 00255 } 00256 00257 00259 virtual bool Transcode(const void * fromPtr, 00260 unsigned & fromLen, 00261 void * toPtr, 00262 unsigned & toLen, 00263 unsigned & flags) = 0; 00264 00265 00267 virtual bool GetStatistics(char * /*bufferPtr*/, unsigned /*bufferSize*/) 00268 { 00269 return true; 00270 } 00271 00272 00274 virtual size_t GetOutputDataSize() 00275 { 00276 return 576-20-16; // Max safe MTU size (576 bytes as per RFC879) minus IP & UDP headers 00277 } 00278 00279 00286 virtual bool SetInstanceID(const char * /*idPtr*/, unsigned /*idLen*/) 00287 { 00288 return true; 00289 } 00290 00291 00293 virtual bool SetOptions(const char * const * options) 00294 { 00295 m_optionsSame = true; 00296 00297 // get the media format options after adjustment from protocol negotiation 00298 for (const char * const * option = options; *option != NULL; option += 2) { 00299 if (!SetOption(option[0], option[1])) 00300 return false; 00301 } 00302 00303 if (m_optionsSame) 00304 return true; 00305 00306 return OnChangedOptions(); 00307 } 00308 00309 00311 virtual bool OnChangedOptions() 00312 { 00313 return true; 00314 } 00315 00316 00318 virtual bool SetOption(const char * optionName, const char * optionValue) 00319 { 00320 if (strcasecmp(optionName, PLUGINCODEC_OPTION_TARGET_BIT_RATE) == 0) 00321 return SetOptionUnsigned(m_maxBitRate, optionValue, 1, m_definition->bitsPerSec); 00322 00323 if (strcasecmp(optionName, PLUGINCODEC_OPTION_FRAME_TIME) == 0) 00324 return SetOptionUnsigned(m_frameTime, optionValue, m_definition->sampleRate/1000, m_definition->sampleRate); // 1ms to 1 second 00325 00326 return true; 00327 } 00328 00329 00330 template <typename T> 00331 bool SetOptionUnsigned(T & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX) 00332 { 00333 unsigned newValue = oldValue; 00334 if (!SetOptionUnsigned(newValue, optionValue, minimum, maximum)) 00335 return false; 00336 oldValue = (T)newValue; 00337 return true; 00338 } 00339 00340 00341 bool SetOptionUnsigned(unsigned & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX) 00342 { 00343 char * end; 00344 unsigned newValue = strtoul(optionValue, &end, 10); 00345 if (*end != '\0') 00346 return false; 00347 00348 if (newValue < minimum) 00349 newValue = minimum; 00350 else if (newValue > maximum) 00351 newValue = maximum; 00352 00353 if (oldValue != newValue) { 00354 oldValue = newValue; 00355 m_optionsSame = false; 00356 } 00357 00358 return true; 00359 } 00360 00361 00362 template <typename T> 00363 bool SetOptionBoolean(T & oldValue, const char * optionValue) 00364 { 00365 bool opt = oldValue != 0; 00366 if (!SetOptionBoolean(opt, optionValue)) 00367 return false; 00368 oldValue = (T)opt; 00369 return true; 00370 } 00371 00372 00373 bool SetOptionBoolean(bool & oldValue, const char * optionValue) 00374 { 00375 bool newValue; 00376 if (strcmp(optionValue, "0") == 0) 00377 newValue = false; 00378 else if (strcmp(optionValue, "1") == 0) 00379 newValue = true; 00380 else 00381 return false; 00382 00383 if (oldValue != newValue) { 00384 oldValue = newValue; 00385 m_optionsSame = false; 00386 } 00387 00388 return true; 00389 } 00390 00391 00392 bool SetOptionBit(int & oldValue, unsigned bit, const char * optionValue) 00393 { 00394 return SetOptionBit((unsigned &)oldValue, bit, optionValue); 00395 } 00396 00397 00398 bool SetOptionBit(unsigned & oldValue, unsigned bit, const char * optionValue) 00399 { 00400 bool newValue; 00401 if (strcmp(optionValue, "0") == 0) 00402 newValue = false; 00403 else if (strcmp(optionValue, "1") == 0) 00404 newValue = true; 00405 else 00406 return false; 00407 00408 if (((oldValue&bit) != 0) != newValue) { 00409 if (newValue) 00410 oldValue |= bit; 00411 else 00412 oldValue &= ~bit; 00413 m_optionsSame = false; 00414 } 00415 00416 return true; 00417 } 00418 00419 00420 template <class CodecClass> static void * Create(const PluginCodec_Definition * defn) 00421 { 00422 CodecClass * codec = new CodecClass(defn); 00423 if (codec != NULL && codec->Construct()) 00424 return codec; 00425 00426 PTRACE(1, "Plugin", "Could not open codec, no context being returned."); 00427 delete codec; 00428 return NULL; 00429 } 00430 00431 00432 static void Destroy(const PluginCodec_Definition * /*defn*/, void * context) 00433 { 00434 delete (PluginCodec *)context; 00435 } 00436 00437 00438 static int Transcode(const PluginCodec_Definition * /*defn*/, 00439 void * context, 00440 const void * fromPtr, 00441 unsigned * fromLen, 00442 void * toPtr, 00443 unsigned * toLen, 00444 unsigned int * flags) 00445 { 00446 if (context != NULL && fromPtr != NULL && fromLen != NULL && toPtr != NULL && toLen != NULL && flags != NULL) 00447 return ((PluginCodec *)context)->Transcode(fromPtr, *fromLen, toPtr, *toLen, *flags); 00448 00449 PTRACE(1, "Plugin", "Invalid parameter to Transcode."); 00450 return false; 00451 } 00452 00453 00454 static int GetOutputDataSize(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *) 00455 { 00456 return context != NULL ? ((PluginCodec *)context)->GetOutputDataSize() : 0; 00457 } 00458 00459 00460 static int ToNormalised(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len) 00461 { 00462 return defn->userData != NULL ? ((PluginCodec_MediaFormat *)defn->userData)->AdjustOptions(parm, len, &PluginCodec_MediaFormat::ToNormalised) : -1; 00463 } 00464 00465 00466 static int ToCustomised(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len) 00467 { 00468 return defn->userData != NULL ? ((PluginCodec_MediaFormat *)defn->userData)->AdjustOptions(parm, len, &PluginCodec_MediaFormat::ToCustomised) : -1; 00469 } 00470 00471 00472 static int FreeOptions(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len) 00473 { 00474 if (parm == NULL || len == NULL || *len != sizeof(char ***)) 00475 return false; 00476 00477 char ** strings = (char **)parm; 00478 for (char ** string = strings; *string != NULL; string++) 00479 free(*string); 00480 free(strings); 00481 return true; 00482 } 00483 00484 00485 static int GetOptions(const struct PluginCodec_Definition * codec, void *, const char *, void * parm, unsigned * len) 00486 { 00487 if (parm == NULL || len == NULL || *len != sizeof(struct PluginCodec_Option **)) 00488 return false; 00489 00490 *(const void **)parm = codec->userData != NULL ? ((PluginCodec_MediaFormat *)codec->userData)->GetOptionsTable() : NULL; 00491 *len = 0; 00492 return true; 00493 } 00494 00495 00496 static int SetOptions(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len) 00497 { 00498 PluginCodec * codec = (PluginCodec *)context; 00499 return len != NULL && *len == sizeof(const char **) && parm != NULL && 00500 codec != NULL && codec->SetOptions((const char * const *)parm); 00501 } 00502 00503 static int ValidForProtocol(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len) 00504 { 00505 return len != NULL && *len == sizeof(const char *) && parm != NULL && defn->userData != NULL && 00506 ((PluginCodec_MediaFormat *)defn->userData)->IsValidForProtocol((const char *)parm); 00507 } 00508 00509 static int SetInstanceID(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len) 00510 { 00511 PluginCodec * codec = (PluginCodec *)context; 00512 return len != NULL && parm != NULL && 00513 codec != NULL && codec->SetInstanceID((const char *)parm, *len); 00514 } 00515 00516 static int GetStatistics(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len) 00517 { 00518 PluginCodec * codec = (PluginCodec *)context; 00519 return len != NULL && parm != NULL && 00520 codec != NULL && codec->GetStatistics((char *)parm, *len); 00521 } 00522 00523 static int Terminate(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *) 00524 { 00525 PluginCodec * codec = (PluginCodec *)context; 00526 return codec != NULL && codec->Terminate(); 00527 } 00528 00529 static struct PluginCodec_ControlDefn * GetControls() 00530 { 00531 static PluginCodec_ControlDefn ControlsTable[] = { 00532 { PLUGINCODEC_CONTROL_GET_OUTPUT_DATA_SIZE, PluginCodec::GetOutputDataSize }, 00533 { PLUGINCODEC_CONTROL_TO_NORMALISED_OPTIONS, PluginCodec::ToNormalised }, 00534 { PLUGINCODEC_CONTROL_TO_CUSTOMISED_OPTIONS, PluginCodec::ToCustomised }, 00535 { PLUGINCODEC_CONTROL_SET_CODEC_OPTIONS, PluginCodec::SetOptions }, 00536 { PLUGINCODEC_CONTROL_GET_CODEC_OPTIONS, PluginCodec::GetOptions }, 00537 { PLUGINCODEC_CONTROL_FREE_CODEC_OPTIONS, PluginCodec::FreeOptions }, 00538 { PLUGINCODEC_CONTROL_VALID_FOR_PROTOCOL, PluginCodec::ValidForProtocol }, 00539 { PLUGINCODEC_CONTROL_SET_INSTANCE_ID, PluginCodec::SetInstanceID }, 00540 { PLUGINCODEC_CONTROL_GET_STATISTICS, PluginCodec::GetStatistics }, 00541 { PLUGINCODEC_CONTROL_TERMINATE_CODEC, PluginCodec::Terminate }, 00542 PLUGINCODEC_CONTROL_LOG_FUNCTION_INC 00543 { NULL } 00544 }; 00545 return ControlsTable; 00546 } 00547 00548 protected: 00549 const PluginCodec_Definition * m_definition; 00550 00551 bool m_optionsSame; 00552 unsigned m_maxBitRate; 00553 unsigned m_frameTime; 00554 }; 00555 00556 00557 #endif // OPAL_CODEC_OPALPLUGIN_HPP