1 /*****************************************************************************
2 * vout_beos.cpp: beos video output display method
3 *****************************************************************************
4 * Copyright (C) 2000, 2001 VideoLAN
5 * $Id: VideoOutput.cpp,v 1.26 2003/11/09 16:00:54 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 int ConvertKey( int key )
140 return KEY_BACKSPACE;
145 /*****************************************************************************
146 * get_interface_window
147 *****************************************************************************/
149 get_interface_window()
151 return beos_GetAppWindow( "VLC " PACKAGE_VERSION );
154 class BackgroundView : public BView
157 BackgroundView(BRect frame, VLCView* view)
158 : BView(frame, "background",
159 B_FOLLOW_ALL, B_FULL_UPDATE_ON_RESIZE),
162 SetViewColor(kBlack);
164 virtual ~BackgroundView() {}
166 virtual void MouseDown(BPoint where)
168 // convert coordinates
169 where = fVideoView->ConvertFromParent(where);
171 fVideoView->MouseDown(where);
173 virtual void MouseMoved(BPoint where, uint32_t transit,
174 const BMessage* dragMessage)
176 // convert coordinates
177 where = fVideoView->ConvertFromParent(where);
179 fVideoView->MouseMoved(where, transit, dragMessage);
180 // notice: It might look like transit should be
181 // B_OUTSIDE_VIEW regardless, but leave it like this,
182 // otherwise, unwanted things will happen!
190 /*****************************************************************************
191 * VideoSettings constructor and destructor
192 *****************************************************************************/
193 VideoSettings::VideoSettings()
194 : fVideoSize( SIZE_100 ),
195 fFlags( FLAG_CORRECT_RATIO ),
196 fSettings( new BMessage( 'sett' ) )
198 // read settings from disk
199 status_t ret = load_settings( fSettings, "video_settings", "VideoLAN Client" );
203 if ( fSettings->FindInt32( "flags", (int32*)&flags ) == B_OK )
206 if ( fSettings->FindInt32( "video size", (int32*)&size ) == B_OK )
207 SetVideoSize( size );
211 // figure out if we should use vertical sync by default
212 BScreen screen(B_MAIN_SCREEN_ID);
213 if (screen.IsValid())
216 screen.GetMode(&mode);
217 float refresh = (mode.timing.pixel_clock * 1000)
218 / ((mode.timing.h_total)* (mode.timing.v_total));
219 if (refresh < MIN_AUTO_VSYNC_REFRESH)
220 AddFlags(FLAG_SYNC_RETRACE);
225 VideoSettings::VideoSettings( const VideoSettings& clone )
226 : fVideoSize( clone.VideoSize() ),
227 fFlags( clone.Flags() ),
233 VideoSettings::~VideoSettings()
237 // we are the default settings
238 // and write our settings to disk
239 if (fSettings->ReplaceInt32( "video size", VideoSize() ) != B_OK)
240 fSettings->AddInt32( "video size", VideoSize() );
241 if (fSettings->ReplaceInt32( "flags", Flags() ) != B_OK)
242 fSettings->AddInt32( "flags", Flags() );
244 save_settings( fSettings, "video_settings", "VideoLAN Client" );
249 // we are just a clone of the default settings
250 fDefaultSettings.SetVideoSize( VideoSize() );
251 fDefaultSettings.SetFlags( Flags() );
255 /*****************************************************************************
256 * VideoSettings::DefaultSettings
257 *****************************************************************************/
259 VideoSettings::DefaultSettings()
261 return &fDefaultSettings;
264 /*****************************************************************************
265 * VideoSettings::SetVideoSize
266 *****************************************************************************/
268 VideoSettings::SetVideoSize( uint32_t mode )
273 // static variable initialization
275 VideoSettings::fDefaultSettings;
278 /*****************************************************************************
279 * VideoWindow constructor and destructor
280 *****************************************************************************/
281 VideoWindow::VideoWindow(int v_width, int v_height, BRect frame,
282 vout_thread_t *p_videoout)
283 : BWindow(frame, NULL, B_TITLED_WINDOW, B_NOT_CLOSABLE | B_NOT_MINIMIZABLE),
284 i_width(frame.IntegerWidth()),
285 i_height(frame.IntegerHeight()),
288 teardownwindow(false),
290 fTrueHeight(v_height),
291 fCachedFeel(B_NORMAL_WINDOW_FEEL),
292 fInterfaceShowing(false),
293 fInitStatus(B_ERROR),
294 fSettings(new VideoSettings(*VideoSettings::DefaultSettings()))
298 // create the view to do the display
299 view = new VLCView( Bounds(), p_vout );
301 // create background view
302 BView *mainView = new BackgroundView( Bounds(), view );
304 mainView->AddChild(view);
306 // allocate bitmap buffers
307 for (int32_t i = 0; i < 3; i++)
309 fInitStatus = _AllocateBuffers(v_width, v_height, &mode);
311 // make sure we layout the view correctly
312 FrameResized(i_width, i_height);
314 if (fInitStatus >= B_OK && mode == OVERLAY)
316 overlay_restrictions r;
318 bitmap[1]->GetOverlayRestrictions(&r);
319 SetSizeLimits((i_width * r.min_width_scale), i_width * r.max_width_scale,
320 (i_height * r.min_height_scale), i_height * r.max_height_scale);
323 // vlc settings override settings from disk
324 if (config_GetInt(p_vout, "fullscreen"))
325 fSettings->AddFlags(VideoSettings::FLAG_FULL_SCREEN);
327 // add a few useful shortcuts
328 AddShortcut( 'f', 0, new BMessage( TOGGLE_FULL_SCREEN ) );
329 AddShortcut( '1', 0, new BMessage( RESIZE_50 ) );
330 AddShortcut( '2', 0, new BMessage( RESIZE_100 ) );
331 AddShortcut( '3', 0, new BMessage( RESIZE_200 ) );
333 // workaround for french keyboards
334 AddShortcut( '&', 0, new BMessage( RESIZE_50 ) );
335 AddShortcut( 'é', 0, new BMessage( RESIZE_100 ) );
336 // FIXME - this one doesn't work because 'é' is a multi-byte character
337 AddShortcut( '"', 0, new BMessage( RESIZE_200 ) );
342 VideoWindow::~VideoWindow()
346 teardownwindow = true;
347 wait_for_thread(fDrawThreadID, &result);
352 /*****************************************************************************
353 * VideoWindow::MessageReceived
354 *****************************************************************************/
356 VideoWindow::MessageReceived( BMessage *p_message )
358 switch( p_message->what )
361 SetInterfaceShowing( true );
363 case TOGGLE_FULL_SCREEN:
371 _SetVideoSize(p_message->what);
374 SetSyncToRetrace(!IsSyncedToRetrace());
379 if (p_message->FindInt32("WinFeel", (int32*)&winFeel) == B_OK)
382 fCachedFeel = winFeel;
383 if (winFeel == B_FLOATING_ALL_WINDOW_FEEL)
384 fSettings->AddFlags(VideoSettings::FLAG_ON_TOP_ALL);
386 fSettings->ClearFlags(VideoSettings::FLAG_ON_TOP_ALL);
391 SetCorrectAspectRatio(!CorrectAspectRatio());
394 // save a screen shot
395 if ( BBitmap* current = bitmap[i_buffer] )
397 // the following line might be tempting, but does not work for some overlay bitmaps!!!
398 // BBitmap* temp = new BBitmap( current );
399 // so we clone the bitmap ourselves
400 // however, we need to take care of potentially different padding!
401 // memcpy() is slow when reading from grafix memory, but what the heck...
402 BBitmap* temp = new BBitmap( current->Bounds(), current->ColorSpace() );
403 if ( temp && temp->IsValid() )
405 int32_t height = (int32_t)current->Bounds().Height();
406 uint8_t* dst = (uint8_t*)temp->Bits();
407 uint8_t* src = (uint8_t*)current->Bits();
408 int32_t dstBpr = temp->BytesPerRow();
409 int32_t srcBpr = current->BytesPerRow();
410 int32_t validBytes = dstBpr > srcBpr ? srcBpr : dstBpr;
411 for ( int32_t y = 0; y < height; y++ )
413 memcpy( dst, src, validBytes );
417 char * path = config_GetPsz( p_vout, "beos-screenshotpath" );
419 path = strdup( DEFAULT_SCREEN_SHOT_PATH );
421 /* FIXME - we should check which translators are
422 actually available */
423 char * psz_format = config_GetPsz( p_vout, "beos-screenshotformat" );
424 int32_t format = DEFAULT_SCREEN_SHOT_FORMAT;
425 if( !strcmp( psz_format, "TGA" ) )
427 else if( !strcmp( psz_format, "PPM" ) )
429 else if( !strcmp( psz_format, "JPEG" ) )
431 else if( !strcmp( psz_format, "BMP" ) )
434 _SaveScreenShot( temp, path, format );
443 BWindow::MessageReceived( p_message );
448 /*****************************************************************************
450 *****************************************************************************/
452 VideoWindow::Zoom(BPoint origin, float width, float height )
457 /*****************************************************************************
458 * VideoWindow::FrameMoved
459 *****************************************************************************/
461 VideoWindow::FrameMoved(BPoint origin)
468 /*****************************************************************************
469 * VideoWindow::FrameResized
470 *****************************************************************************/
472 VideoWindow::FrameResized( float width, float height )
474 int32_t useWidth = CorrectAspectRatio() ? i_width : fTrueWidth;
475 int32_t useHeight = CorrectAspectRatio() ? i_height : fTrueHeight;
476 float out_width, out_height;
477 float out_left, out_top;
478 float width_scale = width / useWidth;
479 float height_scale = height / useHeight;
481 if (width_scale <= height_scale)
483 out_width = (useWidth * width_scale);
484 out_height = (useHeight * width_scale);
486 out_top = (height - out_height) / 2;
488 else /* if the height is proportionally smaller */
490 out_width = (useWidth * height_scale);
491 out_height = (useHeight * height_scale);
493 out_left = (width - out_width) / 2;
495 view->MoveTo(out_left,out_top);
496 view->ResizeTo(out_width, out_height);
502 /*****************************************************************************
503 * VideoWindow::ScreenChanged
504 *****************************************************************************/
506 VideoWindow::ScreenChanged(BRect frame, color_space format)
508 BScreen screen(this);
510 screen.GetMode(&mode);
511 float refresh = (mode.timing.pixel_clock * 1000)
512 / ((mode.timing.h_total) * (mode.timing.v_total));
513 SetSyncToRetrace(refresh < MIN_AUTO_VSYNC_REFRESH);
516 /*****************************************************************************
517 * VideoWindow::Activate
518 *****************************************************************************/
520 VideoWindow::WindowActivated(bool active)
524 /*****************************************************************************
525 * VideoWindow::drawBuffer
526 *****************************************************************************/
528 VideoWindow::drawBuffer(int bufferIndex)
530 i_buffer = bufferIndex;
532 // sync to the screen if required
533 if (IsSyncedToRetrace())
535 BScreen screen(this);
536 screen.WaitForRetrace(22000);
538 if (fInitStatus >= B_OK && LockLooper())
540 // switch the overlay bitmap
544 view->SetViewOverlay(bitmap[i_buffer],
545 bitmap[i_buffer]->Bounds() ,
548 B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL|
549 B_OVERLAY_TRANSFER_CHANNEL);
550 view->SetViewColor(key);
555 view->DrawBitmap(bitmap[i_buffer], view->Bounds() );
561 /*****************************************************************************
562 * VideoWindow::SetInterfaceShowing
563 *****************************************************************************/
565 VideoWindow::ToggleInterfaceShowing()
567 SetInterfaceShowing(!fInterfaceShowing);
570 /*****************************************************************************
571 * VideoWindow::SetInterfaceShowing
572 *****************************************************************************/
574 VideoWindow::SetInterfaceShowing(bool showIt)
576 BWindow* window = get_interface_window();
581 if (fCachedFeel != B_NORMAL_WINDOW_FEEL)
582 SetFeel(B_NORMAL_WINDOW_FEEL);
583 window->Activate(true);
588 SetFeel(fCachedFeel);
590 window->SendBehind(this);
592 fInterfaceShowing = showIt;
596 /*****************************************************************************
597 * VideoWindow::SetCorrectAspectRatio
598 *****************************************************************************/
600 VideoWindow::SetCorrectAspectRatio(bool doIt)
602 if (CorrectAspectRatio() != doIt)
605 fSettings->AddFlags(VideoSettings::FLAG_CORRECT_RATIO);
607 fSettings->ClearFlags(VideoSettings::FLAG_CORRECT_RATIO);
608 FrameResized(Bounds().Width(), Bounds().Height());
612 /*****************************************************************************
613 * VideoWindow::CorrectAspectRatio
614 *****************************************************************************/
616 VideoWindow::CorrectAspectRatio() const
618 return fSettings->HasFlags(VideoSettings::FLAG_CORRECT_RATIO);
621 /*****************************************************************************
622 * VideoWindow::ToggleFullScreen
623 *****************************************************************************/
625 VideoWindow::ToggleFullScreen()
627 SetFullScreen(!IsFullScreen());
630 /*****************************************************************************
631 * VideoWindow::SetFullScreen
632 *****************************************************************************/
634 VideoWindow::SetFullScreen(bool doIt)
638 SetLook( B_NO_BORDER_WINDOW_LOOK );
639 BScreen screen( this );
640 BRect rect = screen.Frame();
643 ResizeTo(rect.IntegerWidth(), rect.IntegerHeight());
644 be_app->ObscureCursor();
645 fInterfaceShowing = false;
646 fSettings->AddFlags(VideoSettings::FLAG_FULL_SCREEN);
650 SetLook( B_TITLED_WINDOW_LOOK );
651 MoveTo(winSize.left, winSize.top);
652 ResizeTo(winSize.IntegerWidth(), winSize.IntegerHeight());
653 be_app->ShowCursor();
654 fInterfaceShowing = true;
655 fSettings->ClearFlags(VideoSettings::FLAG_FULL_SCREEN);
659 /*****************************************************************************
660 * VideoWindow::IsFullScreen
661 *****************************************************************************/
663 VideoWindow::IsFullScreen() const
665 return fSettings->HasFlags(VideoSettings::FLAG_FULL_SCREEN);
668 /*****************************************************************************
669 * VideoWindow::SetSyncToRetrace
670 *****************************************************************************/
672 VideoWindow::SetSyncToRetrace(bool doIt)
675 fSettings->AddFlags(VideoSettings::FLAG_SYNC_RETRACE);
677 fSettings->ClearFlags(VideoSettings::FLAG_SYNC_RETRACE);
680 /*****************************************************************************
681 * VideoWindow::IsSyncedToRetrace
682 *****************************************************************************/
684 VideoWindow::IsSyncedToRetrace() const
686 return fSettings->HasFlags(VideoSettings::FLAG_SYNC_RETRACE);
690 /*****************************************************************************
691 * VideoWindow::_AllocateBuffers
692 *****************************************************************************/
694 VideoWindow::_AllocateBuffers(int width, int height, int* mode)
696 // clear any old buffers
701 BRect bitmapFrame( 0, 0, width, height );
702 // read from config, if we are supposed to use overlay at all
703 int noOverlay = !config_GetInt( p_vout, "overlay" );
704 // test for overlay capability
705 for (int i = 0; i < COLOR_COUNT; i++)
707 if (noOverlay) break;
708 bitmap[0] = new BBitmap ( bitmapFrame,
709 B_BITMAP_WILL_OVERLAY |
710 B_BITMAP_RESERVE_OVERLAY_CHANNEL,
711 colspace[i].colspace);
713 if(bitmap[0] && bitmap[0]->InitCheck() == B_OK)
717 bitmap[1] = new BBitmap( bitmapFrame, B_BITMAP_WILL_OVERLAY,
718 colspace[colspace_index].colspace);
719 bitmap[2] = new BBitmap( bitmapFrame, B_BITMAP_WILL_OVERLAY,
720 colspace[colspace_index].colspace);
721 if ( (bitmap[2] && bitmap[2]->InitCheck() == B_OK) )
725 view->SetViewOverlay(bitmap[0],
726 bitmap[0]->Bounds() ,
729 B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL);
730 view->SetViewColor(key);
731 SetTitle("VLC " PACKAGE_VERSION " (Overlay)");
737 *mode = BITMAP; // might want to try again with normal bitmaps
747 colspace_index = DEFAULT_COL; // B_RGB32
748 SetTitle( "VLC " PACKAGE_VERSION " (Bitmap)" );
749 bitmap[0] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
750 bitmap[1] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
751 bitmap[2] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
753 // see if everything went well
754 status_t status = B_ERROR;
755 for (int32_t i = 0; i < 3; i++)
758 status = bitmap[i]->InitCheck();
764 // clear bitmaps to black
765 for (int32_t i = 0; i < 3; i++)
766 _BlankBitmap(bitmap[i]);
771 /*****************************************************************************
772 * VideoWindow::_FreeBuffers
773 *****************************************************************************/
775 VideoWindow::_FreeBuffers()
783 fInitStatus = B_ERROR;
786 /*****************************************************************************
787 * VideoWindow::_BlankBitmap
788 *****************************************************************************/
790 VideoWindow::_BlankBitmap(BBitmap* bitmap) const
792 // no error checking (we do that earlier on and since it's a private function...
795 // Loss/Saturation points are Y 16-235 (absoulte); Cb/Cr 16-240 (center 128)
798 // Extrema points are Y 0 - 207 (absolute) U -91 - 91 (offset 128) V -127 - 127 (offset 128)
800 // we only handle weird colorspaces with special care
801 switch (bitmap->ColorSpace()) {
803 // Y0[7:0] Cb0[7:0] Y1[7:0] Cr0[7:0] Y2[7:0] Cb2[7:0] Y3[7:0] Cr2[7:0]
804 int32_t height = bitmap->Bounds().IntegerHeight() + 1;
805 uint8_t* bits = (uint8_t*)bitmap->Bits();
806 int32_t bpr = bitmap->BytesPerRow();
807 for (int32_t y = 0; y < height; y++) {
808 // handle 2 bytes at a time
809 for (int32_t i = 0; i < bpr; i += 2) {
821 // Non-interlaced only, Cb0 Y0 Y1 Cb2 Y2 Y3 on even scan lines ...
822 // Cr0 Y0 Y1 Cr2 Y2 Y3 on odd scan lines
823 int32_t height = bitmap->Bounds().IntegerHeight() + 1;
824 uint8_t* bits = (uint8_t*)bitmap->Bits();
825 int32_t bpr = bitmap->BytesPerRow();
826 for (int32_t y = 0; y < height; y += 1) {
827 // handle 3 bytes at a time
828 for (int32_t i = 0; i < bpr; i += 3) {
841 // U0[7:0] Y0[7:0] V0[7:0] Y1[7:0] U2[7:0] Y2[7:0] V2[7:0] Y3[7:0]
842 int32_t height = bitmap->Bounds().IntegerHeight() + 1;
843 uint8_t* bits = (uint8_t*)bitmap->Bits();
844 int32_t bpr = bitmap->BytesPerRow();
845 for (int32_t y = 0; y < height; y += 1) {
846 // handle 2 bytes at a time
847 for (int32_t i = 0; i < bpr; i += 2) {
858 memset(bitmap->Bits(), 0, bitmap->BitsLength());
863 /*****************************************************************************
864 * VideoWindow::_SetVideoSize
865 *****************************************************************************/
867 VideoWindow::_SetVideoSize(uint32_t mode)
869 // let size depend on aspect correction
870 int32_t width = CorrectAspectRatio() ? i_width : fTrueWidth;
871 int32_t height = CorrectAspectRatio() ? i_height : fTrueHeight;
886 fSettings->ClearFlags(VideoSettings::FLAG_FULL_SCREEN);
887 ResizeTo(width, height);
890 /*****************************************************************************
891 * VideoWindow::_SetToSettings
892 *****************************************************************************/
894 VideoWindow::_SetToSettings()
897 uint32_t mode = RESIZE_100;
898 switch (fSettings->VideoSize())
900 case VideoSettings::SIZE_50:
903 case VideoSettings::SIZE_200:
906 case VideoSettings::SIZE_100:
907 case VideoSettings::SIZE_OTHER:
911 bool fullscreen = IsFullScreen(); // remember settings
912 _SetVideoSize(mode); // because this will reset settings
913 // the fullscreen status is reflected in the settings,
914 // but not yet in the windows state
917 if (fSettings->HasFlags(VideoSettings::FLAG_ON_TOP_ALL))
918 fCachedFeel = B_FLOATING_ALL_WINDOW_FEEL;
920 fCachedFeel = B_NORMAL_WINDOW_FEEL;
921 SetFeel(fCachedFeel);
924 /*****************************************************************************
925 * VideoWindow::_SaveScreenShot
926 *****************************************************************************/
928 VideoWindow::_SaveScreenShot( BBitmap* bitmap, char* path,
929 uint32_t translatorID ) const
931 // make the info object from the parameters
932 screen_shot_info* info = new screen_shot_info;
933 info->bitmap = bitmap;
935 info->translatorID = translatorID;
936 info->width = CorrectAspectRatio() ? i_width : fTrueWidth;
937 info->height = CorrectAspectRatio() ? i_height : fTrueHeight;
938 // spawn a new thread to take care of the actual saving to disk
939 thread_id thread = spawn_thread( _save_screen_shot,
941 B_LOW_PRIORITY, (void*)info );
942 // start thread or do the job ourself if something went wrong
943 if ( thread < B_OK || resume_thread( thread ) < B_OK )
944 _save_screen_shot( (void*)info );
947 /*****************************************************************************
948 * VideoWindow::_save_screen_shot
949 *****************************************************************************/
951 VideoWindow::_save_screen_shot( void* cookie )
953 screen_shot_info* info = (screen_shot_info*)cookie;
954 if ( info && info->bitmap && info->bitmap->IsValid() && info->path )
956 // try to be as quick as possible creating the file (the user might have
957 // taken the next screen shot already!)
958 // make sure we have a unique name for the screen shot
959 BString path( info->path );
960 // create the folder if it doesn't exist
961 BString folder( info->path );
962 create_directory( folder.String(), 0777 );
963 path << "/vlc screenshot";
964 BEntry entry( path.String() );
965 int32_t appendedNumber = 0;
966 if ( entry.Exists() && !entry.IsSymLink() )
968 // we would clobber an existing entry
969 bool foundUniqueName = false;
971 while ( !foundUniqueName ) {
972 BString newName( path.String() );
973 newName << " " << appendedNumber;
974 BEntry possiblyClobberedEntry( newName.String() );
975 if ( possiblyClobberedEntry.Exists()
976 && !possiblyClobberedEntry.IsSymLink() )
979 foundUniqueName = true;
982 if ( appendedNumber > 0 )
983 path << " " << appendedNumber;
984 // there is still a slight chance to clobber an existing
985 // file (if it was created in the "meantime"), but we take it...
986 BFile outFile( path.String(),
987 B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE );
989 // make colorspace converted copy of bitmap
990 BBitmap* converted = new BBitmap( BRect( 0.0, 0.0, info->width, info->height ),
992 status_t status = convert_bitmap( info->bitmap, converted );
993 if ( status == B_OK )
995 BTranslatorRoster* roster = BTranslatorRoster::Default();
996 uint32_t imageFormat = 0;
997 translator_id translator = 0;
1000 // find suitable translator
1001 translator_id* ids = NULL;
1004 status = roster->GetAllTranslators( &ids, &count );
1005 if ( status >= B_OK )
1007 for ( int tix = 0; tix < count; tix++ )
1009 const translation_format *formats = NULL;
1010 int32 num_formats = 0;
1012 status = roster->GetInputFormats( ids[tix],
1013 &formats, &num_formats );
1016 for ( int iix = 0; iix < num_formats; iix++ )
1018 if ( formats[iix].type == B_TRANSLATOR_BITMAP )
1027 status = roster->GetOutputFormats( ids[tix],
1028 &formats, &num_formats);
1029 if ( status >= B_OK )
1031 for ( int32_t oix = 0; oix < num_formats; oix++ )
1033 if ( formats[oix].type != B_TRANSLATOR_BITMAP )
1035 if ( formats[oix].type == info->translatorID )
1038 imageFormat = formats[oix].type;
1039 translator = ids[tix];
1050 // make bitmap stream
1051 BBitmapStream outStream( converted );
1053 status = outFile.InitCheck();
1054 if (status == B_OK) {
1055 status = roster->Translate( &outStream, NULL, NULL,
1056 &outFile, imageFormat );
1057 if ( status == B_OK )
1059 BNodeInfo nodeInfo( &outFile );
1060 if ( nodeInfo.InitCheck() == B_OK )
1062 translation_format* formats;
1064 status = roster->GetOutputFormats( translator,
1065 (const translation_format **) &formats,
1067 if ( status >= B_OK )
1069 const char * mime = NULL;
1070 for ( int ix = 0; ix < count; ix++ ) {
1071 if ( formats[ix].type == imageFormat ) {
1072 mime = formats[ix].MIME;
1077 nodeInfo.SetType( mime );
1082 outStream.DetachBitmap( &converted );
1090 delete info->bitmap;
1098 /*****************************************************************************
1100 *****************************************************************************/
1101 VLCView::VLCView(BRect bounds, vout_thread_t *p_vout_instance )
1102 : BView(bounds, "video view", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED),
1103 fLastMouseMovedTime(system_time()),
1104 fCursorHidden(false),
1105 fCursorInside(false),
1106 fIgnoreDoubleClick(false)
1108 p_vout = p_vout_instance;
1109 SetViewColor(B_TRANSPARENT_32_BIT);
1112 /*****************************************************************************
1114 *****************************************************************************/
1119 /*****************************************************************************
1120 * VLCVIew::AttachedToWindow
1121 *****************************************************************************/
1123 VLCView::AttachedToWindow()
1125 // in order to get keyboard events
1127 // periodically check if we want to hide the pointer
1128 Window()->SetPulseRate(1000000);
1131 /*****************************************************************************
1132 * VLCVIew::MouseDown
1133 *****************************************************************************/
1135 VLCView::MouseDown(BPoint where)
1137 VideoWindow* videoWindow = dynamic_cast<VideoWindow*>(Window());
1138 BMessage* msg = Window()->CurrentMessage();
1141 msg->FindInt32("clicks", &clicks);
1142 msg->FindInt32("buttons", (int32*)&buttons);
1146 if (buttons & B_PRIMARY_MOUSE_BUTTON)
1148 if (clicks == 2 && !fIgnoreDoubleClick)
1151 videoWindow->ToggleInterfaceShowing(); */
1152 fIgnoreDoubleClick = false;
1156 if (buttons & B_SECONDARY_MOUSE_BUTTON)
1158 // clicks will be 2 next time (if interval short enough)
1159 // even if the first click and the second
1160 // have not been made with the same mouse button
1161 fIgnoreDoubleClick = true;
1162 // launch popup menu
1163 BPopUpMenu *menu = new BPopUpMenu("context menu");
1164 menu->SetRadioMode(false);
1165 // In full screen, add an item to show/hide the interface
1166 if( videoWindow->IsFullScreen() )
1168 BMenuItem *intfItem =
1169 new BMenuItem( _("Show Interface"), new BMessage(SHOW_INTERFACE) );
1170 menu->AddItem( intfItem );
1173 BMenuItem *halfItem = new BMenuItem(_("50%"), new BMessage(RESIZE_50));
1174 menu->AddItem(halfItem);
1176 BMenuItem *origItem = new BMenuItem(_("100%"), new BMessage(RESIZE_100));
1177 menu->AddItem(origItem);
1179 BMenuItem *doubleItem = new BMenuItem(_("200%"), new BMessage(RESIZE_200));
1180 menu->AddItem(doubleItem);
1181 // Toggle FullScreen
1182 BMenuItem *zoomItem = new BMenuItem(_("Fullscreen"), new BMessage(TOGGLE_FULL_SCREEN));
1183 zoomItem->SetMarked(videoWindow->IsFullScreen());
1184 menu->AddItem(zoomItem);
1186 menu->AddSeparatorItem();
1189 BMenuItem *vsyncItem = new BMenuItem(_("Vertical Sync"), new BMessage(VERT_SYNC));
1190 vsyncItem->SetMarked(videoWindow->IsSyncedToRetrace());
1191 menu->AddItem(vsyncItem);
1192 // Correct Aspect Ratio
1193 BMenuItem *aspectItem = new BMenuItem(_("Correct Aspect Ratio"), new BMessage(ASPECT_CORRECT));
1194 aspectItem->SetMarked(videoWindow->CorrectAspectRatio());
1195 menu->AddItem(aspectItem);
1197 menu->AddSeparatorItem();
1199 // Windwo Feel Items
1200 /* BMessage *winNormFeel = new BMessage(WINDOW_FEEL);
1201 winNormFeel->AddInt32("WinFeel", (int32_t)B_NORMAL_WINDOW_FEEL);
1202 BMenuItem *normWindItem = new BMenuItem("Normal Window", winNormFeel);
1203 normWindItem->SetMarked(videoWindow->Feel() == B_NORMAL_WINDOW_FEEL);
1204 menu->AddItem(normWindItem);
1206 BMessage *winFloatFeel = new BMessage(WINDOW_FEEL);
1207 winFloatFeel->AddInt32("WinFeel", (int32_t)B_FLOATING_APP_WINDOW_FEEL);
1208 BMenuItem *onTopWindItem = new BMenuItem("App Top", winFloatFeel);
1209 onTopWindItem->SetMarked(videoWindow->Feel() == B_FLOATING_APP_WINDOW_FEEL);
1210 menu->AddItem(onTopWindItem);
1212 BMessage *winAllFeel = new BMessage(WINDOW_FEEL);
1213 winAllFeel->AddInt32("WinFeel", (int32_t)B_FLOATING_ALL_WINDOW_FEEL);
1214 BMenuItem *allSpacesWindItem = new BMenuItem("On Top All Workspaces", winAllFeel);
1215 allSpacesWindItem->SetMarked(videoWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL);
1216 menu->AddItem(allSpacesWindItem);*/
1218 BMessage *windowFeelMsg = new BMessage( WINDOW_FEEL );
1219 bool onTop = videoWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL;
1220 window_feel feel = onTop ? B_NORMAL_WINDOW_FEEL : B_FLOATING_ALL_WINDOW_FEEL;
1221 windowFeelMsg->AddInt32( "WinFeel", (int32_t)feel );
1222 BMenuItem *windowFeelItem = new BMenuItem( _("Stay On Top"), windowFeelMsg );
1223 windowFeelItem->SetMarked( onTop );
1224 menu->AddItem( windowFeelItem );
1226 menu->AddSeparatorItem();
1228 BMenuItem* screenShotItem = new BMenuItem( _("Take Screen Shot"),
1229 new BMessage( SCREEN_SHOT ) );
1230 menu->AddItem( screenShotItem );
1232 menu->SetTargetForItems( this );
1233 ConvertToScreen( &where );
1234 BRect mouseRect( where.x - 5, where.y - 5,
1235 where.x + 5, where.y + 5 );
1236 menu->Go( where, true, false, mouseRect, true );
1240 fLastMouseMovedTime = system_time();
1241 fCursorHidden = false;
1244 /*****************************************************************************
1246 *****************************************************************************/
1248 VLCView::MouseUp( BPoint where )
1251 val.b_bool = VLC_TRUE;
1252 var_Set( p_vout, "mouse-clicked", val );
1255 /*****************************************************************************
1256 * VLCVIew::MouseMoved
1257 *****************************************************************************/
1259 VLCView::MouseMoved(BPoint point, uint32_t transit, const BMessage* dragMessage)
1261 fLastMouseMovedTime = system_time();
1262 fCursorHidden = false;
1263 fCursorInside = (transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW);
1264 /* DVD navigation */
1265 unsigned int i_width, i_height, i_x, i_y;
1266 vout_PlacePicture( p_vout, (unsigned int)Bounds().Width(),
1267 (unsigned int)Bounds().Height(),
1268 &i_x, &i_y, &i_width, &i_height );
1270 val.i_int = ( (int)point.x - i_x ) * p_vout->render.i_width / i_width;
1271 var_Set( p_vout, "mouse-x", val );
1272 val.i_int = ( (int)point.y - i_y ) * p_vout->render.i_height / i_height;
1273 var_Set( p_vout, "mouse-y", val );
1274 val.b_bool = VLC_TRUE;
1275 var_Set( p_vout, "mouse-moved", val );
1278 /*****************************************************************************
1280 *****************************************************************************/
1284 // We are getting the pulse messages no matter if the mouse is over
1285 // this view. If we are in full screen mode, we want to hide the cursor
1286 // even if it is not.
1287 VideoWindow *videoWindow = dynamic_cast<VideoWindow*>(Window());
1291 && system_time() - fLastMouseMovedTime > MOUSE_IDLE_TIMEOUT)
1293 be_app->ObscureCursor();
1294 fCursorHidden = true;
1296 // hide the interface window as well if full screen
1297 if (videoWindow && videoWindow->IsFullScreen())
1298 videoWindow->SetInterfaceShowing(false);
1302 // Workaround to disable the screensaver in full screen:
1303 // we simulate an activity every 29 seconds
1304 if( videoWindow && videoWindow->IsFullScreen() &&
1305 system_time() - fLastMouseMovedTime > 29000000 )
1309 GetMouse(&where, &buttons, false);
1310 ConvertToScreen(&where);
1311 set_mouse_position((int32_t) where.x, (int32_t) where.y);
1315 /*****************************************************************************
1317 *****************************************************************************/
1318 void VLCView::KeyDown( const char *bytes, int32 numBytes )
1325 uint32_t mods = modifiers();
1328 val.i_int = ConvertKey( *bytes );
1329 if( mods & B_SHIFT_KEY )
1331 val.i_int |= KEY_MODIFIER_SHIFT;
1333 if( mods & B_CONTROL_KEY )
1335 val.i_int |= KEY_MODIFIER_CTRL;
1337 if( mods & B_COMMAND_KEY )
1339 val.i_int |= KEY_MODIFIER_ALT;
1341 var_Set( p_vout->p_vlc, "key-pressed", val );
1344 /*****************************************************************************
1346 *****************************************************************************/
1348 VLCView::Draw(BRect updateRect)
1350 VideoWindow* window = dynamic_cast<VideoWindow*>( Window() );
1351 if ( window && window->mode == BITMAP )
1352 FillRect( updateRect );
1355 /*****************************************************************************
1357 *****************************************************************************/
1358 static int Init ( vout_thread_t * );
1359 static void End ( vout_thread_t * );
1360 static int Manage ( vout_thread_t * );
1361 static void Display ( vout_thread_t *, picture_t * );
1363 static int BeosOpenDisplay ( vout_thread_t *p_vout );
1364 static void BeosCloseDisplay( vout_thread_t *p_vout );
1366 /*****************************************************************************
1367 * OpenVideo: allocates BeOS video thread output method
1368 *****************************************************************************
1369 * This function allocates and initializes a BeOS vout method.
1370 *****************************************************************************/
1371 int E_(OpenVideo) ( vlc_object_t *p_this )
1373 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1375 /* Allocate structure */
1376 p_vout->p_sys = (vout_sys_t*) malloc( sizeof( vout_sys_t ) );
1377 if( p_vout->p_sys == NULL )
1379 msg_Err( p_vout, "out of memory" );
1382 p_vout->p_sys->i_width = p_vout->render.i_width;
1383 p_vout->p_sys->i_height = p_vout->render.i_height;
1384 p_vout->p_sys->source_chroma = p_vout->render.i_chroma;
1386 p_vout->pf_init = Init;
1387 p_vout->pf_end = End;
1388 p_vout->pf_manage = Manage;
1389 p_vout->pf_render = NULL;
1390 p_vout->pf_display = Display;
1395 /*****************************************************************************
1396 * Init: initialize BeOS video thread output method
1397 *****************************************************************************/
1398 int Init( vout_thread_t *p_vout )
1403 I_OUTPUTPICTURES = 0;
1405 /* Open and initialize device */
1406 if( BeosOpenDisplay( p_vout ) )
1408 msg_Err(p_vout, "vout error: can't open display");
1411 p_vout->output.i_width = p_vout->render.i_width;
1412 p_vout->output.i_height = p_vout->render.i_height;
1414 /* Assume we have square pixels */
1415 p_vout->output.i_aspect = p_vout->p_sys->i_width
1416 * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
1417 p_vout->output.i_chroma = colspace[p_vout->p_sys->p_window->colspace_index].chroma;
1418 p_vout->p_sys->i_index = 0;
1420 p_vout->b_direct = 1;
1422 p_vout->output.i_rmask = 0x00ff0000;
1423 p_vout->output.i_gmask = 0x0000ff00;
1424 p_vout->output.i_bmask = 0x000000ff;
1426 for (int buffer_index = 0 ; buffer_index < 3; buffer_index++)
1429 /* Find an empty picture slot */
1430 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
1433 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
1435 p_pic = p_vout->p_picture + i_index;
1444 p_pic->p->p_pixels = (uint8_t*)p_vout->p_sys->p_window->bitmap[buffer_index]->Bits();
1445 p_pic->p->i_lines = p_vout->p_sys->i_height;
1447 p_pic->p->i_pixel_pitch = colspace[p_vout->p_sys->p_window->colspace_index].pixel_bytes;
1448 p_pic->i_planes = colspace[p_vout->p_sys->p_window->colspace_index].planes;
1449 p_pic->p->i_pitch = p_vout->p_sys->p_window->bitmap[buffer_index]->BytesPerRow();
1450 p_pic->p->i_visible_pitch = p_pic->p->i_pixel_pitch * ( p_vout->p_sys->p_window->bitmap[buffer_index]->Bounds().IntegerWidth() + 1 );
1452 p_pic->i_status = DESTROYED_PICTURE;
1453 p_pic->i_type = DIRECT_PICTURE;
1455 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
1463 /*****************************************************************************
1464 * End: terminate BeOS video thread output method
1465 *****************************************************************************/
1466 void End( vout_thread_t *p_vout )
1468 BeosCloseDisplay( p_vout );
1471 /*****************************************************************************
1473 *****************************************************************************/
1474 static int Manage( vout_thread_t * p_vout )
1476 if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
1478 p_vout->p_sys->p_window->PostMessage( TOGGLE_FULL_SCREEN );
1479 p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
1485 /*****************************************************************************
1486 * CloseVideo: destroy BeOS video thread output method
1487 *****************************************************************************
1488 * Terminate an output method created by DummyCreateOutputMethod
1489 *****************************************************************************/
1490 void E_(CloseVideo) ( vlc_object_t *p_this )
1492 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1494 free( p_vout->p_sys );
1497 /*****************************************************************************
1498 * Display: displays previously rendered output
1499 *****************************************************************************
1500 * This function send the currently rendered image to BeOS image, waits until
1501 * it is displayed and switch the two rendering buffers, preparing next frame.
1502 *****************************************************************************/
1503 void Display( vout_thread_t *p_vout, picture_t *p_pic )
1505 VideoWindow * p_win = p_vout->p_sys->p_window;
1507 /* draw buffer if required */
1508 if (!p_win->teardownwindow)
1510 p_win->drawBuffer(p_vout->p_sys->i_index);
1513 p_vout->p_sys->i_index = ++p_vout->p_sys->i_index % 3;
1514 p_pic->p->p_pixels = (uint8_t*)p_vout->p_sys->p_window->bitmap[p_vout->p_sys->i_index]->Bits();
1517 /* following functions are local */
1519 /*****************************************************************************
1520 * BeosOpenDisplay: open and initialize BeOS device
1521 *****************************************************************************/
1522 static int BeosOpenDisplay( vout_thread_t *p_vout )
1525 p_vout->p_sys->p_window = new VideoWindow( p_vout->p_sys->i_width - 1,
1526 p_vout->p_sys->i_height - 1,
1528 20 + p_vout->i_window_width - 1,
1529 50 + p_vout->i_window_height - 1 ),
1531 if( p_vout->p_sys->p_window == NULL )
1533 msg_Err( p_vout, "cannot allocate VideoWindow" );
1538 p_vout->p_sys->p_window->Show();
1544 /*****************************************************************************
1545 * BeosDisplay: close and reset BeOS device
1546 *****************************************************************************
1547 * Returns all resources allocated by BeosOpenDisplay and restore the original
1548 * state of the device.
1549 *****************************************************************************/
1550 static void BeosCloseDisplay( vout_thread_t *p_vout )
1552 VideoWindow * p_win = p_vout->p_sys->p_window;
1553 /* Destroy the video window */
1554 if( p_win != NULL && !p_win->teardownwindow)
1557 p_win->teardownwindow = true;