Fixed missing marker bit on codec output, get more than just the first frame!
[opal/cbnco.git] / src / codec / h261codec.cxx
blob64de9c98f84f96a207cf20f86eb0688b4d84b60d
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 2.19 2005/08/24 10:15:10 rjongbloed
29 * Fixed missing marker bit on codec output, get more than just the first frame!
31 * Revision 2.18 2005/08/23 12:46:27 rjongbloed
32 * Fix some decoder issues, now get inital frame displayed!
34 * Revision 2.17 2005/08/20 09:01:56 rjongbloed
35 * H.261 port to OPAL model
37 * Revision 2.16 2005/02/24 19:49:44 dsandras
38 * Applied patch from Hannes Friederich to fix quality problem in some circumstances.
40 * Revision 2.15 2005/02/21 12:19:53 rjongbloed
41 * Added new "options list" to the OpalMediaFormat class.
43 * Revision 2.14 2004/04/07 08:21:00 rjongbloed
44 * Changes for new RTTI system.
46 * Revision 2.13 2004/03/11 06:54:28 csoutheren
47 * Added ability to disable SIP or H.323 stacks
49 * Revision 2.12 2004/02/19 10:47:02 rjongbloed
50 * Merged OpenH323 version 1.13.1 changes.
52 * Revision 2.11 2004/01/18 15:35:20 rjongbloed
53 * More work on video support
55 * Revision 2.10 2003/03/17 10:26:59 robertj
56 * Added video support.
58 * Revision 2.9 2003/01/07 04:39:53 robertj
59 * Updated to OpenH323 v1.11.2
61 * Revision 2.8 2002/11/10 11:33:18 robertj
62 * Updated to OpenH323 v1.10.3
64 * Revision 2.7 2002/09/04 06:01:47 robertj
65 * Updated to OpenH323 v1.9.6
67 * Revision 2.6 2002/07/01 04:56:31 robertj
68 * Updated to OpenH323 v1.9.1
70 * Revision 2.5 2002/01/22 05:18:59 robertj
71 * Added RTP encoding name string to media format database.
72 * Changed time units to clock rate in Hz.
74 * Revision 2.4 2002/01/14 06:35:57 robertj
75 * Updated to OpenH323 v1.7.9
77 * Revision 2.3 2001/11/02 10:45:19 robertj
78 * Updated to OpenH323 v1.7.3
80 * Revision 2.2 2001/10/05 00:22:13 robertj
81 * Updated to PWLib 1.2.0 and OpenH323 1.7.0
83 * Revision 2.1 2001/08/01 05:04:28 robertj
84 * Changes to allow control of linking software transcoders, use macros
85 * to force linking.
86 * Allowed codecs to be used without H.,323 being linked by using the
87 * new NO_H323 define.
88 * Major changes to H.323 capabilities, uses OpalMediaFormat for base name.
90 * Revision 2.0 2001/07/27 15:48:24 robertj
91 * Conversion of OpenH323 to Open Phone Abstraction Library (OPAL)
93 * Revision 1.59 2004/01/02 00:31:42 dereksmithies
94 * Fix test on presence/absence of video.
96 * Revision 1.58 2003/12/14 10:42:29 rjongbloed
97 * Changes for compilability without video support.
99 * Revision 1.57 2003/10/02 23:37:56 dereksmithies
100 * Add fix for fast update problem in h261 codec. Thanks to Martin André for doing the initial legwork.
102 * Revision 1.56 2003/04/03 23:54:15 robertj
103 * Added fast update to H.261 codec, thanks Gustavo García Bernardo
105 * Revision 1.55 2003/03/20 23:45:46 dereks
106 * Make formatting more consistant with the openh323.org standard.
108 * Revision 1.54 2003/03/17 08:05:02 robertj
109 * Removed videoio classes in openh323 as now has versions in pwlib.
111 * Revision 1.53 2003/03/11 22:05:00 dereks
112 * Video receive will not terminate in abnormal situations
113 * Thanks to Damien Sandras.
115 * Revision 1.52 2002/12/29 22:35:34 dereks
116 * Fix so video with Windows XP works. Thanks Damien Sandras.
118 * Revision 1.51 2002/12/24 07:38:49 robertj
119 * Patches to fix divide by zero error, thanks Damien Sandras
121 * Revision 1.50 2002/12/16 09:11:19 robertj
122 * Added new video bit rate control, thanks Walter H. Whitlock
124 * Revision 1.49 2002/08/05 10:03:47 robertj
125 * Cosmetic changes to normalise the usage of pragma interface/implementation.
127 * Revision 1.48 2002/05/19 22:03:45 dereks
128 * Add fix from Sean Miceli, so correct P64Decoder is picked in calls with Netmeeting.
129 * Many thanks, good work!
131 * Revision 1.47 2002/04/26 04:58:34 dereks
132 * Add Walter Whitlock's fixes, based on Victor Ivashim's suggestions to improve
133 * the quality with Netmeeting. Thanks guys!!!
135 * Revision 1.46 2002/04/05 00:53:19 dereks
136 * Modify video frame encoding so that frame is encoded on an incremental basis.
137 * Thanks to Walter Whitlock - good work.
139 * Revision 1.45 2002/01/09 06:07:13 robertj
140 * Fixed setting of RTP timestamp values on video transmission.
142 * Revision 1.44 2002/01/09 00:21:39 robertj
143 * Changes to support outgoing H.245 RequstModeChange.
145 * Revision 1.43 2002/01/08 01:30:41 robertj
146 * Tidied up some PTRACE debug output.
148 * Revision 1.42 2002/01/03 23:05:50 dereks
149 * Add methods to count number of H261 packets waiting to be sent.
151 * Revision 1.41 2001/12/20 01:19:43 dereks
152 * modify ptrace statments.
154 * Revision 1.40 2001/12/13 03:01:23 dereks
155 * Modify trace statement.
157 * Revision 1.39 2001/12/04 05:13:12 robertj
158 * Added videa bandwidth limiting code for H.261, thanks Jose Luis Urien.
160 * Revision 1.38 2001/12/04 04:26:06 robertj
161 * Added code to allow change of video quality in H.261, thanks Damian Sandras
163 * Revision 1.37 2001/10/23 02:17:16 dereks
164 * Initial release of cu30 video codec.
166 * Revision 1.36 2001/09/26 01:59:31 robertj
167 * Fixed MSVC warning.
169 * Revision 1.35 2001/09/25 03:14:47 dereks
170 * Add constant bitrate control for the h261 video codec.
171 * Thanks Tiziano Morganti for the code to set bit rate. Good work!
173 * Revision 1.34 2001/09/21 02:51:29 robertj
174 * Added default session ID to media format description.
176 * Revision 1.33 2001/08/22 01:28:20 robertj
177 * Resolved confusion with YUV411P and YUV420P video formats, thanks Mark Cooke.
179 * Revision 1.32 2001/07/09 07:19:40 rogerh
180 * Make the encoder render a frames (for local video) only when there is a
181 * renderer attached
183 * Revision 1.31 2001/06/19 02:01:42 dereks
184 * The video encoder thread ends if the renderframe fails.
186 * Revision 1.30 2001/06/13 21:46:37 dereks
187 * Add 5 msec separator between consecutive packets generated from the same
188 * frame. Prevents lost packets, and improves reliability.
190 * Revision 1.29 2001/05/25 01:10:26 dereks
191 * Remove unnecessary packet receive variable.
192 * Alter the position of the check for change in frame size.
194 * Revision 1.28 2001/02/09 05:13:55 craigs
195 * Added pragma implementation to (hopefully) reduce the executable image size
196 * under Linux
198 * Revision 1.27 2001/01/25 07:27:16 robertj
199 * Major changes to add more flexible OpalMediaFormat class to normalise
200 * all information about media types, especially codecs.
202 * Revision 1.26 2000/12/19 22:33:44 dereks
203 * Adjust so that the video channel is used for reading/writing raw video
204 * data, which better modularizes the video codec.
206 * Revision 1.25 2000/10/13 02:20:32 robertj
207 * Fixed capability clone so gets all fields including those in ancestor.
209 * Revision 1.24 2000/10/13 01:47:26 dereks
210 * Include command option for setting the number of transmitted video
211 * frames per second. use --videotxfps n
213 * Revision 1.23 2000/09/08 06:41:38 craigs
214 * Added ability to set video device
215 * Added ability to select test input frames
217 * Revision 1.22 2000/08/28 23:47:41 dereks
218 * Fix bug in resizing image of received video
220 * Revision 1.21 2000/08/21 04:45:06 dereks
221 * Fix dangling pointer that caused segfaults for windows&unix users.
222 * Improved the test image which is used when video grabber won't open.
223 * Added code to handle setting of video Tx Quality.
224 * Added code to set the number of background blocks sent with every frame.
226 * Revision 1.20 2000/07/13 12:31:31 robertj
227 * Fixed format name output for in band switching H.261
229 * Revision 1.19 2000/07/04 13:00:36 craigs
230 * Fixed problem with selecting large and small video sizes
232 * Revision 1.18 2000/06/10 09:21:36 rogerh
233 * Make GetFormatName return H.261 QCIF or H.261 CIF
235 * Revision 1.17 2000/05/10 04:05:34 robertj
236 * Changed capabilities so has a function to get name of codec, instead of relying on PrintOn.
238 * Revision 1.16 2000/05/02 04:32:26 robertj
239 * Fixed copyright notice comment.
241 * Revision 1.15 2000/04/29 03:01:48 robertj
242 * Fixed bug in receive of H261 capability, setting cif & qcif variables correctly.
244 * Revision 1.14 2000/03/24 01:23:49 robertj
245 * Directory reorganisation.
247 * Revision 1.13 2000/03/21 03:06:49 robertj
248 * Changes to make RTP TX of exact numbers of frames in some codecs.
250 * Revision 1.12 2000/02/10 03:08:02 craigs
251 * Added ability to specify NTSC or PAL video format
253 * Revision 1.11 2000/02/04 05:11:19 craigs
254 * Updated for new Makefiles and for new video transmission code
256 * Revision 1.10 2000/01/13 04:03:45 robertj
257 * Added video transmission
259 * Revision 1.9 1999/12/23 23:02:35 robertj
260 * File reorganision for separating RTP from H.323 and creation of LID for VPB support.
262 * Revision 1.8 1999/11/29 08:20:47 craigs
263 * Updated for new codec interface
265 * Revision 1.7 1999/11/01 00:52:00 robertj
266 * Fixed various problems in video, especially ability to pass error return value.
268 * Revision 1.6 1999/10/08 09:59:03 robertj
269 * Rewrite of capability for sending multiple audio frames
271 * Revision 1.5 1999/10/08 04:58:38 robertj
272 * Added capability for sending multiple audio frames in single RTP packet
274 * Revision 1.4 1999/09/21 14:13:53 robertj
275 * Windows MSVC compatibility.
277 * Revision 1.3 1999/09/21 08:10:03 craigs
278 * Added support for video devices and H261 codec
280 * Revision 1.2 1999/09/18 13:24:38 craigs
281 * Added ability to disable jitter buffer
282 * Added ability to access entire RTP packet in codec Write
284 * Revision 1.1 1999/09/08 04:05:49 robertj
285 * Added support for video capabilities & codec, still needs the actual codec itself!
289 #include <ptlib.h>
291 #ifdef __GNUC__
292 #pragma implementation "h261codec.h"
293 #endif
295 #include <codec/h261codec.h>
297 #ifndef NO_OPAL_VIDEO
299 #include <asn/h245.h>
300 #include "vic/p64.h"
301 #include "vic/p64encoder.h"
304 #define new PNEW
307 const OpalVideoFormat OpalH261_QCIF(OPAL_H261_QCIF, RTP_DataFrame::H261, "H261", 176, 144, 10, 128000);
308 const OpalVideoFormat OpalH261_CIF (OPAL_H261_CIF, RTP_DataFrame::H261, "H261", 352, 288, 10, 128000);
311 ///////////////////////////////////////////////////////////////////////////////
313 #ifndef NO_H323
315 H323_H261Capability::H323_H261Capability(unsigned _qcifMPI,
316 unsigned _cifMPI,
317 BOOL _temporalSpatialTradeOffCapability,
318 BOOL _stillImageTransmission,
319 unsigned _maxBitRate)
321 qcifMPI = _qcifMPI;
322 cifMPI = _cifMPI;
323 temporalSpatialTradeOffCapability = _temporalSpatialTradeOffCapability;
324 maxBitRate = _maxBitRate;
325 stillImageTransmission = _stillImageTransmission;
329 PObject * H323_H261Capability::Clone() const
331 return new H323_H261Capability(*this);
335 PObject::Comparison H323_H261Capability::Compare(const PObject & obj) const
337 Comparison result = H323Capability::Compare(obj);
338 if (result != EqualTo)
339 return result;
341 PAssert(PIsDescendant(&obj, H323_H261Capability), PInvalidCast);
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 unsigned H323_H261Capability::GetSubType() const
357 return H245_VideoCapability::e_h261VideoCapability;
361 PString H323_H261Capability::GetFormatName() const
363 return qcifMPI > 0 ? OpalH261_QCIF : OpalH261_CIF;
367 BOOL H323_H261Capability::OnSendingPDU(H245_VideoCapability & cap) const
369 cap.SetTag(H245_VideoCapability::e_h261VideoCapability);
371 H245_H261VideoCapability & h261 = cap;
372 if (qcifMPI > 0) {
373 h261.IncludeOptionalField(H245_H261VideoCapability::e_qcifMPI);
374 h261.m_qcifMPI = qcifMPI;
376 if (cifMPI > 0) {
377 h261.IncludeOptionalField(H245_H261VideoCapability::e_cifMPI);
378 h261.m_cifMPI = cifMPI;
380 h261.m_temporalSpatialTradeOffCapability = temporalSpatialTradeOffCapability;
381 h261.m_maxBitRate = maxBitRate;
382 h261.m_stillImageTransmission = stillImageTransmission;
383 return TRUE;
387 BOOL H323_H261Capability::OnSendingPDU(H245_VideoMode & pdu) const
389 pdu.SetTag(H245_VideoMode::e_h261VideoMode);
390 H245_H261VideoMode & mode = pdu;
391 mode.m_resolution.SetTag(cifMPI > 0 ? H245_H261VideoMode_resolution::e_cif
392 : H245_H261VideoMode_resolution::e_qcif);
393 mode.m_bitRate = maxBitRate;
394 mode.m_stillImageTransmission = stillImageTransmission;
395 return TRUE;
399 BOOL H323_H261Capability::OnReceivedPDU(const H245_VideoCapability & cap)
401 if (cap.GetTag() != H245_VideoCapability::e_h261VideoCapability)
402 return FALSE;
404 OpalMediaFormat & mediaFormat = GetWritableMediaFormat();
406 const H245_H261VideoCapability & h261 = cap;
407 if (h261.HasOptionalField(H245_H261VideoCapability::e_qcifMPI)) {
408 qcifMPI = h261.m_qcifMPI;
409 mediaFormat.SetOptionInteger(OpalMediaFormat::FrameTimeOption, OpalMediaFormat::VideoClockRate*100*qcifMPI/2997);
410 mediaFormat.SetOptionInteger(OpalVideoFormat::FrameWidthOption, 176);
411 mediaFormat.SetOptionInteger(OpalVideoFormat::FrameHeightOption, 144);
413 else
414 qcifMPI = 0;
416 if (h261.HasOptionalField(H245_H261VideoCapability::e_cifMPI)) {
417 cifMPI = h261.m_cifMPI;
418 mediaFormat.SetOptionInteger(OpalMediaFormat::FrameTimeOption, OpalMediaFormat::VideoClockRate*100*cifMPI/2997);
419 mediaFormat.SetOptionInteger(OpalVideoFormat::FrameWidthOption, 352);
420 mediaFormat.SetOptionInteger(OpalVideoFormat::FrameHeightOption, 288);
422 else
423 cifMPI = 0;
425 maxBitRate = h261.m_maxBitRate;
426 mediaFormat.SetOptionInteger(OpalMediaFormat::MaxBitRateOption, maxBitRate*100);
428 temporalSpatialTradeOffCapability = h261.m_temporalSpatialTradeOffCapability;
429 stillImageTransmission = h261.m_stillImageTransmission;
430 return TRUE;
433 #endif
436 //////////////////////////////////////////////////////////////////////////////
438 Opal_H261_YUV420P::Opal_H261_YUV420P(const OpalTranscoderRegistration & registration)
439 : OpalVideoTranscoder(registration)
441 videoDecoder = NULL;
442 expectedSequenceNumber = 0;
443 nblk = ndblk = 0;
444 rvts = NULL;
445 now = 1;
446 packetReceived = FALSE;
448 PTRACE(3, "Codec\tH261 decoder created");
452 Opal_H261_YUV420P::~Opal_H261_YUV420P()
454 if (rvts)
455 delete rvts;
456 delete videoDecoder;
460 PINDEX Opal_H261_YUV420P::GetOptimalDataFrameSize(BOOL input) const
462 return input ? RTP_DataFrame::MaxEthernetPayloadSize : ((frameWidth * frameHeight * 12) / 8);
466 BOOL Opal_H261_YUV420P::ConvertFrames(const RTP_DataFrame & src, RTP_DataFrameList & dst)
468 dst.RemoveAll();
470 if (videoDecoder == NULL) {
471 // Create the actual decoder
472 videoDecoder = new FullP64Decoder();
473 videoDecoder->marks(rvts);
476 // Check for lost packets to help decoder
477 BOOL lostPreviousPacket = FALSE;
478 if (expectedSequenceNumber != 0 && expectedSequenceNumber != src.GetSequenceNumber()) {
479 lostPreviousPacket = TRUE;
480 PTRACE(3,"H261\tDetected loss of one video packet. "
481 << expectedSequenceNumber << " != "
482 << src.GetSequenceNumber() << " Will recover.");
484 expectedSequenceNumber = (WORD)(src.GetSequenceNumber()+1);
486 videoDecoder->mark(now);
487 if (!videoDecoder->decode(src.GetPayloadPtr(), src.GetPayloadSize(), lostPreviousPacket)) {
488 PTRACE (3, "H261\t Could not decode frame, continuing in hope.");
489 return TRUE;
492 //Check for a resize - can change at any time!
493 if (frameWidth != (unsigned)videoDecoder->width() ||
494 frameHeight != (unsigned)videoDecoder->height()) {
495 frameWidth = videoDecoder->width();
496 frameHeight = videoDecoder->height();
498 nblk = (frameWidth * frameHeight) / 64;
499 delete [] rvts;
500 rvts = new BYTE[nblk];
501 memset(rvts, 0, nblk);
502 videoDecoder->marks(rvts);
505 if (!src.GetMarker()) // Have not built an entire frame yet
506 return TRUE;
508 videoDecoder->sync();
509 ndblk = videoDecoder->ndblk();
511 int wraptime = now ^ 0x80;
512 BYTE * ts = rvts;
513 int k;
514 for (k = nblk; --k >= 0; ++ts) {
515 if (*ts == wraptime)
516 *ts = (BYTE)now;
519 now = (now + 1) & 0xff;
521 PINDEX frameBytes = (frameWidth * frameHeight * 12) / 8;
522 RTP_DataFrame * pkt = new RTP_DataFrame(sizeof(FrameHeader)+frameBytes);
523 pkt->SetMarker(true);
524 FrameHeader * frameHeader = (FrameHeader *)pkt->GetPayloadPtr();
525 frameHeader->x = frameHeader->y = 0;
526 frameHeader->width = frameWidth;
527 frameHeader->height = frameHeight;
528 memcpy(frameHeader->data, videoDecoder->GetFramePtr(), frameBytes);
530 dst.Append(pkt);
532 videoDecoder->resetndblk();
534 return TRUE;
538 //////////////////////////////////////////////////////////////////////////////
540 Opal_YUV420P_H261::Opal_YUV420P_H261(const OpalTranscoderRegistration & registration)
541 : OpalVideoTranscoder(registration)
543 videoEncoder = NULL;
544 PTRACE(3, "Codec\tH261 encoder created");
548 Opal_YUV420P_H261::~Opal_YUV420P_H261()
550 delete videoEncoder;
554 PINDEX Opal_YUV420P_H261::GetOptimalDataFrameSize(BOOL input) const
556 return input ? ((frameWidth * frameHeight * 12) / 8) : maxOutputSize;
560 BOOL Opal_YUV420P_H261::ConvertFrames(const RTP_DataFrame & src, RTP_DataFrameList & dst)
562 dst.RemoveAll();
564 if (src.GetPayloadSize() < sizeof(FrameHeader)) {
565 PTRACE(1,"H261\t Video grab too small, Close down video transmission thread.");
566 return FALSE;
569 FrameHeader * header = (FrameHeader *)src.GetPayloadPtr();
571 if (header->x != 0 && header->y != 0) {
572 PTRACE(1,"H261\tVideo grab of partial frame unsupported, Close down video transmission thread.");
573 return FALSE;
576 if (videoEncoder == NULL)
577 videoEncoder = new P64Encoder(videoQuality, fillLevel);
579 if (frameWidth != header->width || frameHeight != header->height) {
580 frameWidth = header->width;
581 frameHeight = header->height;
582 videoEncoder->SetSize(header->width, header->height);
585 // "grab" the frame
586 memcpy(videoEncoder->GetFramePtr(), header->data, frameWidth*frameHeight*12/8);
588 videoEncoder->PreProcessOneFrame();
590 while (videoEncoder->MoreToIncEncode()) {
591 RTP_DataFrame * pkt = new RTP_DataFrame(2048);
592 unsigned length;
593 videoEncoder->IncEncodeAndGetPacket(pkt->GetPayloadPtr(), length); //get next packet on list
594 pkt->SetPayloadSize(length);
595 pkt->SetTimestamp(src.GetTimestamp());
596 pkt->SetPayloadType(RTP_DataFrame::H261);
597 dst.Append(pkt);
600 dst[dst.GetSize()-1].SetMarker(TRUE);
601 return TRUE;
605 #endif // NO_OPAL_VIDEO
608 /////////////////////////////////////////////////////////////////////////////