Utilise new MergeSym feature to no longer overwrite the source .DEF file when buildin...
[openh323.git] / src / h263codec.cxx
blobef7e2791953abf27bbcbd83f6d71f3b6df7bebed
1 /*
2 * h263codec.cxx
4 * H.323 protocol handler
6 * Open H323 Library
7 *
8 * Copyright (c) 1998-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 * Portions of this code were written by Guilhem Tardy, with financial
25 * assistance from March Networks (http://www.marchnetworks.com)
27 * Portions of this code were written with the financial assistance of
28 * AliceStreet (http://www.alicestreet.com)
30 * Thanks to March Networks, AliceStreet, Guilhem Tardy for releasing
31 * your work back to the openh323 group.
33 * Contributor(s): Guilhem Tardy (gtardy@marchnetworks.com)
35 * $Log$
36 * Revision 1.29 2006/06/26 17:03:16 shorne
37 * Fixed build with latest CVS
39 * Revision 1.28 2005/06/07 07:59:11 csoutheren
40 * Applied patch 1176459 for PocketPC. Thanks to Matthias Weber
42 * Revision 1.27 2004/05/04 03:33:33 csoutheren
43 * Added guards against comparing certain kinds of Capabilities
45 * Revision 1.26 2004/04/19 03:48:19 dereksmithies
46 * Adjust Acknowledgements. Thanks to Guilhem Tardy for describing the error.
48 * Revision 1.25 2004/04/04 13:56:06 rjongbloed
49 * Changes to support native C++ Run Time Type Information
51 * Revision 1.24 2003/08/29 00:33:22 dereksmithies
52 * Add fix for printing vic messages to the log file. MANY thanks to Niklas Ogren
54 * Revision 1.23 2003/08/04 00:03:41 dereksmithies
55 * Reorganise test of H323_VICH263 switch
57 * Revision 1.22 2003/08/01 02:01:42 csoutheren
58 * Changed to disable when VIC 263 not installed
60 * Revision 1.21 2003/07/29 03:57:00 dereksmithies
61 * Remove weird boxes on startup.
63 * Revision 1.20 2003/07/24 08:09:18 dereksmithies
64 * Update to use vich263 codec, instead of ffmpeg
66 * Revision 1.19 2003/06/14 05:54:23 rjongbloed
67 * Fixed MSVC warning.
68 * Fixed what seemed an obvious mistake using boolean or operator (||) instead
69 * of the bitwise or operator (|).
71 * Revision 1.18 2003/06/12 00:24:32 dereksmithies
72 * Modify so QCIF-CIF behaviour similar to that for h261codec.cxx
74 * Revision 1.17 2003/06/10 01:37:25 dereksmithies
75 * Changes so it should not crash under windows/release mode
77 * Revision 1.16 2003/06/06 06:32:08 rjongbloed
78 * Fixed MSVC warning
80 * Revision 1.15 2003/06/06 05:18:54 dereksmithies
81 * Fix startup delay bug. Remove all large packets from the network. Improve reliability.
83 * Revision 1.14 2003/06/03 05:01:23 rjongbloed
84 * Fixed some trace logging (removed usage of cerr)
86 * Revision 1.13 2003/06/03 00:49:01 dereksmithies
87 * Fix divide by zero error, which happens on win95 & win98 machines.
89 * Revision 1.12 2003/06/02 07:56:56 rjongbloed
90 * Fixed media format passed to ancestor codec class
92 * Revision 1.11 2003/05/27 04:20:59 dereksmithies
93 * Fix so that codec resizes correctly after capability exchange
94 * No longer crashes if one endpoint is CIF, other is QCIF.
96 * Revision 1.10 2003/05/16 04:42:24 rjongbloed
97 * Removed extraneous code, and other cosmetic changes.
98 * Fixed compare function for capability.
99 * Extra trace logging.
101 * Revision 1.9 2003/05/15 01:35:27 dereksmithies
102 * Frame length fix
104 * Revision 1.8 2003/05/14 13:51:51 rjongbloed
105 * Removed hack of using special payload type for H.263 for a method which
106 * would be less prone to failure in the future.
107 * Removed static "initialisation" function as this should be done
108 * internally and not in the application.
109 * Changed media format to be straight H.263 and not OpalH.263
110 * Moved Win32 stderr output in ffmpeg AVCODEC interception from
111 * application to library.
112 * Fixed some warnings.
114 * Revision 1.7 2003/05/14 03:07:17 rjongbloed
115 * Made sure video buffer is large enough
117 * Revision 1.6 2003/05/05 11:59:25 robertj
118 * Changed to use autoconf style selection of options and subsystems.
120 * Revision 1.5 2003/05/02 04:21:30 craigs
121 * Added lots of extra H.263 support
123 * Revision 1.4 2003/04/21 21:50:22 dereks
124 * Implement suggestion from Guilhem Tardy. Many thanks.
126 * Revision 1.3 2003/04/16 04:26:57 dereks
127 * Initial release of h263 codec, which utilises the ffmpeg library.
128 * Thanks to Guilhem Tardy, and to AliceStreet.
130 * Revision 1.2 2002/08/05 10:03:47 robertj
131 * Cosmetic changes to normalise the usage of pragma interface/implementation.
133 * Revision 1.1 2002/05/19 22:31:12 dereks
134 * Initial release of stub file for h263 codec. Thanks Guilhem Tardy.
138 * Initial release notes from Guilhem Tardy::
140 * Added support for video capabilities & codec, still needs the actual codec itself!
141 * The code for varying bit rate is copied from h261codec.cxx,
142 * until it is moved to a separate file common to both video codecs.
145 #include <ptlib.h>
146 #include <ptlib/video.h>
148 #ifdef __GNUC__
149 #pragma implementation "h263codec.h"
150 #endif
152 #include "h263codec.h"
153 #if defined(H323_VICH263)
156 #include "h245.h"
157 #include "rtp.h"
159 #if defined(_MSC_VER)
160 #ifndef _WIN32_WINCE
161 #pragma comment(lib, H323_VICH263_LIBRARY)
162 #endif
163 #endif
166 #include <encoder-h263.h>
167 #include <decoder-h263.h>
169 /* #define INC_ENCODE 1 */
171 //////////////////////////////////////////////////////////////////////////////
173 static void h263_vic_printon(char * str);
174 static void h263_vic_printon(char * str)
176 PTRACE(6, "Vic H263\t" << str);
177 strlen(str); /*Stop any compiler warning about unused variable*/
181 class VicH263Link : public PObject
183 PCLASSINFO(VicH263Link, PObject)
185 public:
186 VicH263Link();
189 VicH263Link::VicH263Link()
191 vich263_set_print_fn(h263_vic_printon);
194 VicH263Link vicLink;
196 ///////////////////////////////////////////////////////////////////////////////////////
198 #define new PNEW
201 static OpalMediaFormat const H263_MediaFormat("H.263",
202 OpalMediaFormat::DefaultVideoSessionID,
203 RTP_DataFrame::H263,
204 FALSE, // No jitter for video
205 180000, // bits/sec
206 2000, // Not sure of this value!
207 0, // No intrinsic time per frame
208 OpalMediaFormat::VideoTimeUnits);
211 //////////////////////////////////////////////////////////////////////////////
213 H323_H263Capability::H323_H263Capability(unsigned _sqcifMPI,
214 unsigned _qcifMPI,
215 unsigned _cifMPI,
216 unsigned _cif4MPI,
217 unsigned _cif16MPI,
218 unsigned _maxBitRate,
219 unsigned _videoFrameRate,
220 BOOL _unrestrictedVector,
221 BOOL _arithmeticCoding,
222 BOOL _advancedPrediction,
223 BOOL _pbFrames,
224 BOOL _temporalSpatialTradeOff,
225 unsigned _hrd_B,
226 unsigned _bppMaxKb,
227 unsigned _slowSqcifMPI,
228 unsigned _slowQcifMPI,
229 unsigned _slowCifMPI,
230 unsigned _slowCif4MPI,
231 unsigned _slowCif16MPI,
232 BOOL _errorCompensation)
234 sqcifMPI = (_sqcifMPI>0?_sqcifMPI:-(int)_slowSqcifMPI);
235 qcifMPI = (_qcifMPI>0?_qcifMPI:-(int)_slowQcifMPI);
236 cifMPI = (_cifMPI>0?_cifMPI:-(int)_slowCifMPI);
237 cif4MPI = (_cif4MPI>0?_cif4MPI:-(int)_slowCif4MPI);
238 cif16MPI = (_cif16MPI>0?_cif16MPI:-(int)_slowCif16MPI);
240 maxBitRate = _maxBitRate;
241 videoFrameRate = _videoFrameRate;
243 temporalSpatialTradeOff = _temporalSpatialTradeOff;
244 pbFrames = _pbFrames;
245 advancedPrediction = _advancedPrediction;
246 arithmeticCoding = _arithmeticCoding;
247 unrestrictedVector = _unrestrictedVector;
249 hrd_B = _hrd_B;
250 bppMaxKb = _bppMaxKb;
252 errorCompensation = _errorCompensation;
256 PObject * H323_H263Capability::Clone() const
258 return new H323_H263Capability(*this);
262 PObject::Comparison H323_H263Capability::Compare(const PObject & obj) const
264 if (!PIsDescendant(&obj, H323_H263Capability))
265 return LessThan;
267 Comparison result = H323Capability::Compare(obj);
268 if (result != EqualTo)
269 return result;
271 const H323_H263Capability & other = (const H323_H263Capability &)obj;
274 if ((sqcifMPI > other.sqcifMPI) ||
275 (qcifMPI > other.qcifMPI) ||
276 (cifMPI > other.cifMPI) ||
277 (cif4MPI > other.cif4MPI) ||
278 (cif16MPI > other.cif16MPI))
279 return GreaterThan;
281 if ((cif16MPI < other.cif16MPI) ||
282 (cif4MPI < other.cif4MPI) ||
283 (cifMPI < other.cifMPI) ||
284 (qcifMPI < other.qcifMPI))
285 return LessThan;
288 if (
289 ((sqcifMPI > 0) && (other.sqcifMPI > 0)) ||
290 ((qcifMPI > 0) && (other.qcifMPI > 0)) ||
291 ((cifMPI > 0) && (other.cifMPI > 0)) ||
292 ((cif4MPI > 0) && (other.cif4MPI > 0)) ||
293 ((cif16MPI > 0) && (other.cif16MPI > 0))
295 return EqualTo;
297 if (qcifMPI > 0)
298 return LessThan;
300 return GreaterThan;
303 return EqualTo;
307 PString H323_H263Capability::GetFormatName() const
309 PString ret = H263_MediaFormat;
311 if (sqcifMPI)
312 ret += "-SQCIF";
314 if (qcifMPI)
315 ret += "-QCIF";
317 if (cifMPI)
318 ret += "-CIF";
320 if (cif4MPI)
321 ret += "-CIF4";
323 if (cif16MPI)
324 ret += "-CIF16";
326 return ret;
330 unsigned H323_H263Capability::GetSubType() const
332 return H245_VideoCapability::e_h263VideoCapability;
336 BOOL H323_H263Capability::OnSendingPDU(H245_VideoCapability & cap) const
338 cap.SetTag(H245_VideoCapability::e_h263VideoCapability);
340 H245_H263VideoCapability & h263 = cap;
341 if (sqcifMPI > 0) {
342 h263.IncludeOptionalField(H245_H263VideoCapability::e_sqcifMPI);
343 h263.m_sqcifMPI = sqcifMPI;
345 if (qcifMPI > 0) {
346 h263.IncludeOptionalField(H245_H263VideoCapability::e_qcifMPI);
347 h263.m_qcifMPI = qcifMPI;
349 if (cifMPI > 0) {
350 h263.IncludeOptionalField(H245_H263VideoCapability::e_cifMPI);
351 h263.m_cifMPI = cifMPI;
353 if (cif4MPI > 0) {
354 h263.IncludeOptionalField(H245_H263VideoCapability::e_cif4MPI);
355 h263.m_cif4MPI = cif4MPI;
357 if (cif16MPI > 0) {
358 h263.IncludeOptionalField(H245_H263VideoCapability::e_cif16MPI);
359 h263.m_cif16MPI = cif16MPI;
361 h263.m_temporalSpatialTradeOffCapability = temporalSpatialTradeOff;
362 h263.m_maxBitRate = maxBitRate;
363 if (sqcifMPI < 0) {
364 h263.IncludeOptionalField(H245_H263VideoCapability::e_slowSqcifMPI);
365 h263.m_slowSqcifMPI = -sqcifMPI;
367 if (qcifMPI < 0) {
368 h263.IncludeOptionalField(H245_H263VideoCapability::e_slowQcifMPI);
369 h263.m_slowQcifMPI = -qcifMPI;
371 if (cifMPI < 0) {
372 h263.IncludeOptionalField(H245_H263VideoCapability::e_slowCifMPI);
373 h263.m_slowCifMPI = -cifMPI;
375 if (cif4MPI < 0) {
376 h263.IncludeOptionalField(H245_H263VideoCapability::e_slowCif4MPI);
377 h263.m_slowCif4MPI = -cif4MPI;
379 if (cif16MPI < 0) {
380 h263.IncludeOptionalField(H245_H263VideoCapability::e_slowCif16MPI);
381 h263.m_slowCif16MPI = -cif16MPI;
384 return TRUE;
388 BOOL H323_H263Capability::OnSendingPDU(H245_VideoMode & pdu) const
390 pdu.SetTag(H245_VideoMode::e_h263VideoMode);
391 H245_H263VideoMode & mode = pdu;
392 mode.m_resolution.SetTag(cif16MPI ? H245_H263VideoMode_resolution::e_cif16
393 :(cif4MPI ? H245_H263VideoMode_resolution::e_cif4
394 :(cifMPI ? H245_H263VideoMode_resolution::e_cif
395 :(qcifMPI ? H245_H263VideoMode_resolution::e_qcif
396 : H245_H263VideoMode_resolution::e_sqcif))));
397 mode.m_bitRate = maxBitRate;
398 mode.m_unrestrictedVector = unrestrictedVector;
399 mode.m_arithmeticCoding = arithmeticCoding;
400 mode.m_advancedPrediction = advancedPrediction;
401 mode.m_pbFrames = pbFrames;
402 mode.m_errorCompensation = errorCompensation;
404 return TRUE;
408 BOOL H323_H263Capability::OnReceivedPDU(const H245_VideoCapability & cap)
410 if (cap.GetTag() != H245_VideoCapability::e_h263VideoCapability)
411 return FALSE;
413 const H245_H263VideoCapability & h263 = cap;
414 if (h263.HasOptionalField(H245_H263VideoCapability::e_sqcifMPI))
415 sqcifMPI = h263.m_sqcifMPI;
416 else if (h263.HasOptionalField(H245_H263VideoCapability::e_slowSqcifMPI))
417 sqcifMPI = -(int)h263.m_slowSqcifMPI;
418 else
419 sqcifMPI = 0;
420 if (h263.HasOptionalField(H245_H263VideoCapability::e_qcifMPI))
421 qcifMPI = h263.m_qcifMPI;
422 else if (h263.HasOptionalField(H245_H263VideoCapability::e_slowQcifMPI))
423 qcifMPI = -(int)h263.m_slowQcifMPI;
424 else
425 qcifMPI = 0;
426 if (h263.HasOptionalField(H245_H263VideoCapability::e_cifMPI))
427 cifMPI = h263.m_cifMPI;
428 else if (h263.HasOptionalField(H245_H263VideoCapability::e_slowCifMPI))
429 cifMPI = -(int)h263.m_slowCifMPI;
430 else
431 cifMPI = 0;
432 if (h263.HasOptionalField(H245_H263VideoCapability::e_cif4MPI))
433 cif4MPI = h263.m_cif4MPI;
434 else if (h263.HasOptionalField(H245_H263VideoCapability::e_slowCif4MPI))
435 cif4MPI = -(int)h263.m_slowCif4MPI;
436 else
437 cif4MPI = 0;
438 if (h263.HasOptionalField(H245_H263VideoCapability::e_cif16MPI))
439 cif16MPI = h263.m_cif16MPI;
440 else if (h263.HasOptionalField(H245_H263VideoCapability::e_slowCif16MPI))
441 cif16MPI = -(int)h263.m_slowCif16MPI;
442 else
443 cif16MPI = 0;
444 maxBitRate = h263.m_maxBitRate;
445 unrestrictedVector = h263.m_unrestrictedVector;
446 arithmeticCoding = h263.m_arithmeticCoding;
447 advancedPrediction = h263.m_advancedPrediction;
448 pbFrames = h263.m_pbFrames;
449 temporalSpatialTradeOff = h263.m_temporalSpatialTradeOffCapability;
450 hrd_B = h263.m_hrd_B;
451 bppMaxKb = h263.m_bppMaxKb;
452 errorCompensation = h263.m_errorCompensation;
454 return TRUE;
458 H323Codec * H323_H263Capability::CreateCodec(H323Codec::Direction direction) const
460 return new H323_H263Codec(direction, sqcifMPI, qcifMPI, cifMPI, cif4MPI, cif16MPI, maxBitRate, videoFrameRate);
463 //////////////////////////////////////////////////////////////////////////////
466 H323_H263Codec::H323_H263Codec(Direction dir,
467 unsigned _sqcifMPI,
468 unsigned _qcifMPI,
469 unsigned _cifMPI,
470 unsigned _cif4MPI,
471 unsigned _cif16MPI,
472 unsigned _maxBitRate,
473 unsigned _videoFrameRate)
474 : H323VideoCodec(H263_MediaFormat, dir)
476 PTRACE(3, "H263\t" << (dir == Encoder ? "En" : "De")
477 << "coder created. Data rate=" << _maxBitRate
478 << " Frame rate=" << _videoFrameRate);
480 bitRateHighLimit = _maxBitRate;
481 if (bitRateHighLimit == 0) {
482 PTRACE(3, "H263\tData Rate is set to 1000 Kb/sec, as supplied value (0) is invalid");
483 bitRateHighLimit = 1000 * 1024;
486 framesPerSec = _videoFrameRate;
487 if (framesPerSec == 0) {
488 PTRACE(3, "H263\tFrame Rate is set to 25 frames/sec, as supplied value (0) is invalid");
489 framesPerSec = 25;
492 int shifts = -1;
493 if (_sqcifMPI) {
494 shifts = 0; PTRACE(3, "H263\t" << (dir == Encoder ? "En" : "De") << "coder for _sqcifMPI ");
496 if (_qcifMPI) {
497 shifts = 1; PTRACE(3, "H263\t" << (dir == Encoder ? "En" : "De") << "coder for _qcifMPI");
499 if (_cifMPI) {
500 shifts = 2; PTRACE(3, "H263\t" << (dir == Encoder ? "En" : "De") << "coder for _cifMPI");
502 if (_cif4MPI) {
503 shifts = 3; PTRACE(3, "H263\t" << (dir == Encoder ? "En" : "De") << "coder for _cif4MPI");
505 if (_cif16MPI) {
506 shifts = 4; PTRACE(3, "H263\t" << (dir == Encoder ? "En" : "De") << "coder for _cif16MPI");
509 if (shifts < 0) {
510 PTRACE(1, "H263\tERROR in definition of h263 size");
511 return;
514 PTRACE(3, "H263\t" << (dir == Encoder ? "En" : "De") << "coder created."
515 << "for a size of " << (88 << shifts) << "x" << (72 << shifts));
517 Resize(88 << shifts , 72 << shifts); //Fill picture structure, open codec.
518 frameNum = 0;
520 InitialiseCodec();
524 H323_H263Codec::~H323_H263Codec()
526 PWaitAndSignal mutex1(videoHandlerActive);
528 CloseCodec();
530 if (videoDecoder) {
531 delete videoDecoder;
532 videoDecoder = NULL;
535 if (videoEncoder){
536 delete videoEncoder;
537 videoEncoder = NULL;
541 void H323_H263Codec::InitialiseCodec()
543 // no video decoder until we receive a packet
544 videoDecoder = NULL;
546 // no video encoder until we receive a packet
547 videoEncoder = NULL;
550 void H323_H263Codec::CloseCodec()
552 PTRACE(6, "H263\tClose h263 video " <<(direction == Encoder ? "En" : "De") << "coder");
558 /* Notes:
559 Quality was primarily for NetMeeting?
560 fillLevel simply set the greyscale of the background
564 //This function grabs, displays, and compresses a video frame into
565 //into H263 packets.
566 //Get another frame if all packets of previous frame have been sent.
567 //Get next packet on list and send that one.
568 //Render the current frame if all of its packets have been sent.
569 BOOL H323_H263Codec::Read(BYTE * buffer,
570 unsigned & length,
571 RTP_DataFrame & frame)
573 PWaitAndSignal mutex1(videoHandlerActive);
574 PTRACE(6,"H263\tAcquire next packet from h263 encoder.\n");
576 if (videoEncoder == NULL) {
577 videoEncoder = new H263Encoder(videoQuality, fillLevel);
580 if (rawDataChannel == NULL) {
581 length = 0;
582 PTRACE(1,"H263\tNo channel to connect to video grabber, close down video transmission thread.");
583 return FALSE;
586 if (!rawDataChannel->IsOpen()) {
587 PTRACE(1,"H263\tVideo grabber is not initialised, close down video transmission thread.");
588 length = 0;
589 return FALSE;
592 frameWidth = ((PVideoChannel *)rawDataChannel)->GetGrabWidth();
593 frameHeight = ((PVideoChannel *)rawDataChannel)->GetGrabHeight();
594 PTRACE(6, "H263\tVideo grab size is " << frameWidth << "x" << frameHeight);
596 if (frameWidth == 0) {
597 PTRACE(1,"H263\tVideo grab width is 0 x 0, close down video transmission thread.");
598 length=0;
599 return FALSE;
602 videoEncoder->SetSize(frameWidth, frameHeight);
604 PINDEX bytesInFrame = 0;
605 BOOL ok = TRUE;
607 #define NUMAVG 8
609 #ifdef INC_ENCODE
610 if (!videoEncoder->MoreToIncEncode()) { // get a new frame
611 #else
612 if (!videoEncoder->PacketsOutStanding()) { // }get a new frame
613 #endif
614 if (0 == frameNum) { // frame 0 means no frame has been sent yet
615 frameStartTime = PTimer::Tick();
617 else {
618 int frameTimeMs, avgFrameTimeMs, adjFrameTimeMs, avgAdjFrameTimeMs, avgFrameBytes;
619 PTimeInterval currentTime;
621 currentTime = PTimer::Tick();
622 frameTimeMs = (int)(currentTime - frameStartTime).GetMilliSeconds();
623 adjFrameTimeMs = frameTimeMs - (int)grabInterval.GetMilliSeconds(); // subtract time possibly blocked in grabbing
624 frameStartTime = currentTime;
626 sumFrameTimeMs += frameTimeMs;
627 avgFrameTimeMs = sumFrameTimeMs / NUMAVG;
628 sumFrameTimeMs -= avgFrameTimeMs;
629 sumAdjFrameTimeMs += adjFrameTimeMs;
630 avgAdjFrameTimeMs = sumAdjFrameTimeMs / NUMAVG;
631 sumAdjFrameTimeMs -= avgAdjFrameTimeMs;
632 sumFrameBytes += frameBytes;
633 avgFrameBytes = sumFrameBytes / NUMAVG;
634 sumFrameBytes -= avgFrameBytes;
636 //PTRACE(3,"H263\tframeNum grabInterval: "
637 // << frameNum << " " << grabInterval.GetMilliSeconds());
638 //PTRACE(3,"H263\tframeNum frameBits frameTimeMs Bps: "
639 // << frameNum << " " << (frameBytes*8) << " " << frameTimeMs
640 // << " " << frameBytes*8*1000/frameTimeMs);
641 //PTRACE(3,"H263\tframeNum avgFrameBits avgFrameTimeMs avgBps: "
642 // << frameNum << " " << (avgFrameBytes*8) << " " << avgFrameTimeMs
643 // << " " << avgFrameBytes*8*1000/avgFrameTimeMs);
644 //PTRACE(3,"H263\tframeNum avgFrameBits avgAdjFrameTimeMs avgAdjBps: "
645 // << frameNum << " " << (avgFrameBytes*8) << " " << avgAdjFrameTimeMs
646 // << " " << avgFrameBytes*8*1000/avgAdjFrameTimeMs);
648 if (frameNum > NUMAVG) { // do quality adjustment after first NUMAVG frames
649 if (0 != targetFrameTimeMs && (videoBitRateControlModes & DynamicVideoQuality)) {
650 int error; // error signal
651 int aerror;
652 int act; // action signal
653 int newQuality;
654 int avgFrameBitRate;
655 int targetFrameBits;
657 // keep track of average frame size and
658 // adjust encoder quality to get targetFrameBits bits per frame
659 if (avgAdjFrameTimeMs)
660 avgFrameBitRate = avgFrameBytes*8*1000 / avgAdjFrameTimeMs; // bits per second
661 else
662 avgFrameBitRate = avgFrameBytes*8*1000;
664 targetFrameBits = avgFrameBitRate * targetFrameTimeMs / 1000;
665 error = (frameBytes*8) - targetFrameBits; // error signal
666 aerror = PABS(error);
668 act = 0;
669 if (aerror > (targetFrameBits/8)) {
670 if (aerror > (targetFrameBits/4)) {
671 if (aerror > (targetFrameBits/2)) {
672 act = error>0 ? 2 : -4;
674 else {
675 act = error>0 ? 1 : -2;
678 else {
679 act = error>0 ? 1 : -1;
682 newQuality = videoQuality + act;
683 newQuality = PMIN(PMAX(newQuality, videoQMin), videoQMax);
684 //PTRACE(3,"H263\tframeNum targetFrameBits frameBits videoQuality newQuality: "
685 // << frameNum << " " << targetFrameBits << " " << (frameBytes*8) << " "
686 // << videoQuality << " " << newQuality);
687 videoQuality = newQuality;
689 videoEncoder->SetQualityLevel(videoQuality);
691 //PTRACE(3,"H263\tframeNum avgFrameBitRate bitRateHighLimit: "
692 // << frameNum << " " << avgFrameBitRate << " " << bitRateHighLimit);
697 //NO data is waiting to be read. Go and get some with the read call.
698 PTRACE(3,"H263\tRead frame from the video source.");
699 PTimeInterval grabStartTime = PTimer::Tick();
700 if (rawDataChannel->Read(videoEncoder->GetFramePtr(), bytesInFrame)) {
701 PTRACE(3,"H263\tSuccess. Read frame from the video source in "
702 << (PTimer::Tick() - grabStartTime).GetMilliSeconds() << " ms.");
704 if (frameNum == 0) {
705 memset(videoEncoder->GetFramePtr(), 64, (frameWidth * frameHeight * 3) >> 1);
708 packetNum = 0; // reset packet counter
710 // If there is a Renderer attached, display the grabbed video.
711 if (((PVideoChannel *)rawDataChannel)->IsRenderOpen()) {
712 ok = RenderFrame(); //use data from grab process.
715 #ifdef INC_ENCODE
716 videoEncoder->PreProcessOneFrame(); //Prepare to generate H263 packets
717 #else
718 videoEncoder->ProcessOneFrame(); //Generate H263 packets
719 #endif
720 frameNum++;
721 } else {
722 PTRACE(1,"H263\tFailed to read data from video grabber, close down video transmission thread.");
723 return FALSE; //Read failed, return false.
725 grabInterval = PTimer::Tick() - grabStartTime;
727 /////////////////////////////////////////////////////////////////
728 /// THIS VALUE MUST BE CALCULATED AND NOT JUST SET TO 29.97Hz!!!!
729 /////////////////////////////////////////////////////////////////
730 timestampDelta = 3003;
731 frameBytes = 0;
735 #ifdef INC_ENCODE
736 videoEncoder->IncEncodeAndGetPacket(buffer,length); //encode & get next packet
737 frame.SetMarker(!videoEncoder->MoreToIncEncode());
738 #else
739 videoEncoder->ReadOnePacket(buffer,length); //get next packet on list
740 frame.SetMarker(!videoEncoder->PacketsOutStanding());
741 #endif
742 packetNum++;
744 // Monitor and report bandwidth usage.
745 // If controlling bandwidth, limit the video bandwidth to
746 // bitRateHighLimit by introducing a variable delay between packets.
747 PTimeInterval currentTime;
748 if (0 != bitRateHighLimit &&
749 (videoBitRateControlModes & AdaptivePacketDelay)) {
750 PTimeInterval waitBeforeSending;
752 if (newTime != 0) { // calculate delay and wait
753 currentTime = PTimer::Tick();
754 waitBeforeSending = newTime - currentTime;
755 if (waitBeforeSending > 0) PThread::Current()->Sleep(waitBeforeSending);
756 // report bit rate & control error for previous packet
757 currentTime = PTimer::Tick(); //re-acquire current time after wait
758 //PTRACE(3, "H263\tBitRateControl Packet(" << oldPacketNum
759 // << ") Bits: " << oldLength*8
760 // << " Interval: " << (currentTime - oldTime).GetMilliSeconds()
761 // << " Rate: " << oldLength*8000/(currentTime - oldTime).GetMilliSeconds()
762 // << " Error: " << (currentTime - newTime).GetMilliSeconds()
763 // << " Slept: " << waitBeforeSending.GetMilliSeconds());
765 currentTime = PTimer::Tick(); // re-acquire current time due to possible PTRACE delay
766 // ms = (bytes * 8) / (bps / 1000)
767 if (bitRateHighLimit/1000)
768 newTime = currentTime + length*8/(bitRateHighLimit/1000);
769 else
770 newTime = currentTime + length*8;
772 else {
773 // monitor & report bit rate
774 if (oldTime != 0) { // report bit rate for previous packet
775 PTimeInterval currentTime = PTimer::Tick();
776 //PTRACE(3, "H263\tBitRateReport Packet(" << oldPacketNum
777 // << ") Bits: " << oldLength*8
778 // << " Interval: " << (currentTime - oldTime).GetMilliSeconds()
779 // << " Rate: " << oldLength*8000/(currentTime - oldTime).GetMilliSeconds());
781 currentTime = PTimer::Tick(); // re-acquire current time due to possible PTRACE delay
783 //oldPacketNum = packetNum; // used only for PTRACE
784 oldTime = currentTime;
785 oldLength = length;
786 frameBytes += length; // count current frame bytes
787 return ok;
793 BOOL H323_H263Codec::Write(const BYTE * buffer,
794 unsigned length,
795 const RTP_DataFrame & frame,
796 unsigned & written)
798 PWaitAndSignal mutex1(videoHandlerActive);
800 if (rawDataChannel == NULL) {
801 //Some other task has killed our videohandler. Exit.
802 return FALSE;
805 BOOL lostPreviousPacket = FALSE;
806 if ((++lastSequenceNumber) != frame.GetSequenceNumber()) {
807 lostPreviousPacket = TRUE;
808 PTRACE(3,"H263\tDetected loss of one video packet. "
809 << lastSequenceNumber << " != "
810 << frame.GetSequenceNumber() << " Will recover.");
811 lastSequenceNumber = frame.GetSequenceNumber();
812 // SendMiscCommand(H245_MiscellaneousCommand_type::e_lostPartialPicture);
815 // always indicate we have written the entire packet
816 written = length;
818 // H.263 header is usually at start of buffer
819 const unsigned char * header = buffer;
820 // adjust for any contributing source (see SSRC in RFC1889)
821 PINDEX cnt = frame.GetContribSrcCount();
822 if (cnt > 0) {
823 header += cnt * 4;
824 length -= cnt * 4;
827 // determine video codec type
828 if (videoDecoder == NULL) {
830 if ((*header & 2) && !(*header & 1)) // check value of I field in header
831 AWM: Intra vs. Full?
833 videoDecoder = new H263Decoder();
834 videoDecoder->marks(rvts);
837 videoDecoder->mark(now);
838 BOOL ok = videoDecoder->decode(header, length, (char)lostPreviousPacket,
839 (char)frame.GetMarker(), frame.GetSequenceNumber());
840 if (!ok) {
841 PTRACE (3, "H263\t Could not decode frame, continuing in hope.");
842 return TRUE;
845 // If the incoming video stream changes size, resize the rendering device.
846 ok = Resize(videoDecoder->width(), videoDecoder->height());
848 if (ok && frame.GetMarker()) {
849 videoDecoder->sync();
850 ndblk = videoDecoder->ndblk();
851 ok = RenderFrame();
852 videoDecoder->resetndblk();
855 return ok;
861 BOOL H323_H263Codec::Resize(int _width, int _height)
863 if ((frameWidth == _width) && (frameHeight == _height))
864 return TRUE;
866 PTRACE(6, "H263\t" << (direction == Encoder ? "En" : "De") << "coder resizing to "
867 << _width << "x" << _height << ".");
870 frameWidth = _width;
871 frameHeight = _height;
873 return TRUE;
877 /* RenderFrame does two things:
878 a) Set size of the display frame. This call happens with every frame.
879 A very small overhead.
880 b) Display a frame.
883 BOOL H323_H263Codec::RenderFrame(const void * buffer)
885 if (rawDataChannel == NULL)
886 return TRUE;
888 //Now display local image.
889 ((PVideoChannel *)rawDataChannel)->SetRenderFrameSize(frameWidth, frameHeight);
891 if (buffer == NULL)
892 return TRUE;
894 return rawDataChannel->Write(buffer, 0 /*unused parameter*/);
897 /* AWM: Look-alike to H.261 implementation */
898 BOOL H323_H263Codec::RenderFrame()
900 void *srcData;
902 if (direction == Encoder)
903 srcData = videoEncoder->GetFramePtr();
904 else
905 srcData = videoDecoder->GetFramePtr();
907 return RenderFrame(srcData);
913 void H323_H263Codec::SetTxQualityLevel(int qLevel)
915 int qualityLevel = PMIN(14, PMAX(qLevel,3));
917 int lowLimit = PMIN(10, qualityLevel - 2);
918 int highLimit = qualityLevel + 12;
920 videoQuality = qLevel;
921 videoQMin = lowLimit;
922 videoQMax = highLimit;
926 void H323_H263Codec::SetBackgroundFill(int idle)
928 fillLevel = PMIN(99, PMAX(idle,1));
932 void H323_H263Codec::OnLostPartialPicture()
934 PTRACE(3, "H263\tLost partial picture message ignored, not implemented");
938 void H323_H263Codec::OnLostPicture()
940 PTRACE(3, "H263\tLost picture message ignored, not implemented");
944 //////////////////////////////////////////////////////////////////////
946 #endif // H323_VICH263