1 /*****************************************************************************
2 * vout_beos.cpp: beos video output display method
3 *****************************************************************************
4 * Copyright (C) 2000, 2001 VideoLAN
5 * $Id: vout_beos.cpp,v 1.62 2002/07/22 11:39:56 tcastley Exp $
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>
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.
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.
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 *****************************************************************************/
27 /*****************************************************************************
29 *****************************************************************************/
30 #include <errno.h> /* ENOMEM */
31 #include <stdlib.h> /* free() */
33 #include <string.h> /* strerror() */
34 #include <InterfaceKit.h>
35 #include <DirectWindow.h>
36 #include <Application.h>
43 #include "VideoWindow.h"
44 #include "DrawingTidbits.h"
48 /*****************************************************************************
49 * vout_sys_t: BeOS video output method descriptor
50 *****************************************************************************
51 * This structure is part of the video output thread descriptor.
52 * It describes the BeOS specific properties of an output thread.
53 *****************************************************************************/
56 VideoWindow * p_window;
65 /*****************************************************************************
66 * beos_GetAppWindow : retrieve a BWindow pointer from the window name
67 *****************************************************************************/
68 BWindow *beos_GetAppWindow(char *name)
73 for (index = 0 ; ; index++)
75 window = be_app->WindowAt(index);
78 if (window->LockWithTimeout(20000) == B_OK)
80 if (strcmp(window->Name(), name) == 0)
91 /*****************************************************************************
92 * VideoWindow constructor and destructor
93 *****************************************************************************/
94 VideoWindow::VideoWindow( int v_width, int v_height,
96 : BWindow( frame, NULL, B_TITLED_WINDOW,
97 B_NOT_CLOSABLE | B_NOT_MINIMIZABLE )
99 BView *mainView = new BView( Bounds(), "mainView",
100 B_FOLLOW_ALL, B_FULL_UPDATE_ON_RESIZE);
102 mainView->SetViewColor(kBlack);
104 /* create the view to do the display */
105 view = new VLCView( Bounds() );
106 mainView->AddChild(view);
108 /* set the VideoWindow variables */
109 teardownwindow = false;
113 /* call ScreenChanged to set vsync correctly */
115 display_mode disp_mode;
118 screen = new BScreen(this);
120 screen-> GetMode(&disp_mode);
122 (disp_mode.timing.pixel_clock * 1000)/((disp_mode.timing.h_total)*
123 (disp_mode.timing.v_total));
130 mode = SelectDrawingMode(v_width, v_height);
132 // remember current settings
133 i_width = frame.IntegerWidth();
134 i_height = frame.IntegerHeight();
135 FrameResized(frame.IntegerWidth(), frame.IntegerHeight());
139 overlay_restrictions r;
141 bitmap[1]->GetOverlayRestrictions(&r);
142 SetSizeLimits((i_width * r.min_width_scale), i_width * r.max_width_scale,
143 (i_height * r.min_height_scale), i_height * r.max_height_scale);
148 VideoWindow::~VideoWindow()
150 teardownwindow = true;
156 void VideoWindow::MessageReceived( BMessage *p_message )
158 switch( p_message->what )
160 case TOGGLE_FULL_SCREEN:
161 ((BWindow *)this)->Zoom();
166 ((BWindow *)this)->Zoom();
168 ResizeTo(i_width, i_height);
173 ((BWindow *)this)->Zoom();
175 ResizeTo(i_width * 2, i_height * 2);
183 if (p_message->FindInt16("WinFeel", &winFeel) == B_OK)
185 SetFeel((window_feel)winFeel);
190 BWindow::MessageReceived( p_message );
195 void VideoWindow::drawBuffer(int bufferIndex)
197 i_buffer = bufferIndex;
199 // sync to the screen if required
203 screen = new BScreen(this);
204 screen-> WaitForRetrace(22000);
209 // switch the overlay bitmap
213 view->SetViewOverlay(bitmap[i_buffer],
214 bitmap[i_buffer]->Bounds() ,
217 B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL|
218 B_OVERLAY_TRANSFER_CHANNEL);
219 view->SetViewColor(key);
224 view-> DrawBitmap(bitmap[i_buffer], view->Bounds() );
230 void VideoWindow::Zoom(BPoint origin, float width, float height )
234 is_zoomed = !is_zoomed;
235 MoveTo(winSize.left, winSize.top);
236 ResizeTo(winSize.IntegerWidth(), winSize.IntegerHeight());
237 be_app->ShowCursor();
241 is_zoomed = !is_zoomed;
243 screen = new BScreen(this);
244 BRect rect = screen->Frame();
247 ResizeTo(rect.IntegerWidth(), rect.IntegerHeight());
248 be_app->ObscureCursor();
252 void VideoWindow::FrameMoved(BPoint origin)
254 if (is_zoomed) return ;
258 void VideoWindow::FrameResized( float width, float height )
260 float out_width, out_height;
261 float out_left, out_top;
262 float width_scale = width / i_width;
263 float height_scale = height / i_height;
265 if (width_scale <= height_scale)
267 out_width = (i_width * width_scale);
268 out_height = (i_height * width_scale);
270 out_top = (height - out_height) / 2;
272 else /* if the height is proportionally smaller */
274 out_width = (i_width * height_scale);
275 out_height = (i_height * height_scale);
277 out_left = (width - out_width) /2;
279 view->MoveTo(out_left,out_top);
280 view->ResizeTo(out_width, out_height);
287 void VideoWindow::ScreenChanged(BRect frame, color_space mode)
292 screen = new BScreen(this);
293 display_mode disp_mode;
295 screen-> GetMode(&disp_mode);
297 (disp_mode.timing.pixel_clock * 1000)/((disp_mode.timing.h_total)*
298 (disp_mode.timing.v_total));
305 void VideoWindow::WindowActivated(bool active)
309 int VideoWindow::SelectDrawingMode(int width, int height)
311 int drawingMode = BITMAP;
314 // int noOverlay = !config_GetIntVariable( "overlay" );
315 for (int i = 0; i < COLOR_COUNT; i++)
317 if (noOverlay) break;
318 bitmap[0] = new BBitmap ( BRect( 0, 0, width, height ),
319 B_BITMAP_WILL_OVERLAY,
320 colspace[i].colspace);
322 if(bitmap[0] && bitmap[0]->InitCheck() == B_OK)
326 bitmap[1] = new BBitmap( BRect( 0, 0, width, height ), B_BITMAP_WILL_OVERLAY,
327 colspace[colspace_index].colspace);
328 bitmap[2] = new BBitmap( BRect( 0, 0, width, height ), B_BITMAP_WILL_OVERLAY,
329 colspace[colspace_index].colspace);
330 if ( (bitmap[2] && bitmap[2]->InitCheck() == B_OK) )
332 drawingMode = OVERLAY;
334 view->SetViewOverlay(bitmap[0],
335 bitmap[0]->Bounds() ,
338 B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL);
339 view->SetViewColor(key);
340 SetTitle(VOUT_TITLE " (Overlay)");
356 if (drawingMode == BITMAP)
359 colspace_index = DEFAULT_COL;
360 SetTitle(VOUT_TITLE " (Bitmap)");
361 bitmap[0] = new BBitmap( BRect( 0, 0, width, height ), colspace[colspace_index].colspace);
362 bitmap[1] = new BBitmap( BRect( 0, 0, width, height ), colspace[colspace_index].colspace);
363 bitmap[2] = new BBitmap( BRect( 0, 0, width, height ), colspace[colspace_index].colspace);
368 /*****************************************************************************
370 *****************************************************************************/
371 VLCView::VLCView(BRect bounds) : BView(bounds, "", B_FOLLOW_NONE,
375 SetViewColor(B_TRANSPARENT_32_BIT);
378 /*****************************************************************************
380 *****************************************************************************/
385 /*****************************************************************************
387 *****************************************************************************/
388 void VLCView::MouseDown(BPoint point)
390 BMessage* msg = Window()->CurrentMessage();
391 int32 clicks = msg->FindInt32("clicks");
393 VideoWindow *vWindow = (VideoWindow *)Window();
396 GetMouse(&where, &mouseButtons, true);
398 if ((mouseButtons & B_PRIMARY_MOUSE_BUTTON) && (clicks == 2))
405 if (mouseButtons & B_SECONDARY_MOUSE_BUTTON)
407 BPopUpMenu *menu = new BPopUpMenu("context menu");
408 menu->SetRadioMode(false);
410 BMenuItem *zoomItem = new BMenuItem("Fullscreen", new BMessage(TOGGLE_FULL_SCREEN));
411 zoomItem->SetMarked(vWindow->is_zoomed);
412 menu->AddItem(zoomItem);
414 BMenuItem *origItem = new BMenuItem("100%", new BMessage(RESIZE_100));
415 menu->AddItem(origItem);
417 BMenuItem *doubleItem = new BMenuItem("200%", new BMessage(RESIZE_200));
418 menu->AddItem(doubleItem);
419 menu->AddSeparatorItem();
421 BMenuItem *vsyncItem = new BMenuItem("Vertical Sync", new BMessage(VERT_SYNC));
422 vsyncItem->SetMarked(vWindow->vsync);
423 menu->AddItem(vsyncItem);
424 menu->AddSeparatorItem();
427 BMessage *winNormFeel = new BMessage(WINDOW_FEEL);
428 winNormFeel->AddInt16("WinFeel", (int16)B_NORMAL_WINDOW_FEEL);
429 BMenuItem *normWindItem = new BMenuItem("Normal Window", winNormFeel);
430 normWindItem->SetMarked(vWindow->Feel() == B_NORMAL_WINDOW_FEEL);
431 menu->AddItem(normWindItem);
433 BMessage *winFloatFeel = new BMessage(WINDOW_FEEL);
434 winFloatFeel->AddInt16("WinFeel", (int16)B_FLOATING_APP_WINDOW_FEEL);
435 BMenuItem *onTopWindItem = new BMenuItem("App Top", winFloatFeel);
436 onTopWindItem->SetMarked(vWindow->Feel() == B_FLOATING_APP_WINDOW_FEEL);
437 menu->AddItem(onTopWindItem);
439 BMessage *winAllFeel = new BMessage(WINDOW_FEEL);
440 winAllFeel->AddInt16("WinFeel", (int16)B_FLOATING_ALL_WINDOW_FEEL);
441 BMenuItem *allSpacesWindItem = new BMenuItem("On Top All Workspaces", winAllFeel);
442 allSpacesWindItem->SetMarked(vWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL);
443 menu->AddItem(allSpacesWindItem);
445 menu->SetTargetForItems(this);
446 ConvertToScreen(&where);
447 menu->Go(where, true, false, true);
452 /*****************************************************************************
454 *****************************************************************************/
455 void VLCView::Draw(BRect updateRect)
457 VideoWindow *win = (VideoWindow *) Window();
458 if (win->mode == BITMAP)
459 FillRect(updateRect);
466 /*****************************************************************************
468 *****************************************************************************/
469 static int vout_Create ( vout_thread_t * );
470 static int vout_Init ( vout_thread_t * );
471 static void vout_End ( vout_thread_t * );
472 static void vout_Destroy ( vout_thread_t * );
473 static int vout_Manage ( vout_thread_t * );
474 static void vout_Display ( vout_thread_t *, picture_t * );
475 static void vout_Render ( vout_thread_t *, picture_t * );
477 static int BeosOpenDisplay ( vout_thread_t *p_vout );
478 static void BeosCloseDisplay( vout_thread_t *p_vout );
480 /*****************************************************************************
481 * Functions exported as capabilities. They are declared as static so that
482 * we don't pollute the namespace too much.
483 *****************************************************************************/
484 void _M( vout_getfunctions )( function_list_t * p_function_list )
486 p_function_list->functions.vout.pf_create = vout_Create;
487 p_function_list->functions.vout.pf_init = vout_Init;
488 p_function_list->functions.vout.pf_end = vout_End;
489 p_function_list->functions.vout.pf_destroy = vout_Destroy;
490 p_function_list->functions.vout.pf_manage = vout_Manage;
491 p_function_list->functions.vout.pf_display = vout_Display;
492 p_function_list->functions.vout.pf_render = vout_Render;
495 /*****************************************************************************
496 * vout_Create: allocates BeOS video thread output method
497 *****************************************************************************
498 * This function allocates and initializes a BeOS vout method.
499 *****************************************************************************/
500 int vout_Create( vout_thread_t *p_vout )
502 /* Allocate structure */
503 p_vout->p_sys = (vout_sys_t*) malloc( sizeof( vout_sys_t ) );
504 if( p_vout->p_sys == NULL )
506 msg_Err( p_vout, "out of memory" );
509 p_vout->p_sys->i_width = p_vout->render.i_width;
510 p_vout->p_sys->i_height = p_vout->render.i_height;
511 p_vout->p_sys->source_chroma = p_vout->render.i_chroma;
516 /*****************************************************************************
517 * vout_Init: initialize BeOS video thread output method
518 *****************************************************************************/
519 int vout_Init( vout_thread_t *p_vout )
524 I_OUTPUTPICTURES = 0;
526 /* Open and initialize device */
527 if( BeosOpenDisplay( p_vout ) )
529 msg_Err(p_vout, "vout error: can't open display");
532 p_vout->output.i_width = p_vout->render.i_width;
533 p_vout->output.i_height = p_vout->render.i_height;
535 /* Assume we have square pixels */
536 p_vout->output.i_aspect = p_vout->p_sys->i_width
537 * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
538 p_vout->output.i_chroma = colspace[p_vout->p_sys->p_window->colspace_index].chroma;
539 p_vout->p_sys->i_index = 0;
541 p_vout->b_direct = 1;
543 p_vout->output.i_rmask = 0x00ff0000;
544 p_vout->output.i_gmask = 0x0000ff00;
545 p_vout->output.i_bmask = 0x000000ff;
547 for (int buffer_index = 0 ; buffer_index < 3; buffer_index++)
550 /* Find an empty picture slot */
551 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
554 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
556 p_pic = p_vout->p_picture + i_index;
565 p_pic->p->p_pixels = (u8*)p_vout->p_sys->p_window->bitmap[buffer_index]->Bits();
566 p_pic->p->i_lines = p_vout->p_sys->i_height;
568 p_pic->p->i_pixel_bytes = colspace[p_vout->p_sys->p_window->colspace_index].pixel_bytes;
569 p_pic->i_planes = colspace[p_vout->p_sys->p_window->colspace_index].planes;
570 p_pic->p->i_pitch = p_vout->p_sys->p_window->bitmap[buffer_index]->BytesPerRow();
572 if (p_vout->p_sys->p_window->mode == OVERLAY)
574 p_pic->p->i_visible_bytes = (p_vout->p_sys->p_window->bitmap[buffer_index]->Bounds().IntegerWidth()+1)
575 * p_pic->p->i_pixel_bytes;
576 p_pic->p->b_margin = 1;
577 p_pic->p->b_hidden = 0;
581 p_pic->p->b_margin = 0;
582 p_pic->p->i_visible_bytes = p_pic->p->i_pitch;
585 p_pic->i_status = DESTROYED_PICTURE;
586 p_pic->i_type = DIRECT_PICTURE;
588 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
596 /*****************************************************************************
597 * vout_End: terminate BeOS video thread output method
598 *****************************************************************************/
599 void vout_End( vout_thread_t *p_vout )
601 BeosCloseDisplay( p_vout );
604 /*****************************************************************************
605 * vout_Destroy: destroy BeOS video thread output method
606 *****************************************************************************
607 * Terminate an output method created by DummyCreateOutputMethod
608 *****************************************************************************/
609 void vout_Destroy( vout_thread_t *p_vout )
611 free( p_vout->p_sys );
614 /*****************************************************************************
615 * vout_Manage: handle BeOS events
616 *****************************************************************************
617 * This function should be called regularly by video output thread. It manages
618 * console events. It returns a non null value on error.
619 *****************************************************************************/
620 int vout_Manage( vout_thread_t *p_vout )
626 /*****************************************************************************
627 * vout_Render: render previously calculated output
628 *****************************************************************************/
629 void vout_Render( vout_thread_t *p_vout, picture_t *p_pic )
634 /*****************************************************************************
635 * vout_Display: displays previously rendered output
636 *****************************************************************************
637 * This function send the currently rendered image to BeOS image, waits until
638 * it is displayed and switch the two rendering buffers, preparing next frame.
639 *****************************************************************************/
640 void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
642 VideoWindow * p_win = p_vout->p_sys->p_window;
644 /* draw buffer if required */
645 if (!p_win->teardownwindow)
647 p_win->drawBuffer(p_vout->p_sys->i_index);
650 p_vout->p_sys->i_index = ++p_vout->p_sys->i_index % 3;
651 p_pic->p->p_pixels = (u8*)p_vout->p_sys->p_window->bitmap[p_vout->p_sys->i_index]->Bits();
654 /* following functions are local */
656 /*****************************************************************************
657 * BeosOpenDisplay: open and initialize BeOS device
658 *****************************************************************************/
659 static int BeosOpenDisplay( vout_thread_t *p_vout )
662 p_vout->p_sys->p_window = new VideoWindow( p_vout->p_sys->i_width - 1,
663 p_vout->p_sys->i_height - 1,
665 20 + p_vout->i_window_width - 1,
666 50 + p_vout->i_window_height - 1 ));
668 if( p_vout->p_sys->p_window == NULL )
670 msg_Err( p_vout, "cannot allocate VideoWindow" );
677 /*****************************************************************************
678 * BeosDisplay: close and reset BeOS device
679 *****************************************************************************
680 * Returns all resources allocated by BeosOpenDisplay and restore the original
681 * state of the device.
682 *****************************************************************************/
683 static void BeosCloseDisplay( vout_thread_t *p_vout )
685 VideoWindow * p_win = p_vout->p_sys->p_window;
686 /* Destroy the video window */
687 if( p_win != NULL && !p_win->teardownwindow)
690 p_win->teardownwindow = true;