//
// The contents of this file are subject to the Mozilla Public License
// Version 1.0 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
// the License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is CPhone, a cross platform voip gui.
//
// The Initial Developer of the Original Code is Derek Smithies.
//
// Copyright (C) 2002 Indranet Technologies Ltd,
// http://www.indranet-technologies.com
// All Rights Reserved.
//
// Contributor(s): _______________
/*
*
* $Log: vdisplay.cxx,v $
* Revision 1.6 2004/04/23 05:09:59 dereksmithies
* Fixes so it works with latest openh323 lib, and not lock X display.
*
* Revision 1.5 2003/08/11 01:48:14 dereksmithies
* Fix windows compile errors
*
* Revision 1.4 2003/08/06 05:04:25 dereksmithies
* Add feature to display bmp
*
* Revision 1.3 2003/05/09 03:08:24 dereksmithies
* Fix Microtelco handling, and message display
*
* Revision 1.2 2003/04/04 04:37:49 dereksmithies
* Major upgrade.
* Ixj & microtelco support added. Fix threading issues.
*
* Revision 1.1.1.1 2002/05/12 22:55:05 dereksmithies
* Initial release.
*
*
*
*
*/
#include <ptlib.h>
#include <qdatetime.h>
#include "vdisplay.h"
#include <sys/types.h>
#include <unistd.h>
#include <qpainter.h>
#include <qevent.h>
#include <qapplication.h>
LabelDisplay::LabelDisplay( QWidget *parent, const char *name, WFlags f)
: QLabel( parent, name, f)
{
displayText = "";
}
void LabelDisplay::prepareDisplayText(QString s)
{
PWaitAndSignal m(displayMutex);
displayText = s;
}
void LabelDisplay::customEvent(QCustomEvent *e)
{
PWaitAndSignal m(displayMutex);
setText(displayText);
}
////////////////////////////////////////////////////////////////////////
VideoDisplay::VideoDisplay( QWidget *parent, const char *name, WFlags f)
: QFrame(parent, name, f )
{
blankImage = NULL;
incomingImage = NULL;
displayImage = NULL;
bufferImage = NULL;
scaledImage = NULL;
displayFlipped = FALSE;
newImageData = FALSE;
width = 0;
height = 0;
converter = NULL;
};
VideoDisplay::~VideoDisplay()
{
PWaitAndSignal m(bufferMutex);
if (bufferImage != NULL)
delete bufferImage;
bufferImage = NULL;
if (displayImage != NULL)
delete displayImage;
displayImage = NULL;
if (incomingImage != NULL)
delete incomingImage;
incomingImage = NULL;
if (scaledImage != NULL)
delete scaledImage;
scaledImage = NULL;
if (converter!=NULL)
delete converter;
converter = NULL;
}
void VideoDisplay::RemoveVideoImage()
{
SwapImages( SWAP_BLANK );
InitiateRepaint( TRUE );
}
void VideoDisplay::InitiateRepaint(BOOL doErase)
{
QRect r = contentsRect();
QThread::postEvent(this, new QPaintEvent(r, doErase) );
}
void VideoDisplay::CreateColourConverter()
{
if (converter != NULL) {
delete converter;
converter = NULL;
}
if (converter == NULL)
converter = PColourConverter::Create("YUV420P", "RGB32F", width, height);
}
void VideoDisplay::DisplayQImage(QImage *qImage)
{
fixedImage = qImage;
SwapImages(SWAP_FIXED);
InitiateRepaint(FALSE );
}
//SetDisplayBuffer is only called by one thread. Thus, we do not need to
//protect incomingImage with a mutex.
void VideoDisplay::SetDisplayBuffer(const void *videoFrame, unsigned _width, unsigned _height, BOOL doFlip)
{
width = _width;
height = _height;
if (incomingImage == NULL)
incomingImage = new QImage(width, height, 32);
if ((incomingImage->width() != width) || (incomingImage->height() != height) ) {
delete incomingImage;
incomingImage = new QImage(width, height, 32);
if (incomingImage == NULL)
return;
delete converter; //There has been a size change. The colour converter
converter = NULL; //must be changed to the new size.
}
CreateColourConverter();
if (converter == NULL)
return;
converter->SetVFlipState(doFlip);
PINDEX bytesReturned;
converter->Convert( (const BYTE *)videoFrame, incomingImage->bits(), &bytesReturned);
SwapImages(SWAP_INCOMING );
InitiateRepaint(FALSE );
}
void VideoDisplay::drawContents (QPainter *p)
{
SwapImages ( SWAP_BUFFER );
if (displayImage == NULL)
return;
QRect r = contentsRect();
#if 1
if (scaledImage != NULL) {
if ((scaledImage->width() != r.width()) ||
(scaledImage->height() != r.height())) {
delete scaledImage;
scaledImage = NULL;
}
}
if (scaledImage == NULL)
scaledImage = new QImage(r.width(), r.height(), 32);
ResizeImage(scaledImage->bits(), r.width(), r.height(),
displayImage->bits(), displayImage->width(), displayImage->height());
bitBlt(this, 0, 0, scaledImage);
#else
QPixmap sourcePixmap;
sourcePixmap.convertFromImage(*displayImage);
QWMatrix m; // transformation matrix
double sx,sy;
sx = (double)r.width()/displayImage->width(); //get scale factors.
sy = (double)r.height()/displayImage->height();
m.scale(sx,sy); // scale coordinate system
QPixmap sp = sourcePixmap.xForm( m ); // sp is the sourcepixmap after resizing.
bitBlt(this, 0, 0, &sp);
#endif
}
void VideoDisplay::SwapImages(int actionToTake )
{
PWaitAndSignal m(bufferMutex);
if ((actionToTake == SWAP_BUFFER) && (newImageData == FALSE)) {
return;
}
if (actionToTake == SWAP_BUFFER)
newImageData = FALSE;
else
newImageData = TRUE;
QImage *temp;
switch(actionToTake)
{
case SWAP_FIXED:
temp = fixedImage;
fixedImage = bufferImage;
bufferImage = temp;
break;
case SWAP_BUFFER:
temp = displayImage;
displayImage = bufferImage;
bufferImage = temp;
break;
case SWAP_INCOMING:
temp = incomingImage;
incomingImage = bufferImage;
bufferImage = temp;
break;
case SWAP_BLANK:
temp = blankImage;
blankImage = bufferImage;
bufferImage = temp;
delete blankImage;
blankImage = NULL;
break;
default:
return;
}
}
void VideoDisplay::ResizeImage(uchar *dest_data, unsigned dest_width, unsigned dest_height,
uchar *source_data, unsigned source_width, unsigned source_height)
{
// declare local variables
unsigned source_x,source_y, dest_x,dest_y;
unsigned source_yWidth,dest_yWidth;
unsigned *dest_bitmap = (unsigned *)dest_data;
unsigned *source_bitmap = (unsigned *)source_data;
for(dest_y=0;dest_y<dest_height;dest_y++) {
source_y = dest_y * source_height/dest_height;
source_yWidth = source_y * source_width;
dest_yWidth = dest_y * dest_width;
for(dest_x=0;dest_x<dest_width; dest_x++) {
source_x= dest_x*source_width/dest_width;
dest_bitmap[dest_yWidth + dest_x] =
source_bitmap[source_yWidth + source_x];
}
}
}
/////////////////////////////////////////////////
/////////////////////////////////////////////////
/////////////////////////////////////////////////
/////////////////////////////////////////////////
Rgb32Image::Rgb32Image(int x, int y, QString newMessage)
{
image = NULL;
image = new QImage(x,y,32);
QPainter p;
image->fill( 0xffeeeeee );
frameWidth = x;
frameHeight = y;
textMessage = newMessage;
QCustomEvent *ce = new QCustomEvent(QEvent::User);
QApplication::postEvent(this, ce); //Qt will delete "ce" when done.
}
Rgb32Image::~Rgb32Image()
{
access.lock();
if (image != NULL)
delete image;
access.unlock();
}
void Rgb32Image::CopyData(Q_UINT8 *dest)
{
access.lock();
if (image == NULL)
memset(dest, 64, frameWidth * frameHeight * 3);
else
memcpy(dest, image->bits(), frameWidth * frameHeight * 3);
access.unlock();
return ;
}
void Rgb32Image::MakeImage()
{
access.lock();
if (image != NULL)
delete image;
image = new QImage(frameWidth, frameHeight, 32);
QPainter p; // our painter
image->fill(0xffe0e0e0 ); //alpha r g b // initialize pixmap
QPixmap pm;
pm.convertFromImage(*image);
p.begin(&pm ); // start painting pixmap
QFont f( "Charter", 48 ); // use Charter 24pt font
p.setFont(f ); // text rectangle
p.setPen(QColor(10, 10, 210));
QRect br;
QFontMetrics fm(p.fontMetrics() ); // get widget font metrics
br = fm.boundingRect(textMessage ); // rectangle covering text
QPoint posn = (QPoint(frameWidth,frameHeight) - br.topRight()-br.bottomLeft() )/2;
p.drawText(posn, textMessage);
p.end(); // painting done
*image = pm.convertToImage();
access.unlock();
}
BYTE *Rgb32Image::GetDataPointer() const
{
return (BYTE *)image->bits();
}
bool Rgb32Image::event(QEvent *e)
{
if (e->type() == QEvent::User) {
MakeImage();
return TRUE;
}
return FALSE;
}
syntax highlighted by Code2HTML, v. 0.9.1