1 /*****************************************************************************
2 * vout_beos.cpp: beos video output display method
3 *****************************************************************************
4 * Copyright (C) 2000, 2001 VideoLAN
5 * $Id: VideoOutput.cpp,v 1.12 2003/02/09 17:10:52 stippi 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>
52 #include "InterfaceWindow.h" // for load/save_settings()
53 #include "DrawingTidbits.h"
56 #include "VideoWindow.h"
58 /*****************************************************************************
59 * vout_sys_t: BeOS video output method descriptor
60 *****************************************************************************
61 * This structure is part of the video output thread descriptor.
62 * It describes the BeOS specific properties of an output thread.
63 *****************************************************************************/
66 VideoWindow * p_window;
77 #define MOUSE_IDLE_TIMEOUT 2000000 // two seconds
78 #define MIN_AUTO_VSYNC_REFRESH 61 // Hz
79 #define DEFAULT_SCREEN_SHOT_FORMAT 'PNG '
80 #define DEFAULT_SCREEN_SHOT_PATH "/boot/home/vlc screenshot"
82 /*****************************************************************************
83 * beos_GetAppWindow : retrieve a BWindow pointer from the window name
84 *****************************************************************************/
86 beos_GetAppWindow(char *name)
91 for (index = 0 ; ; index++)
93 window = be_app->WindowAt(index);
96 if (window->LockWithTimeout(20000) == B_OK)
98 if (strcmp(window->Name(), name) == 0)
109 /*****************************************************************************
110 * get_interface_window
111 *****************************************************************************/
113 get_interface_window()
115 return beos_GetAppWindow(VOUT_TITLE);
118 class BackgroundView : public BView
121 BackgroundView(BRect frame, VLCView* view)
122 : BView(frame, "background",
123 B_FOLLOW_ALL, B_FULL_UPDATE_ON_RESIZE),
126 SetViewColor(kBlack);
128 virtual ~BackgroundView() {}
130 virtual void MouseDown(BPoint where)
132 // convert coordinates
133 where = fVideoView->ConvertFromParent(where);
135 fVideoView->MouseDown(where);
137 virtual void MouseMoved(BPoint where, uint32 transit,
138 const BMessage* dragMessage)
140 // convert coordinates
141 where = fVideoView->ConvertFromParent(where);
143 fVideoView->MouseMoved(where, transit, dragMessage);
144 // notice: It might look like transit should be
145 // B_OUTSIDE_VIEW regardless, but leave it like this,
146 // otherwise, unwanted things will happen!
154 /*****************************************************************************
155 * VideoSettings constructor and destructor
156 *****************************************************************************/
157 VideoSettings::VideoSettings()
158 : fVideoSize( SIZE_100 ),
159 fFlags( FLAG_CORRECT_RATIO ),
160 fSettings( new BMessage( 'sett' ) )
162 // read settings from disk
163 status_t ret = load_settings( fSettings, "video_settings", "VideoLAN Client" );
167 if ( fSettings->FindInt32( "flags", (int32*)&flags ) == B_OK )
170 if ( fSettings->FindInt32( "video size", (int32*)&size ) == B_OK )
171 SetVideoSize( size );
175 fprintf( stderr, "error loading video settings: %s\n", strerror( ret ) );
177 // figure out if we should use vertical sync by default
178 BScreen screen(B_MAIN_SCREEN_ID);
179 if (screen.IsValid())
182 screen.GetMode(&mode);
183 float refresh = (mode.timing.pixel_clock * 1000)
184 / ((mode.timing.h_total)* (mode.timing.v_total));
185 if (refresh < MIN_AUTO_VSYNC_REFRESH)
186 AddFlags(FLAG_SYNC_RETRACE);
191 VideoSettings::VideoSettings( const VideoSettings& clone )
192 : fVideoSize( clone.VideoSize() ),
193 fFlags( clone.Flags() ),
199 VideoSettings::~VideoSettings()
203 // we are the default settings
204 // and write our settings to disk
205 if (fSettings->ReplaceInt32( "video size", VideoSize() ) != B_OK)
206 fSettings->AddInt32( "video size", VideoSize() );
207 if (fSettings->ReplaceInt32( "flags", Flags() ) != B_OK)
208 fSettings->AddInt32( "flags", Flags() );
210 status_t ret = save_settings( fSettings, "video_settings", "VideoLAN Client" );
212 fprintf( stderr, "error saving video settings: %s\n", strerror( ret ) );
217 // we are just a clone of the default settings
218 fDefaultSettings.SetVideoSize( VideoSize() );
219 fDefaultSettings.SetFlags( Flags() );
223 /*****************************************************************************
224 * VideoSettings::DefaultSettings
225 *****************************************************************************/
227 VideoSettings::DefaultSettings()
229 return &fDefaultSettings;
232 /*****************************************************************************
233 * VideoSettings::SetVideoSize
234 *****************************************************************************/
236 VideoSettings::SetVideoSize( uint32 mode )
241 // static variable initialization
243 VideoSettings::fDefaultSettings;
246 /*****************************************************************************
247 * VideoWindow constructor and destructor
248 *****************************************************************************/
249 VideoWindow::VideoWindow(int v_width, int v_height, BRect frame,
250 vout_thread_t *p_videoout)
251 : BWindow(frame, NULL, B_TITLED_WINDOW, B_NOT_CLOSABLE | B_NOT_MINIMIZABLE),
252 i_width(frame.IntegerWidth()),
253 i_height(frame.IntegerHeight()),
256 teardownwindow(false),
258 fTrueHeight(v_height),
259 fCachedFeel(B_NORMAL_WINDOW_FEEL),
260 fInterfaceShowing(false),
261 fInitStatus(B_ERROR),
262 fSettings(new VideoSettings(*VideoSettings::DefaultSettings()))
266 // create the view to do the display
267 view = new VLCView( Bounds(), p_vout );
269 // create background view
270 BView *mainView = new BackgroundView( Bounds(), view );
272 mainView->AddChild(view);
274 // allocate bitmap buffers
275 for (int32 i = 0; i < 3; i++)
277 fInitStatus = _AllocateBuffers(v_width, v_height, &mode);
279 // make sure we layout the view correctly
280 FrameResized(i_width, i_height);
282 if (fInitStatus >= B_OK && mode == OVERLAY)
284 overlay_restrictions r;
286 bitmap[1]->GetOverlayRestrictions(&r);
287 SetSizeLimits((i_width * r.min_width_scale), i_width * r.max_width_scale,
288 (i_height * r.min_height_scale), i_height * r.max_height_scale);
291 // vlc settings override settings from disk
292 if (config_GetInt(p_vout, "fullscreen"))
293 fSettings->AddFlags(VideoSettings::FLAG_FULL_SCREEN);
298 VideoWindow::~VideoWindow()
302 teardownwindow = true;
303 wait_for_thread(fDrawThreadID, &result);
308 /*****************************************************************************
309 * VideoWindow::MessageReceived
310 *****************************************************************************/
312 VideoWindow::MessageReceived( BMessage *p_message )
314 switch( p_message->what )
316 case TOGGLE_FULL_SCREEN:
324 _SetVideoSize(p_message->what);
327 SetSyncToRetrace(!IsSyncedToRetrace());
332 if (p_message->FindInt32("WinFeel", (int32*)&winFeel) == B_OK)
335 fCachedFeel = winFeel;
336 if (winFeel == B_FLOATING_ALL_WINDOW_FEEL)
337 fSettings->AddFlags(VideoSettings::FLAG_ON_TOP_ALL);
339 fSettings->ClearFlags(VideoSettings::FLAG_ON_TOP_ALL);
344 SetCorrectAspectRatio(!CorrectAspectRatio());
347 // save a screen shot
348 if ( BBitmap* current = bitmap[i_buffer] )
350 // the following line might be tempting, but does not work for some overlay bitmaps!!!
351 // BBitmap* temp = new BBitmap( current );
352 // so we clone the bitmap ourselves
353 // however, we need to take care of potentially different padding!
354 // memcpy() is slow when reading from grafix memory, but what the heck...
355 BBitmap* temp = new BBitmap( current->Bounds(), current->ColorSpace() );
356 if ( temp && temp->IsValid() )
358 int32 height = (int32)current->Bounds().Height();
359 uint8* dst = (uint8*)temp->Bits();
360 uint8* src = (uint8*)current->Bits();
361 int32 dstBpr = temp->BytesPerRow();
362 int32 srcBpr = current->BytesPerRow();
363 int32 validBytes = dstBpr > srcBpr ? srcBpr : dstBpr;
364 for ( int32 y = 0; y < height; y++ )
366 memcpy( dst, src, validBytes );
370 char* path = config_GetPsz( p_vout, "beos-screenshot-path" );
372 path = strdup( DEFAULT_SCREEN_SHOT_PATH );
373 int32 format = config_GetInt( p_vout, "beos-screenshot-format" );
374 _SaveScreenShot( temp, path, format );
383 BWindow::MessageReceived( p_message );
388 /*****************************************************************************
390 *****************************************************************************/
392 VideoWindow::Zoom(BPoint origin, float width, float height )
397 /*****************************************************************************
398 * VideoWindow::FrameMoved
399 *****************************************************************************/
401 VideoWindow::FrameMoved(BPoint origin)
408 /*****************************************************************************
409 * VideoWindow::FrameResized
410 *****************************************************************************/
412 VideoWindow::FrameResized( float width, float height )
414 int32 useWidth = CorrectAspectRatio() ? i_width : fTrueWidth;
415 int32 useHeight = CorrectAspectRatio() ? i_height : fTrueHeight;
416 float out_width, out_height;
417 float out_left, out_top;
418 float width_scale = width / useWidth;
419 float height_scale = height / useHeight;
421 if (width_scale <= height_scale)
423 out_width = (useWidth * width_scale);
424 out_height = (useHeight * width_scale);
426 out_top = (height - out_height) / 2;
428 else /* if the height is proportionally smaller */
430 out_width = (useWidth * height_scale);
431 out_height = (useHeight * height_scale);
433 out_left = (width - out_width) / 2;
435 view->MoveTo(out_left,out_top);
436 view->ResizeTo(out_width, out_height);
442 /*****************************************************************************
443 * VideoWindow::ScreenChanged
444 *****************************************************************************/
446 VideoWindow::ScreenChanged(BRect frame, color_space format)
448 BScreen screen(this);
450 screen.GetMode(&mode);
451 float refresh = (mode.timing.pixel_clock * 1000)
452 / ((mode.timing.h_total) * (mode.timing.v_total));
453 SetSyncToRetrace(refresh < MIN_AUTO_VSYNC_REFRESH);
456 /*****************************************************************************
457 * VideoWindow::Activate
458 *****************************************************************************/
460 VideoWindow::WindowActivated(bool active)
464 /*****************************************************************************
465 * VideoWindow::drawBuffer
466 *****************************************************************************/
468 VideoWindow::drawBuffer(int bufferIndex)
470 i_buffer = bufferIndex;
472 // sync to the screen if required
473 if (IsSyncedToRetrace())
475 BScreen screen(this);
476 screen.WaitForRetrace(22000);
478 if (fInitStatus >= B_OK && LockLooper())
480 // switch the overlay bitmap
484 view->SetViewOverlay(bitmap[i_buffer],
485 bitmap[i_buffer]->Bounds() ,
488 B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL|
489 B_OVERLAY_TRANSFER_CHANNEL);
490 view->SetViewColor(key);
495 view->DrawBitmap(bitmap[i_buffer], view->Bounds() );
501 /*****************************************************************************
502 * VideoWindow::SetInterfaceShowing
503 *****************************************************************************/
505 VideoWindow::ToggleInterfaceShowing()
507 SetInterfaceShowing(!fInterfaceShowing);
510 /*****************************************************************************
511 * VideoWindow::SetInterfaceShowing
512 *****************************************************************************/
514 VideoWindow::SetInterfaceShowing(bool showIt)
516 BWindow* window = get_interface_window();
521 if (fCachedFeel != B_NORMAL_WINDOW_FEEL)
522 SetFeel(B_NORMAL_WINDOW_FEEL);
523 window->Activate(true);
528 SetFeel(fCachedFeel);
530 window->SendBehind(this);
532 fInterfaceShowing = showIt;
536 /*****************************************************************************
537 * VideoWindow::SetCorrectAspectRatio
538 *****************************************************************************/
540 VideoWindow::SetCorrectAspectRatio(bool doIt)
542 if (CorrectAspectRatio() != doIt)
545 fSettings->AddFlags(VideoSettings::FLAG_CORRECT_RATIO);
547 fSettings->ClearFlags(VideoSettings::FLAG_CORRECT_RATIO);
548 FrameResized(Bounds().Width(), Bounds().Height());
552 /*****************************************************************************
553 * VideoWindow::CorrectAspectRatio
554 *****************************************************************************/
556 VideoWindow::CorrectAspectRatio() const
558 return fSettings->HasFlags(VideoSettings::FLAG_CORRECT_RATIO);
561 /*****************************************************************************
562 * VideoWindow::ToggleFullScreen
563 *****************************************************************************/
565 VideoWindow::ToggleFullScreen()
567 SetFullScreen(!IsFullScreen());
570 /*****************************************************************************
571 * VideoWindow::SetFullScreen
572 *****************************************************************************/
574 VideoWindow::SetFullScreen(bool doIt)
578 BScreen screen(this);
579 BRect rect = screen.Frame();
582 ResizeTo(rect.IntegerWidth(), rect.IntegerHeight());
583 be_app->ObscureCursor();
584 fInterfaceShowing = false;
585 fSettings->AddFlags(VideoSettings::FLAG_FULL_SCREEN);
589 MoveTo(winSize.left, winSize.top);
590 ResizeTo(winSize.IntegerWidth(), winSize.IntegerHeight());
591 be_app->ShowCursor();
592 fInterfaceShowing = true;
593 fSettings->ClearFlags(VideoSettings::FLAG_FULL_SCREEN);
597 /*****************************************************************************
598 * VideoWindow::IsFullScreen
599 *****************************************************************************/
601 VideoWindow::IsFullScreen() const
603 return fSettings->HasFlags(VideoSettings::FLAG_FULL_SCREEN);
606 /*****************************************************************************
607 * VideoWindow::SetSyncToRetrace
608 *****************************************************************************/
610 VideoWindow::SetSyncToRetrace(bool doIt)
613 fSettings->AddFlags(VideoSettings::FLAG_SYNC_RETRACE);
615 fSettings->ClearFlags(VideoSettings::FLAG_SYNC_RETRACE);
618 /*****************************************************************************
619 * VideoWindow::IsSyncedToRetrace
620 *****************************************************************************/
622 VideoWindow::IsSyncedToRetrace() const
624 return fSettings->HasFlags(VideoSettings::FLAG_SYNC_RETRACE);
628 /*****************************************************************************
629 * VideoWindow::_AllocateBuffers
630 *****************************************************************************/
632 VideoWindow::_AllocateBuffers(int width, int height, int* mode)
634 // clear any old buffers
639 BRect bitmapFrame( 0, 0, width, height );
640 // read from config, if we are supposed to use overlay at all
641 int noOverlay = !config_GetInt( p_vout, "overlay" );
642 // test for overlay capability
643 for (int i = 0; i < COLOR_COUNT; i++)
645 if (noOverlay) break;
646 bitmap[0] = new BBitmap ( bitmapFrame,
647 B_BITMAP_WILL_OVERLAY |
648 B_BITMAP_RESERVE_OVERLAY_CHANNEL,
649 colspace[i].colspace);
651 if(bitmap[0] && bitmap[0]->InitCheck() == B_OK)
655 bitmap[1] = new BBitmap( bitmapFrame, B_BITMAP_WILL_OVERLAY,
656 colspace[colspace_index].colspace);
657 bitmap[2] = new BBitmap( bitmapFrame, B_BITMAP_WILL_OVERLAY,
658 colspace[colspace_index].colspace);
659 if ( (bitmap[2] && bitmap[2]->InitCheck() == B_OK) )
663 view->SetViewOverlay(bitmap[0],
664 bitmap[0]->Bounds() ,
667 B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL);
668 view->SetViewColor(key);
669 SetTitle(VOUT_TITLE " (Overlay)");
675 *mode = BITMAP; // might want to try again with normal bitmaps
685 colspace_index = DEFAULT_COL; // B_RGB32
686 SetTitle( VOUT_TITLE " (Bitmap)" );
687 bitmap[0] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
688 bitmap[1] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
689 bitmap[2] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
691 // see if everything went well
692 status_t status = B_ERROR;
693 for (int32 i = 0; i < 3; i++)
696 status = bitmap[i]->InitCheck();
702 // clear bitmaps to black
703 for (int32 i = 0; i < 3; i++)
704 _BlankBitmap(bitmap[i]);
709 /*****************************************************************************
710 * VideoWindow::_FreeBuffers
711 *****************************************************************************/
713 VideoWindow::_FreeBuffers()
721 fInitStatus = B_ERROR;
724 /*****************************************************************************
725 * VideoWindow::_BlankBitmap
726 *****************************************************************************/
728 VideoWindow::_BlankBitmap(BBitmap* bitmap) const
730 // no error checking (we do that earlier on and since it's a private function...
733 // Loss/Saturation points are Y 16-235 (absoulte); Cb/Cr 16-240 (center 128)
736 // Extrema points are Y 0 - 207 (absolute) U -91 - 91 (offset 128) V -127 - 127 (offset 128)
738 // we only handle weird colorspaces with special care
739 switch (bitmap->ColorSpace()) {
741 // Y0[7:0] Cb0[7:0] Y1[7:0] Cr0[7:0] Y2[7:0] Cb2[7:0] Y3[7:0] Cr2[7:0]
742 int32 height = bitmap->Bounds().IntegerHeight() + 1;
743 uint8* bits = (uint8*)bitmap->Bits();
744 int32 bpr = bitmap->BytesPerRow();
745 for (int32 y = 0; y < height; y++) {
746 // handle 2 bytes at a time
747 for (int32 i = 0; i < bpr; i += 2) {
759 // Non-interlaced only, Cb0 Y0 Y1 Cb2 Y2 Y3 on even scan lines ...
760 // Cr0 Y0 Y1 Cr2 Y2 Y3 on odd scan lines
761 int32 height = bitmap->Bounds().IntegerHeight() + 1;
762 uint8* bits = (uint8*)bitmap->Bits();
763 int32 bpr = bitmap->BytesPerRow();
764 for (int32 y = 0; y < height; y += 1) {
765 // handle 3 bytes at a time
766 for (int32 i = 0; i < bpr; i += 3) {
779 // U0[7:0] Y0[7:0] V0[7:0] Y1[7:0] U2[7:0] Y2[7:0] V2[7:0] Y3[7:0]
780 int32 height = bitmap->Bounds().IntegerHeight() + 1;
781 uint8* bits = (uint8*)bitmap->Bits();
782 int32 bpr = bitmap->BytesPerRow();
783 for (int32 y = 0; y < height; y += 1) {
784 // handle 2 bytes at a time
785 for (int32 i = 0; i < bpr; i += 2) {
796 memset(bitmap->Bits(), 0, bitmap->BitsLength());
801 /*****************************************************************************
802 * VideoWindow::_SetVideoSize
803 *****************************************************************************/
805 VideoWindow::_SetVideoSize(uint32 mode)
807 // let size depend on aspect correction
808 int32 width = CorrectAspectRatio() ? i_width : fTrueWidth;
809 int32 height = CorrectAspectRatio() ? i_height : fTrueHeight;
824 fSettings->ClearFlags(VideoSettings::FLAG_FULL_SCREEN);
825 ResizeTo(width, height);
828 /*****************************************************************************
829 * VideoWindow::_SetToSettings
830 *****************************************************************************/
832 VideoWindow::_SetToSettings()
835 uint32 mode = RESIZE_100;
836 switch (fSettings->VideoSize())
838 case VideoSettings::SIZE_50:
841 case VideoSettings::SIZE_200:
844 case VideoSettings::SIZE_100:
845 case VideoSettings::SIZE_OTHER:
849 bool fullscreen = IsFullScreen(); // remember settings
850 _SetVideoSize(mode); // because this will reset settings
851 // the fullscreen status is reflected in the settings,
852 // but not yet in the windows state
855 if (fSettings->HasFlags(VideoSettings::FLAG_ON_TOP_ALL))
856 fCachedFeel = B_FLOATING_ALL_WINDOW_FEEL;
858 fCachedFeel = B_NORMAL_WINDOW_FEEL;
859 SetFeel(fCachedFeel);
862 /*****************************************************************************
863 * VideoWindow::_SaveScreenShot
864 *****************************************************************************/
866 VideoWindow::_SaveScreenShot( BBitmap* bitmap, char* path,
867 uint32 translatorID ) const
869 // make the info object from the parameters
870 screen_shot_info* info = new screen_shot_info;
871 info->bitmap = bitmap;
873 info->translatorID = translatorID;
874 info->width = CorrectAspectRatio() ? i_width : fTrueWidth;
875 info->height = CorrectAspectRatio() ? i_height : fTrueHeight;
876 // spawn a new thread to take care of the actual saving to disk
877 thread_id thread = spawn_thread( _save_screen_shot,
879 B_LOW_PRIORITY, (void*)info );
880 // start thread or do the job ourself if something went wrong
881 if ( thread < B_OK || resume_thread( thread ) < B_OK )
882 _save_screen_shot( (void*)info );
885 /*****************************************************************************
886 * VideoWindow::_save_screen_shot
887 *****************************************************************************/
889 VideoWindow::_save_screen_shot( void* cookie )
891 screen_shot_info* info = (screen_shot_info*)cookie;
892 if ( info && info->bitmap && info->bitmap->IsValid() && info->path )
894 // try to be as quick as possible creating the file (the user might have
895 // taken the next screen shot already!)
896 // make sure we have a unique name for the screen shot
897 BString path( info->path );
898 // create the folder if it doesn't exist
899 BString folder( info->path );
900 int32 pos = folder.FindLast("/");
903 pos++; // leave the last '/' in the string
904 if ( pos == path.Length() )
905 path << "vlc screenshot";
908 int32 removeChars = folder.Length() - pos;
909 folder.Remove( pos, removeChars );
911 create_directory( folder.String(), 0777 );
913 BEntry entry( path.String() );
914 int32 appendedNumber = 0;
915 if ( entry.Exists() && !entry.IsSymLink() )
917 // we would clobber an existing entry
918 bool foundUniqueName = false;
920 while ( !foundUniqueName ) {
921 BString newName( path.String() );
922 newName << " " << appendedNumber;
923 BEntry possiblyClobberedEntry( newName.String() );
924 if ( possiblyClobberedEntry.Exists()
925 && !possiblyClobberedEntry.IsSymLink() )
928 foundUniqueName = true;
931 if ( appendedNumber > 0 )
932 path << " " << appendedNumber;
933 // there is still a slight chance to clobber an existing
934 // file (if it was created in the "meantime"), but we take it...
935 BFile outFile( path.String(),
936 B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE );
938 // make colorspace converted copy of bitmap
939 BBitmap* converted = new BBitmap( BRect( 0.0, 0.0, info->width, info->height ),
941 status_t status = convert_bitmap( info->bitmap, converted );
942 if ( status == B_OK )
944 BTranslatorRoster* roster = BTranslatorRoster::Default();
945 uint32 imageFormat = 0;
946 translator_id translator = 0;
949 // find suitable translator
950 translator_id* ids = NULL;
953 status = roster->GetAllTranslators( &ids, &count );
954 if ( status >= B_OK )
956 for ( int tix = 0; tix < count; tix++ )
958 const translation_format *formats = NULL;
959 int32 num_formats = 0;
961 status = roster->GetInputFormats( ids[tix],
962 &formats, &num_formats );
965 for ( int iix = 0; iix < num_formats; iix++ )
967 if ( formats[iix].type == B_TRANSLATOR_BITMAP )
976 status = roster->GetOutputFormats( ids[tix],
977 &formats, &num_formats);
978 if ( status >= B_OK )
980 for ( int32 oix = 0; oix < num_formats; oix++ )
982 if ( formats[oix].type != B_TRANSLATOR_BITMAP )
984 if ( formats[oix].type == info->translatorID )
987 imageFormat = formats[oix].type;
988 translator = ids[tix];
999 // make bitmap stream
1000 BBitmapStream outStream( converted );
1002 status = outFile.InitCheck();
1003 if (status == B_OK) {
1004 status = roster->Translate( &outStream, NULL, NULL,
1005 &outFile, imageFormat );
1006 if ( status == B_OK )
1008 BNodeInfo nodeInfo( &outFile );
1009 if ( nodeInfo.InitCheck() == B_OK )
1011 translation_format* formats;
1013 status = roster->GetOutputFormats( translator,
1014 (const translation_format **) &formats,
1016 if ( status >= B_OK )
1018 const char * mime = NULL;
1019 for ( int ix = 0; ix < count; ix++ ) {
1020 if ( formats[ix].type == imageFormat ) {
1021 mime = formats[ix].MIME;
1026 nodeInfo.SetType( mime );
1031 outStream.DetachBitmap( &converted );
1039 delete info->bitmap;
1047 /*****************************************************************************
1049 *****************************************************************************/
1050 VLCView::VLCView(BRect bounds, vout_thread_t *p_vout_instance )
1051 : BView(bounds, "video view", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED),
1052 fLastMouseMovedTime(system_time()),
1053 fCursorHidden(false),
1054 fCursorInside(false),
1055 fIgnoreDoubleClick(false)
1057 p_vout = p_vout_instance;
1058 SetViewColor(B_TRANSPARENT_32_BIT);
1061 /*****************************************************************************
1063 *****************************************************************************/
1068 /*****************************************************************************
1069 * VLCVIew::AttachedToWindow
1070 *****************************************************************************/
1072 VLCView::AttachedToWindow()
1074 // in order to get keyboard events
1076 // periodically check if we want to hide the pointer
1077 Window()->SetPulseRate(1000000);
1080 /*****************************************************************************
1081 * VLCVIew::MouseDown
1082 *****************************************************************************/
1084 VLCView::MouseDown(BPoint where)
1086 VideoWindow* videoWindow = dynamic_cast<VideoWindow*>(Window());
1087 BMessage* msg = Window()->CurrentMessage();
1090 msg->FindInt32("clicks", &clicks);
1091 msg->FindInt32("buttons", (int32*)&buttons);
1095 if (buttons & B_PRIMARY_MOUSE_BUTTON)
1097 if (clicks == 2 && !fIgnoreDoubleClick)
1100 videoWindow->ToggleInterfaceShowing();
1101 fIgnoreDoubleClick = false;
1105 if (buttons & B_SECONDARY_MOUSE_BUTTON)
1107 // clicks will be 2 next time (if interval short enough)
1108 // even if the first click and the second
1109 // have not been made with the same mouse button
1110 fIgnoreDoubleClick = true;
1111 // launch popup menu
1112 BPopUpMenu *menu = new BPopUpMenu("context menu");
1113 menu->SetRadioMode(false);
1115 BMenuItem *halfItem = new BMenuItem("50%", new BMessage(RESIZE_50));
1116 menu->AddItem(halfItem);
1118 BMenuItem *origItem = new BMenuItem("100%", new BMessage(RESIZE_100));
1119 menu->AddItem(origItem);
1121 BMenuItem *doubleItem = new BMenuItem("200%", new BMessage(RESIZE_200));
1122 menu->AddItem(doubleItem);
1123 // Toggle FullScreen
1124 BMenuItem *zoomItem = new BMenuItem("Fullscreen", new BMessage(TOGGLE_FULL_SCREEN));
1125 zoomItem->SetMarked(videoWindow->IsFullScreen());
1126 menu->AddItem(zoomItem);
1128 menu->AddSeparatorItem();
1131 BMenuItem *vsyncItem = new BMenuItem("Vertical Sync", new BMessage(VERT_SYNC));
1132 vsyncItem->SetMarked(videoWindow->IsSyncedToRetrace());
1133 menu->AddItem(vsyncItem);
1134 // Correct Aspect Ratio
1135 BMenuItem *aspectItem = new BMenuItem("Correct Aspect Ratio", new BMessage(ASPECT_CORRECT));
1136 aspectItem->SetMarked(videoWindow->CorrectAspectRatio());
1137 menu->AddItem(aspectItem);
1139 menu->AddSeparatorItem();
1141 // Windwo Feel Items
1142 /* BMessage *winNormFeel = new BMessage(WINDOW_FEEL);
1143 winNormFeel->AddInt32("WinFeel", (int32)B_NORMAL_WINDOW_FEEL);
1144 BMenuItem *normWindItem = new BMenuItem("Normal Window", winNormFeel);
1145 normWindItem->SetMarked(videoWindow->Feel() == B_NORMAL_WINDOW_FEEL);
1146 menu->AddItem(normWindItem);
1148 BMessage *winFloatFeel = new BMessage(WINDOW_FEEL);
1149 winFloatFeel->AddInt32("WinFeel", (int32)B_FLOATING_APP_WINDOW_FEEL);
1150 BMenuItem *onTopWindItem = new BMenuItem("App Top", winFloatFeel);
1151 onTopWindItem->SetMarked(videoWindow->Feel() == B_FLOATING_APP_WINDOW_FEEL);
1152 menu->AddItem(onTopWindItem);
1154 BMessage *winAllFeel = new BMessage(WINDOW_FEEL);
1155 winAllFeel->AddInt32("WinFeel", (int32)B_FLOATING_ALL_WINDOW_FEEL);
1156 BMenuItem *allSpacesWindItem = new BMenuItem("On Top All Workspaces", winAllFeel);
1157 allSpacesWindItem->SetMarked(videoWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL);
1158 menu->AddItem(allSpacesWindItem);*/
1160 BMessage *windowFeelMsg = new BMessage( WINDOW_FEEL );
1161 bool onTop = videoWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL;
1162 window_feel feel = onTop ? B_NORMAL_WINDOW_FEEL : B_FLOATING_ALL_WINDOW_FEEL;
1163 windowFeelMsg->AddInt32( "WinFeel", (int32)feel );
1164 BMenuItem *windowFeelItem = new BMenuItem( "Stay On Top", windowFeelMsg );
1165 windowFeelItem->SetMarked( onTop );
1166 menu->AddItem( windowFeelItem );
1168 menu->AddSeparatorItem();
1170 BMenuItem* screenShotItem = new BMenuItem( "Take Screen Shot",
1171 new BMessage( SCREEN_SHOT ) );
1172 menu->AddItem( screenShotItem );
1174 menu->SetTargetForItems( this );
1175 ConvertToScreen( &where );
1176 menu->Go( where, true, false, true );
1180 fLastMouseMovedTime = system_time();
1181 fCursorHidden = false;
1184 /*****************************************************************************
1186 *****************************************************************************/
1188 VLCView::MouseUp( BPoint where )
1191 val.b_bool = VLC_TRUE;
1192 var_Set( p_vout, "mouse-clicked", val );
1195 /*****************************************************************************
1196 * VLCVIew::MouseMoved
1197 *****************************************************************************/
1199 VLCView::MouseMoved(BPoint point, uint32 transit, const BMessage* dragMessage)
1201 fLastMouseMovedTime = system_time();
1202 fCursorHidden = false;
1203 fCursorInside = (transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW);
1204 /* DVD navigation */
1205 unsigned int i_width, i_height, i_x, i_y;
1206 vout_PlacePicture( p_vout, (unsigned int)Bounds().Width(),
1207 (unsigned int)Bounds().Height(),
1208 &i_x, &i_y, &i_width, &i_height );
1210 val.i_int = ( (int)point.x - i_x ) * p_vout->render.i_width / i_width;
1211 var_Set( p_vout, "mouse-x", val );
1212 val.i_int = ( (int)point.y - i_y ) * p_vout->render.i_height / i_height;
1213 var_Set( p_vout, "mouse-y", val );
1214 val.b_bool = VLC_TRUE;
1215 var_Set( p_vout, "mouse-moved", val );
1218 /*****************************************************************************
1220 *****************************************************************************/
1224 // We are getting the pulse messages no matter if the mouse is over
1225 // this view. If we are in full screen mode, we want to hide the cursor
1226 // even if it is not.
1230 && system_time() - fLastMouseMovedTime > MOUSE_IDLE_TIMEOUT)
1232 be_app->ObscureCursor();
1233 fCursorHidden = true;
1234 VideoWindow *videoWindow = dynamic_cast<VideoWindow*>(Window());
1235 // hide the interface window as well if full screen
1236 if (videoWindow && videoWindow->IsFullScreen())
1237 videoWindow->SetInterfaceShowing(false);
1242 /*****************************************************************************
1244 *****************************************************************************/
1246 VLCView::KeyDown(const char *bytes, int32 numBytes)
1248 VideoWindow *videoWindow = dynamic_cast<VideoWindow*>(Window());
1249 BWindow* interfaceWindow = get_interface_window();
1250 if (videoWindow && numBytes > 0) {
1251 uint32 mods = modifiers();
1254 // toggle window and full screen mode
1255 // not passing on the tab key to the default KeyDown()
1256 // implementation also avoids loosing the keyboard focus
1257 videoWindow->PostMessage(TOGGLE_FULL_SCREEN);
1260 // go back to window mode
1261 if (videoWindow->IsFullScreen())
1262 videoWindow->PostMessage(TOGGLE_FULL_SCREEN);
1266 if (interfaceWindow)
1267 interfaceWindow->PostMessage(PAUSE_PLAYBACK);
1270 if (interfaceWindow)
1272 if (mods & B_SHIFT_KEY)
1274 interfaceWindow->PostMessage(NEXT_TITLE);
1277 interfaceWindow->PostMessage(NEXT_CHAPTER);
1281 if (interfaceWindow)
1283 if (mods & B_SHIFT_KEY)
1285 interfaceWindow->PostMessage(PREV_TITLE);
1288 interfaceWindow->PostMessage(PREV_CHAPTER);
1292 // previous file in playlist
1293 interfaceWindow->PostMessage(PREV_FILE);
1296 // next file in playlist
1297 interfaceWindow->PostMessage(NEXT_FILE);
1302 videoWindow->PostMessage( SCREEN_SHOT );
1305 BView::KeyDown(bytes, numBytes);
1311 /*****************************************************************************
1313 *****************************************************************************/
1315 VLCView::Draw(BRect updateRect)
1317 VideoWindow* window = dynamic_cast<VideoWindow*>( Window() );
1318 if ( window && window->mode == BITMAP )
1319 FillRect( updateRect );
1322 /*****************************************************************************
1324 *****************************************************************************/
1325 static int Init ( vout_thread_t * );
1326 static void End ( vout_thread_t * );
1327 // static int Manage ( vout_thread_t * );
1328 static void Display ( vout_thread_t *, picture_t * );
1330 static int BeosOpenDisplay ( vout_thread_t *p_vout );
1331 static void BeosCloseDisplay( vout_thread_t *p_vout );
1333 /*****************************************************************************
1334 * OpenVideo: allocates BeOS video thread output method
1335 *****************************************************************************
1336 * This function allocates and initializes a BeOS vout method.
1337 *****************************************************************************/
1338 int E_(OpenVideo) ( vlc_object_t *p_this )
1340 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1342 /* Allocate structure */
1343 p_vout->p_sys = (vout_sys_t*) malloc( sizeof( vout_sys_t ) );
1344 if( p_vout->p_sys == NULL )
1346 msg_Err( p_vout, "out of memory" );
1349 p_vout->p_sys->i_width = p_vout->render.i_width;
1350 p_vout->p_sys->i_height = p_vout->render.i_height;
1351 p_vout->p_sys->source_chroma = p_vout->render.i_chroma;
1353 p_vout->pf_init = Init;
1354 p_vout->pf_end = End;
1355 p_vout->pf_manage = NULL;
1356 p_vout->pf_render = NULL;
1357 p_vout->pf_display = Display;
1362 /*****************************************************************************
1363 * Init: initialize BeOS video thread output method
1364 *****************************************************************************/
1365 int Init( vout_thread_t *p_vout )
1370 I_OUTPUTPICTURES = 0;
1372 /* Open and initialize device */
1373 if( BeosOpenDisplay( p_vout ) )
1375 msg_Err(p_vout, "vout error: can't open display");
1378 p_vout->output.i_width = p_vout->render.i_width;
1379 p_vout->output.i_height = p_vout->render.i_height;
1381 /* Assume we have square pixels */
1382 p_vout->output.i_aspect = p_vout->p_sys->i_width
1383 * VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
1384 p_vout->output.i_chroma = colspace[p_vout->p_sys->p_window->colspace_index].chroma;
1385 p_vout->p_sys->i_index = 0;
1387 p_vout->b_direct = 1;
1389 p_vout->output.i_rmask = 0x00ff0000;
1390 p_vout->output.i_gmask = 0x0000ff00;
1391 p_vout->output.i_bmask = 0x000000ff;
1393 for (int buffer_index = 0 ; buffer_index < 3; buffer_index++)
1396 /* Find an empty picture slot */
1397 for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
1400 if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
1402 p_pic = p_vout->p_picture + i_index;
1411 p_pic->p->p_pixels = (u8*)p_vout->p_sys->p_window->bitmap[buffer_index]->Bits();
1412 p_pic->p->i_lines = p_vout->p_sys->i_height;
1414 p_pic->p->i_pixel_pitch = colspace[p_vout->p_sys->p_window->colspace_index].pixel_bytes;
1415 p_pic->i_planes = colspace[p_vout->p_sys->p_window->colspace_index].planes;
1416 p_pic->p->i_pitch = p_vout->p_sys->p_window->bitmap[buffer_index]->BytesPerRow();
1417 p_pic->p->i_visible_pitch = p_pic->p->i_pixel_pitch * ( p_vout->p_sys->p_window->bitmap[buffer_index]->Bounds().IntegerWidth() + 1 );
1419 p_pic->i_status = DESTROYED_PICTURE;
1420 p_pic->i_type = DIRECT_PICTURE;
1422 PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
1430 /*****************************************************************************
1431 * End: terminate BeOS video thread output method
1432 *****************************************************************************/
1433 void End( vout_thread_t *p_vout )
1435 BeosCloseDisplay( p_vout );
1438 /*****************************************************************************
1439 * CloseVideo: destroy BeOS video thread output method
1440 *****************************************************************************
1441 * Terminate an output method created by DummyCreateOutputMethod
1442 *****************************************************************************/
1443 void E_(CloseVideo) ( vlc_object_t *p_this )
1445 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1447 free( p_vout->p_sys );
1450 /*****************************************************************************
1451 * Display: displays previously rendered output
1452 *****************************************************************************
1453 * This function send the currently rendered image to BeOS image, waits until
1454 * it is displayed and switch the two rendering buffers, preparing next frame.
1455 *****************************************************************************/
1456 void Display( vout_thread_t *p_vout, picture_t *p_pic )
1458 VideoWindow * p_win = p_vout->p_sys->p_window;
1460 /* draw buffer if required */
1461 if (!p_win->teardownwindow)
1463 p_win->drawBuffer(p_vout->p_sys->i_index);
1466 p_vout->p_sys->i_index = ++p_vout->p_sys->i_index % 3;
1467 p_pic->p->p_pixels = (u8*)p_vout->p_sys->p_window->bitmap[p_vout->p_sys->i_index]->Bits();
1470 /* following functions are local */
1472 /*****************************************************************************
1473 * BeosOpenDisplay: open and initialize BeOS device
1474 *****************************************************************************/
1475 static int BeosOpenDisplay( vout_thread_t *p_vout )
1478 p_vout->p_sys->p_window = new VideoWindow( p_vout->p_sys->i_width - 1,
1479 p_vout->p_sys->i_height - 1,
1481 20 + p_vout->i_window_width - 1,
1482 50 + p_vout->i_window_height - 1 ),
1484 if( p_vout->p_sys->p_window == NULL )
1486 msg_Err( p_vout, "cannot allocate VideoWindow" );
1491 p_vout->p_sys->p_window->Show();
1497 /*****************************************************************************
1498 * BeosDisplay: close and reset BeOS device
1499 *****************************************************************************
1500 * Returns all resources allocated by BeosOpenDisplay and restore the original
1501 * state of the device.
1502 *****************************************************************************/
1503 static void BeosCloseDisplay( vout_thread_t *p_vout )
1505 VideoWindow * p_win = p_vout->p_sys->p_window;
1506 /* Destroy the video window */
1507 if( p_win != NULL && !p_win->teardownwindow)
1510 p_win->teardownwindow = true;