Utilise new MergeSym feature to no longer overwrite the source .DEF file when buildin...
[openh323.git] / src / h261codec.cxx
blob0daf79bddb964e39143ce74d1449973c0c0d340b
1 /*
2 * h261codec.cxx
4 * H.323 protocol handler
6 * Open H323 Library
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 * Contributor(s): Michele Piccini (michele@piccini.com)
25 * Derek Smithies (derek@indranet.co.nz)
27 * $Log$
28 * Revision 1.75 2006/12/19 00:21:01 dereksmithies
29 * Fixed deletion of an array of objects.
30 * Thanks to Ben Weekes and valgrind.
32 * Revision 1.74 2006/06/21 05:11:48 csoutheren
33 * Fixed build with latest PWLib
35 * Revision 1.73 2006/06/06 08:05:40 csoutheren
36 * Make sure maxBitRate is always initialised to a useful value
38 * Revision 1.72 2006/04/19 01:31:46 csoutheren
39 * Fix problem with resizing H.261 video
41 * Revision 1.71 2006/03/28 05:15:02 csoutheren
42 * Change video codecs to set grabber capture size rather than
43 * grabber size setting codec size
45 * Revision 1.70 2006/03/21 10:43:35 csoutheren
46 * Ensure bytes per frame is set when writing to video devices
48 * Revision 1.69 2005/11/25 00:10:24 csoutheren
49 * Applied patch #1303543 from Hannes Friederich
50 * Added guard to weird conditions in H261 codec
52 * Revision 1.68 2005/02/24 19:54:18 dsandras
53 * Fixed quality problem with H.261 thanks to Hannes Friederich.
55 * Revision 1.67 2005/01/21 21:25:42 csoutheren
56 * Fixed delete [] operator
58 * Revision 1.66 2004/08/26 08:05:04 csoutheren
59 * Codecs now appear in abstract factory system
60 * Fixed Windows factory bootstrap system (again)
62 * Revision 1.65 2004/07/07 08:04:55 csoutheren
63 * Added video codecs to default codec list, but H.263 is only loaded if the .so/DLL is found
65 * Revision 1.64 2004/05/20 02:07:29 csoutheren
66 * Use macro to work around MSVC internal compiler errors
68 * Revision 1.63 2004/05/19 07:38:23 csoutheren
69 * Changed OpalMediaFormat handling to use abstract factory method functions
71 * Revision 1.62 2004/05/04 03:33:33 csoutheren
72 * Added guards against comparing certain kinds of Capabilities
74 * Revision 1.61 2004/04/03 08:28:06 csoutheren
75 * Remove pseudo-RTTI and replaced with real RTTI
77 * Revision 1.60 2004/03/24 00:39:12 dereksmithies
78 * Changes from Michael Smith for use in reporting frames/second. Many Thanks
80 * Revision 1.59 2004/01/02 00:31:42 dereksmithies
81 * Fix test on presence/absence of video.
83 * Revision 1.58 2003/12/14 10:42:29 rjongbloed
84 * Changes for compilability without video support.
86 * Revision 1.57 2003/10/02 23:37:56 dereksmithies
87 * Add fix for fast update problem in h261 codec. Thanks to Martin André for doing the initial legwork.
89 * Revision 1.56 2003/04/03 23:54:15 robertj
90 * Added fast update to H.261 codec, thanks Gustavo García Bernardo
92 * Revision 1.55 2003/03/20 23:45:46 dereks
93 * Make formatting more consistant with the openh323.org standard.
95 * Revision 1.54 2003/03/17 08:05:02 robertj
96 * Removed videoio classes in openh323 as now has versions in pwlib.
98 * Revision 1.53 2003/03/11 22:05:00 dereks
99 * Video receive will not terminate in abnormal situations
100 * Thanks to Damien Sandras.
102 * Revision 1.52 2002/12/29 22:35:34 dereks
103 * Fix so video with Windows XP works. Thanks Damien Sandras.
105 * Revision 1.51 2002/12/24 07:38:49 robertj
106 * Patches to fix divide by zero error, thanks Damien Sandras
108 * Revision 1.50 2002/12/16 09:11:19 robertj
109 * Added new video bit rate control, thanks Walter H. Whitlock
111 * Revision 1.49 2002/08/05 10:03:47 robertj
112 * Cosmetic changes to normalise the usage of pragma interface/implementation.
114 * Revision 1.48 2002/05/19 22:03:45 dereks
115 * Add fix from Sean Miceli, so correct P64Decoder is picked in calls with Netmeeting.
116 * Many thanks, good work!
118 * Revision 1.47 2002/04/26 04:58:34 dereks
119 * Add Walter Whitlock's fixes, based on Victor Ivashim's suggestions to improve
120 * the quality with Netmeeting. Thanks guys!!!
122 * Revision 1.46 2002/04/05 00:53:19 dereks
123 * Modify video frame encoding so that frame is encoded on an incremental basis.
124 * Thanks to Walter Whitlock - good work.
126 * Revision 1.45 2002/01/09 06:07:13 robertj
127 * Fixed setting of RTP timestamp values on video transmission.
129 * Revision 1.44 2002/01/09 00:21:39 robertj
130 * Changes to support outgoing H.245 RequstModeChange.
132 * Revision 1.43 2002/01/08 01:30:41 robertj
133 * Tidied up some PTRACE debug output.
135 * Revision 1.42 2002/01/03 23:05:50 dereks
136 * Add methods to count number of H261 packets waiting to be sent.
138 * Revision 1.41 2001/12/20 01:19:43 dereks
139 * modify ptrace statments.
141 * Revision 1.40 2001/12/13 03:01:23 dereks
142 * Modify trace statement.
144 * Revision 1.39 2001/12/04 05:13:12 robertj
145 * Added videa bandwidth limiting code for H.261, thanks Jose Luis Urien.
147 * Revision 1.38 2001/12/04 04:26:06 robertj
148 * Added code to allow change of video quality in H.261, thanks Damian Sandras
150 * Revision 1.37 2001/10/23 02:17:16 dereks
151 * Initial release of cu30 video codec.
153 * Revision 1.36 2001/09/26 01:59:31 robertj
154 * Fixed MSVC warning.
156 * Revision 1.35 2001/09/25 03:14:47 dereks
157 * Add constant bitrate control for the h261 video codec.
158 * Thanks Tiziano Morganti for the code to set bit rate. Good work!
160 * Revision 1.34 2001/09/21 02:51:29 robertj
161 * Added default session ID to media format description.
163 * Revision 1.33 2001/08/22 01:28:20 robertj
164 * Resolved confusion with YUV411P and YUV420P video formats, thanks Mark Cooke.
166 * Revision 1.32 2001/07/09 07:19:40 rogerh
167 * Make the encoder render a frames (for local video) only when there is a
168 * renderer attached
170 * Revision 1.31 2001/06/19 02:01:42 dereks
171 * The video encoder thread ends if the renderframe fails.
173 * Revision 1.30 2001/06/13 21:46:37 dereks
174 * Add 5 msec separator between consecutive packets generated from the same
175 * frame. Prevents lost packets, and improves reliability.
177 * Revision 1.29 2001/05/25 01:10:26 dereks
178 * Remove unnecessary packet receive variable.
179 * Alter the position of the check for change in frame size.
181 * Revision 1.28 2001/02/09 05:13:55 craigs
182 * Added pragma implementation to (hopefully) reduce the executable image size
183 * under Linux
185 * Revision 1.27 2001/01/25 07:27:16 robertj
186 * Major changes to add more flexible OpalMediaFormat class to normalise
187 * all information about media types, especially codecs.
189 * Revision 1.26 2000/12/19 22:33:44 dereks
190 * Adjust so that the video channel is used for reading/writing raw video
191 * data, which better modularizes the video codec.
193 * Revision 1.25 2000/10/13 02:20:32 robertj
194 * Fixed capability clone so gets all fields including those in ancestor.
196 * Revision 1.24 2000/10/13 01:47:26 dereks
197 * Include command option for setting the number of transmitted video
198 * frames per second. use --videotxfps n
200 * Revision 1.23 2000/09/08 06:41:38 craigs
201 * Added ability to set video device
202 * Added ability to select test input frames
204 * Revision 1.22 2000/08/28 23:47:41 dereks
205 * Fix bug in resizing image of received video
207 * Revision 1.21 2000/08/21 04:45:06 dereks
208 * Fix dangling pointer that caused segfaults for windows&unix users.
209 * Improved the test image which is used when video grabber won't open.
210 * Added code to handle setting of video Tx Quality.
211 * Added code to set the number of background blocks sent with every frame.
213 * Revision 1.20 2000/07/13 12:31:31 robertj
214 * Fixed format name output for in band switching H.261
216 * Revision 1.19 2000/07/04 13:00:36 craigs
217 * Fixed problem with selecting large and small video sizes
219 * Revision 1.18 2000/06/10 09:21:36 rogerh
220 * Make GetFormatName return H.261 QCIF or H.261 CIF
222 * Revision 1.17 2000/05/10 04:05:34 robertj
223 * Changed capabilities so has a function to get name of codec, instead of relying on PrintOn.
225 * Revision 1.16 2000/05/02 04:32:26 robertj
226 * Fixed copyright notice comment.
228 * Revision 1.15 2000/04/29 03:01:48 robertj
229 * Fixed bug in receive of H261 capability, setting cif & qcif variables correctly.
231 * Revision 1.14 2000/03/24 01:23:49 robertj
232 * Directory reorganisation.
234 * Revision 1.13 2000/03/21 03:06:49 robertj
235 * Changes to make RTP TX of exact numbers of frames in some codecs.
237 * Revision 1.12 2000/02/10 03:08:02 craigs
238 * Added ability to specify NTSC or PAL video format
240 * Revision 1.11 2000/02/04 05:11:19 craigs
241 * Updated for new Makefiles and for new video transmission code
243 * Revision 1.10 2000/01/13 04:03:45 robertj
244 * Added video transmission
246 * Revision 1.9 1999/12/23 23:02:35 robertj
247 * File reorganision for separating RTP from H.323 and creation of LID for VPB support.
249 * Revision 1.8 1999/11/29 08:20:47 craigs
250 * Updated for new codec interface
252 * Revision 1.7 1999/11/01 00:52:00 robertj
253 * Fixed various problems in video, especially ability to pass error return value.
255 * Revision 1.6 1999/10/08 09:59:03 robertj
256 * Rewrite of capability for sending multiple audio frames
258 * Revision 1.5 1999/10/08 04:58:38 robertj
259 * Added capability for sending multiple audio frames in single RTP packet
261 * Revision 1.4 1999/09/21 14:13:53 robertj
262 * Windows MSVC compatibility.
264 * Revision 1.3 1999/09/21 08:10:03 craigs
265 * Added support for video devices and H261 codec
267 * Revision 1.2 1999/09/18 13:24:38 craigs
268 * Added ability to disable jitter buffer
269 * Added ability to access entire RTP packet in codec Write
271 * Revision 1.1 1999/09/08 04:05:49 robertj
272 * Added support for video capabilities & codec, still needs the actual codec itself!
276 #include <ptlib.h>
277 #include <ptlib/video.h>
279 #ifdef __GNUC__
280 #pragma implementation "h261codec.h"
281 #endif
283 #include "h261codec.h"
285 #ifndef NO_H323_VIDEO
287 #include "h245.h"
288 #include "rtp.h"
290 #include "vic/p64.h"
291 #include "vic/p64encoder.h"
293 #define new PNEW
294 #define INC_ENCODE 1
296 char OpalH261[] = "H.261";
298 namespace PWLibStupidLinkerHacks {
299 int h261Loader;
302 OPAL_MEDIA_FORMAT_DECLARE(OpalH261Format,
303 OpalH261,
304 OpalMediaFormat::DefaultVideoSessionID,
305 RTP_DataFrame::H261,
306 FALSE, // No jitter for video
307 240000, // bits/sec
308 2000, // Not sure of this value!
309 0, // No intrinsic time per frame
310 OpalMediaFormat::VideoTimeUnits,
313 H323_H261Capability::H323_H261Capability(unsigned _qcifMPI,
314 unsigned _cifMPI,
315 BOOL _temporalSpatialTradeOffCapability,
316 BOOL _stillImageTransmission,
317 unsigned _maxBitRate)
319 qcifMPI = _qcifMPI;
320 cifMPI = _cifMPI;
321 temporalSpatialTradeOffCapability = _temporalSpatialTradeOffCapability;
322 maxBitRate = _maxBitRate;
323 stillImageTransmission = _stillImageTransmission;
327 PObject * H323_H261Capability::Clone() const
329 return new H323_H261Capability(*this);
333 PObject::Comparison H323_H261Capability::Compare(const PObject & obj) const
335 if (!PIsDescendant(&obj, H323_H261Capability))
336 return LessThan;
338 Comparison result = H323Capability::Compare(obj);
339 if (result != EqualTo)
340 return result;
342 const H323_H261Capability & other = (const H323_H261Capability &)obj;
344 if (((qcifMPI > 0) && (other.qcifMPI > 0)) ||
345 ((cifMPI > 0) && (other.cifMPI > 0)))
346 return EqualTo;
348 if (qcifMPI > 0)
349 return LessThan;
351 return GreaterThan;
355 PString H323_H261Capability::GetFormatName() const
357 if (qcifMPI > 0 && cifMPI > 0)
358 return "H.261-(Q)CIF";
360 if (qcifMPI > 0)
361 return "H.261-QCIF";
363 if (cifMPI > 0)
364 return "H.261-CIF";
366 return "H.261";
370 unsigned H323_H261Capability::GetSubType() const
372 return H245_VideoCapability::e_h261VideoCapability;
378 BOOL H323_H261Capability::OnSendingPDU(H245_VideoCapability & cap) const
380 cap.SetTag(H245_VideoCapability::e_h261VideoCapability);
382 H245_H261VideoCapability & h261 = cap;
383 if (qcifMPI > 0) {
384 h261.IncludeOptionalField(H245_H261VideoCapability::e_qcifMPI);
385 h261.m_qcifMPI = qcifMPI;
387 if (cifMPI > 0) {
388 h261.IncludeOptionalField(H245_H261VideoCapability::e_cifMPI);
389 h261.m_cifMPI = cifMPI;
391 h261.m_temporalSpatialTradeOffCapability = temporalSpatialTradeOffCapability;
392 h261.m_maxBitRate = (maxBitRate == 0) ? 3270 : maxBitRate;
393 h261.m_stillImageTransmission = stillImageTransmission;
394 return TRUE;
398 BOOL H323_H261Capability::OnSendingPDU(H245_VideoMode & pdu) const
400 pdu.SetTag(H245_VideoMode::e_h261VideoMode);
401 H245_H261VideoMode & mode = pdu;
402 mode.m_resolution.SetTag(cifMPI > 0 ? H245_H261VideoMode_resolution::e_cif
403 : H245_H261VideoMode_resolution::e_qcif);
404 mode.m_bitRate = (maxBitRate == 0) ? 3270 : maxBitRate;
405 mode.m_stillImageTransmission = stillImageTransmission;
406 return TRUE;
410 BOOL H323_H261Capability::OnReceivedPDU(const H245_VideoCapability & cap)
412 if (cap.GetTag() != H245_VideoCapability::e_h261VideoCapability)
413 return FALSE;
415 const H245_H261VideoCapability & h261 = cap;
416 if (h261.HasOptionalField(H245_H261VideoCapability::e_qcifMPI))
417 qcifMPI = h261.m_qcifMPI;
418 else
419 qcifMPI = 0;
420 if (h261.HasOptionalField(H245_H261VideoCapability::e_cifMPI))
421 cifMPI = h261.m_cifMPI;
422 else
423 cifMPI = 0;
424 temporalSpatialTradeOffCapability = h261.m_temporalSpatialTradeOffCapability;
425 maxBitRate = h261.m_maxBitRate;
426 stillImageTransmission = h261.m_stillImageTransmission;
427 return TRUE;
431 H323Codec * H323_H261Capability::CreateCodec(H323Codec::Direction direction) const
433 return new H323_H261Codec(direction, qcifMPI > 0);
437 //////////////////////////////////////////////////////////////////////////////
439 H323_H261Codec::H323_H261Codec(Direction dir, BOOL _isqCIF)
440 : H323VideoCodec("H.261", dir), isqCIF(_isqCIF)
442 PTRACE(3, "H261\t" << (isqCIF ? "Q" : "") << "CIF "
443 << (dir == Encoder ? "en" : "de") << "coder created.");
445 // no video decoder until we receive a packet
446 videoDecoder = NULL;
448 // no video encoder until we receive a packet
449 videoEncoder = NULL;
452 // other stuff
453 now = 1;
454 rvts = NULL;
455 nblk = ndblk = 0;
456 doFastUpdate = FALSE;
458 // initial size of the window is CIF
459 if (dir == Encoder) {
460 frameWidth = isqCIF ? QCIF_WIDTH : CIF_WIDTH;
461 frameHeight = isqCIF ? QCIF_HEIGHT : CIF_HEIGHT;
462 } else {
463 frameWidth=0;
464 frameHeight=0;
467 frameNum = 0; // frame counter
468 timestampDelta = 0;
469 videoBitRateControlModes = None;
471 // video quality control
472 videoQMin = 1;
473 videoQMax = 24;
474 videoQuality = 9; // default = 9
475 //SetTxQualityLevel( videoQuality ); // don't have encoder yet
477 // video bit rate control
478 sumFrameTimeMs = 0;
479 sumAdjFrameTimeMs = 0;
480 sumFrameBytes = 0;
481 bitRateHighLimit = 0;
482 videoBitRateControlModes = None;
483 targetFrameTimeMs = 167;
484 oldTime = newTime = 0;
488 H323_H261Codec::~H323_H261Codec()
490 PWaitAndSignal mutex1(videoHandlerActive);
492 if (videoDecoder)
494 delete videoDecoder;
495 videoDecoder = NULL;
498 if (videoEncoder){
499 delete videoEncoder;
500 videoEncoder = NULL;
503 if (rvts){
504 delete [] rvts;
509 //This function grabs, displays, and compresses a video frame into
510 //into H261 packets.
511 //Get another frame if all packets of previous frame have been sent.
512 //Get next packet on list and send that one.
513 //Render the current frame if all of its packets have been sent.
514 BOOL H323_H261Codec::Read(BYTE * buffer,
515 unsigned & length,
516 RTP_DataFrame & frame)
518 fastUpdateMutex.Wait();
519 if ((videoEncoder != NULL) && doFastUpdate)
520 videoEncoder->FastUpdatePicture();
521 fastUpdateMutex.Signal();
523 PWaitAndSignal mutex1(videoHandlerActive);
524 PTRACE(6,"H261\tAcquire next packet from h261 encoder.\n");
526 if ( videoEncoder == NULL ) {
527 videoEncoder = new P64Encoder(videoQuality, fillLevel);
528 videoEncoder->SetSize(frameWidth, frameHeight);
531 if( rawDataChannel == NULL ) {
532 length = 0;
533 PTRACE(1,"H261\tNo channel to connect to video grabber, close down video transmission thread.");
534 return FALSE;
537 if( !rawDataChannel->IsOpen() ) {
538 PTRACE(1,"H261\tVideo grabber is not initialised, close down video transmission thread.");
539 length = 0;
540 return FALSE;
543 PINDEX w = ((PVideoChannel *)rawDataChannel)->GetGrabWidth();
544 PINDEX h = ((PVideoChannel *)rawDataChannel)->GetGrabHeight();
546 if (w == 0 ) {
547 PTRACE(1,"H261\tVideo grab width is 0 x 0, close down video transmission thread.");
548 length=0;
549 return FALSE;
552 if (w != frameWidth || h != frameHeight) {
553 w = isqCIF ? QCIF_WIDTH : CIF_WIDTH;
554 h = isqCIF ? QCIF_HEIGHT : CIF_HEIGHT;
555 ((PVideoChannel *)rawDataChannel)->SetGrabberFrameSize(w, h);
556 frameWidth = w;
557 frameHeight = h;
559 videoEncoder->SetSize(frameWidth, frameHeight);
562 PINDEX bytesInFrame = (frameWidth * frameHeight * 3) / 2;
563 BOOL ok = TRUE;
565 #define NUMAVG 8
567 #ifdef INC_ENCODE
568 if( !videoEncoder->MoreToIncEncode() ) { // get a new frame
569 #else
570 if( !videoEncoder->PacketsOutStanding() ) { // }get a new frame
571 #endif
572 if (0 == frameNum) { // frame 0 means no frame has been sent yet
573 frameStartTime = PTimer::Tick();
575 else {
576 int frameTimeMs, avgFrameTimeMs, adjFrameTimeMs, avgAdjFrameTimeMs, avgFrameBytes;
577 PTimeInterval currentTime;
579 currentTime = PTimer::Tick();
580 frameTimeMs = (int)(currentTime - frameStartTime).GetMilliSeconds();
581 adjFrameTimeMs = frameTimeMs - (int)grabInterval.GetMilliSeconds(); // subtract time possibly blocked in grabbing
582 frameStartTime = currentTime;
584 sumFrameTimeMs += frameTimeMs;
585 avgFrameTimeMs = sumFrameTimeMs / NUMAVG;
586 sumFrameTimeMs -= avgFrameTimeMs;
587 sumAdjFrameTimeMs += adjFrameTimeMs;
588 avgAdjFrameTimeMs = sumAdjFrameTimeMs / NUMAVG;
589 sumAdjFrameTimeMs -= avgAdjFrameTimeMs;
590 sumFrameBytes += frameBytes;
591 avgFrameBytes = sumFrameBytes / NUMAVG;
592 sumFrameBytes -= avgFrameBytes;
594 //PTRACE(3,"H261\tframeNum grabInterval: "
595 // << frameNum << " " << grabInterval.GetMilliSeconds());
596 //PTRACE(3,"H261\tframeNum frameBits frameTimeMs Bps: "
597 // << frameNum << " " << (frameBytes*8) << " " << frameTimeMs
598 // << " " << frameBytes*8*1000/frameTimeMs );
599 //PTRACE(3,"H261\tframeNum avgFrameBits avgFrameTimeMs avgBps: "
600 // << frameNum << " " << (avgFrameBytes*8) << " " << avgFrameTimeMs
601 // << " " << avgFrameBytes*8*1000/avgFrameTimeMs );
602 //PTRACE(3,"H261\tframeNum avgFrameBits avgAdjFrameTimeMs avgAdjBps: "
603 // << frameNum << " " << (avgFrameBytes*8) << " " << avgAdjFrameTimeMs
604 // << " " << avgFrameBytes*8*1000/avgAdjFrameTimeMs );
606 if (frameNum > NUMAVG) { // do quality adjustment after first NUMAVG frames
607 if( 0 != targetFrameTimeMs && (videoBitRateControlModes & DynamicVideoQuality) ) {
608 int error; // error signal
609 int aerror;
610 int act; // action signal
611 int newQuality;
612 int avgFrameBitRate;
613 int targetFrameBits;
615 // keep track of average frame size and
616 // adjust encoder quality to get targetFrameBits bits per frame
617 if (avgAdjFrameTimeMs)
618 avgFrameBitRate = avgFrameBytes*8*1000 / avgAdjFrameTimeMs; // bits per second
619 else
620 avgFrameBitRate = avgFrameBytes*8*1000;
622 targetFrameBits = avgFrameBitRate * targetFrameTimeMs / 1000;
623 error = (frameBytes*8) - targetFrameBits; // error signal
624 aerror = PABS(error);
626 act = 0;
627 if (aerror > (targetFrameBits/8) ) {
628 if (aerror > (targetFrameBits/4) ) {
629 if (aerror > (targetFrameBits/2) ) {
630 act = error>0 ? 2 : -4;
632 else {
633 act = error>0 ? 1 : -2;
636 else {
637 act = error>0 ? 1 : -1;
640 newQuality = videoQuality + act;
641 newQuality = PMIN(PMAX(newQuality, videoQMin), videoQMax );
642 //PTRACE(3,"H261\tframeNum targetFrameBits frameBits videoQuality newQuality: "
643 // << frameNum << " " << targetFrameBits << " " << (frameBytes*8) << " "
644 // << videoQuality << " " << newQuality );
645 videoQuality = newQuality;
646 videoEncoder->SetQualityLevel( videoQuality );
648 //PTRACE(3,"H261\tframeNum avgFrameBitRate bitRateHighLimit: "
649 // << frameNum << " " << avgFrameBitRate << " " << bitRateHighLimit );
654 //NO data is waiting to be read. Go and get some with the read call.
655 PTRACE(3,"H261\tRead frame from the video source.");
656 PTimeInterval grabStartTime = PTimer::Tick();
657 if (rawDataChannel->Read(videoEncoder->GetFramePtr(), bytesInFrame)) {
658 PTRACE(3,"H261\tSuccess. Read frame from the video source in "
659 << (PTimer::Tick() - grabStartTime).GetMilliSeconds() << " ms.");
660 packetNum = 0; // reset packet counter
661 // If there is a Renderer attached, display the grabbed video.
662 if (((PVideoChannel *)rawDataChannel)->IsRenderOpen() ) {
663 ok = RenderFrame(); //use data from grab process.
665 #ifdef INC_ENCODE
666 videoEncoder->PreProcessOneFrame(); //Prepare to generate H261 packets
667 #else
668 videoEncoder->ProcessOneFrame(); //Generate H261 packets
669 #endif
670 frameNum++;
671 } else {
672 PTRACE(1,"H261\tFailed to read data from video grabber, close down video transmission thread.");
673 return FALSE; //Read failed, return false.
675 grabInterval = PTimer::Tick() - grabStartTime;
677 /////////////////////////////////////////////////////////////////
678 /// THIS VALUE MUST BE CALCULATED AND NOT JUST SET TO 29.97Hz!!!!
679 /////////////////////////////////////////////////////////////////
680 timestampDelta = 3003;
681 frameBytes = 0;
684 else { //if(!videoEncoder->PacketsOutstanding())
685 if( 0 != bitRateHighLimit &&
686 (videoBitRateControlModes & AdaptivePacketDelay) )
687 ; // do nothing now, packet delay will be done later
688 else
689 PThread::Current()->Sleep(5); // Place a 5 ms interval betwen
690 // packets of the same frame.
691 timestampDelta = 0;
694 #ifdef INC_ENCODE
695 videoEncoder->IncEncodeAndGetPacket(buffer,length); //encode & get next packet
696 frame.SetMarker(!videoEncoder->MoreToIncEncode());
697 #else
698 videoEncoder->ReadOnePacket(buffer,length); //get next packet on list
699 frame.SetMarker(!videoEncoder->PacketsOutStanding());
700 #endif
701 packetNum++;
703 // Monitor and report bandwidth usage.
704 // If controlling bandwidth, limit the video bandwidth to
705 // bitRateHighLimit by introducing a variable delay between packets.
706 PTimeInterval currentTime;
707 if( 0 != bitRateHighLimit &&
708 (videoBitRateControlModes & AdaptivePacketDelay) ) {
709 PTimeInterval waitBeforeSending;
711 if (newTime != 0) { // calculate delay and wait
712 currentTime = PTimer::Tick();
713 waitBeforeSending = newTime - currentTime;
714 if (waitBeforeSending > 0) PThread::Current()->Sleep(waitBeforeSending);
715 // report bit rate & control error for previous packet
716 currentTime = PTimer::Tick(); //re-acquire current time after wait
717 //PTRACE(3, "H261\tBitRateControl Packet(" << oldPacketNum
718 // << ") Bits: " << oldLength*8
719 // << " Interval: " << (currentTime - oldTime).GetMilliSeconds()
720 // << " Rate: " << oldLength*8000/(currentTime - oldTime).GetMilliSeconds()
721 // << " Error: " << (currentTime - newTime).GetMilliSeconds()
722 // << " Slept: " << waitBeforeSending.GetMilliSeconds() );
724 currentTime = PTimer::Tick(); // re-acquire current time due to possible PTRACE delay
725 // ms = (bytes * 8) / (bps / 1000)
726 if (bitRateHighLimit/1000)
727 newTime = currentTime + length*8/(bitRateHighLimit/1000);
728 else
729 newTime = currentTime + length*8;
731 else {
732 // monitor & report bit rate
733 if (oldTime != 0) { // report bit rate for previous packet
734 PTimeInterval currentTime = PTimer::Tick();
735 //PTRACE(3, "H261\tBitRateReport Packet(" << oldPacketNum
736 // << ") Bits: " << oldLength*8
737 // << " Interval: " << (currentTime - oldTime).GetMilliSeconds()
738 // << " Rate: " << oldLength*8000/(currentTime - oldTime).GetMilliSeconds() );
740 currentTime = PTimer::Tick(); // re-acquire current time due to possible PTRACE delay
742 //oldPacketNum = packetNum; // used only for PTRACE
743 oldTime = currentTime;
744 oldLength = length;
745 frameBytes += length; // count current frame bytes
746 return ok;
751 BOOL H323_H261Codec::Write(const BYTE * buffer,
752 unsigned length,
753 const RTP_DataFrame & frame,
754 unsigned & written)
756 PWaitAndSignal mutex1(videoHandlerActive);
758 if( rawDataChannel == NULL ) {
759 //Some other task has killed our videohandler. Exit.
760 return FALSE;
763 BOOL lostPreviousPacket = FALSE;
764 if( (++lastSequenceNumber) != frame.GetSequenceNumber() ) {
765 lostPreviousPacket = TRUE;
766 PTRACE(3,"H261\tDetected loss of one video packet. "
767 << lastSequenceNumber << " != "
768 << frame.GetSequenceNumber() << " Will recover.");
769 lastSequenceNumber = frame.GetSequenceNumber();
770 // SendMiscCommand(H245_MiscellaneousCommand_type::e_lostPartialPicture);
773 // always indicate we have written the entire packet
774 written = length;
776 // H.261 header is usually at start of buffer
777 const unsigned char * header = buffer;
779 // determine video codec type
780 if (videoDecoder == NULL) {
781 // the old behaviour was to choose between IntraP64Decoder and FullP64Decoder,
782 // depending on the header of the first packet.
783 // This lead to bad video quality on some endpoints.
784 // Therefore, we chose to only use the FullP64Decoder
785 videoDecoder = new FullP64Decoder();
786 videoDecoder->marks(rvts);
789 videoDecoder->mark(now);
790 BOOL ok = videoDecoder->decode(header, length, lostPreviousPacket);
791 if (!ok) {
792 PTRACE (3, "H261\t Could not decode frame, continuing in hope.");
793 return TRUE;
796 // If the incoming video stream changes size, resize the rendering device.
797 ok = Resize(videoDecoder->width(), videoDecoder->height());
799 if (ok && frame.GetMarker()) {
800 videoDecoder->sync();
801 ndblk = videoDecoder->ndblk();
802 ok = RenderFrame();
803 frameNum++;
804 videoDecoder->resetndblk();
807 return ok;
811 /* Resize is relevant to the decoder only, as the encoder does not
812 change size mid transmission.
814 BOOL H323_H261Codec::Resize(int _width, int _height)
816 //Check for a resize is carried out one two level -.
817 // a) size change in the receive video stream.
819 if ((frameWidth != _width) || (frameHeight != _height) ) {
820 frameWidth = _width;
821 frameHeight = _height;
823 nblk = (frameWidth * frameHeight) / 64;
824 delete [] rvts;
825 rvts = new BYTE[nblk];
826 memset(rvts, 0, nblk);
827 if (videoDecoder != NULL)
828 videoDecoder->marks(rvts);
829 if (rawDataChannel != NULL)
830 ((PVideoChannel *)rawDataChannel)->SetRenderFrameSize(_width, _height);
833 return TRUE;
837 BOOL H323_H261Codec::Redraw()
839 now = 1;
840 memset(rvts, 1, nblk);
842 return RenderFrame();
846 /* RenderFrame does three things.
847 a) Set internal variables
848 b) Set size of the display frame. This call happens with every frame.
849 A very small overhead.
850 c) Display a frame.
852 BOOL H323_H261Codec::RenderFrame()
854 int wraptime = now ^ 0x80;
855 BYTE * ts = rvts;
856 int k;
857 for (k = nblk; --k >= 0; ++ts) {
858 if (*ts == wraptime)
859 *ts = (BYTE)now;
862 BOOL ok = TRUE;
863 if (rawDataChannel != NULL) {
865 //Now display local image.
866 ((PVideoChannel *)rawDataChannel)->SetRenderFrameSize(frameWidth, frameHeight);
867 PTRACE(6, "H261\tSize of video rendering frame set to " <<
868 frameWidth << "x" << frameHeight <<
869 " for channel:" << ((direction == Encoder) ? "encoding" : "decoding"));
871 if (direction == Encoder)
872 ok = rawDataChannel->Write((const void *)videoEncoder->GetFramePtr(),frameWidth*frameHeight*3/2);
873 else
874 ok = rawDataChannel->Write((const void *)videoDecoder->GetFramePtr(),frameWidth*frameHeight*3/2);
877 now = (now + 1) & 0xff;
879 return ok;
883 void H323_H261Codec::SetTxQualityLevel(int qLevel)
885 videoQuality = PMIN(videoQMax, PMAX(qLevel, videoQMin));
887 // If a video encoder is running and if there is no
888 // dynamic video quality control, update the value
889 // in the encoder
890 if (!(DynamicVideoQuality & videoBitRateControlModes) && (videoEncoder != NULL))
891 videoEncoder->SetQualityLevel (videoQuality);
892 PTRACE(3, "H261\tvideoQuality set to " << videoQuality);
895 void H323_H261Codec::SetTxMinQuality(int qlevel) {
896 videoQMin = PMIN(videoQMax, PMAX(1, qlevel));
897 PTRACE(3, "H261\tvideoQMin set to " << videoQMin);
900 void H323_H261Codec::SetTxMaxQuality(int qlevel) {
901 videoQMax = PMAX(videoQMin, PMIN(31, qlevel));
902 PTRACE(3, "H261\tvideoQMax set to " << videoQMax);
905 void H323_H261Codec::SetBackgroundFill(int idle)
907 fillLevel = PMIN(99, PMAX(idle,1));
909 // If a video encoder is running and if there is no
910 // dynamic video quality control, update the value
911 // in the encoder
912 if (!(DynamicVideoQuality & videoBitRateControlModes) && (NULL != videoEncoder))
913 videoEncoder->SetBackgroundFill (idle);
914 PTRACE(3, "H261\tfillLevel set to " << fillLevel);
918 void H323_H261Codec::OnFastUpdatePicture()
920 PTRACE(3,"H261\tFastUpdatePicture received");
921 PWaitAndSignal mutex1(fastUpdateMutex);
923 doFastUpdate = TRUE;
927 void H323_H261Codec::OnLostPartialPicture()
929 PTRACE(3,"H261\tLost partial picture message ignored, not implemented");
933 void H323_H261Codec::OnLostPicture()
935 PTRACE(3,"H261\tLost picture message ignored, not implemented");
939 #endif // NO_H323_VIDEO
942 /////////////////////////////////////////////////////////////////////////////