Fixed issue where OpalMediaOptions are lost when an OpalMediaFormat
[opal.git] / src / opal / mediafmt.cxx
blobfb0a28e4f298d7bd0ddbc7bfa47c4abf020cf751
1 /*
2 * mediafmt.cxx
4 * Media Format descriptions
6 * Open H323 Library
8 * Copyright (c) 1999-2000 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Open H323 Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 2.72 2007/09/07 05:40:12 rjongbloed
28 * Fixed issue where OpalMediaOptions are lost when an OpalMediaFormat
29 * is added to an OpalMediaFormatList.
30 * Also fixes a memory leak in GetAllRegisteredMediaFormats().
32 * Revision 2.71 2007/09/05 07:56:03 csoutheren
33 * Change default frame size for PCM-16 to 1
35 * Revision 2.70 2007/08/17 07:50:09 dsandras
36 * Applied patch from Matthias Schneider <ma30002000 yahoo.de>. Thanks!
38 * Revision 2.69 2007/08/17 07:01:18 csoutheren
39 * Shortcut media format copy when src and dest are the same
41 * Revision 2.68 2007/08/08 11:17:50 csoutheren
42 * Removed warning
44 * Revision 2.67 2007/08/02 07:54:49 csoutheren
45 * Add function to print options on media format
47 * Revision 2.66 2007/07/24 12:57:55 rjongbloed
48 * Made sure all integer OpalMediaOptions are unsigned so is compatible with H.245 generic capabilities.
50 * Revision 2.65 2007/06/27 07:56:08 rjongbloed
51 * Add new OpalMediaOption for octet strings (simple block of bytes).
53 * Revision 2.64 2007/06/22 05:41:47 rjongbloed
54 * Major codec API update:
55 * Automatically map OpalMediaOptions to SIP/SDP FMTP parameters.
56 * Automatically map OpalMediaOptions to H.245 Generic Capability parameters.
57 * Largely removed need to distinguish between SIP and H.323 codecs.
58 * New mechanism for setting OpalMediaOptions from within a plug in.
60 * Revision 2.63 2007/06/16 21:37:01 dsandras
61 * Added H.264 support thanks to Matthias Schneider <ma30002000 yahoo de>.
62 * Thanks a lot !
64 * Baseline Profile:
65 * no B-frames
66 * We make use of the baseline profile (which is the designated profile for interactive vide) ,
67 * that means:
68 * no B-Frames (too much latency in interactive video)
69 * CBR (we want to get the max. quality making use of all the bitrate that is available)
70 * We allow one exeption: configuring a bitrate of > 786 kbit/s
72 * This plugin implements
73 * - Single Time Aggregation Packets A
74 * - Single NAL units
75 * - Fragmentation Units
76 * like described in RFC3984
78 * It requires x264 and ffmpeg.
80 * Revision 2.62 2007/04/10 05:15:54 rjongbloed
81 * Fixed issue with use of static C string variables in DLL environment,
82 * must use functional interface for correct initialisation.
84 * Revision 2.61 2007/03/13 00:33:11 csoutheren
85 * Simple but messy changes to allow compile time removal of protocol
86 * options such as H.450 and H.460
87 * Fix MakeConnection overrides
89 * Revision 2.60 2007/02/14 06:51:44 csoutheren
90 * Extended FindFormat to allow finding multiple matching formats
92 * Revision 2.59 2007/02/10 18:14:32 hfriederich
93 * Add copy constructor to have consistent code with assignment operator.
94 * Only make options unique when they actually differ
96 * Revision 2.58 2006/12/08 07:33:13 csoutheren
97 * Fix problem with wideband audio plugins and sound channel
99 * Revision 2.57 2006/11/21 01:01:00 csoutheren
100 * Ensure SDP only uses codecs that are valid for SIP
102 * Revision 2.56 2006/10/10 07:18:18 csoutheren
103 * Allow compilation with and without various options
105 * Revision 2.55 2006/09/11 04:48:55 csoutheren
106 * Fixed problem with cloning plugin media formats
108 * Revision 2.54 2006/09/07 09:05:44 csoutheren
109 * Fix case significance in IsValidForProtocol
111 * Revision 2.53 2006/09/06 22:36:11 csoutheren
112 * Fix problem with IsValidForProtocol on video codecs
114 * Revision 2.52 2006/09/05 22:50:05 csoutheren
115 * Make sure codecs match full name if specified, or not at all
117 * Revision 2.51 2006/09/05 06:21:07 csoutheren
118 * Add useful comment
120 * Revision 2.50 2006/08/24 02:19:56 csoutheren
121 * Fix problem with calculating the bandwidth of wide-band codecs
123 * Revision 2.49 2006/08/20 03:45:54 csoutheren
124 * Add OpalMediaFormat::IsValidForProtocol to allow plugin codecs to be enabled only for certain protocols
125 * rather than relying on the presence of the IANA rtp encoding name field
127 * Revision 2.48 2006/08/15 23:35:36 csoutheren
128 * Fixed problem with OpalMediaFormat compare which stopped RTP payload map from working
129 * which disabled iLBC codec on SIP
131 * Revision 2.47 2006/08/01 12:46:32 rjongbloed
132 * Added build solution for plug ins
133 * Removed now redundent code due to plug ins addition
135 * Revision 2.46 2006/07/24 14:03:40 csoutheren
136 * Merged in audio and video plugins from CVS branch PluginBranch
138 * Revision 2.45 2006/07/14 04:22:43 csoutheren
139 * Applied 1517397 - More Phobos stability fix
140 * Thanks to Dinis Rosario
142 * Revision 2.44 2006/04/09 12:01:44 rjongbloed
143 * Added missing Clone() functions so media options propagate correctly.
145 * Revision 2.43 2006/03/20 10:37:47 csoutheren
146 * Applied patch #1453753 - added locking on media stream manipulation
147 * Thanks to Dinis Rosario
149 * Revision 2.42.2.4 2006/04/06 05:33:08 csoutheren
150 * Backports from CVS head up to Plugin_Merge2
152 * Revision 2.42.2.3 2006/04/06 01:21:20 csoutheren
153 * More implementation of video codec plugins
155 * Revision 2.42.2.2 2006/03/16 07:06:00 csoutheren
156 * Initial support for audio plugins
158 * Revision 2.42.2.1 2006/03/13 07:20:28 csoutheren
159 * Added OpalMediaFormat clone function
161 * Revision 2.44 2006/04/09 12:01:44 rjongbloed
162 * Added missing Clone() functions so media options propagate correctly.
164 * Revision 2.43 2006/03/20 10:37:47 csoutheren
165 * Applied patch #1453753 - added locking on media stream manipulation
166 * Thanks to Dinis Rosario
168 * Revision 2.42 2006/02/21 09:38:28 csoutheren
169 * Fix problem with incorrect timestamps for uLaw and ALaw
171 * Revision 2.41 2006/02/13 03:46:17 csoutheren
172 * Added initialisation stuff to make sure that everything works OK
174 * Revision 2.40 2006/01/23 22:53:14 csoutheren
175 * Reverted previous change that prevents multiple codecs from being removed using the
176 * removeMask
178 * Revision 2.39 2005/12/27 20:50:46 dsandras
179 * Added clockRate parameter to the media format. Added new merging method that
180 * merges the parameter option from the source into the destination.
182 * Revision 2.38 2005/12/24 17:50:20 dsandras
183 * Added clockRate parameter support to allow wideband audio codecs.
185 * Revision 2.37 2005/12/06 21:38:16 dsandras
186 * Fixed SetMediaFormatMask thanks for Frederic Heem <frederic.heem _Atttt_ telsey.it>. Thanks! (Patch #1368040).
188 * Revision 2.36 2005/09/13 20:48:22 dominance
189 * minor cleanups needed to support mingw compilation. Thanks goes to Julien Puydt.
191 * Revision 2.35 2005/09/06 12:44:49 rjongbloed
192 * Many fixes to finalise the video processing: merging remote media
194 * Revision 2.34 2005/09/02 14:49:21 csoutheren
195 * Fixed link problem in Linux
197 * Revision 2.33 2005/08/31 13:19:25 rjongbloed
198 * Added mechanism for controlling media (especially codecs) including
199 * changing the OpalMediaFormat option list (eg bit rate) and a completely
200 * new OpalMediaCommand abstraction for things like video fast update.
202 * Revision 2.32 2005/08/28 07:59:17 rjongbloed
203 * Converted OpalTranscoder to use factory, requiring sme changes in making sure
204 * OpalMediaFormat instances are initialised before use.
206 * Revision 2.31 2005/08/24 10:18:23 rjongbloed
207 * Fix incorrect session ID for video media format, doesn't work if thinks is audio!
209 * Revision 2.30 2005/08/20 07:33:30 rjongbloed
210 * Added video specific OpalMediaFormat
212 * Revision 2.29 2005/06/02 13:20:46 rjongbloed
213 * Added minimum and maximum check to media format options.
214 * Added ability to set the options on the primordial media format list.
216 * Revision 2.28 2005/03/12 00:33:28 csoutheren
217 * Fixed problems with STL compatibility on MSVC 6
218 * Fixed problems with video streams
219 * Thanks to Adrian Sietsma
221 * Revision 2.27 2005/02/21 20:27:18 dsandras
222 * Fixed compilation with gcc.
224 * Revision 2.26 2005/02/21 12:20:05 rjongbloed
225 * Added new "options list" to the OpalMediaFormat class.
227 * Revision 2.25 2004/10/24 10:46:41 rjongbloed
228 * Back out change of strcasecmp to strcmp for WinCE
230 * Revision 2.24 2004/10/23 11:42:38 ykiryanov
231 * Added ifdef _WIN32_WCE for PocketPC 2003 SDK port
233 * Revision 2.23 2004/07/11 12:32:51 rjongbloed
234 * Added functions to add/subtract lists of media formats from a media format list
236 * Revision 2.22 2004/05/03 00:59:19 csoutheren
237 * Fixed problem with OpalMediaFormat::GetMediaFormatsList
238 * Added new version of OpalMediaFormat::GetMediaFormatsList that minimses copying
240 * Revision 2.21 2004/03/25 11:48:48 rjongbloed
241 * Changed PCM-16 from IllegalPayloadType to MaxPayloadType to avoid problems
242 * in other parts of the code.
244 * Revision 2.20 2004/03/22 11:32:42 rjongbloed
245 * Added new codec type for 16 bit Linear PCM as must distinguish between the internal
246 * format used by such things as the sound card and the RTP payload format which
247 * is always big endian.
249 * Revision 2.19 2004/02/13 22:15:35 csoutheren
250 * Changed stricmp to strcascmp thanks to Diana Cionoiu
252 * Revision 2.18 2004/02/07 02:18:19 rjongbloed
253 * Improved searching for media format to use payload type AND the encoding name.
255 * Revision 2.17 2003/03/17 10:13:41 robertj
256 * Fixed mutex problem with media format database.
258 * Revision 2.16 2003/01/07 04:39:53 robertj
259 * Updated to OpenH323 v1.11.2
261 * Revision 2.15 2002/11/10 11:33:19 robertj
262 * Updated to OpenH323 v1.10.3
264 * Revision 2.14 2002/09/04 06:01:49 robertj
265 * Updated to OpenH323 v1.9.6
267 * Revision 2.13 2002/07/01 04:56:33 robertj
268 * Updated to OpenH323 v1.9.1
270 * Revision 2.12 2002/03/27 05:36:44 robertj
271 * Set RFC2833 payload type to be 101 for Cisco compatibility
273 * Revision 2.11 2002/02/19 07:36:51 robertj
274 * Added OpalRFC2833 as a OpalMediaFormat variable.
276 * Revision 2.10 2002/02/11 09:32:13 robertj
277 * Updated to openH323 v1.8.0
279 * Revision 2.9 2002/01/22 05:14:38 robertj
280 * Added RTP encoding name string to media format database.
281 * Changed time units to clock rate in Hz.
283 * Revision 2.8 2002/01/14 06:35:58 robertj
284 * Updated to OpenH323 v1.7.9
286 * Revision 2.7 2001/11/15 06:55:26 robertj
287 * Fixed Reorder() function so reorders EVERY format that matches wildcard.
289 * Revision 2.6 2001/10/05 00:22:14 robertj
290 * Updated to PWLib 1.2.0 and OpenH323 1.7.0
292 * Revision 2.5 2001/10/04 00:43:57 robertj
293 * Added function to remove wildcard from list.
294 * Added constructor to make a list with one format in it.
295 * Fixed wildcard matching so trailing * works.
296 * Optimised reorder so does not reorder if already in order.
298 * Revision 2.4 2001/08/23 05:51:17 robertj
299 * Completed implementation of codec reordering.
301 * Revision 2.3 2001/08/22 03:51:44 robertj
302 * Added functions to look up media format by payload type.
304 * Revision 2.2 2001/08/01 06:22:07 robertj
305 * Fixed GNU warning.
307 * Revision 2.1 2001/08/01 05:45:34 robertj
308 * Made OpalMediaFormatList class global to help with documentation.
310 * Revision 2.0 2001/07/27 15:48:25 robertj
311 * Conversion of OpenH323 to Open Phone Abstraction Library (OPAL)
313 * Revision 1.11 2002/12/03 09:20:01 craigs
314 * Fixed problem with RFC2833 and a dynamic RTP type using the same RTP payload number
316 * Revision 1.10 2002/12/02 03:06:26 robertj
317 * Fixed over zealous removal of code when NO_AUDIO_CODECS set.
319 * Revision 1.9 2002/10/30 05:54:17 craigs
320 * Fixed compatibilty problems with G.723.1 6k3 and 5k3
322 * Revision 1.8 2002/08/05 10:03:48 robertj
323 * Cosmetic changes to normalise the usage of pragma interface/implementation.
325 * Revision 1.7 2002/06/25 08:30:13 robertj
326 * Changes to differentiate between stright G.723.1 and G.723.1 Annex A using
327 * the OLC dataType silenceSuppression field so does not send SID frames
328 * to receiver codecs that do not understand them.
330 * Revision 1.6 2002/01/22 07:08:26 robertj
331 * Added IllegalPayloadType enum as need marker for none set
332 * and MaxPayloadType is a legal value.
334 * Revision 1.5 2001/12/11 04:27:28 craigs
335 * Added support for 5.3kbps G723.1
337 * Revision 1.4 2001/09/21 02:51:45 robertj
338 * Implemented static object for all "known" media formats.
339 * Added default session ID to media format description.
341 * Revision 1.3 2001/05/11 04:43:43 robertj
342 * Added variable names for standard PCM-16 media format name.
344 * Revision 1.2 2001/02/09 05:13:56 craigs
345 * Added pragma implementation to (hopefully) reduce the executable image size
346 * under Linux
348 * Revision 1.1 2001/01/25 07:27:16 robertj
349 * Major changes to add more flexible OpalMediaFormat class to normalise
350 * all information about media types, especially codecs.
354 #include <ptlib.h>
356 #ifdef __GNUC__
357 #pragma implementation "mediafmt.h"
358 #pragma implementation "mediacmd.h"
359 #endif
361 #include <opal/mediafmt.h>
362 #include <opal/mediacmd.h>
363 #include <codec/opalwavfile.h>
364 #include <ptclib/cypher.h>
367 #define new PNEW
370 namespace PWLibStupidLinkerHacks {
371 extern int opalLoader;
373 static class InstantiateMe
375 public:
376 InstantiateMe()
378 opalLoader = 1;
380 } instance;
382 }; // namespace PWLibStupidLinkerHacks
384 /////////////////////////////////////////////////////////////////////////////
386 #define AUDIO_FORMAT(name, rtpPayloadType, encodingName, frameSize, frameTime, rxFrames, txFrames, maxFrames, clock) \
387 const OpalAudioFormat & GetOpal##name() \
389 static const OpalAudioFormat name(OPAL_##name, RTP_DataFrame::rtpPayloadType, \
390 encodingName, frameSize, frameTime, rxFrames, txFrames, maxFrames, clock); \
391 return name; \
394 AUDIO_FORMAT(PCM16, MaxPayloadType, "", 16, 8, 240, 1, 256, 8000);
395 AUDIO_FORMAT(PCM16_16KHZ, MaxPayloadType, "", 16, 8, 240, 1, 256, 16000);
396 AUDIO_FORMAT(L16_MONO_8KHZ, L16_Mono, "L16", 16, 8, 240, 30, 256, 8000);
397 AUDIO_FORMAT(L16_MONO_16KHZ, L16_Mono, "L16", 16, 4, 120, 15, 256, 16000);
398 AUDIO_FORMAT(G711_ULAW_64K, PCMU, "PCMU", 8, 8, 240, 30, 256, 8000);
399 AUDIO_FORMAT(G711_ALAW_64K, PCMA, "PCMA", 8, 8, 240, 30, 256, 8000);
400 AUDIO_FORMAT(G728, G728, "G728", 5, 20, 100, 10, 256, 8000);
401 AUDIO_FORMAT(G729, G729, "G729", 10, 80, 24, 5, 256, 8000);
402 AUDIO_FORMAT(G729A, G729, "G729", 10, 80, 24, 5, 256, 8000);
403 AUDIO_FORMAT(G729B, G729, "G729", 10, 80, 24, 5, 256, 8000);
404 AUDIO_FORMAT(G729AB, G729, "G729", 10, 80, 24, 5, 256, 8000);
405 AUDIO_FORMAT(G7231_6k3, G7231, "G723", 24, 240, 8, 3, 256, 8000);
406 AUDIO_FORMAT(G7231_5k3, G7231, "G723", 24, 240, 8, 3, 256, 8000);
407 AUDIO_FORMAT(G7231A_6k3, G7231, "G723", 24, 240, 8, 3, 256, 8000);
408 AUDIO_FORMAT(G7231A_5k3, G7231, "G723", 24, 240, 8, 3, 256, 8000);
409 AUDIO_FORMAT(GSM0610, GSM, "GSM", 33, 160, 7, 4, 7 , 8000);
412 const OpalMediaFormat & GetOpalRFC2833()
414 static const OpalMediaFormat RFC2833(
415 OPAL_RFC2833,
417 (RTP_DataFrame::PayloadTypes)101, // Set to this for Cisco compatibility
418 "telephone-event",
419 TRUE, // Needs jitter
420 32*(1000/50), // bits/sec (32 bits every 50ms)
421 4, // bytes/frame
422 150*8, // 150 millisecond
423 OpalMediaFormat::AudioClockRate
425 return RFC2833;
428 const OpalMediaFormat & GetOpalCiscoNSE()
430 static const OpalMediaFormat CiscoNSE(
431 OPAL_CISCONSE,
433 (RTP_DataFrame::PayloadTypes)100, // Set to this for Cisco compatibility
434 "NSE",
435 TRUE, // Needs jitter
436 32*(1000/50), // bits/sec (32 bits every 50ms)
437 4, // bytes/frame
438 150*8, // 150 millisecond
439 OpalMediaFormat::AudioClockRate
441 return CiscoNSE;
444 static OpalMediaFormatList & GetMediaFormatsList()
446 static class OpalMediaFormatListMaster : public OpalMediaFormatList
448 public:
449 OpalMediaFormatListMaster()
451 DisallowDeleteObjects();
453 } registeredFormats;
455 return registeredFormats;
459 static PMutex & GetMediaFormatsListMutex()
461 static PMutex mutex;
462 return mutex;
466 /////////////////////////////////////////////////////////////////////////////
468 OpalMediaOption::OpalMediaOption(const char * name, bool readOnly, MergeType merge)
469 : m_name(name)
470 , m_readOnly(readOnly)
471 , m_merge(merge)
473 m_name.Replace("=", "_", TRUE);
474 memset(&m_H245Generic, 0, sizeof(m_H245Generic));
478 PObject::Comparison OpalMediaOption::Compare(const PObject & obj) const
480 const OpalMediaOption * otherOption = PDownCast(const OpalMediaOption, &obj);
481 if (otherOption == NULL)
482 return GreaterThan;
483 return m_name.Compare(otherOption->m_name);
487 bool OpalMediaOption::Merge(const OpalMediaOption & option)
489 switch (m_merge) {
490 case MinMerge :
491 if (CompareValue(option) == GreaterThan)
492 Assign(option);
493 break;
495 case MaxMerge :
496 if (CompareValue(option) == LessThan)
497 Assign(option);
498 break;
500 case EqualMerge :
501 return CompareValue(option) == EqualTo;
503 case NotEqualMerge :
504 return CompareValue(option) != EqualTo;
506 case AlwaysMerge :
507 Assign(option);
508 break;
510 default :
511 break;
514 return true;
518 PString OpalMediaOption::AsString() const
520 PStringStream strm;
521 PrintOn(strm);
522 return strm;
526 bool OpalMediaOption::FromString(const PString & value)
528 PStringStream strm;
529 strm = value;
530 ReadFrom(strm);
531 return !strm.fail();
535 ///////////////////////////////////////
537 OpalMediaOptionEnum::OpalMediaOptionEnum(const char * name,
538 bool readOnly,
539 const char * const * enumerations,
540 PINDEX count,
541 MergeType merge,
542 PINDEX value)
543 : OpalMediaOption(name, readOnly, merge),
544 m_enumerations(count, enumerations),
545 m_value(value)
547 if (m_value >= count)
548 m_value = count;
552 PObject * OpalMediaOptionEnum::Clone() const
554 return new OpalMediaOptionEnum(*this);
558 void OpalMediaOptionEnum::PrintOn(ostream & strm) const
560 if (m_value < m_enumerations.GetSize())
561 strm << m_enumerations[m_value];
562 else
563 strm << m_value;
567 void OpalMediaOptionEnum::ReadFrom(istream & strm)
569 PCaselessString str;
570 while (strm.good()) {
571 char ch;
572 strm.get(ch);
573 str += ch;
574 for (PINDEX i = 0; i < m_enumerations.GetSize(); i++) {
575 if (str == m_enumerations[i]) {
576 m_value = i;
577 return;
582 m_value = m_enumerations.GetSize();
584 #ifdef __USE_STL__
585 strm.setstate(ios::badbit);
586 #else
587 strm.setf(ios::badbit , ios::badbit);
588 #endif
592 PObject::Comparison OpalMediaOptionEnum::CompareValue(const OpalMediaOption & option) const
594 const OpalMediaOptionEnum * otherOption = PDownCast(const OpalMediaOptionEnum, &option);
595 if (otherOption == NULL)
596 return GreaterThan;
598 if (m_value > otherOption->m_value)
599 return GreaterThan;
601 if (m_value < otherOption->m_value)
602 return LessThan;
604 return EqualTo;
608 void OpalMediaOptionEnum::Assign(const OpalMediaOption & option)
610 const OpalMediaOptionEnum * otherOption = PDownCast(const OpalMediaOptionEnum, &option);
611 if (otherOption != NULL)
612 m_value = otherOption->m_value;
616 void OpalMediaOptionEnum::SetValue(PINDEX value)
618 if (value < m_enumerations.GetSize())
619 m_value = value;
620 else
621 m_value = m_enumerations.GetSize();
625 ///////////////////////////////////////
627 OpalMediaOptionString::OpalMediaOptionString(const char * name, bool readOnly)
628 : OpalMediaOption(name, readOnly, MinMerge)
633 OpalMediaOptionString::OpalMediaOptionString(const char * name, bool readOnly, const PString & value)
634 : OpalMediaOption(name, readOnly, MinMerge),
635 m_value(value)
640 PObject * OpalMediaOptionString::Clone() const
642 OpalMediaOptionString * newObj = new OpalMediaOptionString(*this);
643 newObj->m_value.MakeUnique();
644 return newObj;
648 void OpalMediaOptionString::PrintOn(ostream & strm) const
650 strm << m_value.ToLiteral();
654 void OpalMediaOptionString::ReadFrom(istream & strm)
656 char c;
657 strm >> c; // Skip whitespace
659 if (c != '"') {
660 strm.putback(c);
661 strm >> m_value; // If no " then read to end of line.
663 else {
664 // If there was a '"' then assume it is a C style literal string with \ escapes etc
666 PINDEX count = 0;
667 PStringStream str;
668 str << '"';
670 while (strm.get(c).good()) {
671 str << c;
673 // Keep reading till get a '"' that is not preceded by a '\' that is not itself preceded by a '\'
674 if (c == '"' && count > 0 && (str[count] != '\\' || !(count > 1 && str[count-1] == '\\')))
675 break;
677 count++;
680 m_value = PString(PString::Literal, (const char *)str);
685 PObject::Comparison OpalMediaOptionString::CompareValue(const OpalMediaOption & option) const
687 const OpalMediaOptionString * otherOption = PDownCast(const OpalMediaOptionString, &option);
688 if (otherOption == NULL)
689 return GreaterThan;
691 return m_value.Compare(otherOption->m_value);
695 void OpalMediaOptionString::Assign(const OpalMediaOption & option)
697 const OpalMediaOptionString * otherOption = PDownCast(const OpalMediaOptionString, &option);
698 if (otherOption != NULL) {
699 m_value = otherOption->m_value;
700 m_value.MakeUnique();
705 void OpalMediaOptionString::SetValue(const PString & value)
707 m_value = value;
708 m_value.MakeUnique();
712 ///////////////////////////////////////
714 OpalMediaOptionOctets::OpalMediaOptionOctets(const char * name, bool readOnly, bool base64)
715 : OpalMediaOption(name, readOnly, NoMerge)
716 , m_base64(base64)
721 OpalMediaOptionOctets::OpalMediaOptionOctets(const char * name, bool readOnly, bool base64, const PBYTEArray & value)
722 : OpalMediaOption(name, readOnly, NoMerge)
723 , m_value(value)
724 , m_base64(base64)
729 OpalMediaOptionOctets::OpalMediaOptionOctets(const char * name, bool readOnly, bool base64, const BYTE * data, PINDEX length)
730 : OpalMediaOption(name, readOnly, NoMerge)
731 , m_value(data, length)
732 , m_base64(base64)
737 PObject * OpalMediaOptionOctets::Clone() const
739 OpalMediaOptionOctets * newObj = new OpalMediaOptionOctets(*this);
740 newObj->m_value.MakeUnique();
741 return newObj;
745 void OpalMediaOptionOctets::PrintOn(ostream & strm) const
747 if (m_base64)
748 strm << PBase64::Encode(m_value);
749 else {
750 _Ios_Fmtflags flags = strm.flags();
751 char fill = strm.fill();
753 strm << hex << setfill('0');
754 for (PINDEX i = 0; i < m_value.GetSize(); i++)
755 strm << setw(2) << (unsigned)m_value[i];
757 strm.fill(fill);
758 strm.flags(flags);
763 void OpalMediaOptionOctets::ReadFrom(istream & strm)
765 if (m_base64) {
766 PString str;
767 strm >> str;
768 PBase64::Decode(str, m_value);
770 else {
771 char pair[3];
772 pair[2] = '\0';
774 PINDEX count = 0;
776 while (isxdigit(strm.peek())) {
777 pair[0] = (char)strm.get();
778 if (!isxdigit(strm.peek())) {
779 strm.putback(pair[0]);
780 break;
782 pair[1] = (char)strm.get();
783 if (!m_value.SetMinSize((count+1+99)%100))
784 break;
785 m_value[count++] = (BYTE)strtoul(pair, NULL, 16);
788 m_value.SetSize(count);
793 PObject::Comparison OpalMediaOptionOctets::CompareValue(const OpalMediaOption & option) const
795 const OpalMediaOptionOctets * otherOption = PDownCast(const OpalMediaOptionOctets, &option);
796 if (otherOption == NULL)
797 return GreaterThan;
799 return m_value.Compare(otherOption->m_value);
803 void OpalMediaOptionOctets::Assign(const OpalMediaOption & option)
805 const OpalMediaOptionOctets * otherOption = PDownCast(const OpalMediaOptionOctets, &option);
806 if (otherOption != NULL) {
807 m_value = otherOption->m_value;
808 m_value.MakeUnique();
813 void OpalMediaOptionOctets::SetValue(const PBYTEArray & value)
815 m_value = value;
816 m_value.MakeUnique();
820 void OpalMediaOptionOctets::SetValue(const BYTE * data, PINDEX length)
822 m_value = PBYTEArray(data, length);
826 /////////////////////////////////////////////////////////////////////////////
828 const PString & OpalMediaFormat::NeedsJitterOption() { static PString s = "Needs Jitter"; return s; }
829 const PString & OpalMediaFormat::MaxBitRateOption() { static PString s = "Max Bit Rate"; return s; }
830 const PString & OpalMediaFormat::MaxFrameSizeOption(){ static PString s = "Max Frame Size"; return s; }
831 const PString & OpalMediaFormat::FrameTimeOption() { static PString s = "Frame Time"; return s; }
832 const PString & OpalMediaFormat::ClockRateOption() { static PString s = "Clock Rate"; return s; }
834 OpalMediaFormat::OpalMediaFormat()
836 rtpPayloadType = RTP_DataFrame::IllegalPayloadType;
837 defaultSessionID = 0;
841 OpalMediaFormat::OpalMediaFormat(RTP_DataFrame::PayloadTypes pt, unsigned clockRate, const char * name, const char * protocol)
843 PWaitAndSignal mutex(GetMediaFormatsListMutex());
844 const OpalMediaFormatList & registeredFormats = GetMediaFormatsList();
846 PINDEX idx = registeredFormats.FindFormat(pt, clockRate, name, protocol);
847 if (idx != P_MAX_INDEX)
848 *this = registeredFormats[idx];
849 else
850 *this = OpalMediaFormat();
854 OpalMediaFormat::OpalMediaFormat(const char * wildcard)
856 operator=(PString(wildcard));
860 OpalMediaFormat::OpalMediaFormat(const PString & wildcard)
862 operator=(wildcard);
866 OpalMediaFormat::OpalMediaFormat(const OpalMediaFormat & mediaFormat)
868 operator=(mediaFormat);
872 OpalMediaFormat::OpalMediaFormat(const char * fullName,
873 unsigned dsid,
874 RTP_DataFrame::PayloadTypes pt,
875 const char * en,
876 BOOL nj,
877 unsigned bw,
878 PINDEX fs,
879 unsigned ft,
880 unsigned cr,
881 time_t ts)
882 : PCaselessString(fullName)
884 codecBaseTime = ts;
886 PINDEX i;
887 PWaitAndSignal mutex(GetMediaFormatsListMutex());
888 OpalMediaFormatList & registeredFormats = GetMediaFormatsList();
890 if ((i = registeredFormats.GetValuesIndex(*this)) != P_MAX_INDEX) {
891 *this = registeredFormats[i]; // Already registered, use previous values
892 return;
895 rtpPayloadType = pt;
896 rtpEncodingName = en;
897 defaultSessionID = dsid;
899 if (nj)
900 AddOption(new OpalMediaOptionBoolean(NeedsJitterOption(), true, OpalMediaOption::OrMerge, true));
902 AddOption(new OpalMediaOptionUnsigned(MaxBitRateOption(), true, OpalMediaOption::MinMerge, bw, 100));
904 if (fs > 0)
905 AddOption(new OpalMediaOptionUnsigned(MaxFrameSizeOption(), true, OpalMediaOption::NoMerge, fs));
907 if (ft > 0)
908 AddOption(new OpalMediaOptionUnsigned(FrameTimeOption(), true, OpalMediaOption::NoMerge, ft));
910 if (cr > 0)
911 AddOption(new OpalMediaOptionUnsigned(ClockRateOption(), true, OpalMediaOption::AlwaysMerge, cr));
913 // assume non-dynamic payload types are correct and do not need deconflicting
914 if (rtpPayloadType < RTP_DataFrame::DynamicBase || rtpPayloadType == RTP_DataFrame::MaxPayloadType) {
915 registeredFormats.OpalMediaFormatBaseList::Append(this);
916 return;
919 // find the next unused dynamic number, and find anything with the new
920 // rtp payload type if it is explicitly required
921 OpalMediaFormat * match = NULL;
922 RTP_DataFrame::PayloadTypes nextUnused = RTP_DataFrame::DynamicBase;
923 do {
924 for (i = 0; i < registeredFormats.GetSize(); i++) {
925 if (registeredFormats[i].GetPayloadType() == nextUnused) {
926 nextUnused = (RTP_DataFrame::PayloadTypes)(nextUnused + 1);
927 break;
929 if ((rtpPayloadType >= RTP_DataFrame::DynamicBase) &&
930 (registeredFormats[i].GetPayloadType() == rtpPayloadType))
931 match = &registeredFormats[i];
933 } while (i < registeredFormats.GetSize());
935 // if new format requires a specific payload type in the dynamic range,
936 // then move the old format to the next unused format
937 if (match != NULL)
938 match->rtpPayloadType = nextUnused;
939 else
940 rtpPayloadType = nextUnused;
942 registeredFormats.OpalMediaFormatBaseList::Append(this);
945 OpalMediaFormat & OpalMediaFormat::operator=(const OpalMediaFormat &format)
947 if (this == &format)
948 return *this;
950 PWaitAndSignal m1(media_format_mutex);
951 PWaitAndSignal m2(format.media_format_mutex);
952 *static_cast<PCaselessString *>(this) = *static_cast<const PCaselessString *>(&format);
953 options = format.options;
954 rtpPayloadType = format.rtpPayloadType;
955 rtpEncodingName = format.rtpEncodingName;
956 defaultSessionID = format.defaultSessionID;
957 codecBaseTime = format.codecBaseTime;
958 return *this;
961 OpalMediaFormat & OpalMediaFormat::operator=(RTP_DataFrame::PayloadTypes pt)
963 PWaitAndSignal mutex(GetMediaFormatsListMutex());
964 const OpalMediaFormatList & registeredFormats = GetMediaFormatsList();
966 PINDEX idx = registeredFormats.FindFormat(pt);
967 if (idx == P_MAX_INDEX)
968 *this = OpalMediaFormat();
969 else if (this != &registeredFormats[idx])
970 *this = registeredFormats[idx];
972 return *this;
976 OpalMediaFormat & OpalMediaFormat::operator=(const char * wildcard)
978 return operator=(PString(wildcard));
981 OpalMediaFormat & OpalMediaFormat::operator=(const PString & wildcard)
983 PWaitAndSignal mutex(GetMediaFormatsListMutex());
984 const OpalMediaFormatList & registeredFormats = GetMediaFormatsList();
986 PINDEX idx = registeredFormats.FindFormat(wildcard);
987 if (idx != P_MAX_INDEX)
988 *this = registeredFormats[idx];
989 else
990 *this = OpalMediaFormat();
992 return *this;
996 PObject * OpalMediaFormat::Clone() const
998 return new OpalMediaFormat(*this);
1002 bool OpalMediaFormat::Merge(const OpalMediaFormat & mediaFormat)
1004 PWaitAndSignal m1(media_format_mutex);
1005 PWaitAndSignal m2(mediaFormat.media_format_mutex);
1006 options.MakeUnique();
1007 for (PINDEX i = 0; i < options.GetSize(); i++) {
1008 OpalMediaOption * option = mediaFormat.FindOption(options[i].GetName());
1009 if (option != NULL && !options[i].Merge(*option))
1010 return false;
1013 return true;
1017 bool OpalMediaFormat::GetOptionValue(const PString & name, PString & value) const
1019 PWaitAndSignal m(media_format_mutex);
1020 OpalMediaOption * option = FindOption(name);
1021 if (option == NULL)
1022 return false;
1024 value = option->AsString();
1025 return true;
1029 bool OpalMediaFormat::SetOptionValue(const PString & name, const PString & value)
1031 PWaitAndSignal m(media_format_mutex);
1032 options.MakeUnique();
1034 OpalMediaOption * option = FindOption(name);
1035 if (option == NULL)
1036 return false;
1038 return option->FromString(value);
1042 bool OpalMediaFormat::GetOptionBoolean(const PString & name, bool dflt) const
1044 PWaitAndSignal m(media_format_mutex);
1045 OpalMediaOption * option = FindOption(name);
1046 if (option == NULL)
1047 return dflt;
1049 return PDownCast(OpalMediaOptionBoolean, option)->GetValue();
1053 bool OpalMediaFormat::SetOptionBoolean(const PString & name, bool value)
1055 PWaitAndSignal m(media_format_mutex);
1056 options.MakeUnique();
1058 OpalMediaOption * option = FindOption(name);
1059 if (option == NULL)
1060 return false;
1062 PDownCast(OpalMediaOptionBoolean, option)->SetValue(value);
1063 return true;
1067 int OpalMediaFormat::GetOptionInteger(const PString & name, int dflt) const
1069 PWaitAndSignal m(media_format_mutex);
1070 OpalMediaOption * option = FindOption(name);
1071 if (option == NULL)
1072 return dflt;
1074 OpalMediaOptionUnsigned * optUnsigned = dynamic_cast<OpalMediaOptionUnsigned *>(option);
1075 if (optUnsigned != NULL)
1076 return optUnsigned->GetValue();
1078 OpalMediaOptionInteger * optInteger = dynamic_cast<OpalMediaOptionInteger *>(option);
1079 if (optInteger != NULL)
1080 return optInteger->GetValue();
1082 return 0;
1086 bool OpalMediaFormat::SetOptionInteger(const PString & name, int value)
1088 PWaitAndSignal m(media_format_mutex);
1089 options.MakeUnique();
1091 OpalMediaOption * option = FindOption(name);
1092 if (option == NULL)
1093 return false;
1095 OpalMediaOptionUnsigned * optUnsigned = dynamic_cast<OpalMediaOptionUnsigned *>(option);
1096 if (optUnsigned != NULL) {
1097 optUnsigned->SetValue(value);
1098 return true;
1101 OpalMediaOptionInteger * optInteger = dynamic_cast<OpalMediaOptionInteger *>(option);
1102 if (optInteger != NULL) {
1103 optInteger->SetValue(value);
1104 return true;
1107 return false;
1111 double OpalMediaFormat::GetOptionReal(const PString & name, double dflt) const
1113 PWaitAndSignal m(media_format_mutex);
1114 OpalMediaOption * option = FindOption(name);
1115 if (option == NULL)
1116 return dflt;
1118 return PDownCast(OpalMediaOptionReal, option)->GetValue();
1122 bool OpalMediaFormat::SetOptionReal(const PString & name, double value)
1124 PWaitAndSignal m(media_format_mutex);
1125 options.MakeUnique();
1127 OpalMediaOption * option = FindOption(name);
1128 if (option == NULL)
1129 return false;
1131 PDownCast(OpalMediaOptionReal, option)->SetValue(value);
1132 return true;
1136 PINDEX OpalMediaFormat::GetOptionEnum(const PString & name, PINDEX dflt) const
1138 PWaitAndSignal m(media_format_mutex);
1139 OpalMediaOption * option = FindOption(name);
1140 if (option == NULL)
1141 return dflt;
1143 return PDownCast(OpalMediaOptionEnum, option)->GetValue();
1147 bool OpalMediaFormat::SetOptionEnum(const PString & name, PINDEX value)
1149 PWaitAndSignal m(media_format_mutex);
1150 options.MakeUnique();
1152 OpalMediaOption * option = FindOption(name);
1153 if (option == NULL)
1154 return false;
1156 PDownCast(OpalMediaOptionEnum, option)->SetValue(value);
1157 return true;
1161 PString OpalMediaFormat::GetOptionString(const PString & name, const PString & dflt) const
1163 PWaitAndSignal m(media_format_mutex);
1164 OpalMediaOption * option = FindOption(name);
1165 if (option == NULL)
1166 return dflt;
1168 return PDownCast(OpalMediaOptionString, option)->GetValue();
1172 bool OpalMediaFormat::SetOptionString(const PString & name, const PString & value)
1174 PWaitAndSignal m(media_format_mutex);
1175 options.MakeUnique();
1177 OpalMediaOption * option = FindOption(name);
1178 if (option == NULL)
1179 return false;
1181 PDownCast(OpalMediaOptionString, option)->SetValue(value);
1182 return true;
1186 bool OpalMediaFormat::GetOptionOctets(const PString & name, PBYTEArray & octets) const
1188 PWaitAndSignal m(media_format_mutex);
1189 OpalMediaOption * option = FindOption(name);
1190 if (option == NULL)
1191 return false;
1193 octets = PDownCast(OpalMediaOptionOctets, option)->GetValue();
1194 return true;
1198 bool OpalMediaFormat::SetOptionOctets(const PString & name, const PBYTEArray & octets)
1200 PWaitAndSignal m(media_format_mutex);
1201 options.MakeUnique();
1203 OpalMediaOption * option = FindOption(name);
1204 if (option == NULL)
1205 return false;
1207 PDownCast(OpalMediaOptionOctets, option)->SetValue(octets);
1208 return true;
1212 bool OpalMediaFormat::SetOptionOctets(const PString & name, const BYTE * data, PINDEX length)
1214 PWaitAndSignal m(media_format_mutex);
1215 options.MakeUnique();
1217 OpalMediaOption * option = FindOption(name);
1218 if (option == NULL)
1219 return false;
1221 PDownCast(OpalMediaOptionOctets, option)->SetValue(data, length);
1222 return true;
1226 bool OpalMediaFormat::AddOption(OpalMediaOption * option, BOOL overwrite)
1228 PWaitAndSignal m(media_format_mutex);
1229 if (PAssertNULL(option) == NULL)
1230 return false;
1232 PINDEX index = options.GetValuesIndex(*option);
1233 if (index != P_MAX_INDEX) {
1234 if (!overwrite) {
1235 delete option;
1236 return false;
1239 options.RemoveAt(index);
1242 options.MakeUnique();
1243 options.Append(option);
1244 return true;
1248 OpalMediaOption * OpalMediaFormat::FindOption(const PString & name) const
1250 PWaitAndSignal m(media_format_mutex);
1251 OpalMediaOptionString search(name, false);
1252 PINDEX index = options.GetValuesIndex(search);
1253 if (index == P_MAX_INDEX)
1254 return NULL;
1256 return &options[index];
1260 OpalMediaFormatList OpalMediaFormat::GetAllRegisteredMediaFormats()
1262 OpalMediaFormatList copy;
1263 GetAllRegisteredMediaFormats(copy);
1264 return copy;
1268 void OpalMediaFormat::GetAllRegisteredMediaFormats(OpalMediaFormatList & copy)
1270 PWaitAndSignal mutex(GetMediaFormatsListMutex());
1271 const OpalMediaFormatList & registeredFormats = GetMediaFormatsList();
1273 for (PINDEX i = 0; i < registeredFormats.GetSize(); i++)
1274 copy += registeredFormats[i];
1278 bool OpalMediaFormat::SetRegisteredMediaFormat(const OpalMediaFormat & mediaFormat)
1280 PWaitAndSignal mutex(GetMediaFormatsListMutex());
1281 const OpalMediaFormatList & registeredFormats = GetMediaFormatsList();
1283 for (PINDEX i = 0; i < registeredFormats.GetSize(); i++) {
1284 if (registeredFormats[i] == mediaFormat) {
1285 /* Yes, this looks a little odd as we just did equality above and seem to
1286 be assigning the left hand side with exactly the same value. But what
1287 is really happening is the above only compares the name, and below
1288 copies all of the attributes (OpalMediaFormatOtions) across. */
1289 registeredFormats[i] = mediaFormat;
1290 return true;
1294 return false;
1297 bool OpalMediaFormat::IsValidForProtocol(const PString & protocol) const
1299 // the protocol is only valid for SIP if the RTP name is not NULL
1300 if (protocol *= "sip")
1301 return rtpEncodingName != NULL;
1303 return TRUE;
1306 time_t OpalMediaFormat::GetCodecBaseTime() const
1308 return codecBaseTime;
1311 ostream & OpalMediaFormat::PrintOptions(ostream & strm) const
1313 for (PINDEX i = 0; i < GetOptionCount(); i++) {
1314 const OpalMediaOption & option = GetOption(i);
1315 strm << right << setw(25) << option.GetName() << " (R/" << (option.IsReadOnly() ? 'O' : 'W')
1316 << ") = " << left << setw(10) << option.AsString();
1317 if (!option.GetFMTPName().IsEmpty())
1318 strm << " FMTP name: " << option.GetFMTPName() << " (" << option.GetFMTPDefault() << ')';
1319 const OpalMediaOption::H245GenericInfo & genericInfo = option.GetH245Generic();
1320 if (genericInfo.mode != OpalMediaOption::H245GenericInfo::None) {
1321 strm << " H.245 Ordinal: " << genericInfo.ordinal
1322 << ' ' << (genericInfo.mode == OpalMediaOption::H245GenericInfo::Collapsing ? "Collapsing" : "Non-Collapsing");
1323 if (!genericInfo.excludeTCS)
1324 strm << " TCS";
1325 if (!genericInfo.excludeOLC)
1326 strm << " OLC";
1327 if (!genericInfo.excludeReqMode)
1328 strm << " RM";
1330 strm << endl;
1332 strm << endl;
1334 return strm;
1337 ///////////////////////////////////////////////////////////////////////////////
1339 const PString & OpalAudioFormat::RxFramesPerPacketOption() { static PString s = "Rx Frames Per Packet"; return s; }
1340 const PString & OpalAudioFormat::TxFramesPerPacketOption() { static PString s = "Tx Frames Per Packet"; return s; }
1342 OpalAudioFormat::OpalAudioFormat(const char * fullName,
1343 RTP_DataFrame::PayloadTypes rtpPayloadType,
1344 const char * encodingName,
1345 PINDEX frameSize,
1346 unsigned frameTime,
1347 unsigned rxFrames,
1348 unsigned txFrames,
1349 unsigned maxFrames,
1350 unsigned clockRate,
1351 time_t timeStamp)
1352 : OpalMediaFormat(fullName,
1353 OpalMediaFormat::DefaultAudioSessionID,
1354 rtpPayloadType,
1355 encodingName,
1356 TRUE,
1357 8*frameSize*AudioClockRate/frameTime, // bits per second = 8*frameSize * framesPerSecond
1358 frameSize,
1359 frameTime,
1360 clockRate,
1361 timeStamp)
1363 AddOption(new OpalMediaOptionUnsigned(RxFramesPerPacketOption(), false, OpalMediaOption::MinMerge, rxFrames, 1, maxFrames));
1364 AddOption(new OpalMediaOptionUnsigned(TxFramesPerPacketOption(), false, OpalMediaOption::MinMerge, txFrames, 1, maxFrames));
1368 ///////////////////////////////////////////////////////////////////////////////
1370 #if OPAL_VIDEO
1372 const PString & OpalVideoFormat::FrameWidthOption() { static PString s = "Frame Width"; return s; }
1373 const PString & OpalVideoFormat::FrameHeightOption() { static PString s = "Frame Height"; return s; }
1374 const PString & OpalVideoFormat::EncodingQualityOption() { static PString s = "Encoding Quality"; return s; }
1375 const PString & OpalVideoFormat::TargetBitRateOption() { static PString s = "Target Bit Rate"; return s; }
1376 const PString & OpalVideoFormat::DynamicVideoQualityOption() { static PString s = "Dynamic Video Quality"; return s; }
1377 const PString & OpalVideoFormat::AdaptivePacketDelayOption() { static PString s = "Adaptive Packet Delay"; return s; }
1379 OpalVideoFormat::OpalVideoFormat(const char * fullName,
1380 RTP_DataFrame::PayloadTypes rtpPayloadType,
1381 const char * encodingName,
1382 unsigned frameWidth,
1383 unsigned frameHeight,
1384 unsigned frameRate,
1385 unsigned bitRate,
1386 time_t timeStamp)
1387 : OpalMediaFormat(fullName,
1388 OpalMediaFormat::DefaultVideoSessionID,
1389 rtpPayloadType,
1390 encodingName,
1391 FALSE,
1392 bitRate,
1394 OpalMediaFormat::VideoClockRate/frameRate,
1395 OpalMediaFormat::VideoClockRate,
1396 timeStamp)
1398 AddOption(new OpalMediaOptionUnsigned(FrameWidthOption(), true, OpalMediaOption::MinMerge, frameWidth, 11, 32767));
1399 AddOption(new OpalMediaOptionUnsigned(FrameHeightOption(), true, OpalMediaOption::MinMerge, frameHeight, 9, 32767));
1400 AddOption(new OpalMediaOptionUnsigned(EncodingQualityOption(), false, OpalMediaOption::MinMerge, 15, 1, 31));
1401 AddOption(new OpalMediaOptionUnsigned(TargetBitRateOption(), false, OpalMediaOption::MinMerge, 10000000, 1000));
1402 AddOption(new OpalMediaOptionBoolean(DynamicVideoQualityOption(), false, OpalMediaOption::NoMerge, false));
1403 AddOption(new OpalMediaOptionBoolean(AdaptivePacketDelayOption(), false, OpalMediaOption::NoMerge, false));
1405 // For video the max bit rate and frame rate is adjustable by user
1406 FindOption(MaxBitRateOption())->SetReadOnly(false);
1407 FindOption(FrameTimeOption())->SetReadOnly(false);
1408 FindOption(FrameTimeOption())->SetMerge(OpalMediaOption::MinMerge);
1412 PObject * OpalVideoFormat::Clone() const
1414 return new OpalVideoFormat(*this);
1418 bool OpalVideoFormat::Merge(const OpalMediaFormat & mediaFormat)
1420 if (!OpalMediaFormat::Merge(mediaFormat))
1421 return false;
1423 unsigned maxBitRate = GetOptionInteger(MaxBitRateOption());
1424 unsigned targetBitRate = GetOptionInteger(TargetBitRateOption());
1425 if (targetBitRate > maxBitRate)
1426 SetOptionInteger(TargetBitRateOption(), maxBitRate);
1428 return true;
1431 #endif // OPAL_VIDEO
1433 ///////////////////////////////////////////////////////////////////////////////
1435 OpalMediaFormatList::OpalMediaFormatList()
1440 OpalMediaFormatList::OpalMediaFormatList(const OpalMediaFormat & format)
1442 *this += format;
1446 OpalMediaFormatList & OpalMediaFormatList::operator+=(const OpalMediaFormat & format)
1448 if (format.IsValid() && !HasFormat(format))
1449 OpalMediaFormatBaseList::Append(format.Clone());
1450 return *this;
1454 OpalMediaFormatList & OpalMediaFormatList::operator+=(const OpalMediaFormatList & formats)
1456 for (PINDEX i = 0; i < formats.GetSize(); i++)
1457 *this += formats[i];
1458 return *this;
1462 OpalMediaFormatList & OpalMediaFormatList::operator-=(const OpalMediaFormat & format)
1464 PINDEX idx = FindFormat(format);
1465 if (idx != P_MAX_INDEX)
1466 RemoveAt(idx);
1468 return *this;
1472 OpalMediaFormatList & OpalMediaFormatList::operator-=(const OpalMediaFormatList & formats)
1474 for (PINDEX i = 0; i < formats.GetSize(); i++)
1475 *this -= formats[i];
1476 return *this;
1480 void OpalMediaFormatList::Remove(const PStringArray & mask)
1482 PINDEX i;
1483 for (i = 0; i < mask.GetSize(); i++) {
1484 PINDEX idx;
1485 while ((idx = FindFormat(mask[i])) != P_MAX_INDEX)
1486 RemoveAt(idx);
1490 PINDEX OpalMediaFormatList::FindFormat(RTP_DataFrame::PayloadTypes pt, unsigned clockRate, const char * name, const char * protocol) const
1492 for (PINDEX idx = 0; idx < GetSize(); idx++) {
1493 OpalMediaFormat & mediaFormat = (*this)[idx];
1495 // clock rates must always match
1496 if (clockRate != 0 && clockRate != mediaFormat.GetClockRate())
1497 continue;
1499 // if protocol is specified, must be valid for the protocol
1500 if ((protocol != NULL) && !mediaFormat.IsValidForProtocol(protocol))
1501 continue;
1503 // if an encoding name is specified, and it matches exactly, then use it
1504 // regardless of payload code. This allows the payload code mapping in SIP to work
1505 // if it doesn't match, then don't bother comparing payload codes
1506 if (name != NULL && *name != '\0') {
1507 const char * otherName = mediaFormat.GetEncodingName();
1508 if (otherName != NULL && strcasecmp(otherName, name) == 0)
1509 return idx;
1510 continue;
1513 // if the payload type is not dynamic, and matches, then this is a match
1514 if (pt < RTP_DataFrame::DynamicBase && mediaFormat.GetPayloadType() == pt)
1515 return idx;
1517 //if (RTP_DataFrame::IllegalPayloadType == pt)
1518 // return idx;
1521 return P_MAX_INDEX;
1525 static BOOL WildcardMatch(const PCaselessString & str, const PStringArray & wildcards)
1527 if (wildcards.GetSize() == 1)
1528 return str == wildcards[0];
1530 PINDEX i;
1531 PINDEX last = 0;
1532 for (i = 0; i < wildcards.GetSize(); i++) {
1533 PString wildcard = wildcards[i];
1535 PINDEX next;
1536 if (wildcard.IsEmpty())
1537 next = last;
1538 else {
1539 next = str.Find(wildcard, last);
1540 if (next == P_MAX_INDEX)
1541 return FALSE;
1544 // Check for having * at beginning of search string
1545 if (i == 0 && next != 0 && !wildcard)
1546 return FALSE;
1548 last = next + wildcard.GetLength();
1550 // Check for having * at end of search string
1551 if (i == wildcards.GetSize()-1 && !wildcard && last != str.GetLength())
1552 return FALSE;
1555 return TRUE;
1559 PINDEX OpalMediaFormatList::FindFormat(const PString & search, PINDEX pos) const
1561 PStringArray wildcards = search.Tokenise('*', TRUE);
1562 PINDEX idx;
1563 for (idx = pos; idx < GetSize(); idx++) {
1564 if (WildcardMatch((*this)[idx], wildcards))
1565 return idx;
1568 return P_MAX_INDEX;
1572 void OpalMediaFormatList::Reorder(const PStringArray & order)
1574 DisallowDeleteObjects();
1575 PINDEX nextPos = 0;
1576 for (PINDEX i = 0; i < order.GetSize(); i++) {
1577 PStringArray wildcards = order[i].Tokenise('*', TRUE);
1579 PINDEX findPos = 0;
1580 while (findPos < GetSize()) {
1581 if (WildcardMatch((*this)[findPos], wildcards)) {
1582 if (findPos > nextPos)
1583 OpalMediaFormatBaseList::InsertAt(nextPos, RemoveAt(findPos));
1584 nextPos++;
1586 findPos++;
1589 AllowDeleteObjects();
1593 // End of File ///////////////////////////////////////////////////////////////