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 * 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)
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
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
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
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.
146 #include <ptlib/video.h>
149 #pragma implementation "h263codec.h"
152 #include "h263codec.h"
153 #if defined(H323_VICH263)
159 #if defined(_MSC_VER)
161 #pragma comment(lib, H323_VICH263_LIBRARY)
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
)
189 VicH263Link::VicH263Link()
191 vich263_set_print_fn(h263_vic_printon
);
196 ///////////////////////////////////////////////////////////////////////////////////////
201 static OpalMediaFormat
const H263_MediaFormat("H.263",
202 OpalMediaFormat::DefaultVideoSessionID
,
204 FALSE
, // No jitter for video
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
,
218 unsigned _maxBitRate
,
219 unsigned _videoFrameRate
,
220 BOOL _unrestrictedVector
,
221 BOOL _arithmeticCoding
,
222 BOOL _advancedPrediction
,
224 BOOL _temporalSpatialTradeOff
,
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
;
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
))
267 Comparison result
= H323Capability::Compare(obj
);
268 if (result
!= EqualTo
)
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))
281 if ((cif16MPI < other.cif16MPI) ||
282 (cif4MPI < other.cif4MPI) ||
283 (cifMPI < other.cifMPI) ||
284 (qcifMPI < other.qcifMPI))
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))
307 PString
H323_H263Capability::GetFormatName() const
309 PString ret
= H263_MediaFormat
;
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
;
342 h263
.IncludeOptionalField(H245_H263VideoCapability::e_sqcifMPI
);
343 h263
.m_sqcifMPI
= sqcifMPI
;
346 h263
.IncludeOptionalField(H245_H263VideoCapability::e_qcifMPI
);
347 h263
.m_qcifMPI
= qcifMPI
;
350 h263
.IncludeOptionalField(H245_H263VideoCapability::e_cifMPI
);
351 h263
.m_cifMPI
= cifMPI
;
354 h263
.IncludeOptionalField(H245_H263VideoCapability::e_cif4MPI
);
355 h263
.m_cif4MPI
= cif4MPI
;
358 h263
.IncludeOptionalField(H245_H263VideoCapability::e_cif16MPI
);
359 h263
.m_cif16MPI
= cif16MPI
;
361 h263
.m_temporalSpatialTradeOffCapability
= temporalSpatialTradeOff
;
362 h263
.m_maxBitRate
= maxBitRate
;
364 h263
.IncludeOptionalField(H245_H263VideoCapability::e_slowSqcifMPI
);
365 h263
.m_slowSqcifMPI
= -sqcifMPI
;
368 h263
.IncludeOptionalField(H245_H263VideoCapability::e_slowQcifMPI
);
369 h263
.m_slowQcifMPI
= -qcifMPI
;
372 h263
.IncludeOptionalField(H245_H263VideoCapability::e_slowCifMPI
);
373 h263
.m_slowCifMPI
= -cifMPI
;
376 h263
.IncludeOptionalField(H245_H263VideoCapability::e_slowCif4MPI
);
377 h263
.m_slowCif4MPI
= -cif4MPI
;
380 h263
.IncludeOptionalField(H245_H263VideoCapability::e_slowCif16MPI
);
381 h263
.m_slowCif16MPI
= -cif16MPI
;
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
;
408 BOOL
H323_H263Capability::OnReceivedPDU(const H245_VideoCapability
& cap
)
410 if (cap
.GetTag() != H245_VideoCapability::e_h263VideoCapability
)
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
;
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
;
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
;
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
;
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
;
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
;
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
,
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");
494 shifts
= 0; PTRACE(3, "H263\t" << (dir
== Encoder
? "En" : "De") << "coder for _sqcifMPI ");
497 shifts
= 1; PTRACE(3, "H263\t" << (dir
== Encoder
? "En" : "De") << "coder for _qcifMPI");
500 shifts
= 2; PTRACE(3, "H263\t" << (dir
== Encoder
? "En" : "De") << "coder for _cifMPI");
503 shifts
= 3; PTRACE(3, "H263\t" << (dir
== Encoder
? "En" : "De") << "coder for _cif4MPI");
506 shifts
= 4; PTRACE(3, "H263\t" << (dir
== Encoder
? "En" : "De") << "coder for _cif16MPI");
510 PTRACE(1, "H263\tERROR in definition of h263 size");
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.
524 H323_H263Codec::~H323_H263Codec()
526 PWaitAndSignal
mutex1(videoHandlerActive
);
541 void H323_H263Codec::InitialiseCodec()
543 // no video decoder until we receive a packet
546 // no video encoder until we receive a packet
550 void H323_H263Codec::CloseCodec()
552 PTRACE(6, "H263\tClose h263 video " <<(direction
== Encoder
? "En" : "De") << "coder");
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
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
,
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
) {
582 PTRACE(1,"H263\tNo channel to connect to video grabber, close down video transmission thread.");
586 if (!rawDataChannel
->IsOpen()) {
587 PTRACE(1,"H263\tVideo grabber is not initialised, close down video transmission thread.");
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.");
602 videoEncoder
->SetSize(frameWidth
, frameHeight
);
604 PINDEX bytesInFrame
= 0;
610 if (!videoEncoder
->MoreToIncEncode()) { // get a new frame
612 if (!videoEncoder
->PacketsOutStanding()) { // }get a new frame
614 if (0 == frameNum
) { // frame 0 means no frame has been sent yet
615 frameStartTime
= PTimer::Tick();
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
652 int act
; // action signal
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
662 avgFrameBitRate
= avgFrameBytes
*8*1000;
664 targetFrameBits
= avgFrameBitRate
* targetFrameTimeMs
/ 1000;
665 error
= (frameBytes
*8) - targetFrameBits
; // error signal
666 aerror
= PABS(error
);
669 if (aerror
> (targetFrameBits
/8)) {
670 if (aerror
> (targetFrameBits
/4)) {
671 if (aerror
> (targetFrameBits
/2)) {
672 act
= error
>0 ? 2 : -4;
675 act
= error
>0 ? 1 : -2;
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.");
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.
716 videoEncoder
->PreProcessOneFrame(); //Prepare to generate H263 packets
718 videoEncoder
->ProcessOneFrame(); //Generate H263 packets
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;
736 videoEncoder
->IncEncodeAndGetPacket(buffer
,length
); //encode & get next packet
737 frame
.SetMarker(!videoEncoder
->MoreToIncEncode());
739 videoEncoder
->ReadOnePacket(buffer
,length
); //get next packet on list
740 frame
.SetMarker(!videoEncoder
->PacketsOutStanding());
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);
770 newTime
= currentTime
+ length
*8;
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
;
786 frameBytes
+= length
; // count current frame bytes
793 BOOL
H323_H263Codec::Write(const BYTE
* buffer
,
795 const RTP_DataFrame
& frame
,
798 PWaitAndSignal
mutex1(videoHandlerActive
);
800 if (rawDataChannel
== NULL
) {
801 //Some other task has killed our videohandler. Exit.
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
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();
827 // determine video codec type
828 if (videoDecoder
== NULL
) {
830 if ((*header & 2) && !(*header & 1)) // check value of I field in header
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());
841 PTRACE (3, "H263\t Could not decode frame, continuing in hope.");
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();
852 videoDecoder
->resetndblk();
861 BOOL
H323_H263Codec::Resize(int _width
, int _height
)
863 if ((frameWidth
== _width
) && (frameHeight
== _height
))
866 PTRACE(6, "H263\t" << (direction
== Encoder
? "En" : "De") << "coder resizing to "
867 << _width
<< "x" << _height
<< ".");
871 frameHeight
= _height
;
877 /* RenderFrame does two things:
878 a) Set size of the display frame. This call happens with every frame.
879 A very small overhead.
883 BOOL
H323_H263Codec::RenderFrame(const void * buffer
)
885 if (rawDataChannel
== NULL
)
888 //Now display local image.
889 ((PVideoChannel
*)rawDataChannel
)->SetRenderFrameSize(frameWidth
, frameHeight
);
894 return rawDataChannel
->Write(buffer
, 0 /*unused parameter*/);
897 /* AWM: Look-alike to H.261 implementation */
898 BOOL
H323_H263Codec::RenderFrame()
902 if (direction
== Encoder
)
903 srcData
= videoEncoder
->GetFramePtr();
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