]> git.sesse.net Git - vlc/blob - plugins/beos/vout_beos.cpp
. no need to add "\n" at the end of intf_*Msg() messages anymore.
[vlc] / plugins / beos / vout_beos.cpp
1 /*****************************************************************************
2  * vout_beos.cpp: beos video output display method
3  *****************************************************************************
4  * Copyright (C) 2000 VideoLAN
5  *
6  * Authors:
7  * Jean-Marc Dressler
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include "defs.h"
28
29 #include <errno.h>                                                 /* ENOMEM */
30 #include <stdlib.h>                                                /* free() */
31 #include <stdio.h>
32 #include <string.h>                                            /* strerror() */
33 #include <kernel/OS.h>
34 #include <View.h>
35 #include <Application.h>
36 #include <DirectWindow.h>
37 #include <Locker.h>
38 #include <malloc.h>
39 #include <string.h>
40
41 extern "C"
42 {
43 #include "config.h"
44 #include "common.h"
45 #include "threads.h"
46 #include "mtime.h"
47 #include "plugins.h"
48
49 #include "video.h"
50 #include "video_output.h"
51
52 #include "intf_msg.h"
53 #include "interface.h" /* XXX maybe to remove if beos_window.h is splitted */
54
55 #include "main.h"
56 }
57
58 #include "beos_window.h"
59
60 #define WIDTH 128
61 #define HEIGHT 64
62 #define BITS_PER_PLANE 16
63 #define BYTES_PER_PIXEL 2
64
65 /*****************************************************************************
66  * vout_sys_t: dummy video output method descriptor
67  *****************************************************************************
68  * This structure is part of the video output thread descriptor.
69  * It describes the dummy specific properties of an output thread.
70  *****************************************************************************/
71  
72 typedef struct vout_sys_s
73 {
74     VideoWindow *         p_window;
75     
76     byte_t *              pp_buffer[2];
77     s32                   i_width;
78     s32                   i_height;
79 } vout_sys_t;
80
81
82 /*****************************************************************************
83  * beos_GetAppWindow : retrieve a BWindow pointer from the window name
84  *****************************************************************************/
85
86 BWindow *beos_GetAppWindow(char *name)
87 {
88     int32       index;
89     BWindow     *window;
90     
91     for (index = 0 ; ; index++)
92     {
93         window = be_app->WindowAt(index);
94         if (window == NULL)
95             break;
96         if (window->LockWithTimeout(200000) == B_OK)
97         {
98             if (strcmp(window->Name(), name) == 0)
99             {
100                 window->Unlock();
101                 break;
102             }
103             window->Unlock();
104         }
105     }
106     return window; 
107 }
108
109 /*****************************************************************************
110  * DrawingThread : thread that really does the drawing
111  *****************************************************************************/
112
113 int32 DrawingThread(void *data)
114 {
115     uint32 i, j, y;
116     uint64 *pp, *qq;
117     uint8 *p, *q;
118     uint32 byte_width;
119     uint32 height, bytes_per_line;
120     clipping_rect *clip;
121
122     VideoWindow *w;
123     w = (VideoWindow*) data;
124     
125     while(!w->fConnectionDisabled)
126     {
127         w->locker->Lock();
128         if( w->fConnected )
129         {
130             if( w->fDirty && (!w->fReady || w->i_screen_depth != w->p_vout->i_screen_depth) )
131             {
132                 bytes_per_line = w->fRowBytes;
133                 for( i=0 ; i < w->fNumClipRects ; i++ )
134                 {
135                     clip = &(w->fClipList[i]);
136                     height = clip->bottom - clip->top +1;
137                     byte_width = w->i_bytes_per_pixel * ((clip->right - clip->left)+1);
138                     p = w->fBits + clip->top*w->fRowBytes + clip->left * w->i_bytes_per_pixel;
139                     for( y=0 ; y < height ; )
140                     {
141                         pp = (uint64*) p;
142                         for( j=0 ; j < byte_width/64 ; j++ )
143                         {
144                             *pp++ = 0;
145                             *pp++ = 0; 
146                             *pp++ = 0;
147                             *pp++ = 0; 
148                             *pp++ = 0;
149                             *pp++ = 0; 
150                             *pp++ = 0;
151                             *pp++ = 0; 
152                         }
153                         memset( pp , 0, byte_width & 63 );
154                         y++;
155                         p += bytes_per_line;
156                     }
157                 }
158             }
159             else if( w->fDirty )
160             {
161                 bytes_per_line = w->fRowBytes;
162                 for( i=0 ; i < w->fNumClipRects ; i++ )
163                 {
164                     clip = &(w->fClipList[i]);
165                     height = clip->bottom - clip->top +1;
166                     byte_width = w->i_bytes_per_pixel * ((clip->right - clip->left)+1);
167                     p = w->fBits + clip->top * bytes_per_line + clip->left * w->i_bytes_per_pixel;
168                     q = w->p_vout->p_sys->pp_buffer[ !w->p_vout->i_buffer_index ] +
169                         clip->top * w->p_vout->i_bytes_per_line + clip->left *
170                         w->p_vout->i_bytes_per_pixel;
171                     for( y=0 ; y < height ; )
172                     {
173                         pp = (uint64*) p;
174                         qq = (uint64*) q;
175                         for( j=0 ; j < byte_width/64 ; j++ )
176                         {
177                             *pp++ = *qq++;
178                             *pp++ = *qq++; 
179                             *pp++ = *qq++;
180                             *pp++ = *qq++; 
181                             *pp++ = *qq++;
182                             *pp++ = *qq++; 
183                             *pp++ = *qq++;
184                             *pp++ = *qq++; 
185                         }
186                         memcpy( pp , qq, byte_width & 63 );
187                         y++;
188                         p += bytes_per_line;
189                         q += w->p_vout->p_sys->i_width * w->p_vout->i_bytes_per_pixel;
190                     }
191                 }
192             }
193             w->fDirty = false;
194         }
195         w->locker->Unlock();
196         snooze( 20000 );
197     }
198     return B_OK;
199 }
200
201 /*****************************************************************************
202  * VideoWindow constructor and destructor
203  *****************************************************************************/
204
205 VideoWindow::VideoWindow(BRect frame, const char *name, vout_thread_t *p_video_output )
206         : BDirectWindow(frame, name, B_TITLED_WINDOW, B_NOT_RESIZABLE|B_NOT_ZOOMABLE)
207 {
208     BView * view;
209
210     fReady = false;
211     fConnected = false;
212     fConnectionDisabled = false;
213     locker = new BLocker();
214     fClipList = NULL;
215     fNumClipRects = 0;
216     p_vout = p_video_output;
217
218     view = new BView(Bounds(), "", B_FOLLOW_ALL, B_WILL_DRAW);
219     view->SetViewColor(B_TRANSPARENT_32_BIT);
220     AddChild(view);
221 /*
222     if(!SupportsWindowMode())
223     {
224         SetFullScreen(true);
225     }
226 */
227     fDirty = false;
228     fDrawThreadID = spawn_thread(DrawingThread, "drawing_thread",
229                     B_DISPLAY_PRIORITY, (void*) this);
230     resume_thread(fDrawThreadID);
231     Show();
232 }
233
234 VideoWindow::~VideoWindow()
235 {
236     int32 result;
237
238     fConnectionDisabled = true;
239     Hide();
240     Sync();
241     wait_for_thread(fDrawThreadID, &result);
242     free(fClipList);
243     delete locker;
244 }
245
246 /*****************************************************************************
247  * VideoWindow::DirectConnected
248  *****************************************************************************/
249
250 void VideoWindow::DirectConnected(direct_buffer_info *info)
251 {
252     unsigned int i;
253
254     if(!fConnected && fConnectionDisabled)
255     {
256         return;
257     }
258     locker->Lock();
259
260     switch(info->buffer_state & B_DIRECT_MODE_MASK)
261     {
262     case B_DIRECT_START:
263         fConnected = true;
264     case B_DIRECT_MODIFY:
265         fBits = (uint8*)((char*)info->bits +
266         (info->window_bounds.top) * info->bytes_per_row +
267         (info->window_bounds.left) * (info->bits_per_pixel>>3));;
268         
269         i_bytes_per_pixel = info->bits_per_pixel >> 3;
270         i_screen_depth = info->bits_per_pixel;
271         
272         fRowBytes = info->bytes_per_row;
273         fFormat = info->pixel_format;
274         fBounds = info->window_bounds;
275         fDirty = true;
276
277         if(fClipList)
278         {
279             free(fClipList);
280             fClipList = NULL;
281         }
282         fNumClipRects = info->clip_list_count;
283         fClipList = (clipping_rect*) malloc(fNumClipRects*sizeof(clipping_rect));
284         for( i=0 ; i<info->clip_list_count ; i++ )
285         {
286             fClipList[i].top = info->clip_list[i].top - info->window_bounds.top;
287             fClipList[i].left = info->clip_list[i].left - info->window_bounds.left;
288             fClipList[i].bottom = info->clip_list[i].bottom - info->window_bounds.top;
289             fClipList[i].right = info->clip_list[i].right - info->window_bounds.left;
290         }
291         break;
292     case B_DIRECT_STOP:
293         fConnected = false;
294         break;
295     }
296     locker->Unlock();
297 }
298
299 /*****************************************************************************
300  * VideoWindow::MessageReceived
301  *****************************************************************************/
302
303 void VideoWindow::MessageReceived( BMessage * p_message )
304 {
305     BWindow * p_win;
306     
307     switch( p_message->what )
308     {
309     case B_KEY_DOWN:
310         // post the message to the interface window which will handle it
311         p_win = beos_GetAppWindow( "interface" );
312         if( p_win != NULL )
313         {
314             p_win->PostMessage( p_message );
315         }
316         break;
317     
318     default:
319         BWindow::MessageReceived( p_message );
320         break;
321     }
322 }
323
324 /*****************************************************************************
325  * VideoWindow::QuitRequested
326  *****************************************************************************/
327
328 bool VideoWindow::QuitRequested()
329 {
330     return( true );
331 }
332
333 extern "C"
334 {
335
336 /*****************************************************************************
337  * Local prototypes
338  *****************************************************************************/
339 static int     BeosOpenDisplay   ( vout_thread_t *p_vout );
340 static void    BeosCloseDisplay  ( vout_thread_t *p_vout );
341
342 /*****************************************************************************
343  * vout_BeCreate: allocates dummy video thread output method
344  *****************************************************************************
345  * This function allocates and initializes a dummy vout method.
346  *****************************************************************************/
347 int vout_BeCreate( vout_thread_t *p_vout, char *psz_display,
348                     int i_root_window, void *p_data )
349 {
350     /* Allocate structure */
351     p_vout->p_sys = (vout_sys_t*) malloc( sizeof( vout_sys_t ) );
352     if( p_vout->p_sys == NULL )
353     {
354         intf_ErrMsg( "error: %s", strerror(ENOMEM) );
355         return( 1 );
356     }
357     
358     /* Set video window's size */
359     p_vout->i_width =  main_GetIntVariable( VOUT_WIDTH_VAR, VOUT_WIDTH_DEFAULT );
360     p_vout->i_height = main_GetIntVariable( VOUT_HEIGHT_VAR, VOUT_HEIGHT_DEFAULT );
361
362     /* Open and initialize device */
363     if( BeosOpenDisplay( p_vout ) )
364     {
365         intf_ErrMsg("vout error: can't open display");
366         free( p_vout->p_sys );
367         return( 1 );
368     }
369
370     return( 0 );
371 }
372
373 /*****************************************************************************
374  * vout_BeInit: initialize dummy video thread output method
375  *****************************************************************************/
376 int vout_BeInit( vout_thread_t *p_vout )
377 {
378     VideoWindow * p_win = p_vout->p_sys->p_window;
379     u32 i_page_size;
380
381     p_win->locker->Lock();
382
383     i_page_size =   p_vout->i_width * p_vout->i_height * p_vout->i_bytes_per_pixel;
384     
385     p_vout->p_sys->i_width =         p_vout->i_width;
386     p_vout->p_sys->i_height =        p_vout->i_height;    
387
388     /* Allocate memory for the 2 display buffers */
389     p_vout->p_sys->pp_buffer[0] = (byte_t*) malloc( i_page_size );
390     p_vout->p_sys->pp_buffer[1] = (byte_t*) malloc( i_page_size );
391     if( p_vout->p_sys->pp_buffer[0] == NULL  || p_vout->p_sys->pp_buffer[0] == NULL )
392     {
393         intf_ErrMsg("vout error: can't allocate video memory (%s)", strerror(errno) );
394         if( p_vout->p_sys->pp_buffer[0] != NULL ) free( p_vout->p_sys->pp_buffer[0] );
395         if( p_vout->p_sys->pp_buffer[1] != NULL ) free( p_vout->p_sys->pp_buffer[1] );
396         p_win->locker->Unlock();
397         return( 1 );
398     }
399
400     /* Set and initialize buffers */
401     vout_SetBuffers( p_vout, p_vout->p_sys->pp_buffer[0],
402                      p_vout->p_sys->pp_buffer[1] );
403
404     p_win->locker->Unlock();
405     return( 0 );
406 }
407
408 /*****************************************************************************
409  * vout_BeEnd: terminate dummy video thread output method
410  *****************************************************************************/
411 void vout_BeEnd( vout_thread_t *p_vout )
412 {
413    VideoWindow * p_win = p_vout->p_sys->p_window;
414    
415    p_win->Lock();
416    
417    free( p_vout->p_sys->pp_buffer[0] );
418    free( p_vout->p_sys->pp_buffer[1] );
419
420    p_win->fReady = false;
421    p_win->Unlock();   
422 }
423
424 /*****************************************************************************
425  * vout_BeDestroy: destroy dummy video thread output method
426  *****************************************************************************
427  * Terminate an output method created by DummyCreateOutputMethod
428  *****************************************************************************/
429 void vout_BeDestroy( vout_thread_t *p_vout )
430 {
431     BeosCloseDisplay( p_vout );
432     
433     free( p_vout->p_sys );
434 }
435
436 /*****************************************************************************
437  * vout_BeManage: handle dummy events
438  *****************************************************************************
439  * This function should be called regularly by video output thread. It manages
440  * console events. It returns a non null value on error.
441  *****************************************************************************/
442 int vout_BeManage( vout_thread_t *p_vout )
443 {
444     if( p_vout->i_changes & VOUT_SIZE_CHANGE )
445     {
446         intf_DbgMsg("resizing window");
447         p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
448
449         /* Resize window */
450         p_vout->p_sys->p_window->ResizeTo( p_vout->i_width, p_vout->i_height );
451
452         /* Destroy XImages to change their size */
453         vout_BeEnd( p_vout );
454
455         /* Recreate XImages. If SysInit failed, the thread can't go on. */
456         if( vout_BeInit( p_vout ) )
457         {
458             intf_ErrMsg("error: can't resize display");
459             return( 1 );
460         }
461
462         /* Tell the video output thread that it will need to rebuild YUV
463          * tables. This is needed since convertion buffer size may have changed */
464         p_vout->i_changes |= VOUT_YUV_CHANGE;
465         intf_Msg("Video display resized (%dx%d)", p_vout->i_width, p_vout->i_height);
466     }
467     return( 0 );
468 }
469
470 /*****************************************************************************
471  * vout_BeDisplay: displays previously rendered output
472  *****************************************************************************
473  * This function send the currently rendered image to dummy image, waits until
474  * it is displayed and switch the two rendering buffers, preparing next frame.
475  *****************************************************************************/
476 void vout_BeDisplay( vout_thread_t *p_vout )
477 {
478     VideoWindow * p_win = p_vout->p_sys->p_window;
479     
480     p_win->locker->Lock();
481     p_vout->i_buffer_index = ++p_vout->i_buffer_index & 1;
482     p_win->fReady = true;
483     p_win->fDirty = true;
484     p_win->locker->Unlock();
485 }
486
487 /* following functions are local */
488
489 /*****************************************************************************
490  * BeosOpenDisplay: open and initialize dummy device
491  *****************************************************************************
492  * XXX?? The framebuffer mode is only provided as a fast and efficient way to
493  * display video, providing the card is configured and the mode ok. It is
494  * not portable, and is not supposed to work with many cards. Use at your
495  * own risk !
496  *****************************************************************************/
497
498 static int BeosOpenDisplay( vout_thread_t *p_vout )
499
500     /* Create the DirectDraw video window */
501     p_vout->p_sys->p_window =
502         new VideoWindow(  BRect( 100, 100, 100+p_vout->i_width-1, 100+p_vout->i_height-1 ), "VideoLAN", p_vout );
503     if( p_vout->p_sys->p_window == 0 )
504     {
505         free( p_vout->p_sys );
506         intf_ErrMsg( "error: cannot allocate memory for VideoWindow" );
507         return( 1 );
508     }   
509     VideoWindow * p_win = p_vout->p_sys->p_window;
510     
511     /* Wait until DirectConnected has been called */
512     while( !p_win->fConnected )
513         snooze( 50000 );
514
515     p_vout->i_screen_depth =         p_win->i_screen_depth;
516     p_vout->i_bytes_per_pixel =      p_win->i_bytes_per_pixel;
517     p_vout->i_bytes_per_line =       p_vout->i_width*p_win->i_bytes_per_pixel;
518     
519     switch( p_vout->i_screen_depth )
520     {
521     case 8:
522         intf_ErrMsg( "vout error: 8 bit mode not fully supported" );
523         break;
524     case 15:
525         p_vout->i_red_mask =        0x7c00;
526         p_vout->i_green_mask =      0x03e0;
527         p_vout->i_blue_mask =       0x001f;
528         break;
529     case 16:
530         p_vout->i_red_mask =        0xf800;
531         p_vout->i_green_mask =      0x07e0;
532         p_vout->i_blue_mask =       0x001f;
533         break;
534     case 24:
535     case 32:
536     default:
537         p_vout->i_red_mask =        0xff0000;
538         p_vout->i_green_mask =      0x00ff00;
539         p_vout->i_blue_mask =       0x0000ff;
540         break;
541     }
542
543     return( 0 );
544 }
545
546 /*****************************************************************************
547  * BeosDisplay: close and reset dummy device
548  *****************************************************************************
549  * Returns all resources allocated by BeosOpenDisplay and restore the original
550  * state of the device.
551  *****************************************************************************/
552 static void BeosCloseDisplay( vout_thread_t *p_vout )
553 {    
554     /* Destroy the video window */
555     p_vout->p_sys->p_window->Lock();
556     p_vout->p_sys->p_window->Quit();
557 }
558
559 } /* extern "C" */