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_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
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;
00318 static unsigned const MinHeight = 3*16;
00319
00320 unsigned maxWidth = maxFrameSize*16*16/MinHeight;
00321 unsigned maxHeight = maxFrameSize*16*16/MinWidth;
00322
00323
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 * )
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 & , OptionMap & )
00470 {
00471 return true;
00472 }
00473
00474
00475
00476 virtual bool ToCustomised(OptionMap & , OptionMap & )
00477 {
00478 return true;
00479 }
00480
00481
00482 virtual void AdjustForVersion(unsigned version, const PluginCodec_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
00537 | PluginCodec_InputTypeRaw
00538 | PluginCodec_OutputTypeRaw;
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
00574 | PluginCodec_InputTypeRTP
00575 | PluginCodec_OutputTypeRTP;
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)
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 * , unsigned )
00634 {
00635 return true;
00636 }
00637
00638
00640 virtual size_t GetOutputDataSize()
00641 {
00642 return 576-20-16;
00643 }
00644
00645
00652 virtual bool SetInstanceID(const char * , unsigned )
00653 {
00654 return true;
00655 }
00656
00657
00659 virtual bool GetActiveOptions(PluginCodec_OptionMap & )
00660 {
00661 return false;
00662 }
00663
00664
00666 virtual bool SetOptions(const char * const * options)
00667 {
00668 this->m_optionsSame = true;
00669
00670
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);
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 * , void * context)
00817 {
00818 delete (PluginCodec *)context;
00819 }
00820
00821
00822 static int Transcode_s(const PluginCodec_Definition * ,
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,
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;
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)
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
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(), \
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(), \
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