1 /*****************************************************************************
2 * vout_beos.cpp: beos video output display method
3 *****************************************************************************
4 * Copyright (C) 2000, 2001 VideoLAN
5 * $Id: VideoOutput.cpp,v 1.28 2003/12/22 11:14:25 titer 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>
11 * Stephan Aßmus <stippi@yellowbites.com>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
31 #include <errno.h> /* ENOMEM */
32 #include <stdlib.h> /* free() */
34 #include <string.h> /* strerror() */
36 #include <Application.h>
37 #include <BitmapStream.h>
39 #include <Directory.h>
40 #include <DirectWindow.h>
42 #include <InterfaceKit.h>
45 #include <TranslatorRoster.h>
46 #include <WindowScreen.h>
54 #include "InterfaceWindow.h" // for load/save_settings()
55 #include "DrawingTidbits.h"
58 #include "VideoWindow.h"
60 /*****************************************************************************
61 * vout_sys_t: BeOS video output method descriptor
62 *****************************************************************************
63 * This structure is part of the video output thread descriptor.
64 * It describes the BeOS specific properties of an output thread.
65 *****************************************************************************/
68 VideoWindow * p_window;
73 // uint8_t *pp_buffer[3];
74 uint32_t source_chroma;
79 #define MOUSE_IDLE_TIMEOUT 2000000 // two seconds
80 #define MIN_AUTO_VSYNC_REFRESH 61 // Hz
81 #define DEFAULT_SCREEN_SHOT_FORMAT 'PNG '
82 #define DEFAULT_SCREEN_SHOT_PATH "/boot/home/vlc screenshot"
84 /*****************************************************************************
85 * beos_GetAppWindow : retrieve a BWindow pointer from the window name
86 *****************************************************************************/
88 beos_GetAppWindow(char *name)
93 for (index = 0 ; ; index++)
95 window = be_app->WindowAt(index);
98 if (window->LockWithTimeout(20000) == B_OK)
100 if (strcmp(window->Name(), name) == 0)
111 static const int beos_keys[][2] =
113 { B_LEFT_ARROW, KEY_LEFT },
114 { B_RIGHT_ARROW, KEY_RIGHT },
115 { B_UP_ARROW, KEY_UP },
116 { B_DOWN_ARROW, KEY_DOWN },
117 { B_SPACE, KEY_SPACE },
118 { B_ENTER, KEY_ENTER },
119 { B_F1_KEY, KEY_F1 },
120 { B_F2_KEY, KEY_F2 },
121 { B_F3_KEY, KEY_F3 },
122 { B_F4_KEY, KEY_F4 },
123 { B_F5_KEY, KEY_F5 },
124 { B_F6_KEY, KEY_F6 },
125 { B_F7_KEY, KEY_F7 },
126 { B_F8_KEY, KEY_F8 },
127 { B_F9_KEY, KEY_F9 },
128 { B_F10_KEY, KEY_F10 },
129 { B_F11_KEY, KEY_F11 },
130 { B_F12_KEY, KEY_F12 },
131 { B_HOME, KEY_HOME },
133 { B_ESCAPE, KEY_ESC },
134 { B_PAGE_UP, KEY_PAGEUP },
135 { B_PAGE_DOWN, KEY_PAGEDOWN },
137 { B_BACKSPACE, KEY_BACKSPACE }
140 static int ConvertKeyFromVLC( int key )
142 for( unsigned i = 0; i < sizeof( beos_keys ) / sizeof( int ) / 2; i++ )
144 if( beos_keys[i][1] == key )
146 return beos_keys[i][0];
152 static int ConvertKeyToVLC( int key )
154 for( unsigned i = 0; i < sizeof( beos_keys ) / sizeof( int ) / 2; i++ )
156 if( beos_keys[i][0] == key )
158 return beos_keys[i][1];
164 /*****************************************************************************
165 * get_interface_window
166 *****************************************************************************/
168 get_interface_window()
170 return beos_GetAppWindow( "VLC " PACKAGE_VERSION );
173 class BackgroundView : public BView
176 BackgroundView(BRect frame, VLCView* view)
177 : BView(frame, "background",
178 B_FOLLOW_ALL, B_FULL_UPDATE_ON_RESIZE),
181 SetViewColor(kBlack);
183 virtual ~BackgroundView() {}
185 virtual void MouseDown(BPoint where)
187 // convert coordinates
188 where = fVideoView->ConvertFromParent(where);
190 fVideoView->MouseDown(where);
192 virtual void MouseMoved(BPoint where, uint32_t transit,
193 const BMessage* dragMessage)
195 // convert coordinates
196 where = fVideoView->ConvertFromParent(where);
198 fVideoView->MouseMoved(where, transit, dragMessage);
199 // notice: It might look like transit should be
200 // B_OUTSIDE_VIEW regardless, but leave it like this,
201 // otherwise, unwanted things will happen!
209 /*****************************************************************************
210 * VideoSettings constructor and destructor
211 *****************************************************************************/
212 VideoSettings::VideoSettings()
213 : fVideoSize( SIZE_100 ),
214 fFlags( FLAG_CORRECT_RATIO ),
215 fSettings( new BMessage( 'sett' ) )
217 // read settings from disk
218 status_t ret = load_settings( fSettings, "video_settings", "VideoLAN Client" );
222 if ( fSettings->FindInt32( "flags", (int32*)&flags ) == B_OK )
225 if ( fSettings->FindInt32( "video size", (int32*)&size ) == B_OK )
226 SetVideoSize( size );
230 // figure out if we should use vertical sync by default
231 BScreen screen(B_MAIN_SCREEN_ID);
232 if (screen.IsValid())
235 screen.GetMode(&mode);
236 float refresh = (mode.timing.pixel_clock * 1000)
237 / ((mode.timing.h_total)* (mode.timing.v_total));
238 if (refresh < MIN_AUTO_VSYNC_REFRESH)
239 AddFlags(FLAG_SYNC_RETRACE);
244 VideoSettings::VideoSettings( const VideoSettings& clone )
245 : fVideoSize( clone.VideoSize() ),
246 fFlags( clone.Flags() ),
252 VideoSettings::~VideoSettings()
256 // we are the default settings
257 // and write our settings to disk
258 if (fSettings->ReplaceInt32( "video size", VideoSize() ) != B_OK)
259 fSettings->AddInt32( "video size", VideoSize() );
260 if (fSettings->ReplaceInt32( "flags", Flags() ) != B_OK)
261 fSettings->AddInt32( "flags", Flags() );
263 save_settings( fSettings, "video_settings", "VideoLAN Client" );
268 // we are just a clone of the default settings
269 fDefaultSettings.SetVideoSize( VideoSize() );
270 fDefaultSettings.SetFlags( Flags() );
274 /*****************************************************************************
275 * VideoSettings::DefaultSettings
276 *****************************************************************************/
278 VideoSettings::DefaultSettings()
280 return &fDefaultSettings;
283 /*****************************************************************************
284 * VideoSettings::SetVideoSize
285 *****************************************************************************/
287 VideoSettings::SetVideoSize( uint32_t mode )
292 // static variable initialization
294 VideoSettings::fDefaultSettings;
297 /*****************************************************************************
298 * VideoWindow constructor and destructor
299 *****************************************************************************/
300 VideoWindow::VideoWindow(int v_width, int v_height, BRect frame,
301 vout_thread_t *p_videoout)
302 : BWindow(frame, NULL, B_TITLED_WINDOW, B_NOT_CLOSABLE | B_NOT_MINIMIZABLE),
303 i_width(frame.IntegerWidth()),
304 i_height(frame.IntegerHeight()),
307 teardownwindow(false),
309 fTrueHeight(v_height),
310 fCachedFeel(B_NORMAL_WINDOW_FEEL),
311 fInterfaceShowing(false),
312 fInitStatus(B_ERROR),
313 fSettings(new VideoSettings(*VideoSettings::DefaultSettings()))
317 // create the view to do the display
318 view = new VLCView( Bounds(), p_vout );
320 // create background view
321 BView *mainView = new BackgroundView( Bounds(), view );
323 mainView->AddChild(view);
325 // allocate bitmap buffers
326 for (int32_t i = 0; i < 3; i++)
328 fInitStatus = _AllocateBuffers(v_width, v_height, &mode);
330 // make sure we layout the view correctly
331 FrameResized(i_width, i_height);
333 if (fInitStatus >= B_OK && mode == OVERLAY)
335 overlay_restrictions r;
337 bitmap[1]->GetOverlayRestrictions(&r);
338 SetSizeLimits((i_width * r.min_width_scale), i_width * r.max_width_scale,
339 (i_height * r.min_height_scale), i_height * r.max_height_scale);
342 // vlc settings override settings from disk
343 if (config_GetInt(p_vout, "fullscreen"))
344 fSettings->AddFlags(VideoSettings::FLAG_FULL_SCREEN);
346 // add a few useful shortcuts
347 // XXX works only with US keymap
348 AddShortcut( '1', 0, new BMessage( RESIZE_50 ) );
349 AddShortcut( '2', 0, new BMessage( RESIZE_100 ) );
350 AddShortcut( '3', 0, new BMessage( RESIZE_200 ) );
352 // workaround to have Alt+X shortcuts working
354 for( unsigned i = 1; /* skip KEY_UNSET */
355 i < sizeof( vlc_keys ) / sizeof( key_descriptor_t ); i++ )
358 message = new BMessage( SHORTCUT );
359 message->AddInt32( "key", vlc_keys[i].i_key_code | KEY_MODIFIER_ALT );
360 AddShortcut( ConvertKeyFromVLC( vlc_keys[i].i_key_code ),
364 message = new BMessage( SHORTCUT );
365 message->AddInt32( "key", vlc_keys[i].i_key_code |
366 KEY_MODIFIER_ALT | KEY_MODIFIER_SHIFT );
367 AddShortcut( ConvertKeyFromVLC( vlc_keys[i].i_key_code ),
368 B_SHIFT_KEY, message );
371 message = new BMessage( SHORTCUT );
372 message->AddInt32( "key", vlc_keys[i].i_key_code |
373 KEY_MODIFIER_ALT | KEY_MODIFIER_CTRL );
374 AddShortcut( ConvertKeyFromVLC( vlc_keys[i].i_key_code ),
375 B_CONTROL_KEY, message );
377 /* Alt+Shift+Ctrl+X */
378 message = new BMessage( SHORTCUT );
379 message->AddInt32( "key", vlc_keys[i].i_key_code |
380 KEY_MODIFIER_ALT | KEY_MODIFIER_SHIFT | KEY_MODIFIER_CTRL );
381 AddShortcut( ConvertKeyFromVLC( vlc_keys[i].i_key_code ),
382 B_SHIFT_KEY | B_CONTROL_KEY, message );
388 VideoWindow::~VideoWindow()
392 teardownwindow = true;
393 wait_for_thread(fDrawThreadID, &result);
398 /*****************************************************************************
399 * VideoWindow::MessageReceived
400 *****************************************************************************/
402 VideoWindow::MessageReceived( BMessage *p_message )
404 switch( p_message->what )
407 SetInterfaceShowing( true );
409 case TOGGLE_FULL_SCREEN:
417 _SetVideoSize(p_message->what);
420 SetSyncToRetrace(!IsSyncedToRetrace());
425 if (p_message->FindInt32("WinFeel", (int32*)&winFeel) == B_OK)
428 fCachedFeel = winFeel;
429 if (winFeel == B_FLOATING_ALL_WINDOW_FEEL)
430 fSettings->AddFlags(VideoSettings::FLAG_ON_TOP_ALL);
432 fSettings->ClearFlags(VideoSettings::FLAG_ON_TOP_ALL);
437 SetCorrectAspectRatio(!CorrectAspectRatio());
440 // save a screen shot
441 if ( BBitmap* current = bitmap[i_buffer] )
443 // the following line might be tempting, but does not work for some overlay bitmaps!!!
444 // BBitmap* temp = new BBitmap( current );
445 // so we clone the bitmap ourselves
446 // however, we need to take care of potentially different padding!
447 // memcpy() is slow when reading from grafix memory, but what the heck...
448 BBitmap* temp = new BBitmap( current->Bounds(), current->ColorSpace() );
449 if ( temp && temp->IsValid() )
451 int32_t height = (int32_t)current->Bounds().Height();
452 uint8_t* dst = (uint8_t*)temp->Bits();
453 uint8_t* src = (uint8_t*)current->Bits();
454 int32_t dstBpr = temp->BytesPerRow();
455 int32_t srcBpr = current->BytesPerRow();
456 int32_t validBytes = dstBpr > srcBpr ? srcBpr : dstBpr;
457 for ( int32_t y = 0; y < height; y++ )
459 memcpy( dst, src, validBytes );
463 char * path = config_GetPsz( p_vout, "beos-screenshotpath" );
465 path = strdup( DEFAULT_SCREEN_SHOT_PATH );
467 /* FIXME - we should check which translators are
468 actually available */
469 char * psz_format = config_GetPsz( p_vout, "beos-screenshotformat" );
470 int32_t format = DEFAULT_SCREEN_SHOT_FORMAT;
471 if( !strcmp( psz_format, "TGA" ) )
473 else if( !strcmp( psz_format, "PPM" ) )
475 else if( !strcmp( psz_format, "JPEG" ) )
477 else if( !strcmp( psz_format, "BMP" ) )
480 _SaveScreenShot( temp, path, format );
491 p_message->FindInt32( "key", (int32*) &val.i_int );
492 var_Set( p_vout->p_vlc, "key-pressed", val );
496 BWindow::MessageReceived( p_message );
501 /*****************************************************************************
503 *****************************************************************************/
505 VideoWindow::Zoom(BPoint origin, float width, float height )
510 /*****************************************************************************
511 * VideoWindow::FrameMoved
512 *****************************************************************************/
514 VideoWindow::FrameMoved(BPoint origin)
521 /*****************************************************************************
522 * VideoWindow::FrameResized
523 *****************************************************************************/
525 VideoWindow::FrameResized( float width, float height )
527 int32_t useWidth = CorrectAspectRatio() ? i_width : fTrueWidth;
528 int32_t useHeight = CorrectAspectRatio() ? i_height : fTrueHeight;
529 float out_width, out_height;
530 float out_left, out_top;
531 float width_scale = width / useWidth;
532 float height_scale = height / useHeight;
534 if (width_scale <= height_scale)
536 out_width = (useWidth * width_scale);
537 out_height = (useHeight * width_scale);
539 out_top = (height - out_height) / 2;
541 else /* if the height is proportionally smaller */
543 out_width = (useWidth * height_scale);
544 out_height = (useHeight * height_scale);
546 out_left = (width - out_width) / 2;
548 view->MoveTo(out_left,out_top);
549 view->ResizeTo(out_width, out_height);
555 /*****************************************************************************
556 * VideoWindow::ScreenChanged
557 *****************************************************************************/
559 VideoWindow::ScreenChanged(BRect frame, color_space format)
561 BScreen screen(this);
563 screen.GetMode(&mode);
564 float refresh = (mode.timing.pixel_clock * 1000)
565 / ((mode.timing.h_total) * (mode.timing.v_total));
566 SetSyncToRetrace(refresh < MIN_AUTO_VSYNC_REFRESH);
569 /*****************************************************************************
570 * VideoWindow::Activate
571 *****************************************************************************/
573 VideoWindow::WindowActivated(bool active)
577 /*****************************************************************************
578 * VideoWindow::drawBuffer
579 *****************************************************************************/
581 VideoWindow::drawBuffer(int bufferIndex)
583 i_buffer = bufferIndex;
585 // sync to the screen if required
586 if (IsSyncedToRetrace())
588 BScreen screen(this);
589 screen.WaitForRetrace(22000);
591 if (fInitStatus >= B_OK && LockLooper())
593 // switch the overlay bitmap
597 view->SetViewOverlay(bitmap[i_buffer],
598 bitmap[i_buffer]->Bounds() ,
601 B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL|
602 B_OVERLAY_TRANSFER_CHANNEL);
603 view->SetViewColor(key);
608 view->DrawBitmap(bitmap[i_buffer], view->Bounds() );
614 /*****************************************************************************
615 * VideoWindow::SetInterfaceShowing
616 *****************************************************************************/
618 VideoWindow::ToggleInterfaceShowing()
620 SetInterfaceShowing(!fInterfaceShowing);
623 /*****************************************************************************
624 * VideoWindow::SetInterfaceShowing
625 *****************************************************************************/
627 VideoWindow::SetInterfaceShowing(bool showIt)
629 BWindow* window = get_interface_window();
634 if (fCachedFeel != B_NORMAL_WINDOW_FEEL)
635 SetFeel(B_NORMAL_WINDOW_FEEL);
636 window->Activate(true);
641 SetFeel(fCachedFeel);
643 window->SendBehind(this);
645 fInterfaceShowing = showIt;
649 /*****************************************************************************
650 * VideoWindow::SetCorrectAspectRatio
651 *****************************************************************************/
653 VideoWindow::SetCorrectAspectRatio(bool doIt)
655 if (CorrectAspectRatio() != doIt)
658 fSettings->AddFlags(VideoSettings::FLAG_CORRECT_RATIO);
660 fSettings->ClearFlags(VideoSettings::FLAG_CORRECT_RATIO);
661 FrameResized(Bounds().Width(), Bounds().Height());
665 /*****************************************************************************
666 * VideoWindow::CorrectAspectRatio
667 *****************************************************************************/
669 VideoWindow::CorrectAspectRatio() const
671 return fSettings->HasFlags(VideoSettings::FLAG_CORRECT_RATIO);
674 /*****************************************************************************
675 * VideoWindow::ToggleFullScreen
676 *****************************************************************************/
678 VideoWindow::ToggleFullScreen()
680 SetFullScreen(!IsFullScreen());
683 /*****************************************************************************
684 * VideoWindow::SetFullScreen
685 *****************************************************************************/
687 VideoWindow::SetFullScreen(bool doIt)
691 SetLook( B_NO_BORDER_WINDOW_LOOK );
692 BScreen screen( this );
693 BRect rect = screen.Frame();
696 ResizeTo(rect.IntegerWidth(), rect.IntegerHeight());
697 be_app->ObscureCursor();
698 fInterfaceShowing = false;
699 fSettings->AddFlags(VideoSettings::FLAG_FULL_SCREEN);
703 SetLook( B_TITLED_WINDOW_LOOK );
704 MoveTo(winSize.left, winSize.top);
705 ResizeTo(winSize.IntegerWidth(), winSize.IntegerHeight());
706 be_app->ShowCursor();
707 fInterfaceShowing = true;
708 fSettings->ClearFlags(VideoSettings::FLAG_FULL_SCREEN);
712 /*****************************************************************************
713 * VideoWindow::IsFullScreen
714 *****************************************************************************/
716 VideoWindow::IsFullScreen() const
718 return fSettings->HasFlags(VideoSettings::FLAG_FULL_SCREEN);
721 /*****************************************************************************
722 * VideoWindow::SetSyncToRetrace
723 *****************************************************************************/
725 VideoWindow::SetSyncToRetrace(bool doIt)
728 fSettings->AddFlags(VideoSettings::FLAG_SYNC_RETRACE);
730 fSettings->ClearFlags(VideoSettings::FLAG_SYNC_RETRACE);
733 /*****************************************************************************
734 * VideoWindow::IsSyncedToRetrace
735 *****************************************************************************/
737 VideoWindow::IsSyncedToRetrace() const
739 return fSettings->HasFlags(VideoSettings::FLAG_SYNC_RETRACE);
743 /*****************************************************************************
744 * VideoWindow::_AllocateBuffers
745 *****************************************************************************/
747 VideoWindow::_AllocateBuffers(int width, int height, int* mode)
749 // clear any old buffers
754 BRect bitmapFrame( 0, 0, width, height );
755 // read from config, if we are supposed to use overlay at all
756 int noOverlay = !config_GetInt( p_vout, "overlay" );
757 // test for overlay capability
758 for (int i = 0; i < COLOR_COUNT; i++)
760 if (noOverlay) break;
761 bitmap[0] = new BBitmap ( bitmapFrame,
762 B_BITMAP_WILL_OVERLAY |
763 B_BITMAP_RESERVE_OVERLAY_CHANNEL,
764 colspace[i].colspace);
766 if(bitmap[0] && bitmap[0]->InitCheck() == B_OK)
770 bitmap[1] = new BBitmap( bitmapFrame, B_BITMAP_WILL_OVERLAY,
771 colspace[colspace_index].colspace);
772 bitmap[2] = new BBitmap( bitmapFrame, B_BITMAP_WILL_OVERLAY,
773 colspace[colspace_index].colspace);
774 if ( (bitmap[2] && bitmap[2]->InitCheck() == B_OK) )
778 view->SetViewOverlay(bitmap[0],
779 bitmap[0]->Bounds() ,
782 B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL);
783 view->SetViewColor(key);
784 SetTitle("VLC " PACKAGE_VERSION " (Overlay)");
790 *mode = BITMAP; // might want to try again with normal bitmaps
800 colspace_index = DEFAULT_COL; // B_RGB32
801 SetTitle( "VLC " PACKAGE_VERSION " (Bitmap)" );
802 bitmap[0] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
803 bitmap[1] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
804 bitmap[2] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
806 // see if everything went well
807 status_t status = B_ERROR;
808 for (int32_t i = 0; i < 3; i++)
811 status = bitmap[i]->InitCheck();
817 // clear bitmaps to black
818 for (int32_t i = 0; i < 3; i++)
819 _BlankBitmap(bitmap[i]);
824 /*****************************************************************************
825 * VideoWindow::_FreeBuffers
826 *****************************************************************************/
828 VideoWindow::_FreeBuffers()
836 fInitStatus = B_ERROR;
839 /*****************************************************************************
840 * VideoWindow::_BlankBitmap
841 *****************************************************************************/
843 VideoWindow::_BlankBitmap(BBitmap* bitmap) const
845 // no error checking (we do that earlier on and since it's a private function...
848 // Loss/Saturation points are Y 16-235 (absoulte); Cb/Cr 16-240 (center 128)
851 // Extrema points are Y 0 - 207 (absolute) U -91 - 91 (offset 128) V -127 - 127 (offset 128)
853 // we only handle weird colorspaces with special care
854 switch (bitmap->ColorSpace()) {
856 // Y0[7:0] Cb0[7:0] Y1[7:0] Cr0[7:0] Y2[7:0] Cb2[7:0] Y3[7:0] Cr2[7:0]
857 int32_t height = bitmap->Bounds().IntegerHeight() + 1;
858 uint8_t* bits = (uint8_t*)bitmap->Bits();
859 int32_t bpr = bitmap->BytesPerRow();
860 for (int32_t y = 0; y < height; y++) {
861 // handle 2 bytes at a time
862 for (int32_t i = 0; i < bpr; i += 2) {
874 // Non-interlaced only, Cb0 Y0 Y1 Cb2 Y2 Y3 on even scan lines ...
875 // Cr0 Y0 Y1 Cr2 Y2 Y3 on odd scan lines
876 int32_t height = bitmap->Bounds().IntegerHeight() + 1;
877 uint8_t* bits = (uint8_t*)bitmap->Bits();
878 int32_t bpr = bitmap->BytesPerRow();
879 for (int32_t y = 0; y < height; y += 1) {
880 // handle 3 bytes at a time
881 for (int32_t i = 0; i < bpr; i += 3) {
894 // U0[7:0] Y0[7:0] V0[7:0] Y1[7:0] U2[7:0] Y2[7:0] V2[7:0] Y3[7:0]
895 int32_t height = bitmap->Bounds().IntegerHeight() + 1;
896 uint8_t* bits = (uint8_t*)bitmap->Bits();
897 int32_t bpr = bitmap->BytesPerRow();
898 for (int32_t y = 0; y < height; y += 1) {
899 // handle 2 bytes at a time
900 for (int32_t i = 0; i < bpr; i += 2) {
911 memset(bitmap->Bits(), 0, bitmap->BitsLength());
916 /*****************************************************************************
917 * VideoWindow::_SetVideoSize
918 *****************************************************************************/
920 VideoWindow::_SetVideoSize(uint32_t mode)
922 // let size depend on aspect correction
923 int32_t width = CorrectAspectRatio() ? i_width : fTrueWidth;
924 int32_t height = CorrectAspectRatio() ? i_height : fTrueHeight;
939 fSettings->ClearFlags(VideoSettings::FLAG_FULL_SCREEN);
940 ResizeTo(width, height);
943 /*****************************************************************************
944 * VideoWindow::_SetToSettings
945 *****************************************************************************/
947 VideoWindow::_SetToSettings()
950 uint32_t mode = RESIZE_100;
951 switch (fSettings->VideoSize())
953 case VideoSettings::SIZE_50:
956 case VideoSettings::SIZE_200:
959 case VideoSettings::SIZE_100:
960 case VideoSettings::SIZE_OTHER:
964 bool fullscreen = IsFullScreen(); // remember settings
965 _SetVideoSize(mode); // because this will reset settings
966 // the fullscreen status is reflected in the settings,
967 // but not yet in the windows state
970 if (fSettings->HasFlags(VideoSettings::FLAG_ON_TOP_ALL))
971 fCachedFeel = B_FLOATING_ALL_WINDOW_FEEL;
973 fCachedFeel = B_NORMAL_WINDOW_FEEL;
974 SetFeel(fCachedFeel);
977 /*****************************************************************************
978 * VideoWindow::_SaveScreenShot
979 *****************************************************************************/
981 VideoWindow::_SaveScreenShot( BBitmap* bitmap, char* path,
982 uint32_t translatorID ) const
984 // make the info object from the parameters
985 screen_shot_info* info = new screen_shot_info;
986 info->bitmap = bitmap;
988 info->translatorID = translatorID;
989 info->width = CorrectAspectRatio() ? i_width : fTrueWidth;
990 info->height = CorrectAspectRatio() ? i_height : fTrueHeight;
991 // spawn a new thread to take care of the actual saving to disk
992 thread_id thread = spawn_thread( _save_screen_shot,
994 B_LOW_PRIORITY, (void*)info );
995 // start thread or do the job ourself if something went wrong
996 if ( thread < B_OK || resume_thread( thread ) < B_OK )
997 _save_screen_shot( (void*)info );
1000 /*****************************************************************************
1001 * VideoWindow::_save_screen_shot
1002 *****************************************************************************/
1004 VideoWindow::_save_screen_shot( void* cookie )
1006 screen_shot_info* info = (screen_shot_info*)cookie;
1007 if ( info && info->bitmap && info->bitmap->IsValid() && info->path )
1009 // try to be as quick as possible creating the file (the user might have
1010 // taken the next screen shot already!)
1011 // make sure we have a unique name for the screen shot
1012 BString path( info->path );
1013 // create the folder if it doesn't exist
1014 BString folder( info->path );
1015 create_directory( folder.String(), 0777 );
1016 path << "/vlc screenshot";
1017 BEntry entry( path.String() );
1018 int32_t appendedNumber = 0;
1019 if ( entry.Exists() && !entry.IsSymLink() )
1021 // we would clobber an existing entry
1022 bool foundUniqueName = false;
1024 while ( !foundUniqueName ) {
1025 BString newName( path.String() );
1026 newName << " " << appendedNumber;
1027 BEntry possiblyClobberedEntry( newName.String() );
1028 if ( possiblyClobberedEntry.Exists()
1029 && !possiblyClobberedEntry.IsSymLink() )
1032 foundUniqueName = true;
1035 if ( appendedNumber > 0 )
1036 path << " " << appendedNumber;
1037 // there is still a slight chance to clobber an existing
1038 // file (if it was created in the "meantime"), but we take it...
1039 BFile outFile( path.String(),
1040 B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE );
1042 // make colorspace converted copy of bitmap
1043 BBitmap* converted = new BBitmap( BRect( 0.0, 0.0, info->width, info->height ),
1045 status_t status = convert_bitmap( info->bitmap, converted );
1046 if ( status == B_OK )
1048 BTranslatorRoster* roster = BTranslatorRoster::Default();
1049 uint32_t imageFormat = 0;
1050 translator_id translator = 0;
1053 // find suitable translator
1054 translator_id* ids = NULL;
1057 status = roster->GetAllTranslators( &ids, &count );
1058 if ( status >= B_OK )
1060 for ( int tix = 0; tix < count; tix++ )
1062 const translation_format *formats = NULL;
1063 int32 num_formats = 0;
1065 status = roster->GetInputFormats( ids[tix],
1066 &formats, &num_formats );
1069 for ( int iix = 0; iix < num_formats; iix++ )
1071 if ( formats[iix].type == B_TRANSLATOR_BITMAP )
1080 status = roster->GetOutputFormats( ids[tix],
1081 &formats, &num_formats);
1082 if ( status >= B_OK )
1084 for ( int32_t oix = 0; oix < num_formats; oix++ )
1086 if ( formats[oix].type != B_TRANSLATOR_BITMAP )
1088 if ( formats[oix].type == info->translatorID )
1091 imageFormat = formats[oix].type;
1092 translator = ids[tix];
1103 // make bitmap stream
1104 BBitmapStream outStream( converted );
1106 status = outFile.InitCheck();
1107 if (status == B_OK) {
1108 status = roster->Translate( &outStream, NULL, NULL,
1109 &outFile, imageFormat );
1110 if ( status == B_OK )
1112 BNodeInfo nodeInfo( &outFile );
1113 if ( nodeInfo.InitCheck() == B_OK )
1115 translation_format* formats;
1117 status = roster->GetOutputFormats( translator,
1118 (const translation_format **) &formats,
1120 if ( status >= B_OK )
1122 const char * mime = NULL;
1123 for ( int ix = 0; ix < count; ix++ ) {
1124 if ( formats[ix].type == imageFormat ) {
1125 mime = formats[ix].MIME;
1130 nodeInfo.SetType( mime );
1135 outStream.DetachBitmap( &converted );
1143 delete info->bitmap;
1151 /*****************************************************************************
1153 *****************************************************************************/
1154 VLCView::VLCView(BRect bounds, vout_thread_t *p_vout_instance )
1155 : BView(bounds, "video view", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED),
1156 fLastMouseMovedTime(system_time()),
1157 fCursorHidden(false),
1158 fCursorInside(false),
1159 fIgnoreDoubleClick(false)
1161 p_vout = p_vout_instance;
1162 SetViewColor(B_TRANSPARENT_32_BIT);
1165 /*****************************************************************************
1167 *****************************************************************************/
1172 /*****************************************************************************
1173 * VLCVIew::AttachedToWindow
1174 *****************************************************************************/
1176 VLCView::AttachedToWindow()
1178 // in order to get keyboard events
1180 // periodically check if we want to hide the pointer
1181 Window()->SetPulseRate(1000000);
1184 /*****************************************************************************
1185 * VLCVIew::MouseDown
1186 *****************************************************************************/
1188 VLCView::MouseDown(BPoint where)
1190 VideoWindow* videoWindow = dynamic_cast<VideoWindow*>(Window());
1191 BMessage* msg = Window()->CurrentMessage();
1194 msg->FindInt32("clicks", &clicks);
1195 msg->FindInt32("buttons", (int32*)&buttons);
1199 if (buttons & B_PRIMARY_MOUSE_BUTTON)
1201 if (clicks == 2 && !fIgnoreDoubleClick)
1204 videoWindow->ToggleInterfaceShowing(); */
1205 fIgnoreDoubleClick = false;
1209 if (buttons & B_SECONDARY_MOUSE_BUTTON)
1211 // clicks will be 2 next time (if interval short enough)
1212 // even if the first click and the second
1213 // have not been made with the same mouse button
1214 fIgnoreDoubleClick = true;
1215 // launch popup menu
1216 BPopUpMenu *menu = new BPopUpMenu("context menu");
1217 menu->SetRadioMode(false);
1218 // In full screen, add an item to show/hide the interface
1219 if( videoWindow->IsFullScreen() )
1221 BMenuItem *intfItem =
1222 new BMenuItem( _("Show Interface"), new BMessage(SHOW_INTERFACE) );
1223 menu->AddItem( intfItem );
1226 BMenuItem *halfItem = new BMenuItem(_("50%"), new BMessage(RESIZE_50));
1227 menu->AddItem(halfItem);
1229 BMenuItem *origItem = new BMenuItem(_("100%"), new BMessage(RESIZE_100));
1230 menu->AddItem(origItem);
1232 BMenuItem *doubleItem = new BMenuItem(_("200%"), new BMessage(RESIZE_200));
1233 menu->AddItem(doubleItem);
1234 // Toggle FullScreen
1235 BMenuItem *zoomItem = new BMenuItem(_("Fullscreen"), new BMessage(TOGGLE_FULL_SCREEN));
1236 zoomItem->SetMarked(videoWindow->IsFullScreen());
1237 menu->AddItem(zoomItem);
1239 menu->AddSeparatorItem();
1242 BMenuItem *vsyncItem = new BMenuItem(_("Vertical Sync"), new BMessage(VERT_SYNC));
1243 vsyncItem->SetMarked(videoWindow->IsSyncedToRetrace());
1244 menu->AddItem(vsyncItem);
1245 // Correct Aspect Ratio
1246 BMenuItem *aspectItem = new BMenuItem(_("Correct Aspect Ratio"), new BMessage(ASPECT_CORRECT));
1247 aspectItem->SetMarked(videoWindow->CorrectAspectRatio());
1248 menu->AddItem(aspectItem);
1250 menu->AddSeparatorItem();
1252 // Windwo Feel Items
1253 /* BMessage *winNormFeel = new BMessage(WINDOW_FEEL);
1254 winNormFeel->AddInt32("WinFeel", (int32_t)B_NORMAL_WINDOW_FEEL);
1255 BMenuItem *normWindItem = new BMenuItem("Normal Window", winNormFeel);
1256 normWindItem->SetMarked(videoWindow->Feel() == B_NORMAL_WINDOW_FEEL);
1257 menu->AddItem(normWindItem);
1259 BMessage *winFloatFeel = new BMessage(WINDOW_FEEL);
1260 winFloatFeel->AddInt32("WinFeel", (int32_t)B_FLOATING_APP_WINDOW_FEEL);
1261 BMenuItem *onTopWindItem = new BMenuItem("App Top", winFloatFeel);
1262 onTopWindItem->SetMarked(videoWindow->Feel() == B_FLOATING_APP_WINDOW_FEEL);
1263 menu->AddItem(onTopWindItem);
1265 BMessage *winAllFeel = new BMessage(WINDOW_FEEL);
1266 winAllFeel->AddInt32("WinFeel", (int32_t)B_FLOATING_ALL_WINDOW_FEEL);
1267 BMenuItem *allSpacesWindItem = new BMenuItem("On Top All Workspaces", winAllFeel);
1268 allSpacesWindItem->SetMarked(videoWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL);
1269 menu->AddItem(allSpacesWindItem);*/
1271 BMessage *windowFeelMsg = new BMessage( WINDOW_FEEL );
1272 bool onTop = videoWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL;
1273 window_feel feel = onTop ? B_NORMAL_WINDOW_FEEL : B_FLOATING_ALL_WINDOW_FEEL;
1274 windowFeelMsg->AddInt32( "WinFeel", (int32_t)feel );
1275 BMenuItem *windowFeelItem = new BMenuItem( _("Stay On Top"), windowFeelMsg );
1276 windowFeelItem->SetMarked( onTop );
1277 menu->AddItem( windowFeelItem );
1279 menu->AddSeparatorItem();
1281 BMenuItem* screenShotItem = new BMenuItem( _("Take Screen Shot"),
1282 new BMessage( SCREEN_SHOT ) );
1283 menu->AddItem( screenShotItem );
1285 menu->SetTargetForItems( this );
1286 ConvertToScreen( &where );
1287 BRect mouseRect( where.x - 5, where.y - 5,
1288 where.x + 5, where.y + 5 );
1289 menu->Go( where, true, false, mouseRect, true );
1293 fLastMouseMovedTime = system_time();
1294 fCursorHidden = false;
1297 /*****************************************************************************
1299 *****************************************************************************/
1301 VLCView::MouseUp( BPoint where )
1304 val.b_bool = VLC_TRUE;
1305 var_Set( p_vout, "mouse-clicked", val );
1308 /*****************************************************************************
1309 * VLCVIew::MouseMoved
1310 *****************************************************************************/
1312 VLCView::MouseMoved(BPoint point, uint32 transit, const BMessage* dragMessage)
1314 fLastMouseMovedTime = system_time();
1315 fCursorHidden = false;
1316 fCursorInside = (transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW);
1317 /* DVD navigation */
1318 unsigned int i_width, i_height, i_x, i_y;
1319 vout_PlacePicture( p_vout, (unsigned int)Bounds().Width(),
1320 (unsigned int)Bounds().Height(),
1321 &i_x, &i_y, &i_width, &i_height );
1323 val.i_int = ( (int)point.x - i_x ) * p_vout->render.i_width / i_width;
1324 var_Set( p_vout, "mouse-x", val );
1325 val.i_int = ( (int)point.y - i_y ) * p_vout->render.i_height / i_height;
1326 var_Set( p_vout, "mouse-y", val );
1327 val.b_bool = VLC_TRUE;
1328 var_Set( p_vout, "mouse-moved", val );
1331 /*****************************************************************************
1333 *****************************************************************************/
1337 // We are getting the pulse messages no matter if the mouse is over
1338 // this view. If we are in full screen mode, we want to hide the cursor
1339 // even if it is not.
1340 VideoWindow *videoWindow = dynamic_cast<VideoWindow*>(Window());
1344 && system_time() - fLastMouseMovedTime > MOUSE_IDLE_TIMEOUT)
1346 be_app->ObscureCursor();
1347 fCursorHidden = true;
1349 // hide the interface window as well if full screen
1350 if (videoWindow && videoWindow->IsFullScreen())
1351 videoWindow->SetInterfaceShowing(false);
1355 // Workaround to disable the screensaver in full screen:
1356 // we simulate an activity every 29 seconds
1357 if( videoWindow && videoWindow->IsFullScreen() &&
1358 system_time() - fLastMouseMovedTime > 29000000 )
1362 GetMouse(&where, &buttons, false);
1363 ConvertToScreen(&where);
1364 set_mouse_position((int32_t) where.x, (int32_t) where.y);
1368 /*****************************************************************************
1370 *****************************************************************************/
1371 void VLCView::KeyDown( const char *bytes, int32 numBytes )
1378 uint32_t mods = modifiers();
1381 val.i_int = ConvertKeyToVLC( *bytes );
1382 if( mods & B_SHIFT_KEY )
1384 val.i_int |= KEY_MODIFIER_SHIFT;
1386 if( mods & B_CONTROL_KEY )
1388 val.i_int |= KEY_MODIFIER_CTRL;
1390 var_Set( p_vout->p_vlc, "key-pressed", val );
1393 /*****************************************************************************
1395 *****************************************************************************/
1397 VLCView::Draw(BRect updateRect)
1399 VideoWindow* window = dynamic_cast<VideoWindow*>( Window() );
1400 if ( window && window->mode == BITMAP )
1401 FillRect( updateRect );
1404 /*****************************************************************************
1406 *****************************************************************************/
1407 static int Init ( vout_thread_t * );
1408 static void End ( vout_thread_t * );
1409 static int Manage ( vout_thread_t * );
1410 static void Display ( vout_thread_t *, picture_t * );
1412 static int BeosOpenDisplay ( vout_thread_t *p_vout );
1413 static void BeosCloseDisplay( vout_thread_t *p_vout );
1415 /*****************************************************************************
1416 * OpenVideo: allocates BeOS video thread output method
1417 *****************************************************************************
1418 * This function allocates and initializes a BeOS vout method.
1419 *****************************************************************************/
1420 int E_(OpenVideo) ( vlc_object_t *p_this )
1422 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1424 /* Allocate structure */
1425 p_vout->p_sys = (vout_sys_t*) malloc( sizeof( vout_sys_t ) );
1426 if( p_vout->p_sys == NULL )
1428 msg_Err( p_vout, "out of memory" );
1431 p_vout->p_sys->i_width = p_vout->render.i_width;
1432 p_vout->p_sys->i_height = p_vout->render.i_height;
1433 p_vout->p_sys->source_chroma = p_vout->render.i_chroma;
1435 p_vout->pf_init = Init;
1436 p_vout->pf_end = End;
1437 p_vout->pf_manage = Manage;
1438 p_vout->pf_render = NULL;
1439 p_vout->pf_display = Display;
1444 /*****************************************************************************
1445 * Init: initialize BeOS video thread output method
1446 *****************************************************************************/
1447 int Init( vout_thread_t *p_vout )
1452 I_OUTPUTPICTURES = 0;
1454 /* Open and initialize device */
1455 if( BeosOpenDisplay( p_vout ) )
1457 msg_Err(p_vout, "vout error: can't open display");
1460 p_vout->output.i_width = p_vout->render.i_width;
1461 p_vout->output.i_height = p_vout->render.i_height;
1463 /* Assume we have square pixels */
1464 p_vout->output.i_aspect = p_vout->p_sys->i_width
1465 * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
1466 p_vout->output.i_chroma = colspace[p_vout->p_sys->p_window->colspace_index].chroma;
1467 p_vout->p_sys->i_index = 0;
1469 p_vout->b_direct = 1;
1471 p_vout->output.i_rmask = 0x00ff0000;
1472 p_vout->output.i_gmask = 0x0000ff00;
1473 p_vout->output.i_bmask = 0x000000ff;
1475 for (int buffer_index = 0 ; buffer_index < 3; buffer_index++)
1478 /* Find an empty picture slot */
1479 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
1482 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
1484 p_pic = p_vout->p_picture + i_index;
1493 p_pic->p->p_pixels = (uint8_t*)p_vout->p_sys->p_window->bitmap[buffer_index]->Bits();
1494 p_pic->p->i_lines = p_vout->p_sys->i_height;
1496 p_pic->p->i_pixel_pitch = colspace[p_vout->p_sys->p_window->colspace_index].pixel_bytes;
1497 p_pic->i_planes = colspace[p_vout->p_sys->p_window->colspace_index].planes;
1498 p_pic->p->i_pitch = p_vout->p_sys->p_window->bitmap[buffer_index]->BytesPerRow();
1499 p_pic->p->i_visible_pitch = p_pic->p->i_pixel_pitch * ( p_vout->p_sys->p_window->bitmap[buffer_index]->Bounds().IntegerWidth() + 1 );
1501 p_pic->i_status = DESTROYED_PICTURE;
1502 p_pic->i_type = DIRECT_PICTURE;
1504 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
1512 /*****************************************************************************
1513 * End: terminate BeOS video thread output method
1514 *****************************************************************************/
1515 void End( vout_thread_t *p_vout )
1517 BeosCloseDisplay( p_vout );
1520 /*****************************************************************************
1522 *****************************************************************************/
1523 static int Manage( vout_thread_t * p_vout )
1525 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
1527 p_vout->p_sys->p_window->PostMessage( TOGGLE_FULL_SCREEN );
1528 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
1534 /*****************************************************************************
1535 * CloseVideo: destroy BeOS video thread output method
1536 *****************************************************************************
1537 * Terminate an output method created by DummyCreateOutputMethod
1538 *****************************************************************************/
1539 void E_(CloseVideo) ( vlc_object_t *p_this )
1541 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1543 free( p_vout->p_sys );
1546 /*****************************************************************************
1547 * Display: displays previously rendered output
1548 *****************************************************************************
1549 * This function send the currently rendered image to BeOS image, waits until
1550 * it is displayed and switch the two rendering buffers, preparing next frame.
1551 *****************************************************************************/
1552 void Display( vout_thread_t *p_vout, picture_t *p_pic )
1554 VideoWindow * p_win = p_vout->p_sys->p_window;
1556 /* draw buffer if required */
1557 if (!p_win->teardownwindow)
1559 p_win->drawBuffer(p_vout->p_sys->i_index);
1562 p_vout->p_sys->i_index = ++p_vout->p_sys->i_index % 3;
1563 p_pic->p->p_pixels = (uint8_t*)p_vout->p_sys->p_window->bitmap[p_vout->p_sys->i_index]->Bits();
1566 /* following functions are local */
1568 /*****************************************************************************
1569 * BeosOpenDisplay: open and initialize BeOS device
1570 *****************************************************************************/
1571 static int BeosOpenDisplay( vout_thread_t *p_vout )
1574 p_vout->p_sys->p_window = new VideoWindow( p_vout->p_sys->i_width - 1,
1575 p_vout->p_sys->i_height - 1,
1577 20 + p_vout->i_window_width - 1,
1578 50 + p_vout->i_window_height - 1 ),
1580 if( p_vout->p_sys->p_window == NULL )
1582 msg_Err( p_vout, "cannot allocate VideoWindow" );
1587 p_vout->p_sys->p_window->Show();
1593 /*****************************************************************************
1594 * BeosDisplay: close and reset BeOS device
1595 *****************************************************************************
1596 * Returns all resources allocated by BeosOpenDisplay and restore the original
1597 * state of the device.
1598 *****************************************************************************/
1599 static void BeosCloseDisplay( vout_thread_t *p_vout )
1601 VideoWindow * p_win = p_vout->p_sys->p_window;
1602 /* Destroy the video window */
1603 if( p_win != NULL && !p_win->teardownwindow)
1606 p_win->teardownwindow = true;