00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
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 * )
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
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 OptionMap::iterator it = original.find(option);
00179 if (it != original.end() && it->second != value)
00180 changed[option] = value;
00181 }
00182
00183
00184 static unsigned String2Unsigned(const std::string & str)
00185 {
00186 return strtoul(str.c_str(), NULL, 10);
00187 }
00188
00189
00190 static void AppendUnsigned2String(unsigned value, std::string & str)
00191 {
00192
00193 if (value > 9)
00194 AppendUnsigned2String(value/10, str);
00195 str += (char)(value%10 + '0');
00196 }
00197
00198
00199 static void Unsigned2String(unsigned value, std::string & str)
00200 {
00201 str.clear();
00202 AppendUnsigned2String(value,str);
00203 }
00204
00205
00206 static void Change(unsigned value,
00207 OptionMap & original,
00208 OptionMap & changed,
00209 const char * option)
00210 {
00211 if (String2Unsigned(original[option]) != value)
00212 Unsigned2String(value, changed[option]);
00213 }
00214
00215
00216 static void ClampMax(unsigned maximum,
00217 OptionMap & original,
00218 OptionMap & changed,
00219 const char * option)
00220 {
00221 unsigned value = String2Unsigned(original[option]);
00222 if (value > maximum)
00223 Unsigned2String(maximum, changed[option]);
00224 }
00225
00226
00227 static void ClampMin(unsigned minimum,
00228 OptionMap & original,
00229 OptionMap & changed,
00230 const char * option)
00231 {
00232 unsigned value = String2Unsigned(original[option]);
00233 if (value < minimum)
00234 Unsigned2String(minimum, changed[option]);
00235 }
00236
00237 virtual void AdjustForVersion(unsigned version, const PluginCodec_Definition * )
00238 {
00239 if (version < PLUGIN_CODEC_VERSION_INTERSECT) {
00240 for (PluginCodec_Option ** options = (PluginCodec_Option **)m_options; *options != NULL; ++options) {
00241 if (strcmp((*options)->m_name, PLUGINCODEC_MEDIA_PACKETIZATIONS) == 0) {
00242 *options = NULL;
00243 break;
00244 }
00245 }
00246 }
00247 }
00248
00249 static void AdjustAllForVersion(unsigned version, const PluginCodec_Definition * definitions, size_t size)
00250 {
00251 while (size-- > 0) {
00252 PluginCodec_MediaFormat * info = (PluginCodec_MediaFormat *)definitions->userData;
00253 if (info != NULL)
00254 info->AdjustForVersion(version, definitions);
00255 ++definitions;
00256 }
00257 }
00258 };
00259
00260
00262
00263 template<typename NAME>
00264 class PluginCodec
00265 {
00266 protected:
00267 PluginCodec(const PluginCodec_Definition * defn)
00268 : m_definition(defn)
00269 , m_optionsSame(false)
00270 , m_maxBitRate(defn->bitsPerSec)
00271 , m_frameTime((defn->sampleRate/1000*defn->usPerFrame)/1000)
00272 {
00273 PTRACE(3, "Plugin", "Codec created: \"" << defn->descr
00274 << "\", \"" << defn->sourceFormat << "\" -> \"" << defn->destFormat << '"');
00275 }
00276
00277
00278 public:
00279 virtual ~PluginCodec()
00280 {
00281 }
00282
00283
00285 virtual bool Construct()
00286 {
00287 return true;
00288 }
00289
00290
00295 static bool Terminate()
00296 {
00297 return true;
00298 }
00299
00300
00302 virtual bool Transcode(const void * fromPtr,
00303 unsigned & fromLen,
00304 void * toPtr,
00305 unsigned & toLen,
00306 unsigned & flags) = 0;
00307
00308
00310 virtual bool GetStatistics(char * , unsigned )
00311 {
00312 return true;
00313 }
00314
00315
00317 virtual size_t GetOutputDataSize()
00318 {
00319 return 576-20-16;
00320 }
00321
00322
00329 virtual bool SetInstanceID(const char * , unsigned )
00330 {
00331 return true;
00332 }
00333
00334
00336 virtual bool SetOptions(const char * const * options)
00337 {
00338 m_optionsSame = true;
00339
00340
00341 for (const char * const * option = options; *option != NULL; option += 2) {
00342 if (!SetOption(option[0], option[1])) {
00343 PTRACE(1, "Plugin", "Could not set option \"" << option[0] << "\" to \"" << option[1] << '"');
00344 return false;
00345 }
00346 }
00347
00348 if (m_optionsSame)
00349 return true;
00350
00351 return OnChangedOptions();
00352 }
00353
00354
00356 virtual bool OnChangedOptions()
00357 {
00358 return true;
00359 }
00360
00361
00363 virtual bool SetOption(const char * optionName, const char * optionValue)
00364 {
00365 if (strcasecmp(optionName, PLUGINCODEC_OPTION_TARGET_BIT_RATE) == 0)
00366 return SetOptionUnsigned(m_maxBitRate, optionValue, 1, m_definition->bitsPerSec);
00367
00368 if (strcasecmp(optionName, PLUGINCODEC_OPTION_FRAME_TIME) == 0)
00369 return SetOptionUnsigned(m_frameTime, optionValue, m_definition->sampleRate/1000, m_definition->sampleRate);
00370
00371 return true;
00372 }
00373
00374
00375 template <typename T>
00376 bool SetOptionUnsigned(T & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX)
00377 {
00378 unsigned newValue = oldValue;
00379 if (!SetOptionUnsigned(newValue, optionValue, minimum, maximum))
00380 return false;
00381 oldValue = (T)newValue;
00382 return true;
00383 }
00384
00385
00386 bool SetOptionUnsigned(unsigned & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX)
00387 {
00388 char * end;
00389 unsigned newValue = strtoul(optionValue, &end, 10);
00390 if (*end != '\0')
00391 return false;
00392
00393 if (newValue < minimum)
00394 newValue = minimum;
00395 else if (newValue > maximum)
00396 newValue = maximum;
00397
00398 if (oldValue != newValue) {
00399 oldValue = newValue;
00400 m_optionsSame = false;
00401 }
00402
00403 return true;
00404 }
00405
00406
00407 template <typename T>
00408 bool SetOptionBoolean(T & oldValue, const char * optionValue)
00409 {
00410 bool opt = oldValue != 0;
00411 if (!SetOptionBoolean(opt, optionValue))
00412 return false;
00413 oldValue = (T)opt;
00414 return true;
00415 }
00416
00417
00418 bool SetOptionBoolean(bool & oldValue, const char * optionValue)
00419 {
00420 bool newValue;
00421 if ( strcasecmp(optionValue, "0") == 0 ||
00422 strcasecmp(optionValue, "n") == 0 ||
00423 strcasecmp(optionValue, "f") == 0 ||
00424 strcasecmp(optionValue, "no") == 0 ||
00425 strcasecmp(optionValue, "false") == 0)
00426 newValue = false;
00427 else if (strcasecmp(optionValue, "1") == 0 ||
00428 strcasecmp(optionValue, "y") == 0 ||
00429 strcasecmp(optionValue, "t") == 0 ||
00430 strcasecmp(optionValue, "yes") == 0 ||
00431 strcasecmp(optionValue, "true") == 0)
00432 newValue = true;
00433 else
00434 return false;
00435
00436 if (oldValue != newValue) {
00437 oldValue = newValue;
00438 m_optionsSame = false;
00439 }
00440
00441 return true;
00442 }
00443
00444
00445 bool SetOptionBit(int & oldValue, unsigned bit, const char * optionValue)
00446 {
00447 return SetOptionBit((unsigned &)oldValue, bit, optionValue);
00448 }
00449
00450
00451 bool SetOptionBit(unsigned & oldValue, unsigned bit, const char * optionValue)
00452 {
00453 bool newValue;
00454 if (strcmp(optionValue, "0") == 0)
00455 newValue = false;
00456 else if (strcmp(optionValue, "1") == 0)
00457 newValue = true;
00458 else
00459 return false;
00460
00461 if (((oldValue&bit) != 0) != newValue) {
00462 if (newValue)
00463 oldValue |= bit;
00464 else
00465 oldValue &= ~bit;
00466 m_optionsSame = false;
00467 }
00468
00469 return true;
00470 }
00471
00472
00473 template <class CodecClass> static void * Create(const PluginCodec_Definition * defn)
00474 {
00475 CodecClass * codec = new CodecClass(defn);
00476 if (codec != NULL && codec->Construct())
00477 return codec;
00478
00479 PTRACE(1, "Plugin", "Could not open codec, no context being returned.");
00480 delete codec;
00481 return NULL;
00482 }
00483
00484
00485 static void Destroy(const PluginCodec_Definition * , void * context)
00486 {
00487 delete (PluginCodec *)context;
00488 }
00489
00490
00491 static int Transcode(const PluginCodec_Definition * ,
00492 void * context,
00493 const void * fromPtr,
00494 unsigned * fromLen,
00495 void * toPtr,
00496 unsigned * toLen,
00497 unsigned int * flags)
00498 {
00499 if (context != NULL && fromPtr != NULL && fromLen != NULL && toPtr != NULL && toLen != NULL && flags != NULL)
00500 return ((PluginCodec *)context)->Transcode(fromPtr, *fromLen, toPtr, *toLen, *flags);
00501
00502 PTRACE(1, "Plugin", "Invalid parameter to Transcode.");
00503 return false;
00504 }
00505
00506
00507 static int GetOutputDataSize(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *)
00508 {
00509 return context != NULL ? ((PluginCodec *)context)->GetOutputDataSize() : 0;
00510 }
00511
00512
00513 static int ToNormalised(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
00514 {
00515 return defn->userData != NULL ? ((PluginCodec_MediaFormat *)defn->userData)->AdjustOptions(parm, len, &PluginCodec_MediaFormat::ToNormalised) : -1;
00516 }
00517
00518
00519 static int ToCustomised(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
00520 {
00521 return defn->userData != NULL ? ((PluginCodec_MediaFormat *)defn->userData)->AdjustOptions(parm, len, &PluginCodec_MediaFormat::ToCustomised) : -1;
00522 }
00523
00524
00525 static int FreeOptions(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len)
00526 {
00527 if (parm == NULL || len == NULL || *len != sizeof(char ***))
00528 return false;
00529
00530 char ** strings = (char **)parm;
00531 for (char ** string = strings; *string != NULL; string++)
00532 free(*string);
00533 free(strings);
00534 return true;
00535 }
00536
00537
00538 static int GetOptions(const struct PluginCodec_Definition * codec, void *, const char *, void * parm, unsigned * len)
00539 {
00540 if (parm == NULL || len == NULL || *len != sizeof(struct PluginCodec_Option **))
00541 return false;
00542
00543 *(const void **)parm = codec->userData != NULL ? ((PluginCodec_MediaFormat *)codec->userData)->GetOptionsTable() : NULL;
00544 *len = 0;
00545 return true;
00546 }
00547
00548
00549 static int SetOptions(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
00550 {
00551 PluginCodec * codec = (PluginCodec *)context;
00552 return len != NULL && *len == sizeof(const char **) && parm != NULL &&
00553 codec != NULL && codec->SetOptions((const char * const *)parm);
00554 }
00555
00556 static int ValidForProtocol(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
00557 {
00558 return len != NULL && *len == sizeof(const char *) && parm != NULL && defn->userData != NULL &&
00559 ((PluginCodec_MediaFormat *)defn->userData)->IsValidForProtocol((const char *)parm);
00560 }
00561
00562 static int SetInstanceID(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
00563 {
00564 PluginCodec * codec = (PluginCodec *)context;
00565 return len != NULL && parm != NULL &&
00566 codec != NULL && codec->SetInstanceID((const char *)parm, *len);
00567 }
00568
00569 static int GetStatistics(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
00570 {
00571 PluginCodec * codec = (PluginCodec *)context;
00572 return len != NULL && parm != NULL &&
00573 codec != NULL && codec->GetStatistics((char *)parm, *len);
00574 }
00575
00576 static int Terminate(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *)
00577 {
00578 PluginCodec * codec = (PluginCodec *)context;
00579 return codec != NULL && codec->Terminate();
00580 }
00581
00582 static struct PluginCodec_ControlDefn * GetControls()
00583 {
00584 static PluginCodec_ControlDefn ControlsTable[] = {
00585 { PLUGINCODEC_CONTROL_GET_OUTPUT_DATA_SIZE, PluginCodec::GetOutputDataSize },
00586 { PLUGINCODEC_CONTROL_TO_NORMALISED_OPTIONS, PluginCodec::ToNormalised },
00587 { PLUGINCODEC_CONTROL_TO_CUSTOMISED_OPTIONS, PluginCodec::ToCustomised },
00588 { PLUGINCODEC_CONTROL_SET_CODEC_OPTIONS, PluginCodec::SetOptions },
00589 { PLUGINCODEC_CONTROL_GET_CODEC_OPTIONS, PluginCodec::GetOptions },
00590 { PLUGINCODEC_CONTROL_FREE_CODEC_OPTIONS, PluginCodec::FreeOptions },
00591 { PLUGINCODEC_CONTROL_VALID_FOR_PROTOCOL, PluginCodec::ValidForProtocol },
00592 { PLUGINCODEC_CONTROL_SET_INSTANCE_ID, PluginCodec::SetInstanceID },
00593 { PLUGINCODEC_CONTROL_GET_STATISTICS, PluginCodec::GetStatistics },
00594 { PLUGINCODEC_CONTROL_TERMINATE_CODEC, PluginCodec::Terminate },
00595 PLUGINCODEC_CONTROL_LOG_FUNCTION_INC
00596 { NULL }
00597 };
00598 return ControlsTable;
00599 }
00600
00601 protected:
00602 const PluginCodec_Definition * m_definition;
00603
00604 bool m_optionsSame;
00605 unsigned m_maxBitRate;
00606 unsigned m_frameTime;
00607 };
00608
00609
00610 #endif // OPAL_CODEC_OPALPLUGIN_HPP