summaryrefslogtreecommitdiff
path: root/core/multimedia/opieplayer/videowidget.cpp
Side-by-side diff
Diffstat (limited to 'core/multimedia/opieplayer/videowidget.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--core/multimedia/opieplayer/videowidget.cpp423
1 files changed, 423 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/videowidget.cpp b/core/multimedia/opieplayer/videowidget.cpp
new file mode 100644
index 0000000..f3974a0
--- a/dev/null
+++ b/core/multimedia/opieplayer/videowidget.cpp
@@ -0,0 +1,423 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+#include <qpe/resource.h>
+#include <qwidget.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qslider.h>
+#include <qdrawutil.h>
+#include "videowidget.h"
+#include "mediaplayerplugininterface.h"
+#include "mediaplayerstate.h"
+
+
+#ifdef Q_WS_QWS
+# define USE_DIRECT_PAINTER
+# include <qdirectpainter_qws.h>
+# include <qgfxraster_qws.h>
+#endif
+
+
+extern MediaPlayerState *mediaPlayerState;
+
+
+static const int xo = 2; // movable x offset
+static const int yo = 0; // movable y offset
+
+
+struct MediaButton {
+ int xPos, yPos;
+ bool isToggle, isHeld, isDown;
+ int controlType;
+};
+
+
+// Layout information for the videoButtons (and if it is a toggle button or not)
+MediaButton videoButtons[] = {
+ { 5+0*32+xo, 200+yo, FALSE, FALSE, FALSE, 4 }, // previous
+ { 5+1*32+xo, 200+yo, FALSE, FALSE, FALSE, 1 }, // stop
+ { 5+2*32+xo, 200+yo, TRUE, FALSE, FALSE, 0 }, // play
+ { 5+3*32+xo, 200+yo, TRUE, FALSE, FALSE, 2 }, // pause
+ { 5+4*32+xo, 200+yo, FALSE, FALSE, FALSE, 3 }, // next
+ { 5+5*32+xo, 200+yo, FALSE, FALSE, FALSE, 8 }, // playlist
+ { 5+6*32+xo, 200+yo, TRUE, FALSE, FALSE, 9 } // fullscreen
+};
+
+
+static const int numButtons = (sizeof(videoButtons)/sizeof(MediaButton));
+
+
+VideoWidget::VideoWidget(QWidget* parent, const char* name, WFlags f) :
+ QWidget( parent, name, f ), scaledWidth( 0 ), scaledHeight( 0 ) {
+ setCaption( tr("MediaPlayer") );
+ setBackgroundPixmap( Resource::loadPixmap( "mpegplayer/metalFinish" ) );
+ pixmaps[0] = new QPixmap( Resource::loadPixmap( "mpegplayer/mediaButton0a" ) );
+ pixmaps[1] = new QPixmap( Resource::loadPixmap( "mpegplayer/mediaButton0b" ) );
+ pixmaps[2] = new QPixmap( Resource::loadPixmap( "mpegplayer/mediaControls0" ) );
+ currentFrame = new QImage( 220 + 2, 160, (QPixmap::defaultDepth() == 16) ? 16 : 32 );
+
+ slider = new QSlider( Qt::Horizontal, this );
+ slider->setMinValue( 0 );
+ slider->setMaxValue( 1 );
+ slider->setBackgroundPixmap( Resource::loadPixmap( "mpegplayer/metalFinish" ) );
+ slider->setFocusPolicy( QWidget::NoFocus );
+ slider->setGeometry( QRect( 7, 250, 220, 20 ) );
+
+ connect( slider, SIGNAL( sliderPressed() ), this, SLOT( sliderPressed() ) );
+ connect( slider, SIGNAL( sliderReleased() ), this, SLOT( sliderReleased() ) );
+
+ connect( mediaPlayerState, SIGNAL( lengthChanged(long) ), this, SLOT( setLength(long) ) );
+ connect( mediaPlayerState, SIGNAL( positionChanged(long) ),this, SLOT( setPosition(long) ) );
+ connect( mediaPlayerState, SIGNAL( positionUpdated(long) ),this, SLOT( setPosition(long) ) );
+ connect( mediaPlayerState, SIGNAL( viewChanged(char) ), this, SLOT( setView(char) ) );
+ connect( mediaPlayerState, SIGNAL( pausedToggled(bool) ), this, SLOT( setPaused(bool) ) );
+ connect( mediaPlayerState, SIGNAL( playingToggled(bool) ), this, SLOT( setPlaying(bool) ) );
+
+ // Intialise state
+ setLength( mediaPlayerState->length() );
+ setPosition( mediaPlayerState->position() );
+ setFullscreen( mediaPlayerState->fullscreen() );
+ setPaused( mediaPlayerState->paused() );
+ setPlaying( mediaPlayerState->playing() );
+}
+
+
+VideoWidget::~VideoWidget() {
+ for ( int i = 0; i < 3; i++ )
+ delete pixmaps[i];
+ delete currentFrame;
+}
+
+
+static bool videoSliderBeingMoved = FALSE;
+
+
+void VideoWidget::sliderPressed() {
+ videoSliderBeingMoved = TRUE;
+}
+
+
+void VideoWidget::sliderReleased() {
+ videoSliderBeingMoved = FALSE;
+ if ( slider->width() == 0 )
+ return;
+ long val = long((double)slider->value() * mediaPlayerState->length() / slider->width());
+ mediaPlayerState->setPosition( val );
+}
+
+
+void VideoWidget::setPosition( long i ) {
+ updateSlider( i, mediaPlayerState->length() );
+}
+
+
+void VideoWidget::setLength( long max ) {
+ updateSlider( mediaPlayerState->position(), max );
+}
+
+
+void VideoWidget::setView( char view ) {
+ if ( view == 'v' ) {
+ makeVisible();
+ } else {
+ // Effectively blank the view next time we show it so it looks nicer
+ scaledWidth = 0;
+ scaledHeight = 0;
+ hide();
+ }
+}
+
+
+void VideoWidget::updateSlider( long i, long max ) {
+ // Will flicker too much if we don't do this
+ if ( max == 0 )
+ return;
+ int width = slider->width();
+ int val = int((double)i * width / max);
+ if ( !mediaPlayerState->fullscreen() && !videoSliderBeingMoved ) {
+ if ( slider->value() != val )
+ slider->setValue( val );
+ if ( slider->maxValue() != width )
+ slider->setMaxValue( width );
+ }
+}
+
+
+void VideoWidget::setToggleButton( int i, bool down ) {
+ if ( down != videoButtons[i].isDown )
+ toggleButton( i );
+}
+
+
+void VideoWidget::toggleButton( int i ) {
+ videoButtons[i].isDown = !videoButtons[i].isDown;
+ QPainter p(this);
+ paintButton ( &p, i );
+}
+
+
+void VideoWidget::paintButton( QPainter *p, int i ) {
+ int x = videoButtons[i].xPos;
+ int y = videoButtons[i].yPos;
+ int offset = 10 + videoButtons[i].isDown;
+ p->drawPixmap( x, y, *pixmaps[videoButtons[i].isDown] );
+ p->drawPixmap( x + 1 + offset, y + offset, *pixmaps[2], 9 * videoButtons[i].controlType, 0, 9, 9 );
+}
+
+
+void VideoWidget::mouseMoveEvent( QMouseEvent *event ) {
+ for ( int i = 0; i < numButtons; i++ ) {
+ int x = videoButtons[i].xPos;
+ int y = videoButtons[i].yPos;
+ if ( event->state() == QMouseEvent::LeftButton ) {
+ // The test to see if the mouse click is inside the circular button or not
+ // (compared with the radius squared to avoid a square-root of our distance)
+ int radius = 16;
+ QPoint center = QPoint( x + radius, y + radius );
+ QPoint dXY = center - event->pos();
+ int dist = dXY.x() * dXY.x() + dXY.y() * dXY.y();
+ bool isOnButton = dist <= (radius * radius);
+ if ( isOnButton != videoButtons[i].isHeld ) {
+ videoButtons[i].isHeld = isOnButton;
+ toggleButton(i);
+ }
+ } else {
+ if ( videoButtons[i].isHeld ) {
+ videoButtons[i].isHeld = FALSE;
+ if ( !videoButtons[i].isToggle )
+ setToggleButton( i, FALSE );
+ switch (i) {
+ case VideoPlay: mediaPlayerState->setPlaying(videoButtons[i].isDown); return;
+ case VideoStop: mediaPlayerState->setPlaying(FALSE); return;
+ case VideoPause: mediaPlayerState->setPaused(videoButtons[i].isDown); return;
+ case VideoNext: mediaPlayerState->setNext(); return;
+ case VideoPrevious: mediaPlayerState->setPrev(); return;
+ case VideoPlayList: mediaPlayerState->setList(); return;
+ case VideoFullscreen: mediaPlayerState->setFullscreen( TRUE ); makeVisible(); return;
+ }
+ }
+ }
+ }
+}
+
+
+void VideoWidget::mousePressEvent( QMouseEvent *event ) {
+ mouseMoveEvent( event );
+}
+
+
+void VideoWidget::mouseReleaseEvent( QMouseEvent *event ) {
+ if ( mediaPlayerState->fullscreen() ) {
+ mediaPlayerState->setFullscreen( FALSE );
+ makeVisible();
+ } else {
+ mouseMoveEvent( event );
+ }
+}
+
+
+void VideoWidget::makeVisible() {
+ if ( mediaPlayerState->fullscreen() ) {
+ setBackgroundMode( QWidget::NoBackground );
+ showFullScreen();
+ resize( qApp->desktop()->size() );
+ slider->hide();
+ } else {
+ setBackgroundPixmap( Resource::loadPixmap( "mpegplayer/metalFinish" ) );
+ showNormal();
+ showMaximized();
+ slider->show();
+ }
+}
+
+
+void VideoWidget::paintEvent( QPaintEvent * ) {
+ QPainter p( this );
+
+ if ( mediaPlayerState->fullscreen() ) {
+ // Clear the background
+ p.setBrush( QBrush( Qt::black ) );
+ p.drawRect( rect() );
+
+ // Draw the current frame
+ //p.drawImage( ); // If using directpainter we won't have a copy except whats on the screen
+ } else {
+ // draw border
+ qDrawShadePanel( &p, 4, 15, 230, 170, colorGroup(), TRUE, 5, NULL );
+
+ // Clear the movie screen first
+ p.setBrush( QBrush( Qt::black ) );
+ p.drawRect( 9, 20, 220, 160 );
+
+ // draw current frame (centrally positioned from scaling to maintain aspect ratio)
+ p.drawImage( 9 + (220 - scaledWidth) / 2, 20 + (160 - scaledHeight) / 2, *currentFrame, 0, 0, scaledWidth, scaledHeight );
+
+ // draw the buttons
+ for ( int i = 0; i < numButtons; i++ )
+ paintButton( &p, i );
+
+ // draw the slider
+ slider->repaint( TRUE );
+ }
+}
+
+
+void VideoWidget::closeEvent( QCloseEvent* ) {
+ mediaPlayerState->setList();
+}
+
+
+bool VideoWidget::playVideo() {
+ bool result = FALSE;
+
+ int stream = 0;
+
+ int sw = mediaPlayerState->curDecoder()->videoWidth( stream );
+ int sh = mediaPlayerState->curDecoder()->videoHeight( stream );
+ int dd = QPixmap::defaultDepth();
+ int w = height();
+ int h = width();
+
+ ColorFormat format = (dd == 16) ? RGB565 : BGRA8888;
+
+ if ( mediaPlayerState->fullscreen() ) {
+#ifdef USE_DIRECT_PAINTER
+ QDirectPainter p(this);
+
+ if ( ( qt_screen->transformOrientation() == 3 ) &&
+ ( ( dd == 16 ) || ( dd == 32 ) ) && ( p.numRects() == 1 ) ) {
+
+ w = 320;
+ h = 240;
+
+ if ( mediaPlayerState->scaled() ) {
+ // maintain aspect ratio
+ if ( w * sh > sw * h )
+ w = sw * h / sh;
+ else
+ h = sh * w / sw;
+ } else {
+ w = sw;
+ h = sh;
+ }
+
+ w--; // we can't allow libmpeg to overwrite.
+ QPoint roff = qt_screen->mapToDevice( p.offset(), QSize( qt_screen->width(), qt_screen->height() ) );
+
+ int ox = roff.x() - height() + 2 + (height() - w) / 2;
+ int oy = roff.y() + (width() - h) / 2;
+ int sx = 0, sy = 0;
+
+ uchar* fp = p.frameBuffer() + p.lineStep() * oy;
+ fp += dd * ox / 8;
+ uchar **jt = new uchar*[h];
+ for ( int i = h; i; i-- ) {
+ jt[h - i] = fp;
+ fp += p.lineStep();
+ }
+
+ result = mediaPlayerState->curDecoder()->videoReadScaledFrame( jt, sx, sy, sw, sh, w, h, format, 0) == 0;
+
+ delete [] jt;
+ } else {
+#endif
+ QPainter p(this);
+
+ w = 320;
+ h = 240;
+
+ if ( mediaPlayerState->scaled() ) {
+ // maintain aspect ratio
+ if ( w * sh > sw * h )
+ w = sw * h / sh;
+ else
+ h = sh * w / sw;
+ } else {
+ w = sw;
+ h = sh;
+ }
+
+ int bytes = ( dd == 16 ) ? 2 : 4;
+ QImage tempFrame( w, h, bytes << 3 );
+ result = mediaPlayerState->curDecoder()->videoReadScaledFrame( tempFrame.jumpTable(),
+ 0, 0, sw, sh, w, h, format, 0) == 0;
+ if ( result && mediaPlayerState->fullscreen() ) {
+
+ int rw = h, rh = w;
+ QImage rotatedFrame( rw, rh, bytes << 3 );
+
+ ushort* in = (ushort*)tempFrame.bits();
+ ushort* out = (ushort*)rotatedFrame.bits();
+ int spl = rotatedFrame.bytesPerLine() / bytes;
+ for (int x=0; x<h; x++) {
+ if ( bytes == 2 ) {
+ ushort* lout = out++ + (w - 1)*spl;
+ for (int y=0; y<w; y++) {
+ *lout=*in++;
+ lout-=spl;
+ }
+ } else {
+ ulong* lout = ((ulong *)out)++ + (w - 1)*spl;
+ for (int y=0; y<w; y++) {
+ *lout=*((ulong*)in)++;
+ lout-=spl;
+ }
+ }
+ }
+
+ p.drawImage( (240 - rw) / 2, (320 - rh) / 2, rotatedFrame, 0, 0, rw, rh );
+ }
+#ifdef USE_DIRECT_PAINTER
+ }
+#endif
+ } else {
+
+ w = 220;
+ h = 160;
+
+ // maintain aspect ratio
+ if ( w * sh > sw * h )
+ w = sw * h / sh;
+ else
+ h = sh * w / sw;
+
+ result = mediaPlayerState->curDecoder()->videoReadScaledFrame( currentFrame->jumpTable(), 0, 0, sw, sh, w, h, format, 0) == 0;
+
+ QPainter p( this );
+
+ // Image changed size, therefore need to blank the possibly unpainted regions first
+ if ( scaledWidth != w || scaledHeight != h ) {
+ p.setBrush( QBrush( Qt::black ) );
+ p.drawRect( 9, 20, 220, 160 );
+ }
+
+ scaledWidth = w;
+ scaledHeight = h;
+
+ if ( result ) {
+ p.drawImage( 9 + (220 - scaledWidth) / 2, 20 + (160 - scaledHeight) / 2, *currentFrame, 0, 0, scaledWidth, scaledHeight );
+ }
+
+ }
+
+ return result;
+}
+
+