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