1 /*****************************************************************************
2 * vout.cpp: beos video output display method
3 *****************************************************************************
4 * Copyright (C) 2000, 2001 VideoLAN
5 * $Id: VideoOutput.cpp,v 1.1 2002/08/04 17:23:43 sam 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;
114 /* call ScreenChanged to set vsync correctly */
116 display_mode disp_mode;
119 screen = new BScreen(this);
121 screen-> GetMode(&disp_mode);
123 (disp_mode.timing.pixel_clock * 1000)/((disp_mode.timing.h_total)*
124 (disp_mode.timing.v_total));
131 mode = SelectDrawingMode(v_width, v_height);
133 // remember current settings
136 FrameResized(v_width, v_height);
140 overlay_restrictions r;
142 bitmap[1]->GetOverlayRestrictions(&r);
143 SetSizeLimits((i_width * r.min_width_scale) + 1, i_width * r.max_width_scale,
144 (i_height * r.min_height_scale) + 1, i_height * r.max_height_scale);
149 VideoWindow::~VideoWindow()
151 teardownwindow = true;
157 void VideoWindow::MessageReceived( BMessage *p_message )
159 switch( p_message->what )
161 case TOGGLE_FULL_SCREEN:
162 ((BWindow *)this)->Zoom();
167 ((BWindow *)this)->Zoom();
169 ResizeTo(i_width, i_height);
174 ((BWindow *)this)->Zoom();
176 ResizeTo(i_width * 2, i_height * 2);
184 if (p_message->FindInt16("WinFeel", &winFeel) == B_OK)
186 SetFeel((window_feel)winFeel);
191 BWindow::MessageReceived( p_message );
196 void VideoWindow::drawBuffer(int bufferIndex)
198 i_buffer = bufferIndex;
200 // sync to the screen if required
204 screen = new BScreen(this);
205 screen-> WaitForRetrace(22000);
210 // switch the overlay bitmap
214 view->SetViewOverlay(bitmap[i_buffer],
215 bitmap[i_buffer]->Bounds() ,
218 B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL|
219 B_OVERLAY_TRANSFER_CHANNEL);
220 view->SetViewColor(key);
225 view-> DrawBitmap(bitmap[i_buffer], view->Bounds() );
231 void VideoWindow::Zoom(BPoint origin, float width, float height )
235 is_zoomed = !is_zoomed;
236 MoveTo(winSize.left, winSize.top);
237 ResizeTo(winSize.IntegerWidth(), winSize.IntegerHeight());
238 be_app->ShowCursor();
242 is_zoomed = !is_zoomed;
244 screen = new BScreen(this);
245 BRect rect = screen->Frame();
248 ResizeTo(rect.IntegerWidth(), rect.IntegerHeight());
249 be_app->ObscureCursor();
253 void VideoWindow::FrameMoved(BPoint origin)
255 if (is_zoomed) return ;
259 void VideoWindow::FrameResized( float width, float height )
261 float out_width, out_height;
262 float out_left, out_top;
263 float width_scale = width / i_width;
264 float height_scale = height / i_height;
266 if (width_scale <= height_scale)
268 out_width = (i_width * width_scale);
269 out_height = (i_height * width_scale);
271 out_top = (height - out_height) / 2;
273 else /* if the height is proportionally smaller */
275 out_width = (i_width * height_scale);
276 out_height = (i_height * height_scale);
278 out_left = (width - out_width) /2;
280 view->MoveTo(out_left,out_top);
281 view->ResizeTo(out_width, out_height);
288 void VideoWindow::ScreenChanged(BRect frame, color_space mode)
293 screen = new BScreen(this);
294 display_mode disp_mode;
296 screen-> GetMode(&disp_mode);
298 (disp_mode.timing.pixel_clock * 1000)/((disp_mode.timing.h_total)*
299 (disp_mode.timing.v_total));
306 void VideoWindow::WindowActivated(bool active)
310 int VideoWindow::SelectDrawingMode(int width, int height)
312 int drawingMode = BITMAP;
315 // int noOverlay = !config_GetIntVariable( "overlay" );
316 for (int i = 0; i < COLOR_COUNT; i++)
318 if (noOverlay) break;
319 bitmap[0] = new BBitmap ( BRect( 0, 0, width, height ),
320 B_BITMAP_WILL_OVERLAY,
321 colspace[i].colspace);
323 if(bitmap[0] && bitmap[0]->InitCheck() == B_OK)
327 bitmap[1] = new BBitmap( BRect( 0, 0, width, height ), B_BITMAP_WILL_OVERLAY,
328 colspace[colspace_index].colspace);
329 bitmap[2] = new BBitmap( BRect( 0, 0, width, height ), B_BITMAP_WILL_OVERLAY,
330 colspace[colspace_index].colspace);
331 if ( (bitmap[2] && bitmap[2]->InitCheck() == B_OK) )
333 drawingMode = OVERLAY;
335 view->SetViewOverlay(bitmap[0],
336 bitmap[0]->Bounds() ,
339 B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL);
340 view->SetViewColor(key);
341 SetTitle(VOUT_TITLE " (Overlay)");
357 if (drawingMode == BITMAP)
360 colspace_index = DEFAULT_COL;
361 SetTitle(VOUT_TITLE " (Bitmap)");
362 bitmap[0] = new BBitmap( BRect( 0, 0, width, height ), colspace[colspace_index].colspace);
363 bitmap[1] = new BBitmap( BRect( 0, 0, width, height ), colspace[colspace_index].colspace);
364 bitmap[2] = new BBitmap( BRect( 0, 0, width, height ), colspace[colspace_index].colspace);
369 /*****************************************************************************
371 *****************************************************************************/
372 VLCView::VLCView(BRect bounds) : BView(bounds, "", B_FOLLOW_NONE,
376 SetViewColor(B_TRANSPARENT_32_BIT);
379 /*****************************************************************************
381 *****************************************************************************/
386 /*****************************************************************************
388 *****************************************************************************/
389 void VLCView::MouseDown(BPoint point)
391 BMessage* msg = Window()->CurrentMessage();
392 int32 clicks = msg->FindInt32("clicks");
394 VideoWindow *vWindow = (VideoWindow *)Window();
397 GetMouse(&where, &mouseButtons, true);
399 if ((mouseButtons & B_PRIMARY_MOUSE_BUTTON) && (clicks == 2))
406 if (mouseButtons & B_SECONDARY_MOUSE_BUTTON)
408 BPopUpMenu *menu = new BPopUpMenu("context menu");
409 menu->SetRadioMode(false);
411 BMenuItem *zoomItem = new BMenuItem("Fullscreen", new BMessage(TOGGLE_FULL_SCREEN));
412 zoomItem->SetMarked(vWindow->is_zoomed);
413 menu->AddItem(zoomItem);
415 BMenuItem *origItem = new BMenuItem("100%", new BMessage(RESIZE_100));
416 menu->AddItem(origItem);
418 BMenuItem *doubleItem = new BMenuItem("200%", new BMessage(RESIZE_200));
419 menu->AddItem(doubleItem);
420 menu->AddSeparatorItem();
422 BMenuItem *vsyncItem = new BMenuItem("Vertical Sync", new BMessage(VERT_SYNC));
423 vsyncItem->SetMarked(vWindow->vsync);
424 menu->AddItem(vsyncItem);
425 menu->AddSeparatorItem();
428 BMessage *winNormFeel = new BMessage(WINDOW_FEEL);
429 winNormFeel->AddInt16("WinFeel", (int16)B_NORMAL_WINDOW_FEEL);
430 BMenuItem *normWindItem = new BMenuItem("Normal Window", winNormFeel);
431 normWindItem->SetMarked(vWindow->Feel() == B_NORMAL_WINDOW_FEEL);
432 menu->AddItem(normWindItem);
434 BMessage *winFloatFeel = new BMessage(WINDOW_FEEL);
435 winFloatFeel->AddInt16("WinFeel", (int16)B_MODAL_ALL_WINDOW_FEEL);
436 BMenuItem *onTopWindItem = new BMenuItem("App Top", winFloatFeel);
437 onTopWindItem->SetMarked(vWindow->Feel() == B_MODAL_ALL_WINDOW_FEEL);
438 menu->AddItem(onTopWindItem);
440 BMessage *winAllFeel = new BMessage(WINDOW_FEEL);
441 winAllFeel->AddInt16("WinFeel", (int16)B_FLOATING_ALL_WINDOW_FEEL);
442 BMenuItem *allSpacesWindItem = new BMenuItem("On Top All Workspaces", winAllFeel);
443 allSpacesWindItem->SetMarked(vWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL);
444 menu->AddItem(allSpacesWindItem);
446 menu->SetTargetForItems(this);
447 ConvertToScreen(&where);
448 menu->Go(where, true, false, true);
453 /*****************************************************************************
455 *****************************************************************************/
456 void VLCView::Draw(BRect updateRect)
458 VideoWindow *win = (VideoWindow *) Window();
459 if (win->mode == BITMAP)
460 FillRect(updateRect);
463 /*****************************************************************************
465 *****************************************************************************/
466 static int Init ( vout_thread_t * );
467 static void End ( vout_thread_t * );
468 static int Manage ( vout_thread_t * );
469 static void Display ( vout_thread_t *, picture_t * );
471 static int BeosOpenDisplay ( vout_thread_t *p_vout );
472 static void BeosCloseDisplay( vout_thread_t *p_vout );
474 /*****************************************************************************
475 * OpenVideo: allocates BeOS video thread output method
476 *****************************************************************************
477 * This function allocates and initializes a BeOS vout method.
478 *****************************************************************************/
479 int E_(OpenVideo) ( vlc_object_t *p_this )
481 vout_thread_t * p_vout = (vout_thread_t *)p_this;
483 /* Allocate structure */
484 p_vout->p_sys = (vout_sys_t*) malloc( sizeof( vout_sys_t ) );
485 if( p_vout->p_sys == NULL )
487 msg_Err( p_vout, "out of memory" );
490 p_vout->p_sys->i_width = p_vout->render.i_width;
491 p_vout->p_sys->i_height = p_vout->render.i_height;
492 p_vout->p_sys->source_chroma = p_vout->render.i_chroma;
494 p_vout->pf_init = Init;
495 p_vout->pf_end = End;
496 p_vout->pf_manage = NULL;
497 p_vout->pf_render = NULL;
498 p_vout->pf_display = Display;
503 /*****************************************************************************
504 * Init: initialize BeOS video thread output method
505 *****************************************************************************/
506 int Init( vout_thread_t *p_vout )
511 I_OUTPUTPICTURES = 0;
513 /* Open and initialize device */
514 if( BeosOpenDisplay( p_vout ) )
516 msg_Err(p_vout, "vout error: can't open display");
519 p_vout->output.i_width = p_vout->render.i_width;
520 p_vout->output.i_height = p_vout->render.i_height;
522 /* Assume we have square pixels */
523 p_vout->output.i_aspect = p_vout->p_sys->i_width
524 * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
525 p_vout->output.i_chroma = colspace[p_vout->p_sys->p_window->colspace_index].chroma;
526 p_vout->p_sys->i_index = 0;
528 p_vout->b_direct = 1;
530 p_vout->output.i_rmask = 0x00ff0000;
531 p_vout->output.i_gmask = 0x0000ff00;
532 p_vout->output.i_bmask = 0x000000ff;
534 for (int buffer_index = 0 ; buffer_index < 3; buffer_index++)
537 /* Find an empty picture slot */
538 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
541 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
543 p_pic = p_vout->p_picture + i_index;
552 p_pic->p->p_pixels = (u8*)p_vout->p_sys->p_window->bitmap[buffer_index]->Bits();
553 p_pic->p->i_lines = p_vout->p_sys->i_height;
555 p_pic->p->i_pixel_pitch = colspace[p_vout->p_sys->p_window->colspace_index].pixel_bytes;
556 p_pic->i_planes = colspace[p_vout->p_sys->p_window->colspace_index].planes;
557 p_pic->p->i_pitch = p_vout->p_sys->p_window->bitmap[buffer_index]->BytesPerRow();
558 p_pic->p->i_visible_pitch = p_pic->p->i_pixel_pitch * ( p_vout->p_sys->p_window->bitmap[buffer_index]->Bounds().IntegerWidth() + 1 );
560 p_pic->i_status = DESTROYED_PICTURE;
561 p_pic->i_type = DIRECT_PICTURE;
563 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
571 /*****************************************************************************
572 * End: terminate BeOS video thread output method
573 *****************************************************************************/
574 void End( vout_thread_t *p_vout )
576 BeosCloseDisplay( p_vout );
579 /*****************************************************************************
580 * CloseVideo: destroy BeOS video thread output method
581 *****************************************************************************
582 * Terminate an output method created by DummyCreateOutputMethod
583 *****************************************************************************/
584 void E_(CloseVideo) ( vlc_object_t *p_this )
586 vout_thread_t * p_vout = (vout_thread_t *)p_this;
588 free( p_vout->p_sys );
591 /*****************************************************************************
592 * Display: displays previously rendered output
593 *****************************************************************************
594 * This function send the currently rendered image to BeOS image, waits until
595 * it is displayed and switch the two rendering buffers, preparing next frame.
596 *****************************************************************************/
597 void Display( vout_thread_t *p_vout, picture_t *p_pic )
599 VideoWindow * p_win = p_vout->p_sys->p_window;
601 /* draw buffer if required */
602 if (!p_win->teardownwindow)
604 p_win->drawBuffer(p_vout->p_sys->i_index);
607 p_vout->p_sys->i_index = ++p_vout->p_sys->i_index % 3;
608 p_pic->p->p_pixels = (u8*)p_vout->p_sys->p_window->bitmap[p_vout->p_sys->i_index]->Bits();
611 /* following functions are local */
613 /*****************************************************************************
614 * BeosOpenDisplay: open and initialize BeOS device
615 *****************************************************************************/
616 static int BeosOpenDisplay( vout_thread_t *p_vout )
619 p_vout->p_sys->p_window = new VideoWindow( p_vout->p_sys->i_width - 1,
620 p_vout->p_sys->i_height - 1,
622 20 + p_vout->i_window_width - 1,
623 50 + p_vout->i_window_height - 1 ));
625 if( p_vout->p_sys->p_window == NULL )
627 msg_Err( p_vout, "cannot allocate VideoWindow" );
634 /*****************************************************************************
635 * BeosDisplay: close and reset BeOS device
636 *****************************************************************************
637 * Returns all resources allocated by BeosOpenDisplay and restore the original
638 * state of the device.
639 *****************************************************************************/
640 static void BeosCloseDisplay( vout_thread_t *p_vout )
642 VideoWindow * p_win = p_vout->p_sys->p_window;
643 /* Destroy the video window */
644 if( p_win != NULL && !p_win->teardownwindow)
647 p_win->teardownwindow = true;