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