]> git.sesse.net Git - vlc/blob - plugins/macosx/vout_macosx.c
Some heavy changes today:
[vlc] / plugins / macosx / vout_macosx.c
1 /*****************************************************************************
2  * vout_macosx.c: MacOS X video output plugin
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  *
6  * Authors: Colin Delacroix <colin@zoy.org>
7  *          Florian G. Pflug <fgp@phlo.org>
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 <errno.h>                                                 /* ENOMEM */
28 #include <stdlib.h>                                                /* free() */
29 #include <string.h>                                            /* strerror() */
30
31 #include <videolan/vlc.h>
32
33 #include "interface.h"
34
35 #include "video.h"
36 #include "video_output.h"
37
38 #include "macosx.h"
39
40 #include <QuickTime/QuickTime.h>
41
42 /*****************************************************************************
43  * vout_sys_t: MacOS X video output method descriptor
44  *****************************************************************************
45  * This structure is part of the video output thread descriptor.
46  * It describes the MacOS X specific properties of an output thread.
47  *****************************************************************************/
48 typedef unsigned int yuv2_data_t ;
49 typedef struct vout_sys_s
50 {
51     osx_com_t osx_communication ;
52
53     ImageDescriptionHandle h_img_descr ;
54     ImageSequence i_seq ;   
55     unsigned int c_codec ;
56     MatrixRecordPtr p_matrix ;
57     
58     yuv2_data_t *p_yuv2 ;
59     unsigned i_yuv2_size ;
60     PlanarPixmapInfoYUV420 s_ppiy420 ;
61 } vout_sys_t;
62
63
64 /*****************************************************************************
65  * Local prototypes
66  *****************************************************************************/
67 static int  vout_Probe     ( probedata_t *p_data );
68 static int  vout_Create    ( struct vout_thread_s * );
69 static int  vout_Init      ( struct vout_thread_s * );
70 static void vout_End       ( struct vout_thread_s * );
71 static void vout_Destroy   ( struct vout_thread_s * );
72 static int  vout_Manage    ( struct vout_thread_s * );
73 static void vout_Display   ( struct vout_thread_s * );
74
75 /* OS Specific */
76 static void fillout_PPIYUV420( picture_t *p_y420, PlanarPixmapInfoYUV420 *p_ppiy420 ) ;
77 static void fillout_ImageDescription(ImageDescriptionHandle h_descr, unsigned int i_with, unsigned int i_height, unsigned int c_codec) ;
78 static void fillout_ScalingMatrix( vout_thread_t *p_vout ) ;
79 static OSErr new_QTSequence(ImageSequence *i_seq, CGrafPtr p_port, ImageDescriptionHandle h_descr, MatrixRecordPtr p_matrix) ;
80 static int create_QTSequenceBestCodec( vout_thread_t *p_vout ) ;
81 static void dispose_QTSequence( vout_thread_t *p_vout ) ;
82 static void convert_Y420_to_YUV2( picture_t *p_y420, yuv2_data_t *p_yuv2 ) ;
83
84 /*****************************************************************************
85  * Functions exported as capabilities. They are declared as static so that
86  * we don't pollute the namespace too much.
87  *****************************************************************************/
88 void _M( vout_getfunctions )( function_list_t * p_function_list )
89 {
90     p_function_list->pf_probe = vout_Probe;
91     p_function_list->functions.vout.pf_create     = vout_Create;
92     p_function_list->functions.vout.pf_init       = vout_Init;
93     p_function_list->functions.vout.pf_end        = vout_End;
94     p_function_list->functions.vout.pf_destroy    = vout_Destroy;
95     p_function_list->functions.vout.pf_manage     = vout_Manage;
96     p_function_list->functions.vout.pf_display    = vout_Display;
97     p_function_list->functions.vout.pf_setpalette = NULL;
98 }
99
100 /*****************************************************************************
101  * intf_Probe: return a score
102  *****************************************************************************/
103 static int vout_Probe( probedata_t *p_data )
104 {
105     if( TestMethod( VOUT_METHOD_VAR, "macosx" ) )
106     {
107         return( 999 );
108     }
109
110     return( 100 );
111 }
112
113 /*****************************************************************************
114  * vout_Create: allocates MacOS X video thread output method
115  *****************************************************************************
116  * This function allocates and initializes a MacOS X vout method.
117  *****************************************************************************/
118 static int vout_Create( vout_thread_t *p_vout )
119 {
120     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
121     if( p_vout->p_sys == NULL )
122     {
123         intf_ErrMsg( "error: %s", strerror( ENOMEM ) );
124         return( 1 );
125     }
126     p_vout->p_sys->h_img_descr = (ImageDescriptionHandle)NewHandleClear( sizeof( ImageDescription ) ) ;
127     p_vout->p_sys->p_matrix = (MatrixRecordPtr)malloc( sizeof( MatrixRecord ) ) ;
128     p_vout->p_sys->c_codec = 'NONE' ;
129
130     EnterMovies() ;
131
132     return( 0 );
133 }
134
135 /*****************************************************************************
136  * vout_Init: initialize video thread output method
137  *****************************************************************************/
138 static int vout_Init( vout_thread_t *p_vout )
139 {
140     p_vout->b_need_render = 0 ;
141     p_vout->i_bytes_per_line = p_vout->i_width ;
142     p_vout->p_sys->c_codec = 'NONE' ;
143     p_vout->p_sys->osx_communication.i_changes |= OSX_VOUT_INTF_REQUEST_QDPORT ;
144     
145     return 0 ;
146 }
147
148 /*****************************************************************************
149  * vout_End: terminate video thread output method
150  *****************************************************************************/
151 static void vout_End( vout_thread_t *p_vout )
152 {
153     dispose_QTSequence( p_vout ) ;
154     p_vout->p_sys->osx_communication.i_changes |= OSX_VOUT_INTF_RELEASE_QDPORT ;
155 }
156
157 /*****************************************************************************
158  * vout_Destroy: destroy video thread output method
159  *****************************************************************************/
160 static void vout_Destroy( vout_thread_t *p_vout )
161 {
162     free( p_vout->p_sys->p_matrix ) ;
163     DisposeHandle( (Handle)p_vout->p_sys->h_img_descr ) ;
164     free( p_vout->p_sys );
165 }
166
167 /*****************************************************************************
168  * vout_Manage: handle events
169  *****************************************************************************
170  * This function should be called regularly by video output thread. It manages
171  * console events. It returns a non null value on error.
172  *****************************************************************************/
173 static int vout_Manage( vout_thread_t *p_vout )
174 {    
175       if ( p_vout->p_sys->osx_communication.i_changes & OSX_INTF_VOUT_QDPORT_CHANGE ) {
176           dispose_QTSequence( p_vout ) ;
177           create_QTSequenceBestCodec( p_vout ) ;
178       }
179       else if ( p_vout->p_sys->osx_communication.i_changes & OSX_INTF_VOUT_SIZE_CHANGE ) {
180           if ( p_vout->p_sys->c_codec != 'NONE' ) {
181               fillout_ScalingMatrix( p_vout ) ;
182               SetDSequenceMatrix( p_vout->p_sys->i_seq, p_vout->p_sys->p_matrix ) ;
183           }
184       }
185
186       p_vout->p_sys->osx_communication.i_changes &= ~( 
187           OSX_INTF_VOUT_QDPORT_CHANGE |
188           OSX_INTF_VOUT_SIZE_CHANGE
189       ) ;
190
191     return 0 ;
192 }
193
194
195 /*****************************************************************************
196  * vout_OSX_Display: displays previously rendered output
197  *****************************************************************************
198  * This function send the currently rendered image to image, waits until
199  * it is displayed and switch the two rendering buffers, preparing next frame.
200  *****************************************************************************/
201 void vout_Display( vout_thread_t *p_vout )
202 {
203     CodecFlags out_flags ;
204
205     switch (p_vout->p_sys->c_codec)
206     {
207         case 'yuv2':
208             convert_Y420_to_YUV2(p_vout->p_rendered_pic, p_vout->p_sys->p_yuv2) ;
209             DecompressSequenceFrameS(
210                 p_vout->p_sys->i_seq,
211                 (void *)p_vout->p_sys->p_yuv2,
212                 p_vout->p_sys->i_yuv2_size,
213                 codecFlagUseScreenBuffer,
214                 &out_flags,
215                 nil
216             ) ;
217             break ;
218         case 'y420':
219             fillout_PPIYUV420(p_vout->p_rendered_pic, &p_vout->p_sys->s_ppiy420) ;
220             DecompressSequenceFrameS(
221                 p_vout->p_sys->i_seq,
222                 (void *)&p_vout->p_sys->s_ppiy420,
223                 sizeof(PlanarPixmapInfoYUV420),
224                 codecFlagUseScreenBuffer,
225                 &out_flags,
226                 nil
227             ) ;            
228             break ;
229        default:
230            intf_WarnMsg( 1, "vout_macosx: vout_Display called, but no codec available" ) ;
231     }
232 }
233
234 static void fillout_PPIYUV420( picture_t *p_y420, PlanarPixmapInfoYUV420 *p_ppiy420 )
235 {
236     p_ppiy420->componentInfoY.offset = (void *)p_y420->p_y - (void *)p_ppiy420 ;
237     p_ppiy420->componentInfoY.rowBytes = p_y420->i_width ;
238     p_ppiy420->componentInfoCb.offset = (void *)p_y420->p_u - (void *)p_ppiy420 ;
239     p_ppiy420->componentInfoCb.rowBytes = p_y420->i_width / 2;
240     p_ppiy420->componentInfoCr.offset = (void *)p_y420->p_v - (void *)p_ppiy420 ;
241     p_ppiy420->componentInfoCr.rowBytes = p_y420->i_width / 2;
242 }
243
244
245 static void fillout_ImageDescription(ImageDescriptionHandle h_descr, unsigned int i_width, unsigned int i_height, unsigned int c_codec)
246 {
247     ImageDescriptionPtr p_descr ;
248
249     HLock((Handle)h_descr) ;
250     p_descr = *h_descr ;
251     p_descr->idSize = sizeof(ImageDescription) ;
252     p_descr->cType = c_codec ;
253     p_descr->resvd1 = 0 ; //Reserved
254     p_descr->resvd2 = 0 ; //Reserved
255     p_descr->dataRefIndex = 0 ; //Reserved
256     p_descr->version = 1 ; //
257     p_descr->revisionLevel = 0 ;
258     p_descr->vendor = 'appl' ; //How do we get a vendor id??
259     p_descr->width = i_width  ;
260     p_descr->height = i_height ;
261     p_descr->hRes = Long2Fix(72) ;
262     p_descr->vRes = Long2Fix(72) ;
263     p_descr->spatialQuality = codecLosslessQuality ;
264     p_descr->frameCount = 1 ;
265     p_descr->clutID = -1 ; //We don't need a color table
266     
267     switch (c_codec)
268     {
269         case 'yuv2':
270             p_descr->dataSize=i_width * i_height * 2 ;
271             p_descr->depth = 24 ;
272             break ;
273         case 'y420':
274             p_descr->dataSize=i_width * i_height * 1.5 ;
275             p_descr->depth = 12 ;
276             break ;
277     }
278     
279     HUnlock((Handle)h_descr) ;
280 }
281
282 static void fillout_ScalingMatrix( vout_thread_t *p_vout)
283 {
284         Rect s_rect ;
285         Fixed factor_x ;
286         Fixed factor_y ;
287                 
288         GetPortBounds( p_vout->p_sys->osx_communication.p_qdport, &s_rect ) ;
289 //      if (((s_rect.right - s_rect.left) / ((float) p_vout->i_width)) < ((s_rect.bottom - s_rect.top) / ((float) p_vout->i_height)))
290                 factor_x = FixDiv(Long2Fix(s_rect.right - s_rect.left), Long2Fix(p_vout->i_width)) ;
291 //      else
292                 factor_y = FixDiv(Long2Fix(s_rect.bottom - s_rect.top), Long2Fix(p_vout->i_height)) ;
293         
294         SetIdentityMatrix(p_vout->p_sys->p_matrix) ;
295         ScaleMatrix( p_vout->p_sys->p_matrix, factor_x, factor_y, Long2Fix(0), Long2Fix(0) ) ;
296 }
297
298 static OSErr new_QTSequence( ImageSequence *i_seq, CGrafPtr p_qdport, ImageDescriptionHandle h_descr, MatrixRecordPtr p_matrix )
299 {
300     return DecompressSequenceBeginS(
301         i_seq, 
302         h_descr,
303         NULL,
304         0,
305         p_qdport,
306         NULL, //device to display (is set implicit via the qdPort)
307         NULL, //src-rect
308         p_matrix, //matrix
309         0, //just do plain copying
310         NULL, //no mask region
311         codecFlagUseScreenBuffer,
312         codecLosslessQuality,
313         (DecompressorComponent) bestSpeedCodec
314     ) ;
315 }
316
317 static int create_QTSequenceBestCodec( vout_thread_t *p_vout )
318 {
319     if ( p_vout->p_sys->osx_communication.p_qdport == nil)
320     {
321         p_vout->p_sys->c_codec = 'NONE' ;
322         return 1 ;
323     }
324
325     SetPort( p_vout->p_sys->osx_communication.p_qdport ) ;
326     fillout_ScalingMatrix( p_vout ) ;
327     fillout_ImageDescription(
328         p_vout->p_sys->h_img_descr,
329         p_vout->i_width,
330         p_vout->i_height,
331         'y420'
332     ) ;
333     if ( !new_QTSequence(
334             &p_vout->p_sys->i_seq,
335             p_vout->p_sys->osx_communication.p_qdport,
336             p_vout->p_sys->h_img_descr,
337             p_vout->p_sys->p_matrix
338         ) )
339     {
340         p_vout->p_sys->c_codec = 'y420' ;
341         return 0 ;
342     }
343    
344     p_vout->p_sys->c_codec = 'NONE' ;
345     return 1 ;
346 }
347
348 static void dispose_QTSequence( vout_thread_t *p_vout )
349 {
350     if (p_vout->p_sys->c_codec == 'NONE')
351         return ;
352         
353     CDSequenceEnd( p_vout->p_sys->i_seq ) ;
354     switch (p_vout->p_sys->c_codec)
355     {
356         case 'yuv2':
357             free( (void *)p_vout->p_sys->p_yuv2 ) ;
358             p_vout->p_sys->i_yuv2_size = 0 ;
359             break ;
360         default:
361             break ;            
362     }
363     p_vout->p_sys->c_codec = 'NONE' ;
364 }
365
366 static void convert_Y420_to_YUV2( picture_t *p_y420, yuv2_data_t *p_yuv2 )
367 {
368     unsigned int width = p_y420->i_width, height = p_y420->i_height ;
369     unsigned int x, y ;
370     
371     for( x=0; x < height; x++ )
372     {
373         for( y=0; y < (width/2); y++ )
374         {
375             p_yuv2[(width/2)*x + y] =
376                 (p_y420->p_y[width*x + 2*y]) << 24 |
377                 ((p_y420->p_u[(width/2)*(x/2) + y] ^ 0x80) << 16) |
378                 (p_y420->p_y[width*x + 2*y + 1] << 8) |
379                 (p_y420->p_v[(width/2)*(x/2) + y] ^ 0x80) ;   
380         }
381     }
382 }