summaryrefslogtreecommitdiff
path: root/core/multimedia/opieplayer/videowidget.cpp
authorkergoth <kergoth>2002-01-25 22:14:26 (UTC)
committer kergoth <kergoth>2002-01-25 22:14:26 (UTC)
commit15318cad33835e4e2dc620d033e43cd930676cdd (patch) (unidiff)
treec2fa0399a2c47fda8e2cd0092c73a809d17f68eb /core/multimedia/opieplayer/videowidget.cpp
downloadopie-15318cad33835e4e2dc620d033e43cd930676cdd.zip
opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.gz
opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.bz2
Initial revision
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 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20#include <qpe/resource.h>
21#include <qwidget.h>
22#include <qpainter.h>
23#include <qpixmap.h>
24#include <qslider.h>
25#include <qdrawutil.h>
26#include "videowidget.h"
27#include "mediaplayerplugininterface.h"
28#include "mediaplayerstate.h"
29
30
31#ifdef Q_WS_QWS
32# define USE_DIRECT_PAINTER
33# include <qdirectpainter_qws.h>
34# include <qgfxraster_qws.h>
35#endif
36
37
38extern MediaPlayerState *mediaPlayerState;
39
40
41static const int xo = 2; // movable x offset
42static const int yo = 0; // movable y offset
43
44
45struct MediaButton {
46 int xPos, yPos;
47 bool isToggle, isHeld, isDown;
48 int controlType;
49};
50
51
52// Layout information for the videoButtons (and if it is a toggle button or not)
53MediaButton videoButtons[] = {
54 { 5+0*32+xo, 200+yo, FALSE, FALSE, FALSE, 4 }, // previous
55 { 5+1*32+xo, 200+yo, FALSE, FALSE, FALSE, 1 }, // stop
56 { 5+2*32+xo, 200+yo, TRUE, FALSE, FALSE, 0 }, // play
57 { 5+3*32+xo, 200+yo, TRUE, FALSE, FALSE, 2 }, // pause
58 { 5+4*32+xo, 200+yo, FALSE, FALSE, FALSE, 3 }, // next
59 { 5+5*32+xo, 200+yo, FALSE, FALSE, FALSE, 8 }, // playlist
60 { 5+6*32+xo, 200+yo, TRUE, FALSE, FALSE, 9 } // fullscreen
61};
62
63
64static const int numButtons = (sizeof(videoButtons)/sizeof(MediaButton));
65
66
67VideoWidget::VideoWidget(QWidget* parent, const char* name, WFlags f) :
68 QWidget( parent, name, f ), scaledWidth( 0 ), scaledHeight( 0 ) {
69 setCaption( tr("MediaPlayer") );
70 setBackgroundPixmap( Resource::loadPixmap( "mpegplayer/metalFinish" ) );
71 pixmaps[0] = new QPixmap( Resource::loadPixmap( "mpegplayer/mediaButton0a" ) );
72 pixmaps[1] = new QPixmap( Resource::loadPixmap( "mpegplayer/mediaButton0b" ) );
73 pixmaps[2] = new QPixmap( Resource::loadPixmap( "mpegplayer/mediaControls0" ) );
74 currentFrame = new QImage( 220 + 2, 160, (QPixmap::defaultDepth() == 16) ? 16 : 32 );
75
76 slider = new QSlider( Qt::Horizontal, this );
77 slider->setMinValue( 0 );
78 slider->setMaxValue( 1 );
79 slider->setBackgroundPixmap( Resource::loadPixmap( "mpegplayer/metalFinish" ) );
80 slider->setFocusPolicy( QWidget::NoFocus );
81 slider->setGeometry( QRect( 7, 250, 220, 20 ) );
82
83 connect( slider, SIGNAL( sliderPressed() ), this, SLOT( sliderPressed() ) );
84 connect( slider, SIGNAL( sliderReleased() ), this, SLOT( sliderReleased() ) );
85
86 connect( mediaPlayerState, SIGNAL( lengthChanged(long) ), this, SLOT( setLength(long) ) );
87 connect( mediaPlayerState, SIGNAL( positionChanged(long) ),this, SLOT( setPosition(long) ) );
88 connect( mediaPlayerState, SIGNAL( positionUpdated(long) ),this, SLOT( setPosition(long) ) );
89 connect( mediaPlayerState, SIGNAL( viewChanged(char) ), this, SLOT( setView(char) ) );
90 connect( mediaPlayerState, SIGNAL( pausedToggled(bool) ), this, SLOT( setPaused(bool) ) );
91 connect( mediaPlayerState, SIGNAL( playingToggled(bool) ), this, SLOT( setPlaying(bool) ) );
92
93 // Intialise state
94 setLength( mediaPlayerState->length() );
95 setPosition( mediaPlayerState->position() );
96 setFullscreen( mediaPlayerState->fullscreen() );
97 setPaused( mediaPlayerState->paused() );
98 setPlaying( mediaPlayerState->playing() );
99}
100
101
102VideoWidget::~VideoWidget() {
103 for ( int i = 0; i < 3; i++ )
104 delete pixmaps[i];
105 delete currentFrame;
106}
107
108
109static bool videoSliderBeingMoved = FALSE;
110
111
112void VideoWidget::sliderPressed() {
113 videoSliderBeingMoved = TRUE;
114}
115
116
117void VideoWidget::sliderReleased() {
118 videoSliderBeingMoved = FALSE;
119 if ( slider->width() == 0 )
120 return;
121 long val = long((double)slider->value() * mediaPlayerState->length() / slider->width());
122 mediaPlayerState->setPosition( val );
123}
124
125
126void VideoWidget::setPosition( long i ) {
127 updateSlider( i, mediaPlayerState->length() );
128}
129
130
131void VideoWidget::setLength( long max ) {
132 updateSlider( mediaPlayerState->position(), max );
133}
134
135
136void VideoWidget::setView( char view ) {
137 if ( view == 'v' ) {
138 makeVisible();
139 } else {
140 // Effectively blank the view next time we show it so it looks nicer
141 scaledWidth = 0;
142 scaledHeight = 0;
143 hide();
144 }
145}
146
147
148void VideoWidget::updateSlider( long i, long max ) {
149 // Will flicker too much if we don't do this
150 if ( max == 0 )
151 return;
152 int width = slider->width();
153 int val = int((double)i * width / max);
154 if ( !mediaPlayerState->fullscreen() && !videoSliderBeingMoved ) {
155 if ( slider->value() != val )
156 slider->setValue( val );
157 if ( slider->maxValue() != width )
158 slider->setMaxValue( width );
159 }
160}
161
162
163void VideoWidget::setToggleButton( int i, bool down ) {
164 if ( down != videoButtons[i].isDown )
165 toggleButton( i );
166}
167
168
169void VideoWidget::toggleButton( int i ) {
170 videoButtons[i].isDown = !videoButtons[i].isDown;
171 QPainter p(this);
172 paintButton ( &p, i );
173}
174
175
176void VideoWidget::paintButton( QPainter *p, int i ) {
177 int x = videoButtons[i].xPos;
178 int y = videoButtons[i].yPos;
179 int offset = 10 + videoButtons[i].isDown;
180 p->drawPixmap( x, y, *pixmaps[videoButtons[i].isDown] );
181 p->drawPixmap( x + 1 + offset, y + offset, *pixmaps[2], 9 * videoButtons[i].controlType, 0, 9, 9 );
182}
183
184
185void VideoWidget::mouseMoveEvent( QMouseEvent *event ) {
186 for ( int i = 0; i < numButtons; i++ ) {
187 int x = videoButtons[i].xPos;
188 int y = videoButtons[i].yPos;
189 if ( event->state() == QMouseEvent::LeftButton ) {
190 // The test to see if the mouse click is inside the circular button or not
191 // (compared with the radius squared to avoid a square-root of our distance)
192 int radius = 16;
193 QPoint center = QPoint( x + radius, y + radius );
194 QPoint dXY = center - event->pos();
195 int dist = dXY.x() * dXY.x() + dXY.y() * dXY.y();
196 bool isOnButton = dist <= (radius * radius);
197 if ( isOnButton != videoButtons[i].isHeld ) {
198 videoButtons[i].isHeld = isOnButton;
199 toggleButton(i);
200 }
201 } else {
202 if ( videoButtons[i].isHeld ) {
203 videoButtons[i].isHeld = FALSE;
204 if ( !videoButtons[i].isToggle )
205 setToggleButton( i, FALSE );
206 switch (i) {
207 case VideoPlay: mediaPlayerState->setPlaying(videoButtons[i].isDown); return;
208 case VideoStop: mediaPlayerState->setPlaying(FALSE); return;
209 case VideoPause: mediaPlayerState->setPaused(videoButtons[i].isDown); return;
210 case VideoNext: mediaPlayerState->setNext(); return;
211 case VideoPrevious: mediaPlayerState->setPrev(); return;
212 case VideoPlayList: mediaPlayerState->setList(); return;
213 case VideoFullscreen: mediaPlayerState->setFullscreen( TRUE ); makeVisible(); return;
214 }
215 }
216 }
217 }
218}
219
220
221void VideoWidget::mousePressEvent( QMouseEvent *event ) {
222 mouseMoveEvent( event );
223}
224
225
226void VideoWidget::mouseReleaseEvent( QMouseEvent *event ) {
227 if ( mediaPlayerState->fullscreen() ) {
228 mediaPlayerState->setFullscreen( FALSE );
229 makeVisible();
230 } else {
231 mouseMoveEvent( event );
232 }
233}
234
235
236void VideoWidget::makeVisible() {
237 if ( mediaPlayerState->fullscreen() ) {
238 setBackgroundMode( QWidget::NoBackground );
239 showFullScreen();
240 resize( qApp->desktop()->size() );
241 slider->hide();
242 } else {
243 setBackgroundPixmap( Resource::loadPixmap( "mpegplayer/metalFinish" ) );
244 showNormal();
245 showMaximized();
246 slider->show();
247 }
248}
249
250
251void VideoWidget::paintEvent( QPaintEvent * ) {
252 QPainter p( this );
253
254 if ( mediaPlayerState->fullscreen() ) {
255 // Clear the background
256 p.setBrush( QBrush( Qt::black ) );
257 p.drawRect( rect() );
258
259 // Draw the current frame
260 //p.drawImage( ); // If using directpainter we won't have a copy except whats on the screen
261 } else {
262 // draw border
263 qDrawShadePanel( &p, 4, 15, 230, 170, colorGroup(), TRUE, 5, NULL );
264
265 // Clear the movie screen first
266 p.setBrush( QBrush( Qt::black ) );
267 p.drawRect( 9, 20, 220, 160 );
268
269 // draw current frame (centrally positioned from scaling to maintain aspect ratio)
270 p.drawImage( 9 + (220 - scaledWidth) / 2, 20 + (160 - scaledHeight) / 2, *currentFrame, 0, 0, scaledWidth, scaledHeight );
271
272 // draw the buttons
273 for ( int i = 0; i < numButtons; i++ )
274 paintButton( &p, i );
275
276 // draw the slider
277 slider->repaint( TRUE );
278 }
279}
280
281
282void VideoWidget::closeEvent( QCloseEvent* ) {
283 mediaPlayerState->setList();
284}
285
286
287bool VideoWidget::playVideo() {
288 bool result = FALSE;
289
290 int stream = 0;
291
292 int sw = mediaPlayerState->curDecoder()->videoWidth( stream );
293 int sh = mediaPlayerState->curDecoder()->videoHeight( stream );
294 int dd = QPixmap::defaultDepth();
295 int w = height();
296 int h = width();
297
298 ColorFormat format = (dd == 16) ? RGB565 : BGRA8888;
299
300 if ( mediaPlayerState->fullscreen() ) {
301#ifdef USE_DIRECT_PAINTER
302 QDirectPainter p(this);
303
304 if ( ( qt_screen->transformOrientation() == 3 ) &&
305 ( ( dd == 16 ) || ( dd == 32 ) ) && ( p.numRects() == 1 ) ) {
306
307 w = 320;
308 h = 240;
309
310 if ( mediaPlayerState->scaled() ) {
311 // maintain aspect ratio
312 if ( w * sh > sw * h )
313 w = sw * h / sh;
314 else
315 h = sh * w / sw;
316 } else {
317 w = sw;
318 h = sh;
319 }
320
321 w--; // we can't allow libmpeg to overwrite.
322 QPoint roff = qt_screen->mapToDevice( p.offset(), QSize( qt_screen->width(), qt_screen->height() ) );
323
324 int ox = roff.x() - height() + 2 + (height() - w) / 2;
325 int oy = roff.y() + (width() - h) / 2;
326 int sx = 0, sy = 0;
327
328 uchar* fp = p.frameBuffer() + p.lineStep() * oy;
329 fp += dd * ox / 8;
330 uchar **jt = new uchar*[h];
331 for ( int i = h; i; i-- ) {
332 jt[h - i] = fp;
333 fp += p.lineStep();
334 }
335
336 result = mediaPlayerState->curDecoder()->videoReadScaledFrame( jt, sx, sy, sw, sh, w, h, format, 0) == 0;
337
338 delete [] jt;
339 } else {
340#endif
341 QPainter p(this);
342
343 w = 320;
344 h = 240;
345
346 if ( mediaPlayerState->scaled() ) {
347 // maintain aspect ratio
348 if ( w * sh > sw * h )
349 w = sw * h / sh;
350 else
351 h = sh * w / sw;
352 } else {
353 w = sw;
354 h = sh;
355 }
356
357 int bytes = ( dd == 16 ) ? 2 : 4;
358 QImage tempFrame( w, h, bytes << 3 );
359 result = mediaPlayerState->curDecoder()->videoReadScaledFrame( tempFrame.jumpTable(),
360 0, 0, sw, sh, w, h, format, 0) == 0;
361 if ( result && mediaPlayerState->fullscreen() ) {
362
363 int rw = h, rh = w;
364 QImage rotatedFrame( rw, rh, bytes << 3 );
365
366 ushort* in = (ushort*)tempFrame.bits();
367 ushort* out = (ushort*)rotatedFrame.bits();
368 int spl = rotatedFrame.bytesPerLine() / bytes;
369 for (int x=0; x<h; x++) {
370 if ( bytes == 2 ) {
371 ushort* lout = out++ + (w - 1)*spl;
372 for (int y=0; y<w; y++) {
373 *lout=*in++;
374 lout-=spl;
375 }
376 } else {
377 ulong* lout = ((ulong *)out)++ + (w - 1)*spl;
378 for (int y=0; y<w; y++) {
379 *lout=*((ulong*)in)++;
380 lout-=spl;
381 }
382 }
383 }
384
385 p.drawImage( (240 - rw) / 2, (320 - rh) / 2, rotatedFrame, 0, 0, rw, rh );
386 }
387#ifdef USE_DIRECT_PAINTER
388 }
389#endif
390 } else {
391
392 w = 220;
393 h = 160;
394
395 // maintain aspect ratio
396 if ( w * sh > sw * h )
397 w = sw * h / sh;
398 else
399 h = sh * w / sw;
400
401 result = mediaPlayerState->curDecoder()->videoReadScaledFrame( currentFrame->jumpTable(), 0, 0, sw, sh, w, h, format, 0) == 0;
402
403 QPainter p( this );
404
405 // Image changed size, therefore need to blank the possibly unpainted regions first
406 if ( scaledWidth != w || scaledHeight != h ) {
407 p.setBrush( QBrush( Qt::black ) );
408 p.drawRect( 9, 20, 220, 160 );
409 }
410
411 scaledWidth = w;
412 scaledHeight = h;
413
414 if ( result ) {
415 p.drawImage( 9 + (220 - scaledWidth) / 2, 20 + (160 - scaledHeight) / 2, *currentFrame, 0, 0, scaledWidth, scaledHeight );
416 }
417
418 }
419
420 return result;
421}
422
423