4 * H.323 protocol handler
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
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)
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
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
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!
277 #include <ptlib/video.h>
280 #pragma implementation "h261codec.h"
283 #include "h261codec.h"
285 #ifndef NO_H323_VIDEO
291 #include "vic/p64encoder.h"
296 char OpalH261
[] = "H.261";
298 namespace PWLibStupidLinkerHacks
{
302 OPAL_MEDIA_FORMAT_DECLARE(OpalH261Format
,
304 OpalMediaFormat::DefaultVideoSessionID
,
306 FALSE
, // No jitter for video
308 2000, // Not sure of this value!
309 0, // No intrinsic time per frame
310 OpalMediaFormat::VideoTimeUnits
,
313 H323_H261Capability::H323_H261Capability(unsigned _qcifMPI
,
315 BOOL _temporalSpatialTradeOffCapability
,
316 BOOL _stillImageTransmission
,
317 unsigned _maxBitRate
)
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
))
338 Comparison result
= H323Capability::Compare(obj
);
339 if (result
!= EqualTo
)
342 const H323_H261Capability
& other
= (const H323_H261Capability
&)obj
;
344 if (((qcifMPI
> 0) && (other
.qcifMPI
> 0)) ||
345 ((cifMPI
> 0) && (other
.cifMPI
> 0)))
355 PString
H323_H261Capability::GetFormatName() const
357 if (qcifMPI
> 0 && cifMPI
> 0)
358 return "H.261-(Q)CIF";
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
;
384 h261
.IncludeOptionalField(H245_H261VideoCapability::e_qcifMPI
);
385 h261
.m_qcifMPI
= qcifMPI
;
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
;
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
;
410 BOOL
H323_H261Capability::OnReceivedPDU(const H245_VideoCapability
& cap
)
412 if (cap
.GetTag() != H245_VideoCapability::e_h261VideoCapability
)
415 const H245_H261VideoCapability
& h261
= cap
;
416 if (h261
.HasOptionalField(H245_H261VideoCapability::e_qcifMPI
))
417 qcifMPI
= h261
.m_qcifMPI
;
420 if (h261
.HasOptionalField(H245_H261VideoCapability::e_cifMPI
))
421 cifMPI
= h261
.m_cifMPI
;
424 temporalSpatialTradeOffCapability
= h261
.m_temporalSpatialTradeOffCapability
;
425 maxBitRate
= h261
.m_maxBitRate
;
426 stillImageTransmission
= h261
.m_stillImageTransmission
;
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
448 // no video encoder until we receive a packet
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
;
467 frameNum
= 0; // frame counter
469 videoBitRateControlModes
= None
;
471 // video quality control
474 videoQuality
= 9; // default = 9
475 //SetTxQualityLevel( videoQuality ); // don't have encoder yet
477 // video bit rate control
479 sumAdjFrameTimeMs
= 0;
481 bitRateHighLimit
= 0;
482 videoBitRateControlModes
= None
;
483 targetFrameTimeMs
= 167;
484 oldTime
= newTime
= 0;
488 H323_H261Codec::~H323_H261Codec()
490 PWaitAndSignal
mutex1(videoHandlerActive
);
509 //This function grabs, displays, and compresses a video frame into
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
,
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
) {
533 PTRACE(1,"H261\tNo channel to connect to video grabber, close down video transmission thread.");
537 if( !rawDataChannel
->IsOpen() ) {
538 PTRACE(1,"H261\tVideo grabber is not initialised, close down video transmission thread.");
543 PINDEX w
= ((PVideoChannel
*)rawDataChannel
)->GetGrabWidth();
544 PINDEX h
= ((PVideoChannel
*)rawDataChannel
)->GetGrabHeight();
547 PTRACE(1,"H261\tVideo grab width is 0 x 0, close down video transmission thread.");
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
);
559 videoEncoder
->SetSize(frameWidth
, frameHeight
);
562 PINDEX bytesInFrame
= (frameWidth
* frameHeight
* 3) / 2;
568 if( !videoEncoder
->MoreToIncEncode() ) { // get a new frame
570 if( !videoEncoder
->PacketsOutStanding() ) { // }get a new frame
572 if (0 == frameNum
) { // frame 0 means no frame has been sent yet
573 frameStartTime
= PTimer::Tick();
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
610 int act
; // action signal
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
620 avgFrameBitRate
= avgFrameBytes
*8*1000;
622 targetFrameBits
= avgFrameBitRate
* targetFrameTimeMs
/ 1000;
623 error
= (frameBytes
*8) - targetFrameBits
; // error signal
624 aerror
= PABS(error
);
627 if (aerror
> (targetFrameBits
/8) ) {
628 if (aerror
> (targetFrameBits
/4) ) {
629 if (aerror
> (targetFrameBits
/2) ) {
630 act
= error
>0 ? 2 : -4;
633 act
= error
>0 ? 1 : -2;
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.
666 videoEncoder
->PreProcessOneFrame(); //Prepare to generate H261 packets
668 videoEncoder
->ProcessOneFrame(); //Generate H261 packets
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;
684 else { //if(!videoEncoder->PacketsOutstanding())
685 if( 0 != bitRateHighLimit
&&
686 (videoBitRateControlModes
& AdaptivePacketDelay
) )
687 ; // do nothing now, packet delay will be done later
689 PThread::Current()->Sleep(5); // Place a 5 ms interval betwen
690 // packets of the same frame.
695 videoEncoder
->IncEncodeAndGetPacket(buffer
,length
); //encode & get next packet
696 frame
.SetMarker(!videoEncoder
->MoreToIncEncode());
698 videoEncoder
->ReadOnePacket(buffer
,length
); //get next packet on list
699 frame
.SetMarker(!videoEncoder
->PacketsOutStanding());
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);
729 newTime
= currentTime
+ length
*8;
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
;
745 frameBytes
+= length
; // count current frame bytes
751 BOOL
H323_H261Codec::Write(const BYTE
* buffer
,
753 const RTP_DataFrame
& frame
,
756 PWaitAndSignal
mutex1(videoHandlerActive
);
758 if( rawDataChannel
== NULL
) {
759 //Some other task has killed our videohandler. Exit.
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
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
);
792 PTRACE (3, "H261\t Could not decode frame, continuing in hope.");
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();
804 videoDecoder
->resetndblk();
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
) ) {
821 frameHeight
= _height
;
823 nblk
= (frameWidth
* frameHeight
) / 64;
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
);
837 BOOL
H323_H261Codec::Redraw()
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.
852 BOOL
H323_H261Codec::RenderFrame()
854 int wraptime
= now
^ 0x80;
857 for (k
= nblk
; --k
>= 0; ++ts
) {
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);
874 ok
= rawDataChannel
->Write((const void *)videoDecoder
->GetFramePtr(),frameWidth
*frameHeight
*3/2);
877 now
= (now
+ 1) & 0xff;
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
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
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
);
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 /////////////////////////////////////////////////////////////////////////////