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