95c8903f27bca40234ba9a002bd44466f080acfc
[vlc.git] / 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.49 2002/03/31 08:13:38 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 #include "DrawingTidbits.h"
51
52 #define BITS_PER_PLANE  16
53 #define BYTES_PER_PIXEL 2
54
55 /*****************************************************************************
56  * vout_sys_t: BeOS video output method descriptor
57  *****************************************************************************
58  * This structure is part of the video output thread descriptor.
59  * It describes the BeOS specific properties of an output thread.
60  *****************************************************************************/
61 typedef struct vout_sys_s
62 {
63     VideoWindow *  p_window;
64
65     s32 i_width;
66     s32 i_height;
67
68     u8 *pp_buffer[2];
69     int i_index;
70
71 } vout_sys_t;
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  * DrawingThread : thread that really does the drawing
100  ****************************************************************************/
101 int32 Draw(void *data)
102 {
103     VideoWindow* p_win;
104     p_win = (VideoWindow *) data;
105
106     if ( p_win->LockWithTimeout(50000) == B_OK )
107     {
108         if (p_win->vsync)
109         {
110             BScreen *screen;
111             screen = new BScreen(p_win);
112             screen-> WaitForRetrace(22000);
113             delete screen;
114         }
115         if (p_win-> is_overlay)
116         {
117             p_win-> overlaybitmap->LockBits();
118                 memcpy(p_win-> overlaybitmap->Bits(), 
119                        p_win-> bitmap[p_win-> i_buffer]->Bits(),
120                            p_win-> bitmap[p_win-> i_buffer]->BitsLength() );
121             p_win-> overlaybitmap->UnlockBits();
122             p_win-> view-> Invalidate();
123         }
124         else
125         {
126             p_win-> view-> DrawBitmap( p_win-> bitmap[p_win-> i_buffer] );
127         }                                
128         p_win-> Unlock();
129     }
130     else
131     {
132         intf_Msg("Dropped Frame");
133     }
134     return B_OK;
135 }
136
137 /*****************************************************************************
138  * VideoWindow constructor and destructor
139  *****************************************************************************/
140 VideoWindow::VideoWindow( int v_width, int v_height, 
141                           BRect frame )
142             : BWindow( frame, NULL, B_TITLED_WINDOW, 
143                     B_NOT_CLOSABLE | B_NOT_MINIMIZABLE )
144 {
145     BView *mainView =  new BView( Bounds(), "mainView", 
146                                   B_FOLLOW_ALL, B_FULL_UPDATE_ON_RESIZE);
147     AddChild(mainView);
148     mainView->SetViewColor(kBlack);
149                                   
150     /* create the view to do the display */
151     view = new VLCView( Bounds() );
152     mainView->AddChild(view);
153
154     /* set the VideoWindow variables */
155     teardownwindow = false;
156     is_zoomed = false;
157
158     /* call ScreenChanged to set vsync correctly */
159     BScreen *screen;
160     screen = new BScreen(this);
161     ScreenChanged(screen->Frame(), screen->ColorSpace());
162     delete screen;
163     
164     // remember current settings
165     i_width = frame.IntegerWidth();
166     i_height = frame.IntegerHeight();
167     FrameResized(frame.IntegerWidth(), frame.IntegerHeight());
168
169     overlaybitmap = new BBitmap ( BRect( 0, 0, v_width, v_height ), 
170                                   B_BITMAP_WILL_OVERLAY|B_BITMAP_RESERVE_OVERLAY_CHANNEL,
171                                   B_RGB16);
172
173
174     if(overlaybitmap && overlaybitmap->InitCheck() == B_OK) 
175     {
176         is_overlay = true;
177             bitmap[0] = new BBitmap( BRect( 0, 0, v_width, v_height ), B_RGB16);
178         bitmap[1] = new BBitmap( BRect( 0, 0, v_width, v_height ), B_RGB16);
179         memset(bitmap[0]->Bits(), 0, bitmap[0]->BitsLength());
180         memset(bitmap[1]->Bits(), 0, bitmap[1]->BitsLength());
181         memset(overlaybitmap->Bits(), 0, overlaybitmap->BitsLength());
182         rgb_color key;
183                 view->SetViewOverlay(overlaybitmap, overlaybitmap->Bounds() ,view->Bounds(),
184                                      &key, B_FOLLOW_ALL,
185                                          B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL);
186                 view->SetViewColor(key);
187         SetTitle(VOUT_TITLE " (RGB Overlay)");
188         }
189         else
190         {
191             bitmap[0] = new BBitmap( BRect( 0, 0, v_width, v_height ), B_RGB32);
192         bitmap[1] = new BBitmap( BRect( 0, 0, v_width, v_height ), B_RGB32);
193         memset(bitmap[0]->Bits(), 0, bitmap[0]->BitsLength());
194         memset(bitmap[1]->Bits(), 0, bitmap[1]->BitsLength());
195             is_overlay = false;
196         view->DrawBitmap(bitmap[0], view->Bounds());
197         SetTitle(VOUT_TITLE " (RGB Bitmap)");
198         }
199     Show();
200 }
201
202 VideoWindow::~VideoWindow()
203 {
204     int32 result;
205
206     teardownwindow = true;
207     wait_for_thread(fDrawThreadID, &result);
208     kill_thread(fDrawThreadID);
209 //    delete overlaybitmap;
210 //    delete bitmap[0];
211 //    delete bitmap[1];
212     Lock();
213     Quit();
214 }
215
216 void VideoWindow::drawBuffer(int bufferIndex)
217 {
218     status_t status;
219
220     i_buffer = bufferIndex;
221     fDrawThreadID = spawn_thread(Draw, "drawing_thread",
222                                  B_DISPLAY_PRIORITY, (void*) this);
223     wait_for_thread(fDrawThreadID, &status);
224 }
225
226 void VideoWindow::Zoom(BPoint origin, float width, float height )
227 {
228     if(is_zoomed)
229     {
230         is_zoomed = !is_zoomed;
231         MoveTo(winSize.left, winSize.top);
232         ResizeTo(winSize.IntegerWidth(), winSize.IntegerHeight());
233         be_app->ShowCursor();
234     }
235     else
236     {
237         is_zoomed = !is_zoomed;
238         BScreen *screen;
239         screen = new BScreen(this);
240         BRect rect = screen->Frame();
241         delete screen;
242         MoveTo(0,0);
243         ResizeTo(rect.IntegerWidth(), rect.IntegerHeight());
244         be_app->ObscureCursor();
245     }
246     view->Invalidate();
247 }
248
249 void VideoWindow::FrameMoved(BPoint origin) 
250 {
251         if (is_zoomed) return ;
252     winSize = Frame();
253     view->Invalidate();
254 }
255
256 void VideoWindow::FrameResized( float width, float height )
257 {
258     float out_width, out_height;
259     float out_left, out_top;
260     float width_scale = width / i_width;
261     float height_scale = height / i_height;
262
263     if (width_scale <= height_scale)
264     {
265         out_width = i_width * width_scale;
266         out_height = i_height * width_scale;
267         out_left = 0; 
268         out_top = (height - out_height) / 2;
269     }
270     else   /* if the height is proportionally smaller */
271     {
272         out_width = i_width * height_scale;
273         out_height = i_height * height_scale;
274         out_top = 0;
275         out_left = (width - out_width) /2;
276     }
277     view->MoveTo(out_left,out_top);
278     view->ResizeTo(out_width, out_height);
279         if (!is_zoomed)
280         {
281         winSize = Frame();
282     }
283     view->Invalidate();
284 }
285
286 void VideoWindow::ScreenChanged(BRect frame, color_space mode)
287 {
288     BScreen *screen;
289     float refresh;
290     
291     view->Invalidate();
292     screen = new BScreen(this);
293     display_mode disp_mode; 
294     
295     screen-> GetMode(&disp_mode); 
296     refresh = 
297          (disp_mode.timing.pixel_clock * 1000)/((disp_mode.timing.h_total)* 
298          (disp_mode.timing.v_total)); 
299     if (refresh  < 61) 
300     { 
301         vsync = true; 
302     } 
303 }
304
305 void VideoWindow::WindowActivated(bool active)
306 {
307     view->Invalidate();
308 }
309
310 /*****************************************************************************
311  * VLCView::VLCView
312  *****************************************************************************/
313 VLCView::VLCView(BRect bounds) : BView(bounds, "", B_FOLLOW_NONE,
314                                        B_WILL_DRAW)
315
316 {
317     SetViewColor(B_TRANSPARENT_32_BIT);
318 }
319
320 /*****************************************************************************
321  * VLCView::~VLCView
322  *****************************************************************************/
323 VLCView::~VLCView()
324 {
325 }
326
327 /*****************************************************************************
328  * VLCVIew::MouseDown
329  *****************************************************************************/
330 void VLCView::MouseDown(BPoint point)
331 {
332     BWindow *win = Window();
333     win->Zoom();
334 }
335
336 /*****************************************************************************
337  * VLCVIew::Draw
338  *****************************************************************************/
339 void VLCView::Draw(BRect updateRect) 
340 {
341     VideoWindow *win = (VideoWindow *) Window();
342     if (!win->is_overlay)
343       FillRect(updateRect);
344 }
345
346
347 extern "C"
348 {
349
350 /*****************************************************************************
351  * Local prototypes
352  *****************************************************************************/
353 static int  vout_Create     ( vout_thread_t * );
354 static int  vout_Init       ( vout_thread_t * );
355 static void vout_End        ( vout_thread_t * );
356 static void vout_Destroy    ( vout_thread_t * );
357 static int  vout_Manage     ( vout_thread_t * );
358 static void vout_Display    ( vout_thread_t *, picture_t * );
359 static void vout_Render     ( vout_thread_t *, picture_t * );
360
361 static int  BeosOpenDisplay ( vout_thread_t *p_vout );
362 static void BeosCloseDisplay( vout_thread_t *p_vout );
363
364 /*****************************************************************************
365  * Functions exported as capabilities. They are declared as static so that
366  * we don't pollute the namespace too much.
367  *****************************************************************************/
368 void _M( vout_getfunctions )( function_list_t * p_function_list )
369 {
370     p_function_list->functions.vout.pf_create     = vout_Create;
371     p_function_list->functions.vout.pf_init       = vout_Init;
372     p_function_list->functions.vout.pf_end        = vout_End;
373     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
374     p_function_list->functions.vout.pf_manage     = vout_Manage;
375     p_function_list->functions.vout.pf_display    = vout_Display;
376     p_function_list->functions.vout.pf_render     = vout_Render;
377 }
378
379 /*****************************************************************************
380  * vout_Create: allocates BeOS video thread output method
381  *****************************************************************************
382  * This function allocates and initializes a BeOS vout method.
383  *****************************************************************************/
384 int vout_Create( vout_thread_t *p_vout )
385 {
386     /* Allocate structure */
387     p_vout->p_sys = (vout_sys_t*) malloc( sizeof( vout_sys_t ) );
388     if( p_vout->p_sys == NULL )
389     {
390         intf_ErrMsg( "error: %s", strerror(ENOMEM) );
391         return( 1 );
392     }
393     p_vout->p_sys->i_width = p_vout->render.i_width;
394     p_vout->p_sys->i_height = p_vout->render.i_height;
395
396     return( 0 );
397 }
398
399 /*****************************************************************************
400  * vout_Init: initialize BeOS video thread output method
401  *****************************************************************************/
402 int vout_Init( vout_thread_t *p_vout )
403 {
404     int i_index;
405     picture_t *p_pic;
406
407     I_OUTPUTPICTURES = 0;
408
409     /* Open and initialize device */
410     if( BeosOpenDisplay( p_vout ) )
411     {
412         intf_ErrMsg("vout error: can't open display");
413         return 0;
414     }
415     /* Set the buffers */
416     p_vout->p_sys->pp_buffer[0] = (u8*)p_vout->p_sys->p_window->bitmap[0]->Bits();
417     p_vout->p_sys->pp_buffer[1] = (u8*)p_vout->p_sys->p_window->bitmap[1]->Bits();
418
419     p_vout->output.i_width  = p_vout->render.i_width;
420     p_vout->output.i_height = p_vout->render.i_height;
421
422     /* Assume we have square pixels */
423     p_vout->output.i_aspect = p_vout->p_sys->i_width
424                                * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
425
426     if (p_vout->p_sys->p_window->is_overlay)
427     {
428         p_vout->output.i_chroma = FOURCC_RV16;
429     }
430     else
431     {
432         p_vout->output.i_chroma = FOURCC_RV32;
433     }
434
435     p_vout->output.i_rmask  = 0x00ff0000;
436     p_vout->output.i_gmask  = 0x0000ff00;
437     p_vout->output.i_bmask  = 0x000000ff;
438
439     p_pic = NULL;
440
441     /* Find an empty picture slot */
442     for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
443     {
444         if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
445         {
446             p_pic = p_vout->p_picture + i_index;
447             break;
448         }
449     }
450
451     if( p_pic == NULL )
452     {
453         return 0;
454     }
455
456     p_vout->p_sys->i_index = 0;
457     p_pic->p->p_pixels = p_vout->p_sys->pp_buffer[0];
458     p_pic->p->i_lines = p_vout->p_sys->i_height;
459     p_pic->p->b_margin = 0;
460     p_pic->p->i_pitch = p_vout->p_sys->p_window->bitmap[0]->BytesPerRow();
461     p_pic->p->i_pixel_bytes = p_pic->p->i_pitch / p_vout->p_sys->p_window->bitmap[0]->Bounds().IntegerWidth();
462
463     p_pic->i_planes = 1;
464
465     p_pic->i_status = DESTROYED_PICTURE;
466     p_pic->i_type   = DIRECT_PICTURE;
467
468     PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
469
470     I_OUTPUTPICTURES++;
471
472     return( 0 );
473 }
474
475 /*****************************************************************************
476  * vout_End: terminate BeOS video thread output method
477  *****************************************************************************/
478 void vout_End( vout_thread_t *p_vout )
479 {
480     BeosCloseDisplay( p_vout );
481 }
482
483 /*****************************************************************************
484  * vout_Destroy: destroy BeOS video thread output method
485  *****************************************************************************
486  * Terminate an output method created by DummyCreateOutputMethod
487  *****************************************************************************/
488 void vout_Destroy( vout_thread_t *p_vout )
489 {
490     free( p_vout->p_sys );
491 }
492
493 /*****************************************************************************
494  * vout_Manage: handle BeOS events
495  *****************************************************************************
496  * This function should be called regularly by video output thread. It manages
497  * console events. It returns a non null value on error.
498  *****************************************************************************/
499 int vout_Manage( vout_thread_t *p_vout )
500 {
501                           
502     return( 0 );
503 }
504
505 /*****************************************************************************
506  * vout_Render: render previously calculated output
507  *****************************************************************************/
508 void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
509 {
510     ;
511 }
512
513 /*****************************************************************************
514  * vout_Display: displays previously rendered output
515  *****************************************************************************
516  * This function send the currently rendered image to BeOS image, waits until
517  * it is displayed and switch the two rendering buffers, preparing next frame.
518  *****************************************************************************/
519 void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
520 {
521     VideoWindow * p_win = p_vout->p_sys->p_window;
522
523     /* draw buffer if required */    
524     if (!p_win->teardownwindow)
525     { 
526        p_win->drawBuffer(p_vout->p_sys->i_index);
527     }
528     /* change buffer */
529     p_vout->p_sys->i_index = ++p_vout->p_sys->i_index & 1;
530     p_pic->p->p_pixels = p_vout->p_sys->pp_buffer[p_vout->p_sys->i_index];
531 }
532
533 /* following functions are local */
534
535 /*****************************************************************************
536  * BeosOpenDisplay: open and initialize BeOS device
537  *****************************************************************************/
538 static int BeosOpenDisplay( vout_thread_t *p_vout )
539
540
541     p_vout->p_sys->p_window = new VideoWindow( p_vout->p_sys->i_width - 1,
542                                                p_vout->p_sys->i_height - 1,
543                                                BRect( 20, 50,
544                                                       20 + p_vout->i_window_width -1, 
545                                                       50 + p_vout->i_window_height ));
546
547     if( p_vout->p_sys->p_window == NULL )
548     {
549         intf_ErrMsg( "error: cannot allocate memory for VideoWindow" );
550         return( 1 );
551     }   
552     
553     return( 0 );
554 }
555
556 /*****************************************************************************
557  * BeosDisplay: close and reset BeOS device
558  *****************************************************************************
559  * Returns all resources allocated by BeosOpenDisplay and restore the original
560  * state of the device.
561  *****************************************************************************/
562 static void BeosCloseDisplay( vout_thread_t *p_vout )
563 {    
564     /* Destroy the video window */
565     delete p_vout->p_sys->p_window;
566 }
567
568
569
570 } /* extern "C" */