1 /*****************************************************************************
2 * vout_qte.cpp : Qt Embedded video output plugin implementation
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
5 * $Id: vout_qte.cpp,v 1.1.2.1 2002/11/26 19:54:12 jpsaman Exp $
7 * Authors: Gerald Hansink <gerald.hansink@ordina.nl>
8 * Jean-Paul Saman <jpsaman@wxs.nl>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 * - written for ipaq, so hardcoded assumptions specific for ipaq...
29 * - no "mouse events" handling
31 *****************************************************************************/
33 /*****************************************************************************
35 *****************************************************************************/
38 #include <errno.h> /* ENOMEM */
39 #include <stdlib.h> /* free() */
40 #include <string.h> /* strerror() */
42 #include <videolan/vlc.h>
44 #ifdef HAVE_MACHINE_PARAM_H
46 # include <machine/param.h>
47 # include <sys/types.h> /* typedef ushort */
52 # include <netinet/in.h> /* BSD: struct in_addr */
56 # include <sys/shm.h> /* shmget(), shmctl() */
60 #include "video_output.h"
62 #include "interface.h"
63 #include "netutils.h" /* network_ChannelJoin */
65 #include "stream_control.h" /* needed by input_ext-intf.h... */
66 #include "input_ext-intf.h"
69 /* QT Embedded include files */
70 #include <qapplication.h>
74 # define USE_DIRECT_PAINTER
75 # include <qdirectpainter_qws.h>
76 # include <qgfxraster_qws.h>
79 /*****************************************************************************
81 *****************************************************************************/
82 #define QTE_MAX_DIRECTBUFFERS 2
84 /*****************************************************************************
86 *****************************************************************************/
89 static int vout_Create ( vout_thread_t * );
90 static void vout_Destroy ( vout_thread_t * );
91 static void vout_Render ( vout_thread_t *, picture_t * );
92 static void vout_Display ( vout_thread_t *, picture_t * );
93 static int vout_Manage ( vout_thread_t * );
94 static int vout_Init ( vout_thread_t * );
95 static void vout_End ( vout_thread_t * );
97 static int CreateQtWindow ( vout_thread_t * );
98 static void DestroyQtWindow( vout_thread_t * );
100 static int NewPicture ( vout_thread_t *, picture_t * );
101 static void FreePicture ( vout_thread_t *, picture_t * );
103 static void ToggleFullScreen ( vout_thread_t * );
106 static void* vout_run_qtapp_exec (void* pVoid);
108 /*****************************************************************************
109 * vout_sys_t: video output method descriptor
110 *****************************************************************************
111 * This structure is part of the video output thread descriptor.
112 * It describes the specific properties of an video output plugin
113 *****************************************************************************/
114 typedef struct vout_sys_s
116 /* Internal settings and properties */
123 QApplication* pcQApplication;
124 QWidget* pcVoutWidget;
128 /*****************************************************************************
129 * picture_sys_t: direct buffer method descriptor
130 *****************************************************************************/
131 typedef struct picture_sys_s
140 /*****************************************************************************
141 * * * Seeking function TODO: put this in a generic location !
142 *****************************************************************************/
143 static inline void vout_Seek( off_t i_seek )
148 void _M( vout_getfunctions )( function_list_t * p_function_list );
150 /*****************************************************************************
151 * Functions exported as capabilities. They are declared as static so that
152 * we don't pollute the namespace too much.
153 *****************************************************************************/
154 void _M( vout_getfunctions )( function_list_t * p_function_list )
156 p_function_list->functions.vout.pf_create = vout_Create;
157 p_function_list->functions.vout.pf_init = vout_Init;
158 p_function_list->functions.vout.pf_end = vout_End;
159 p_function_list->functions.vout.pf_destroy = vout_Destroy;
160 p_function_list->functions.vout.pf_manage = vout_Manage;
161 p_function_list->functions.vout.pf_render = vout_Render;
162 p_function_list->functions.vout.pf_display = vout_Display;
167 /*****************************************************************************
168 * vout_Create: allocate video thread output method
169 *****************************************************************************/
170 static int vout_Create( vout_thread_t *p_vout )
172 //intf_ErrMsg( "+vout_Create::qte" );
174 /* Allocate structure */
175 p_vout->p_sys = (vout_sys_s*) malloc( sizeof( vout_sys_t ) );
177 if( p_vout->p_sys == NULL )
179 intf_ErrMsg( "vout error: %s", strerror(ENOMEM) );
183 memset(p_vout->p_sys, 0, sizeof( vout_sys_t ));
185 CreateQtWindow(p_vout);
187 //intf_ErrMsg( "-vout_Create::qte\n" );
191 /*****************************************************************************
192 * vout_Destroy: destroy video thread output method
193 *****************************************************************************
194 * Terminate an output method created by vout_Create
195 *****************************************************************************/
196 static void vout_Destroy( vout_thread_t *p_vout )
198 //intf_ErrMsg( "+vout_Destroy::qte\n" );
199 DestroyQtWindow(p_vout);
203 /*****************************************************************************
204 * vout_Init: initialize video thread output method
205 *****************************************************************************
206 * This function create the buffers needed by the output thread. It is called
207 * at the beginning of the thread, but also each time the window is resized.
208 *****************************************************************************/
209 static int vout_Init( vout_thread_t *p_vout )
212 char *psz_display, *psz_window;
214 int dd = QPixmap::defaultDepth();
216 //intf_ErrMsg( "+vout_Init::qte\n" );
218 /* Initialize the output structure */
219 I_OUTPUTPICTURES = 0;
221 psz_display = config_GetPszVariable("qte-display");
222 psz_window = config_GetPszVariable("qte-window");
223 if( strncmp(psz_display, "portrait", 8)==0 )
225 /* All we have is an RGB image with square pixels */
226 p_vout->output.i_width = p_vout->p_sys->i_width;
227 p_vout->output.i_height = p_vout->p_sys->i_height;
228 p_vout->output.i_aspect = p_vout->output.i_width
230 / p_vout->output.i_height;
234 /* We may need to convert the chroma, but at least we keep the
236 p_vout->output.i_width = p_vout->render.i_width;
237 p_vout->output.i_height = p_vout->render.i_height;
238 p_vout->output.i_aspect = p_vout->render.i_aspect;
241 p_vout->output.i_chroma = (dd == 16) ? FOURCC_RV16 : FOURCC_RV32;
242 p_vout->output.i_rmask = 0xf800;
243 p_vout->output.i_gmask = 0x07e0;
244 p_vout->output.i_bmask = 0x001f;
245 // p_vout->output.i_width = p_vout->p_sys->i_width;
246 // p_vout->output.i_height = p_vout->p_sys->i_height;
247 // p_vout->output.i_aspect = p_vout->render.i_aspect;
249 /* Try to initialize MAX_DIRECTBUFFERS direct buffers */
250 while( I_OUTPUTPICTURES < QTE_MAX_DIRECTBUFFERS )
254 /* Find an empty picture slot */
255 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
257 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
259 p_pic = p_vout->p_picture + i_index;
264 /* Allocate the picture */
265 if( p_pic == NULL || NewPicture( p_vout, p_pic ) )
270 p_pic->i_status = DESTROYED_PICTURE;
271 p_pic->i_type = DIRECT_PICTURE;
273 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
278 //intf_ErrMsg( "-vout_Init::qte %d output pictures\n", I_OUTPUTPICTURES);
284 /*****************************************************************************
285 * vout_Render: render previously calculated output
286 *****************************************************************************/
287 static void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
289 //intf_ErrMsg( "+vout_Render::qte\n" );
293 /*****************************************************************************
294 * vout_Display: displays previously rendered output
295 *****************************************************************************
296 * This function sends the currently rendered image to screen.
297 *****************************************************************************/
298 static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
302 vout_PlacePicture( p_vout, p_vout->p_sys->i_width, p_vout->p_sys->i_height,
305 if(p_vout->p_sys->pcVoutWidget)
307 // shameless borrowed from opie mediaplayer....
308 #ifndef USE_DIRECT_PAINTER
309 QPainter p(p_vout->p_sys->pcVoutWidget);
312 int dd = QPixmap::defaultDepth();
313 int bytes = ( dd == 16 ) ? 2 : 4;
316 QImage rotatedFrame( rw, rh, bytes << 3 );
318 ushort* in = (ushort*)p_pic->p_sys->pQImage->bits();
319 ushort* out = (ushort*)rotatedFrame.bits();
321 int spl = rotatedFrame.bytesPerLine() / bytes;
322 for (int x=0; x<h; x++)
326 ushort* lout = out++ + (w - 1)*spl;
327 for (int y=0; y<w; y++)
335 ulong* lout = ((ulong *)out)++ + (w - 1)*spl;
336 for (int y=0; y<w; y++)
338 *lout=*((ulong*)in)++;
344 p.drawImage( x, y, rotatedFrame, 0, 0, rw, rh );
346 QDirectPainter p(p_vout->p_sys->pcVoutWidget);
348 // just copy the image to the frame buffer...
349 memcpy(p.frameBuffer(), (p_pic->p_sys->pQImage->jumpTable())[0], h * p.lineStep());
354 /*****************************************************************************
355 * vout_Manage: handle QT Embedded events
356 *****************************************************************************
357 * This function should be called regularly by video output thread. It manages
358 * X11 events and allows window resizing. It returns a non null value on
360 *****************************************************************************/
361 static int vout_Manage( vout_thread_t *p_vout )
363 //intf_ErrMsg( "+vout_Manage::qte\n" );
367 /*****************************************************************************
368 * vout_End: terminate video thread output method
369 *****************************************************************************
370 * Destroy the buffers created by vout_Init. It is called at the end of
371 * the thread, but also each time the window is resized.
372 *****************************************************************************/
373 static void vout_End( vout_thread_t *p_vout )
377 //intf_ErrMsg( "+vout_End::qte\n" );
379 /* Free the direct buffers we allocated */
380 for( i_index = I_OUTPUTPICTURES ; i_index ; )
383 FreePicture( p_vout, PP_OUTPUTPICTURE[ i_index ] );
388 /*****************************************************************************
389 * NewPicture: allocate a picture
390 *****************************************************************************
391 * Returns 0 on success, -1 otherwise
392 *****************************************************************************/
393 static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
395 int dd = QPixmap::defaultDepth();
397 //intf_ErrMsg( "+NewPicture::dd = %d\n",dd );
399 p_pic->p_sys = (picture_sys_t*) malloc( sizeof( picture_sys_t ) );
401 if( p_pic->p_sys == NULL )
406 switch(p_vout->output.i_chroma)
411 p_pic->p_sys->pQImage = new QImage(p_vout->output.i_width,
412 p_vout->output.i_height,
415 if(p_pic->p_sys->pQImage == NULL)
420 p_pic->p->p_pixels = (p_pic->p_sys->pQImage->jumpTable())[0];
422 p_pic->p->i_pitch = p_pic->p_sys->pQImage->bytesPerLine();
424 p_pic->p->i_lines = p_vout->output.i_height;
425 p_pic->p->i_pixel_bytes = 2;
426 p_pic->p->b_margin = 0;
437 p_pic->p_sys->pQImage = new QImage(p_vout->output.i_width,
438 p_vout->output.i_height,
441 if(p_pic->p_sys->pQImage == NULL)
446 p_pic->p->p_pixels = (p_pic->p_sys->pQImage->jumpTable())[0];
448 p_pic->p->i_pitch = p_pic->p_sys->pQImage->bytesPerLine();
450 p_pic->p->i_lines = p_vout->output.i_height;
451 p_pic->p->i_pixel_bytes = 4;
452 p_pic->p->b_margin = 0;
466 intf_ErrMsg( "NewPicture: %d %d %d\n",p_vout->output.i_width,
467 p_vout->output.i_height,
468 p_vout->output.i_chroma );
473 /*****************************************************************************
474 * FreePicture: destroy a picture allocated with NewPicture
475 *****************************************************************************/
476 static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
478 delete p_pic->p_sys->pQImage;
481 /*****************************************************************************
482 * ToggleFullScreen: Enable or disable full screen mode
483 *****************************************************************************
484 * This function will switch between fullscreen and window mode.
486 *****************************************************************************/
487 static void ToggleFullScreen ( vout_thread_t *p_vout )
492 /*****************************************************************************
493 * CreateQtWindow: create qte applicaton / window
494 *****************************************************************************
495 * Create a window according to video output given size, and set other
496 * properties according to the display properties.
497 *****************************************************************************/
498 static int CreateQtWindow( vout_thread_t *p_vout )
500 //intf_ErrMsg( "vout_qt: +init qt window");
502 /* for displaying the vout in a qt window we need the QtApplication */
503 vlc_thread_t thread_id;
504 //intf_ErrMsg( "vout_qt: +init qt window, creating qpe application");
506 p_vout->p_sys->pcVoutWidget = NULL;
508 /* create thread to exec the qpe application */
509 if ( vlc_thread_create( &thread_id, "vout qte",
510 (vlc_thread_func_t)vout_run_qtapp_exec,
513 intf_ErrMsg( "input error: can't spawn vout thread");
517 p_vout->p_sys->i_width = 320;
518 p_vout->p_sys->i_height = 240;
520 // just wait until the crew is complete...
521 while(p_vout->p_sys->pcVoutWidget == NULL)
526 //intf_ErrMsg( "vout_qt: -init qt window");
532 /*****************************************************************************
533 * DestroyQtWindow: destroy the window
534 *****************************************************************************/
535 static void DestroyQtWindow( vout_thread_t *p_vout )
537 // quit qt application loop
538 if(p_vout->p_sys->pcQApplication)
540 if(p_vout->p_sys->bOwnsQApp)
542 p_vout->p_sys->pcQApplication->quit();
546 p_vout->p_sys->bRunning = FALSE;
549 while(p_vout->p_sys->pcVoutWidget)
556 /*****************************************************************************
557 * main loop of qtapplication
558 *****************************************************************************/
560 vout_run_qtapp_exec(void* pVoid)
563 char arg0[] = "vout qte";
565 vout_thread_t* p_vout = (vout_thread_t*) pVoid;
569 QApplication* pApp = new QApplication(argc, NULL);
572 p_vout->p_sys->pcQApplication = pApp;
573 p_vout->p_sys->bOwnsQApp = TRUE;
582 p_vout->p_sys->pcQApplication = qApp;
586 QWidget vo(0, "vout");
589 p_vout->p_sys->pcVoutWidget = &vo;
591 p_vout->p_sys->bRunning = TRUE;
593 if(p_vout->p_sys->bOwnsQApp)
595 // run the main loop of qtapplication until someone says: 'quit'
596 p_vout->p_sys->pcQApplication->exec();
600 while(p_vout->p_sys->bRunning) msleep(100);
604 p_vout->p_sys->pcVoutWidget = NULL;
606 if(p_vout->p_sys->bOwnsQApp)
608 delete p_vout->p_sys->pcQApplication;
609 p_vout->p_sys->pcQApplication = NULL;