]> git.sesse.net Git - vlc/blob - plugins/beos/vout_beos.cpp
Tidied code and prevented curruption on window not containing the video.
[vlc] / plugins / beos / vout_beos.cpp
1 /*****************************************************************************
2  * vout_beos.cpp: beos video output display method
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 VideoLAN
5  * $Id: vout_beos.cpp,v 1.46 2002/03/17 05:48:18 tcastley Exp $
6  *
7  * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
8  *          Samuel Hocevar <sam@zoy.org>
9  *          Tony Castley <tcastley@mail.powerup.com.au>
10  *          Richard Shepherd <richard@rshepherd.demon.co.uk>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #include <errno.h>                                                 /* ENOMEM */
31 #include <stdlib.h>                                                /* free() */
32 #include <stdio.h>
33 #include <string.h>                                            /* strerror() */
34 #include <InterfaceKit.h>
35 #include <DirectWindow.h>
36 #include <Application.h>
37 #include <Bitmap.h>
38
39 extern "C"
40 {
41 #include <videolan/vlc.h>
42
43 #include "video.h"
44 #include "video_output.h"
45
46 #include "interface.h"
47 }
48
49 #include "VideoWindow.h"
50
51 #define BITS_PER_PLANE  16
52 #define BYTES_PER_PIXEL 2
53
54 /*****************************************************************************
55  * vout_sys_t: BeOS video output method descriptor
56  *****************************************************************************
57  * This structure is part of the video output thread descriptor.
58  * It describes the BeOS specific properties of an output thread.
59  *****************************************************************************/
60 typedef struct vout_sys_s
61 {
62     VideoWindow *  p_window;
63
64     s32 i_width;
65     s32 i_height;
66
67     u8 *pp_buffer[2];
68     int i_index;
69
70 } vout_sys_t;
71
72
73 /*****************************************************************************
74  * beos_GetAppWindow : retrieve a BWindow pointer from the window name
75  *****************************************************************************/
76 BWindow *beos_GetAppWindow(char *name)
77 {
78     int32       index;
79     BWindow     *window;
80     
81     for (index = 0 ; ; index++)
82     {
83         window = be_app->WindowAt(index);
84         if (window == NULL)
85             break;
86         if (window->LockWithTimeout(20000) == B_OK)
87         {
88             if (strcmp(window->Name(), name) == 0)
89             {
90                 window->Unlock();
91                 break;
92             }
93             window->Unlock();
94         }
95     }
96     return window; 
97 }
98
99 /**************************************************************************** 
100  * Modify Refresh : code to detect refresh changes 
101  ****************************************************************************/ 
102 void waitForRefreshIfRequired(BScreen *screen)
103 {
104     //rudolf: sync init: 
105     display_mode disp_mode; 
106     static uint32 refresh, oldrefresh = 0; 
107     
108     screen-> GetMode(&disp_mode); 
109     refresh = 
110          (disp_mode.timing.pixel_clock * 1000)/((disp_mode.timing.h_total)* 
111          (disp_mode.timing.v_total)); 
112     if (!(refresh == oldrefresh)) 
113     { 
114         oldrefresh = refresh; 
115     } 
116     //rudolf: sync: 
117     if (refresh  < 61) 
118     { 
119         screen-> WaitForRetrace(22000);//set timeout for  < 45 Hz... 
120     } 
121 }
122
123 /**************************************************************************** 
124  * DrawingThread : thread that really does the drawing 
125  ****************************************************************************/ 
126 int32 Draw(void *data) 
127
128     static float out_top, out_left, out_height, out_width;
129     BScreen *screen; 
130     VideoWindow* p_win; 
131
132     screen = new BScreen(); 
133     p_win = (VideoWindow *) data; 
134
135     if ( p_win-> voutWindow-> LockLooper() ) 
136     {
137         waitForRefreshIfRequired(screen); 
138         if (p_win->resized)
139         {
140             p_win->resized = false;
141             p_win-> view-> FillRect(p_win-> voutWindow-> Bounds());
142             /* if the width is proportionally smaller */
143             if (p_win->width_scale <= p_win->height_scale)
144             {
145                 out_width = p_win->i_width * p_win->width_scale;
146                 out_height = p_win->i_height * p_win->width_scale;
147                 out_left = 0; 
148                 if (p_win-> is_zoomed)
149                 {
150                    out_top = (screen-> Frame().Height() - out_height) / 2;
151                 }
152                 else
153                 {
154                    out_top = (p_win->winSize.Height() - out_height) / 2;
155                 }
156             }
157             else   /* if the height is proportionally smaller */
158             {
159                 out_width = p_win->i_width * p_win->height_scale;
160                 out_height = p_win->i_height * p_win->height_scale;
161                 out_top = 0;
162                 if (p_win-> is_zoomed)
163                 {
164                    out_left = (screen-> Frame().Width() - out_width) / 2;
165                 } 
166                 else
167                 {
168                    out_left = (p_win->winSize.Width() - out_width) /2;
169                 }
170             }
171         }  
172         p_win-> view-> DrawBitmap( p_win-> bitmap[p_win-> i_buffer],  
173                                  BRect(out_left, out_top,
174                                        out_left + out_width, out_top + out_height) );  
175         p_win-> voutWindow-> UnlockLooper(); 
176     } 
177     return B_OK; 
178 }
179
180 /*****************************************************************************
181  * bitmapWindow : This is the bitmap window output
182  *****************************************************************************/
183 bitmapWindow::bitmapWindow(BRect frame, VideoWindow *theOwner)
184         : BWindow( frame, NULL, B_TITLED_WINDOW, 
185                     B_NOT_CLOSABLE | B_NOT_MINIMIZABLE )
186 {
187     owner = theOwner;
188     owner->winSize = frame;
189     owner->width_scale = frame.Width() / owner->i_width;
190     owner->height_scale = frame.Height() / owner->i_height;
191     owner->resized = true;
192     SetTitle(VOUT_TITLE " (BBitmap output)");
193 }
194
195 bitmapWindow::~bitmapWindow()
196 {
197 }
198
199 void bitmapWindow::FrameResized( float width, float height )
200 {
201     owner->winSize = Frame();
202     owner->width_scale = width / owner->i_width;
203     owner->height_scale = height / owner->i_height;
204     owner->resized = true;
205 }
206
207 void bitmapWindow::Zoom(BPoint origin, float width, float height )
208 {
209     if(owner-> is_zoomed)
210     {
211         MoveTo(owner->winSize.left, owner->winSize.top);
212         ResizeTo(owner->winSize.IntegerWidth(), owner->winSize.IntegerHeight());
213         owner->width_scale = owner->winSize.IntegerWidth() / owner->i_width;
214         owner->height_scale = owner->winSize.IntegerHeight() / owner->i_height;
215         be_app->ShowCursor();
216     }
217     else
218     {
219         BScreen *screen;
220         screen = new BScreen(this);
221         BRect rect = screen->Frame();
222         delete screen;
223         MoveTo(0,0);
224         ResizeTo(rect.IntegerWidth(), rect.IntegerHeight());
225         owner->width_scale = rect.IntegerWidth() / owner->i_width;
226         owner->height_scale = rect.IntegerHeight() / owner->i_height;
227         be_app->HideCursor();
228     }
229     owner-> is_zoomed = !owner-> is_zoomed;
230     owner->resized = true;
231 }
232
233 /*****************************************************************************
234  * directWindow : This is the bitmap window output
235  *****************************************************************************/
236 directWindow::directWindow(BRect frame, VideoWindow *theOwner)
237         : BDirectWindow( frame, NULL, B_TITLED_WINDOW, 
238                     B_NOT_CLOSABLE | B_NOT_MINIMIZABLE )
239 {
240     owner = theOwner;
241     owner->winSize = frame;
242     owner->width_scale = frame.Width() / owner->i_width;
243     owner->height_scale = frame.Height() / owner->i_height;
244     owner->resized = true;
245     SetTitle(VOUT_TITLE " (DirectWindow output)");
246 }
247
248 directWindow::~directWindow()
249 {
250 }
251
252 void directWindow::DirectConnected(direct_buffer_info *info)
253 {
254 }
255
256 void directWindow::FrameResized( float width, float height )
257 {
258     owner->winSize = Frame();
259     owner->width_scale = width / owner->i_width;
260     owner->height_scale = height / owner->i_height;
261     owner->resized = true;
262 }
263
264 void directWindow::Zoom(BPoint origin, float width, float height )
265 {
266     if(owner-> is_zoomed)
267     {
268         SetFullScreen(false);
269         MoveTo(owner->winSize.left, owner->winSize.top);
270         ResizeTo(owner->winSize.Width(), owner->winSize.Height());
271         owner->width_scale = owner->winSize.Width() / owner->i_width;
272         owner->height_scale = owner->winSize.Height() / owner->i_height;
273         be_app->ShowCursor();
274     }
275     else
276     {
277         owner->winSize = Frame();
278         SetFullScreen(true);
279         BScreen *screen;
280         screen = new BScreen(this);
281         BRect rect = screen->Frame();
282         delete screen;
283         MoveTo(0,0);
284         ResizeTo(rect.Width(), rect.Height());
285         owner->width_scale = rect.Width() / owner->i_width;
286         owner->height_scale = rect.Height() / owner->i_height;
287         be_app->HideCursor();
288     }
289     owner-> is_zoomed = !owner-> is_zoomed;
290     owner->resized = true;
291 }
292
293 /*****************************************************************************
294  * VideoWindow constructor and destructor
295  *****************************************************************************/
296 VideoWindow::VideoWindow( int width, int height, 
297                           vout_thread_t *p_video_output )
298 {
299     if ( BDirectWindow::SupportsWindowMode() )
300     { 
301         voutWindow = new directWindow( BRect( 80, 50, 
302                                           80 + width, 50 + height ), this );
303     }
304     else
305     {
306         voutWindow = new bitmapWindow( BRect( 80, 50, 
307                                           80 + width, 50 + height ), this );
308     }
309
310     /* set the VideoWindow variables */
311     teardownwindow = false;
312     is_zoomed = false;
313     resized = true;
314     
315     /* create the view to do the display */
316     view = new VLCView( voutWindow->Bounds() );
317     voutWindow->AddChild(view);
318     
319     /* Bitmap mode overlay not available, set the system to 32bits
320      * and let BeOS do all the work */
321     bitmap[0] = new BBitmap( voutWindow->Bounds(), B_RGB32);
322     bitmap[1] = new BBitmap( voutWindow->Bounds(), B_RGB32);
323     memset(bitmap[0]->Bits(), 0, bitmap[0]->BitsLength());
324     memset(bitmap[1]->Bits(), 0, bitmap[1]->BitsLength());
325
326     i_width = bitmap[0]->Bounds().IntegerWidth();
327     i_height = bitmap[0]->Bounds().IntegerHeight();
328     
329     winSize = voutWindow->Frame();
330     width_scale = winSize.Width() / i_width;
331     height_scale = winSize.Height() / i_height;
332
333     voutWindow->Show();
334 }
335
336 VideoWindow::~VideoWindow()
337 {
338     int32 result;
339
340     teardownwindow = true;
341     wait_for_thread(fDrawThreadID, &result);
342     voutWindow->Hide();
343     voutWindow->Sync();
344     voutWindow->Lock();
345     voutWindow->Quit();
346     delete bitmap[0];
347     delete bitmap[1];
348 }
349
350 void VideoWindow::drawBuffer(int bufferIndex)
351 {
352     status_t status;
353     
354     i_buffer = bufferIndex; 
355     
356     fDrawThreadID = spawn_thread(Draw, "drawing_thread",
357                     B_DISPLAY_PRIORITY, (void*) this);
358     wait_for_thread(fDrawThreadID, &status);
359 }
360
361 /*****************************************************************************
362  * VLCView::VLCView
363  *****************************************************************************/
364 VLCView::VLCView(BRect bounds) : BView(bounds, "", B_FOLLOW_ALL, B_WILL_DRAW)
365 {
366     SetViewColor(B_TRANSPARENT_32_BIT);
367 }
368
369 /*****************************************************************************
370  * VLCView::~VLCView
371  *****************************************************************************/
372 VLCView::~VLCView()
373 {
374 }
375
376 /*****************************************************************************
377  * VLCVIew::MouseDown
378  *****************************************************************************/
379 void VLCView::MouseDown(BPoint point)
380 {
381     BWindow *win = Window();
382     win->Zoom();
383 }
384
385 /*****************************************************************************
386  * VLCVIew::Draw
387  *****************************************************************************/
388 void VLCView::Draw(BRect updateRect) 
389 {
390     FillRect(updateRect);
391 }
392
393
394 extern "C"
395 {
396
397 /*****************************************************************************
398  * Local prototypes
399  *****************************************************************************/
400 static int  vout_Create     ( vout_thread_t * );
401 static int  vout_Init       ( vout_thread_t * );
402 static void vout_End        ( vout_thread_t * );
403 static void vout_Destroy    ( vout_thread_t * );
404 static int  vout_Manage     ( vout_thread_t * );
405 static void vout_Display    ( vout_thread_t *, picture_t * );
406 static void vout_Render     ( vout_thread_t *, picture_t * );
407
408 static int  BeosOpenDisplay ( vout_thread_t *p_vout );
409 static void BeosCloseDisplay( vout_thread_t *p_vout );
410
411 /*****************************************************************************
412  * Functions exported as capabilities. They are declared as static so that
413  * we don't pollute the namespace too much.
414  *****************************************************************************/
415 void _M( vout_getfunctions )( function_list_t * p_function_list )
416 {
417     p_function_list->functions.vout.pf_create     = vout_Create;
418     p_function_list->functions.vout.pf_init       = vout_Init;
419     p_function_list->functions.vout.pf_end        = vout_End;
420     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
421     p_function_list->functions.vout.pf_manage     = vout_Manage;
422     p_function_list->functions.vout.pf_display    = vout_Display;
423     p_function_list->functions.vout.pf_render     = vout_Render;
424 }
425
426 /*****************************************************************************
427  * vout_Create: allocates BeOS video thread output method
428  *****************************************************************************
429  * This function allocates and initializes a BeOS vout method.
430  *****************************************************************************/
431 int vout_Create( vout_thread_t *p_vout )
432 {
433     /* Allocate structure */
434     p_vout->p_sys = (vout_sys_t*) malloc( sizeof( vout_sys_t ) );
435     if( p_vout->p_sys == NULL )
436     {
437         intf_ErrMsg( "error: %s", strerror(ENOMEM) );
438         return( 1 );
439     }
440
441     if( p_vout->render.i_height * p_vout->render.i_aspect
442          >= p_vout->render.i_width * VOUT_ASPECT_FACTOR )
443     {
444         p_vout->p_sys->i_width = p_vout->render.i_height
445             * p_vout->render.i_aspect / VOUT_ASPECT_FACTOR;
446         p_vout->p_sys->i_height = p_vout->render.i_height;
447     }
448     else
449     {
450         p_vout->p_sys->i_width = p_vout->render.i_width;
451         p_vout->p_sys->i_height = p_vout->render.i_width
452             * VOUT_ASPECT_FACTOR / p_vout->render.i_aspect;
453     }
454
455     return( 0 );
456 }
457
458 /*****************************************************************************
459  * vout_Init: initialize BeOS video thread output method
460  *****************************************************************************/
461 int vout_Init( vout_thread_t *p_vout )
462 {
463     int i_index;
464     picture_t *p_pic;
465
466     I_OUTPUTPICTURES = 0;
467
468     /* Open and initialize device */
469     if( BeosOpenDisplay( p_vout ) )
470     {
471         intf_ErrMsg("vout error: can't open display");
472         return 0;
473     }
474
475     p_vout->p_sys->pp_buffer[0] = (u8*)p_vout->p_sys->p_window->bitmap[0]->Bits();
476     p_vout->p_sys->pp_buffer[1] = (u8*)p_vout->p_sys->p_window->bitmap[1]->Bits();
477
478     p_vout->output.i_width  = p_vout->p_sys->i_width;
479     p_vout->output.i_height = p_vout->p_sys->i_height;
480     p_vout->output.i_aspect = p_vout->p_sys->i_width
481                                * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
482     p_vout->output.i_chroma = FOURCC_RV32;
483
484     p_vout->output.i_rmask  = 0x00ff0000;
485     p_vout->output.i_gmask  = 0x0000ff00;
486     p_vout->output.i_bmask  = 0x000000ff;
487
488     p_pic = NULL;
489
490     /* Find an empty picture slot */
491     for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
492     {
493         if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
494         {
495             p_pic = p_vout->p_picture + i_index;
496             break;
497         }
498     }
499
500     if( p_pic == NULL )
501     {
502         return 0;
503     }
504
505     p_vout->p_sys->i_index = 0;
506     p_pic->p->p_pixels = p_vout->p_sys->pp_buffer[0];
507     p_pic->p->i_pixel_bytes = 4;
508     p_pic->p->i_lines = p_vout->p_sys->i_height;
509     p_pic->p->b_margin = 0;
510     p_pic->p->i_pitch = 4 * p_vout->p_sys->i_width;
511
512     p_pic->i_planes = 1;
513
514     p_pic->i_status = DESTROYED_PICTURE;
515     p_pic->i_type   = DIRECT_PICTURE;
516
517     PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
518
519     I_OUTPUTPICTURES++;
520
521     return( 0 );
522 }
523
524 /*****************************************************************************
525  * vout_End: terminate BeOS video thread output method
526  *****************************************************************************/
527 void vout_End( vout_thread_t *p_vout )
528 {
529     BeosCloseDisplay( p_vout );
530 }
531
532 /*****************************************************************************
533  * vout_Destroy: destroy BeOS video thread output method
534  *****************************************************************************
535  * Terminate an output method created by DummyCreateOutputMethod
536  *****************************************************************************/
537 void vout_Destroy( vout_thread_t *p_vout )
538 {
539     free( p_vout->p_sys );
540 }
541
542 /*****************************************************************************
543  * vout_Manage: handle BeOS events
544  *****************************************************************************
545  * This function should be called regularly by video output thread. It manages
546  * console events. It returns a non null value on error.
547  *****************************************************************************/
548 int vout_Manage( vout_thread_t *p_vout )
549 {
550                           
551     return( 0 );
552 }
553
554 /*****************************************************************************
555  * vout_Render: render previously calculated output
556  *****************************************************************************/
557 void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
558 {
559     ;
560 }
561
562 /*****************************************************************************
563  * vout_Display: displays previously rendered output
564  *****************************************************************************
565  * This function send the currently rendered image to BeOS image, waits until
566  * it is displayed and switch the two rendering buffers, preparing next frame.
567  *****************************************************************************/
568 void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
569 {
570     VideoWindow * p_win = p_vout->p_sys->p_window;
571
572     /* draw buffer if required */    
573     if (!p_win->teardownwindow)
574     {
575        p_win->drawBuffer(p_vout->p_sys->i_index);
576     }
577     /* change buffer */
578     p_vout->p_sys->i_index = ++p_vout->p_sys->i_index & 1;
579     p_pic->p->p_pixels = p_vout->p_sys->pp_buffer[p_vout->p_sys->i_index];
580 }
581
582 /* following functions are local */
583
584 /*****************************************************************************
585  * BeosOpenDisplay: open and initialize BeOS device
586  *****************************************************************************/
587 static int BeosOpenDisplay( vout_thread_t *p_vout )
588
589     p_vout->p_sys->p_window = new VideoWindow( p_vout->p_sys->i_width - 1,
590                                                p_vout->p_sys->i_height - 1,
591                                                p_vout );
592
593     if( p_vout->p_sys->p_window == NULL )
594     {
595         intf_ErrMsg( "error: cannot allocate memory for VideoWindow" );
596         return( 1 );
597     }   
598     
599     return( 0 );
600 }
601
602 /*****************************************************************************
603  * BeosDisplay: close and reset BeOS device
604  *****************************************************************************
605  * Returns all resources allocated by BeosOpenDisplay and restore the original
606  * state of the device.
607  *****************************************************************************/
608 static void BeosCloseDisplay( vout_thread_t *p_vout )
609 {    
610     /* Destroy the video window */
611     delete p_vout->p_sys->p_window;
612 }
613
614 } /* extern "C" */