OPAL Version 3.10.4

- Main Page
- Related Pages
- Namespaces
- Data Structures
- Files

- File List
- Globals

opalplugin.hpp
Go to the documentation of this file.
1 /*
2 * opalplugins.hpp
3 *
4 * OPAL codec plugins handler (C++ version)
5 *
6 * Open Phone Abstraction Library (OPAL)
7 * Formally known as the Open H323 project.
8 *
9 * Copyright (C) 2010 Vox Lucida
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * - Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17
18 * - Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 * $Revision: 26787 $
35 * $Author: rjongbloed $
36 * $Date: 2011-12-08 18:49:50 -0600 (Thu, 08 Dec 2011) $
37 */
38
39 #ifndef OPAL_CODEC_OPALPLUGIN_HPP
40 #define OPAL_CODEC_OPALPLUGIN_HPP
41
42 #include "opalplugin.h"
43
44 #include <string.h>
45 #include <stdlib.h>
46 #include <limits.h>
47
48 #include <map>
49 #include <string>
50
51
53
54 #ifndef PLUGINCODEC_TRACING
55 #define PLUGINCODEC_TRACING 1
56 #endif
57
58 #if PLUGINCODEC_TRACING
59 extern PluginCodec_LogFunction PluginCodec_LogFunctionInstance;
60 extern int PluginCodec_SetLogFunction(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len);
61
62 #define PLUGINCODEC_CONTROL_LOG_FUNCTION_DEF \
63 PluginCodec_LogFunction PluginCodec_LogFunctionInstance; \
64 int PluginCodec_SetLogFunction(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len) \
65 { \
66 if (len == NULL || *len != sizeof(PluginCodec_LogFunction)) \
67 return false; \
68 \
69 PluginCodec_LogFunctionInstance = (PluginCodec_LogFunction)parm; \
70 if (PluginCodec_LogFunctionInstance != NULL) \
71 PluginCodec_LogFunctionInstance(4, __FILE__, __LINE__, "Plugin", "Started logging."); \
72 \
73 return true; \
74 } \
75
76 #define PLUGINCODEC_CONTROL_LOG_FUNCTION_INC { PLUGINCODEC_CONTROL_SET_LOG_FUNCTION, PluginCodec_SetLogFunction },
77 #else
78 #define PLUGINCODEC_CONTROL_LOG_FUNCTION_DEF
79 #define PLUGINCODEC_CONTROL_LOG_FUNCTION_INC
80 #endif
81
82 #if !defined(PTRACE)
83 #if PLUGINCODEC_TRACING
84 #include <sstream>
85 #define PTRACE_CHECK(level) \
86 (PluginCodec_LogFunctionInstance != NULL && PluginCodec_LogFunctionInstance(level, NULL, 0, NULL, NULL))
87 #define PTRACE(level, section, args) \
88 if (PTRACE_CHECK(level)) { \
89 std::ostringstream strm; strm << args; \
90 PluginCodec_LogFunctionInstance(level, __FILE__, __LINE__, section, strm.str().c_str()); \
91 } else (void)0
92 #else
93 #define PTRACE_CHECK(level)
94 #define PTRACE(level, section, expr)
95 #endif
96 #endif
97
98
100
101 class PluginCodec_MediaFormat
102 {
103 public:
104 typedef struct PluginCodec_Option const * const * OptionsTable;
105 typedef std::map<std::string, std::string> OptionMap;
106
107 protected:
108 OptionsTable m_options;
109
110 protected:
111 PluginCodec_MediaFormat(OptionsTable options)
112 : m_options(options)
113 {
114 }
115
116 public:
117 virtual ~PluginCodec_MediaFormat()
118 {
119 }
120
121
122 const void * GetOptionsTable() const { return m_options; }
123
125 virtual bool IsValidForProtocol(const char * /*protocol*/)
126 {
127 return true;
128 }
129
130
132 bool AdjustOptions(void * parm, unsigned * parmLen, bool (PluginCodec_MediaFormat:: * adjuster)(OptionMap & original, OptionMap & changed))
133 {
134 if (parmLen == NULL || parm == NULL || *parmLen != sizeof(char ***)) {
135 PTRACE(1, "Plugin", "Invalid parameters to AdjustOptions.");
136 return false;
137 }
138
139 OptionMap originalOptions;
140 for (const char * const * option = *(const char * const * *)parm; *option != NULL; option += 2)
141 originalOptions[option[0]] = option[1];
142
143 OptionMap changedOptions;
144 if (!(this->*adjuster)(originalOptions, changedOptions)) {
145 PTRACE(1, "Plugin", "Could not normalise/customise options.");
146 return false;
147 }
148
149 char ** options = (char **)calloc(changedOptions.size()*2+1, sizeof(char *));
150 *(char ***)parm = options;
151 if (options == NULL) {
152 PTRACE(1, "Plugin", "Could not allocate new option lists.");
153 return false;
154 }
155
156 for (OptionMap::iterator i = changedOptions.begin(); i != changedOptions.end(); ++i) {
157 *options++ = strdup(i->first.c_str());
158 *options++ = strdup(i->second.c_str());
159 }
160
161 return true;
162 }
163
164
166 virtual bool ToNormalised(OptionMap & original, OptionMap & changed) = 0;
167
168
169 // Adjust codec specific options calculated from normalised options.
170 virtual bool ToCustomised(OptionMap & original, OptionMap & changed) = 0;
171
172
173 static void Change(const char * value,
174 OptionMap & original,
175 OptionMap & changed,
176 const char * option)
177 {
178 if (original[option] != value)
179 changed[option] = value;
180 }
181
182
183 static unsigned String2Unsigned(const std::string & str)
184 {
185 return strtoul(str.c_str(), NULL, 10);
186 }
187
188
189 static void AppendUnsigned2String(unsigned value, std::string & str)
190 {
191 // Not very efficient, but really, really simple
192 if (value > 9)
193 AppendUnsigned2String(value/10, str);
194 str += (char)(value%10 + '0');
195 }
196
197
198 static void Unsigned2String(unsigned value, std::string & str)
199 {
200 str.clear();
201 AppendUnsigned2String(value,str);
202 }
203
204
205 static void Change(unsigned value,
206 OptionMap & original,
207 OptionMap & changed,
208 const char * option)
209 {
210 if (String2Unsigned(original[option]) != value)
211 Unsigned2String(value, changed[option]);
212 }
213
214
215 static void ClampMax(unsigned maximum,
216 OptionMap & original,
217 OptionMap & changed,
218 const char * option)
219 {
220 unsigned value = String2Unsigned(original[option]);
221 if (value > maximum)
222 Unsigned2String(maximum, changed[option]);
223 }
224
225
226 static void ClampMin(unsigned minimum,
227 OptionMap & original,
228 OptionMap & changed,
229 const char * option)
230 {
231 unsigned value = String2Unsigned(original[option]);
232 if (value < minimum)
233 Unsigned2String(minimum, changed[option]);
234 }
235
236 virtual void AdjustForVersion(unsigned version, const PluginCodec_Definition * /*definition*/)
237 {
238 if (version < PLUGIN_CODEC_VERSION_INTERSECT) {
239 for (PluginCodec_Option ** options = (PluginCodec_Option **)m_options; *options != NULL; ++options) {
240 if (strcmp((*options)->m_name, PLUGINCODEC_MEDIA_PACKETIZATIONS) == 0) {
241 *options = NULL;
242 break;
243 }
244 }
245 }
246 }
247
248 static void AdjustAllForVersion(unsigned version, const PluginCodec_Definition * definitions, size_t size)
249 {
250 while (size-- > 0) {
251 PluginCodec_MediaFormat * info = (PluginCodec_MediaFormat *)definitions->userData;
252 if (info != NULL)
253 info->AdjustForVersion(version, definitions);
254 ++definitions;
255 }
256 }
257 };
258
259
261
262 template<typename NAME>
263 class PluginCodec
264 {
265 protected:
266 PluginCodec(const PluginCodec_Definition * defn)
267 : m_definition(defn)
268 , m_optionsSame(false)
269 , m_maxBitRate(defn->bitsPerSec)
270 , m_frameTime((defn->sampleRate/1000*defn->usPerFrame)/1000) // Odd way of calculation to avoid 32 bit integer overflow
271 {
272 PTRACE(3, "Plugin", "Codec created: \"" << defn->descr
273 << "\", \"" << defn->sourceFormat << "\" -> \"" << defn->destFormat << '"');
274 }
275
276
277 public:
278 virtual ~PluginCodec()
279 {
280 }
281
282
284 virtual bool Construct()
285 {
286 return true;
287 }
288
289
294 static bool Terminate()
295 {
296 return true;
297 }
298
299
301 virtual bool Transcode(const void * fromPtr,
302 unsigned & fromLen,
303 void * toPtr,
304 unsigned & toLen,
305 unsigned & flags) = 0;
306
307
309 virtual bool GetStatistics(char * /*bufferPtr*/, unsigned /*bufferSize*/)
310 {
311 return true;
312 }
313
314
316 virtual size_t GetOutputDataSize()
317 {
318 return 576-20-16; // Max safe MTU size (576 bytes as per RFC879) minus IP & UDP headers
319 }
320
321
328 virtual bool SetInstanceID(const char * /*idPtr*/, unsigned /*idLen*/)
329 {
330 return true;
331 }
332
333
335 virtual bool SetOptions(const char * const * options)
336 {
337 m_optionsSame = true;
338
339 // get the media format options after adjustment from protocol negotiation
340 for (const char * const * option = options; *option != NULL; option += 2) {
341 if (!SetOption(option[0], option[1])) {
342 PTRACE(1, "Plugin", "Could not set option \"" << option[0] << "\" to \"" << option[1] << '"');
343 return false;
344 }
345 }
346
347 if (m_optionsSame)
348 return true;
349
350 return OnChangedOptions();
351 }
352
353
355 virtual bool OnChangedOptions()
356 {
357 return true;
358 }
359
360
362 virtual bool SetOption(const char * optionName, const char * optionValue)
363 {
364 if (strcasecmp(optionName, PLUGINCODEC_OPTION_TARGET_BIT_RATE) == 0)
365 return SetOptionUnsigned(m_maxBitRate, optionValue, 1, m_definition->bitsPerSec);
366
367 if (strcasecmp(optionName, PLUGINCODEC_OPTION_FRAME_TIME) == 0)
368 return SetOptionUnsigned(m_frameTime, optionValue, m_definition->sampleRate/1000, m_definition->sampleRate); // 1ms to 1 second
369
370 return true;
371 }
372
373
374 template <typename T>
375 bool SetOptionUnsigned(T & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX)
376 {
377 unsigned newValue = oldValue;
378 if (!SetOptionUnsigned(newValue, optionValue, minimum, maximum))
379 return false;
380 oldValue = (T)newValue;
381 return true;
382 }
383
384
385 bool SetOptionUnsigned(unsigned & oldValue, const char * optionValue, unsigned minimum, unsigned maximum = UINT_MAX)
386 {
387 char * end;
388 unsigned newValue = strtoul(optionValue, &end, 10);
389 if (*end != '\0')
390 return false;
391
392 if (newValue < minimum)
393 newValue = minimum;
394 else if (newValue > maximum)
395 newValue = maximum;
396
397 if (oldValue != newValue) {
398 oldValue = newValue;
399 m_optionsSame = false;
400 }
401
402 return true;
403 }
404
405
406 template <typename T>
407 bool SetOptionBoolean(T & oldValue, const char * optionValue)
408 {
409 bool opt = oldValue != 0;
410 if (!SetOptionBoolean(opt, optionValue))
411 return false;
412 oldValue = (T)opt;
413 return true;
414 }
415
416
417 bool SetOptionBoolean(bool & oldValue, const char * optionValue)
418 {
419 bool newValue;
420 if ( strcasecmp(optionValue, "0") == 0 ||
421 strcasecmp(optionValue, "n") == 0 ||
422 strcasecmp(optionValue, "f") == 0 ||
423 strcasecmp(optionValue, "no") == 0 ||
424 strcasecmp(optionValue, "false") == 0)
425 newValue = false;
426 else if (strcasecmp(optionValue, "1") == 0 ||
427 strcasecmp(optionValue, "y") == 0 ||
428 strcasecmp(optionValue, "t") == 0 ||
429 strcasecmp(optionValue, "yes") == 0 ||
430 strcasecmp(optionValue, "true") == 0)
431 newValue = true;
432 else
433 return false;
434
435 if (oldValue != newValue) {
436 oldValue = newValue;
437 m_optionsSame = false;
438 }
439
440 return true;
441 }
442
443
444 bool SetOptionBit(int & oldValue, unsigned bit, const char * optionValue)
445 {
446 return SetOptionBit((unsigned &)oldValue, bit, optionValue);
447 }
448
449
450 bool SetOptionBit(unsigned & oldValue, unsigned bit, const char * optionValue)
451 {
452 bool newValue;
453 if (strcmp(optionValue, "0") == 0)
454 newValue = false;
455 else if (strcmp(optionValue, "1") == 0)
456 newValue = true;
457 else
458 return false;
459
460 if (((oldValue&bit) != 0) != newValue) {
461 if (newValue)
462 oldValue |= bit;
463 else
464 oldValue &= ~bit;
465 m_optionsSame = false;
466 }
467
468 return true;
469 }
470
471
472 template <class CodecClass> static void * Create(const PluginCodec_Definition * defn)
473 {
474 CodecClass * codec = new CodecClass(defn);
475 if (codec != NULL && codec->Construct())
476 return codec;
477
478 PTRACE(1, "Plugin", "Could not open codec, no context being returned.");
479 delete codec;
480 return NULL;
481 }
482
483
484 static void Destroy(const PluginCodec_Definition * /*defn*/, void * context)
485 {
486 delete (PluginCodec *)context;
487 }
488
489
490 static int Transcode(const PluginCodec_Definition * /*defn*/,
491 void * context,
492 const void * fromPtr,
493 unsigned * fromLen,
494 void * toPtr,
495 unsigned * toLen,
496 unsigned int * flags)
497 {
498 if (context != NULL && fromPtr != NULL && fromLen != NULL && toPtr != NULL && toLen != NULL && flags != NULL)
499 return ((PluginCodec *)context)->Transcode(fromPtr, *fromLen, toPtr, *toLen, *flags);
500
501 PTRACE(1, "Plugin", "Invalid parameter to Transcode.");
502 return false;
503 }
504
505
506 static int GetOutputDataSize(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *)
507 {
508 return context != NULL ? ((PluginCodec *)context)->GetOutputDataSize() : 0;
509 }
510
511
512 static int ToNormalised(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
513 {
514 return defn->userData != NULL ? ((PluginCodec_MediaFormat *)defn->userData)->AdjustOptions(parm, len, &PluginCodec_MediaFormat::ToNormalised) : -1;
515 }
516
517
518 static int ToCustomised(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
519 {
520 return defn->userData != NULL ? ((PluginCodec_MediaFormat *)defn->userData)->AdjustOptions(parm, len, &PluginCodec_MediaFormat::ToCustomised) : -1;
521 }
522
523
524 static int FreeOptions(const PluginCodec_Definition *, void *, const char *, void * parm, unsigned * len)
525 {
526 if (parm == NULL || len == NULL || *len != sizeof(char ***))
527 return false;
528
529 char ** strings = (char **)parm;
530 for (char ** string = strings; *string != NULL; string++)
531 free(*string);
532 free(strings);
533 return true;
534 }
535
536
537 static int GetOptions(const struct PluginCodec_Definition * codec, void *, const char *, void * parm, unsigned * len)
538 {
539 if (parm == NULL || len == NULL || *len != sizeof(struct PluginCodec_Option **))
540 return false;
541
542 *(const void **)parm = codec->userData != NULL ? ((PluginCodec_MediaFormat *)codec->userData)->GetOptionsTable() : NULL;
543 *len = 0;
544 return true;
545 }
546
547
548 static int SetOptions(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
549 {
550 PluginCodec * codec = (PluginCodec *)context;
551 return len != NULL && *len == sizeof(const char **) && parm != NULL &&
552 codec != NULL && codec->SetOptions((const char * const *)parm);
553 }
554
555 static int ValidForProtocol(const PluginCodec_Definition * defn, void *, const char *, void * parm, unsigned * len)
556 {
557 return len != NULL && *len == sizeof(const char *) && parm != NULL && defn->userData != NULL &&
558 ((PluginCodec_MediaFormat *)defn->userData)->IsValidForProtocol((const char *)parm);
559 }
560
561 static int SetInstanceID(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
562 {
563 PluginCodec * codec = (PluginCodec *)context;
564 return len != NULL && parm != NULL &&
565 codec != NULL && codec->SetInstanceID((const char *)parm, *len);
566 }
567
568 static int GetStatistics(const PluginCodec_Definition *, void * context, const char *, void * parm, unsigned * len)
569 {
570 PluginCodec * codec = (PluginCodec *)context;
571 return len != NULL && parm != NULL &&
572 codec != NULL && codec->GetStatistics((char *)parm, *len);
573 }
574
575 static int Terminate(const PluginCodec_Definition *, void * context, const char *, void *, unsigned *)
576 {
577 PluginCodec * codec = (PluginCodec *)context;
578 return codec != NULL && codec->Terminate();
579 }
580
581 static struct PluginCodec_ControlDefn * GetControls()
582 {
583 static PluginCodec_ControlDefn ControlsTable[] = {
584 { PLUGINCODEC_CONTROL_GET_OUTPUT_DATA_SIZE, PluginCodec::GetOutputDataSize },
585 { PLUGINCODEC_CONTROL_TO_NORMALISED_OPTIONS, PluginCodec::ToNormalised },
586 { PLUGINCODEC_CONTROL_TO_CUSTOMISED_OPTIONS, PluginCodec::ToCustomised },
587 { PLUGINCODEC_CONTROL_SET_CODEC_OPTIONS, PluginCodec::SetOptions },
588 { PLUGINCODEC_CONTROL_GET_CODEC_OPTIONS, PluginCodec::GetOptions },
589 { PLUGINCODEC_CONTROL_FREE_CODEC_OPTIONS, PluginCodec::FreeOptions },
590 { PLUGINCODEC_CONTROL_VALID_FOR_PROTOCOL, PluginCodec::ValidForProtocol },
591 { PLUGINCODEC_CONTROL_SET_INSTANCE_ID, PluginCodec::SetInstanceID },
592 { PLUGINCODEC_CONTROL_GET_STATISTICS, PluginCodec::GetStatistics },
593 { PLUGINCODEC_CONTROL_TERMINATE_CODEC, PluginCodec::Terminate },
594 PLUGINCODEC_CONTROL_LOG_FUNCTION_INC
595 { NULL }
596 };
597 return ControlsTable;
598 }
599
600 protected:
601 const PluginCodec_Definition * m_definition;
602
603 bool m_optionsSame;
604 unsigned m_maxBitRate;
605 unsigned m_frameTime;
606 };
607
608
609 #endif // OPAL_CODEC_OPALPLUGIN_HPP