12296
|
1 /*
|
|
2 vo_quartz.c
|
|
3
|
|
4 by Nicolas Plourde <nicolasplourde@hotmail.com>
|
|
5
|
|
6 Copyright (c) Nicolas Plourde - April 2004
|
12414
|
7
|
|
8 YUV support Copyright (C) 2004 Romain Dolbeau <romain@dolbeau.org>
|
12296
|
9
|
|
10 MPlayer Mac OSX Quartz video out module.
|
|
11
|
12432
|
12 todo: -'plist' resource
|
|
13 -Redo event handling.
|
|
14 -Choose fullscreen display device (-xineramascreen / -multiscreen).
|
12296
|
15 -resize black bar without CGContext
|
|
16 -rootwin
|
|
17 -non-blocking event
|
|
18 -(add sugestion here)
|
12414
|
19
|
|
20 Direct YUV support is functional, and is now enabled
|
|
21 by default. To constrain what format should be used,
|
|
22 use the format=XXX video filter (i.e. -vf format=uyvy).
|
12120
|
23 */
|
|
24
|
|
25 //SYS
|
|
26 #include <stdio.h>
|
|
27
|
|
28 //OSX
|
|
29 #include <Carbon/Carbon.h>
|
12414
|
30 #include <QuickTime/QuickTime.h>
|
12120
|
31
|
|
32 //MPLAYER
|
|
33 #include "config.h"
|
12414
|
34 #include "fastmemcpy.h"
|
12120
|
35 #include "video_out.h"
|
|
36 #include "video_out_internal.h"
|
|
37 #include "aspect.h"
|
12414
|
38 #include "mp_msg.h"
|
|
39 #include "m_option.h"
|
12120
|
40
|
|
41 #include "../input/input.h"
|
|
42 #include "../input/mouse.h"
|
|
43
|
|
44 #include "vo_quartz.h"
|
|
45
|
12296
|
46 static vo_info_t info =
|
|
47 {
|
|
48 "Mac OSX (Quartz)",
|
|
49 "quartz",
|
12414
|
50 "Nicolas Plourde <nicolasplourde@hotmail.com>, Romain Dolbeau <romain@dolbeau.org>",
|
12296
|
51 ""
|
12120
|
52 };
|
|
53
|
12296
|
54 LIBVO_EXTERN(quartz)
|
12120
|
55
|
12414
|
56 static uint32_t image_width;
|
|
57 static uint32_t image_height;
|
|
58 static uint32_t image_depth;
|
|
59 static uint32_t image_format;
|
|
60 static uint32_t image_size;
|
|
61 static uint32_t image_buffer_size;
|
12432
|
62 static char *image_data;
|
12414
|
63
|
12432
|
64 static ImageSequence seqId;
|
12414
|
65 static CodecType image_qtcodec;
|
|
66 static PlanarPixmapInfoYUV420 *P;
|
12424
|
67 static struct
|
|
68 {
|
|
69 ImageDescriptionHandle desc;
|
|
70 Handle extension_colr;
|
|
71 Handle extension_fiel;
|
|
72 Handle extension_clap;
|
|
73 Handle extension_pasp;
|
12414
|
74 } yuv_qt_stuff;
|
12432
|
75 static MatrixRecord matrix;
|
12414
|
76 static int EnterMoviesDone = 0;
|
12120
|
77
|
12296
|
78 extern int vo_ontop;
|
|
79 extern int vo_fs;
|
12120
|
80
|
12296
|
81 int int_pause = 0;
|
|
82 float winAlpha = 1;
|
|
83
|
12424
|
84 int device_width;
|
|
85 int device_height;
|
12120
|
86
|
|
87 WindowRef theWindow;
|
12296
|
88
|
|
89 GWorldPtr imgGWorld;
|
|
90
|
|
91 Rect imgRect;
|
|
92 Rect dstRect;
|
|
93 Rect winRect;
|
|
94
|
12120
|
95 CGContextRef context;
|
|
96
|
|
97 #include "../osdep/keycodes.h"
|
12296
|
98 extern void mplayer_put_key(int code);
|
|
99
|
|
100 extern void vo_draw_text(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride));
|
12120
|
101
|
|
102 //PROTOTYPE/////////////////////////////////////////////////////////////////
|
12296
|
103 void window_resized();
|
|
104 void window_ontop();
|
|
105 void window_fullscreen();
|
12120
|
106
|
12296
|
107 static OSStatus MainWindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
|
|
108 static OSStatus MainKeyboardEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
|
|
109 static OSStatus MainMouseEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
|
|
110
|
|
111 static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride)
|
|
112 {
|
12424
|
113 switch (image_format)
|
|
114 {
|
|
115 case IMGFMT_RGB32:
|
|
116 vo_draw_alpha_rgb32(w,h,src,srca,stride,image_data+4*(y0*imgRect.right+x0),4*imgRect.right);
|
|
117 break;
|
|
118 case IMGFMT_YV12:
|
|
119 case IMGFMT_IYUV:
|
|
120 case IMGFMT_I420:
|
|
121 vo_draw_alpha_yv12(w,h,src,srca,stride, ((char*)P) + P->componentInfoY.offset + x0 + y0 * image_width, image_width);
|
|
122 break;
|
|
123 case IMGFMT_UYVY:
|
|
124 //vo_draw_alpha_uyvy(w,h,src,srca,stride,((char*)P) + (x0 + y0 * image_width) * 2,image_width*2);
|
|
125 break;
|
|
126 case IMGFMT_YUY2:
|
|
127 vo_draw_alpha_yuy2(w,h,src,srca,stride,((char*)P) + (x0 + y0 * image_width) * 2,image_width*2);
|
|
128 break;
|
12414
|
129 }
|
12296
|
130 }
|
12120
|
131
|
|
132 //default window event handler
|
12296
|
133 static OSStatus MainWindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData)
|
12120
|
134 {
|
12296
|
135 OSStatus err = noErr;
|
|
136 WindowRef window;
|
|
137 Rect rectPort = {0,0,0,0};
|
|
138 OSStatus result = eventNotHandledErr;
|
|
139 UInt32 class = GetEventClass (event);
|
|
140 UInt32 kind = GetEventKind (event);
|
12120
|
141
|
12296
|
142 GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &window);
|
|
143 if(window)
|
|
144 {
|
|
145 GetWindowPortBounds (window, &rectPort);
|
|
146 }
|
|
147
|
|
148 switch (kind)
|
|
149 {
|
|
150 //close window
|
|
151 case kEventWindowClosed:
|
|
152 HideWindow(window);
|
|
153 mplayer_put_key(KEY_ESC);
|
|
154 break;
|
|
155
|
|
156 //resize window
|
|
157 case kEventWindowBoundsChanged:
|
|
158 window_resized();
|
|
159 flip_page();
|
|
160 break;
|
|
161
|
|
162 default:
|
|
163 err = eventNotHandledErr;
|
|
164 break;
|
12120
|
165 }
|
12296
|
166
|
|
167 return err;
|
12120
|
168 }
|
|
169
|
|
170 //keyboard event handler
|
12296
|
171 static OSStatus MainKeyboardEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData)
|
12120
|
172 {
|
12296
|
173 OSStatus err = noErr;
|
|
174 UInt32 macKeyCode;
|
|
175
|
|
176 GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(macKeyCode), NULL, &macKeyCode);
|
|
177
|
|
178 switch (GetEventKind (event))
|
|
179 {
|
|
180 case kEventRawKeyDown:
|
|
181 {
|
|
182 switch(macKeyCode)
|
|
183 {
|
|
184 case QZ_RETURN: mplayer_put_key(KEY_ENTER);break;
|
|
185 case QZ_ESCAPE: mplayer_put_key(KEY_ESC);break;
|
|
186 case QZ_q: mplayer_put_key('q');break;
|
|
187 case QZ_F1: mplayer_put_key(KEY_F+1);break;
|
|
188 case QZ_F2: mplayer_put_key(KEY_F+2);break;
|
|
189 case QZ_F3: mplayer_put_key(KEY_F+3);break;
|
|
190 case QZ_F4: mplayer_put_key(KEY_F+4);break;
|
|
191 case QZ_F5: mplayer_put_key(KEY_F+5);break;
|
|
192 case QZ_F6: mplayer_put_key(KEY_F+6);break;
|
|
193 case QZ_F7: mplayer_put_key(KEY_F+7);break;
|
|
194 case QZ_F8: mplayer_put_key(KEY_F+8);break;
|
|
195 case QZ_F9: mplayer_put_key(KEY_F+9);break;
|
|
196 case QZ_F10: mplayer_put_key(KEY_F+10);break;
|
|
197 case QZ_F11: mplayer_put_key(KEY_F+11);break;
|
|
198 case QZ_F12: mplayer_put_key(KEY_F+12);break;
|
|
199 case QZ_o: mplayer_put_key('o');break;
|
|
200 case QZ_SPACE: mplayer_put_key(' ');break;
|
|
201 case QZ_p: mplayer_put_key('p');break;
|
|
202 //case QZ_7: mplayer_put_key(shift_key?'/':'7');
|
|
203 //case QZ_PLUS: mplayer_put_key(shift_key?'*':'+');
|
|
204 case QZ_KP_PLUS: mplayer_put_key('+');break;
|
|
205 case QZ_MINUS:
|
|
206 case QZ_KP_MINUS: mplayer_put_key('-');break;
|
|
207 case QZ_TAB: mplayer_put_key('\t');break;
|
|
208 case QZ_PAGEUP: mplayer_put_key(KEY_PAGE_UP);break;
|
|
209 case QZ_PAGEDOWN: mplayer_put_key(KEY_PAGE_DOWN);break;
|
|
210 case QZ_UP: mplayer_put_key(KEY_UP);break;
|
|
211 case QZ_DOWN: mplayer_put_key(KEY_DOWN);break;
|
|
212 case QZ_LEFT: mplayer_put_key(KEY_LEFT);break;
|
|
213 case QZ_RIGHT: mplayer_put_key(KEY_RIGHT);break;
|
|
214 //case QZ_LESS: mplayer_put_key(shift_key?'>':'<'); break;
|
|
215 //case QZ_GREATER: mplayer_put_key('>'); break;
|
|
216 //case QZ_ASTERISK:
|
|
217 case QZ_KP_MULTIPLY: mplayer_put_key('*'); break;
|
|
218 case QZ_SLASH:
|
|
219 case QZ_KP_DIVIDE: mplayer_put_key('/'); break;
|
|
220 case QZ_KP0: mplayer_put_key(KEY_KP0); break;
|
|
221 case QZ_KP1: mplayer_put_key(KEY_KP1); break;
|
|
222 case QZ_KP2: mplayer_put_key(KEY_KP2); break;
|
|
223 case QZ_KP3: mplayer_put_key(KEY_KP3); break;
|
|
224 case QZ_KP4: mplayer_put_key(KEY_KP4); break;
|
|
225 case QZ_KP5: mplayer_put_key(KEY_KP5); break;
|
|
226 case QZ_KP6: mplayer_put_key(KEY_KP6); break;
|
|
227 case QZ_KP7: mplayer_put_key(KEY_KP7); break;
|
|
228 case QZ_KP8: mplayer_put_key(KEY_KP8); break;
|
|
229 case QZ_KP9: mplayer_put_key(KEY_KP9); break;
|
|
230 case QZ_KP_PERIOD: mplayer_put_key(KEY_KPDEC); break;
|
|
231 case QZ_KP_ENTER: mplayer_put_key(KEY_KPENTER); break;
|
|
232 case QZ_LEFTBRACKET: SetWindowAlpha(theWindow, winAlpha-=0.05);break;
|
|
233 case QZ_RIGHTBRACKET: SetWindowAlpha(theWindow, winAlpha+=0.05);break;
|
|
234 case QZ_f: mplayer_put_key('f'); break;
|
|
235 case QZ_t: mplayer_put_key('T'); break;
|
|
236 default:
|
|
237 break;
|
|
238 }
|
|
239 }
|
|
240 break;
|
|
241 default:
|
|
242 err = eventNotHandledErr;
|
|
243 break;
|
|
244 }
|
|
245
|
|
246 return err;
|
|
247 }
|
12120
|
248
|
12296
|
249 //Mouse event handler
|
|
250 static OSStatus MainMouseEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData)
|
|
251 {
|
|
252 OSStatus err = noErr;
|
|
253 WindowPtr tmpWin;
|
|
254 Point mousePos;
|
|
255
|
|
256 GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, 0, sizeof(Point), 0, &mousePos);
|
12120
|
257
|
12296
|
258 switch (GetEventKind (event))
|
12120
|
259 {
|
12296
|
260 case kEventMouseDown:
|
|
261 {
|
|
262 short part = FindWindow(mousePos,&tmpWin);
|
|
263
|
|
264 if(part == inMenuBar)
|
|
265 {
|
|
266 MenuSelect(mousePos);
|
|
267 }
|
|
268 }
|
|
269 break;
|
|
270 default:
|
|
271 err = eventNotHandledErr;
|
|
272 break;
|
12120
|
273 }
|
12296
|
274
|
|
275 HiliteMenu(0);
|
|
276 return err;
|
|
277 }
|
12120
|
278
|
12296
|
279 static uint32_t config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format)
|
|
280 {
|
|
281 WindowAttributes windowAttrs;
|
|
282 CFStringRef titleKey;
|
|
283 CFStringRef windowTitle;
|
|
284 OSStatus result;
|
|
285 GDHandle deviceHdl;
|
|
286 Rect deviceRect;
|
12414
|
287 OSErr qterr;
|
12296
|
288
|
|
289 //Get Main device info///////////////////////////////////////////////////
|
|
290 deviceHdl = GetMainDevice();
|
|
291 deviceRect = (*deviceHdl)->gdRect;
|
|
292
|
|
293 device_width = deviceRect.right;
|
|
294 device_height = deviceRect.bottom;
|
|
295
|
|
296 //misc mplayer setup/////////////////////////////////////////////////////
|
|
297 image_width = width;
|
|
298 image_height = height;
|
12414
|
299 switch (image_format)
|
|
300 {
|
|
301 case IMGFMT_RGB32:
|
12432
|
302 image_depth = 32;
|
12414
|
303 break;
|
|
304 case IMGFMT_YV12:
|
|
305 case IMGFMT_IYUV:
|
|
306 case IMGFMT_I420:
|
|
307 case IMGFMT_UYVY:
|
|
308 case IMGFMT_YUY2:
|
|
309 image_depth = 16;
|
|
310 break;
|
|
311 }
|
|
312 image_size = ((image_width*image_height*image_depth)+7)/8;
|
12296
|
313
|
|
314 vo_fs = flags & VOFLAG_FULLSCREEN;
|
|
315
|
|
316 //get movie aspect
|
|
317 aspect_save_orig(width,height);
|
|
318 aspect_save_prescale(d_width,d_height);
|
|
319 aspect_save_screenres(device_width, device_height);
|
|
320
|
|
321 aspect(&d_width,&d_height,A_NOZOOM);
|
|
322
|
|
323 //Create player window//////////////////////////////////////////////////
|
|
324 windowAttrs = kWindowStandardDocumentAttributes
|
|
325 | kWindowStandardHandlerAttribute
|
|
326 | kWindowLiveResizeAttribute;
|
12425
|
327
|
12432
|
328 windowAttrs &= (~kWindowResizableAttribute);
|
12296
|
329
|
|
330 SetRect(&winRect, 0, 0, d_width, d_height);
|
|
331 SetRect(&dstRect, 0, 0, d_width, d_height);
|
|
332 SetRect(&imgRect, 0, 0, image_width, image_height);
|
|
333
|
|
334 CreateNewWindow(kDocumentWindowClass, windowAttrs, &winRect, &theWindow);
|
|
335
|
|
336 //Set window title
|
|
337 titleKey = CFSTR("MPlayer");
|
|
338 windowTitle = CFCopyLocalizedString(titleKey, NULL);
|
|
339 result = SetWindowTitleWithCFString(theWindow, windowTitle);
|
|
340 CFRelease(titleKey);
|
|
341 CFRelease(windowTitle);
|
|
342
|
|
343 //Install event handler
|
|
344 const EventTypeSpec winEvents[] = { { kEventClassWindow, kEventWindowClosed }, { kEventClassWindow, kEventWindowBoundsChanged } };
|
|
345 const EventTypeSpec keyEvents[] = { { kEventClassKeyboard, kEventRawKeyDown } };
|
|
346 const EventTypeSpec mouseEvents[] = { { kEventClassMouse, kEventMouseDown } };
|
|
347
|
|
348 InstallWindowEventHandler (theWindow, NewEventHandlerUPP (MainWindowEventHandler), GetEventTypeCount(winEvents), winEvents, theWindow, NULL);
|
|
349 InstallWindowEventHandler (theWindow, NewEventHandlerUPP (MainKeyboardEventHandler), GetEventTypeCount(keyEvents), keyEvents, theWindow, NULL);
|
|
350 InstallApplicationEventHandler (NewEventHandlerUPP (MainMouseEventHandler), GetEventTypeCount(mouseEvents), mouseEvents, 0, NULL);
|
|
351
|
12432
|
352 if (!EnterMoviesDone)
|
|
353 {
|
|
354 qterr = EnterMovies();
|
|
355 EnterMoviesDone = 1;
|
|
356 }
|
|
357 else
|
|
358 qterr = 0;
|
|
359
|
|
360 if (qterr)
|
12424
|
361 {
|
12432
|
362 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: EnterMovies (%d)\n", qterr);
|
|
363 }
|
|
364
|
|
365 SetPort(GetWindowPort(theWindow));
|
|
366 SetIdentityMatrix(&matrix);
|
|
367
|
|
368 if ((d_width != width) || (d_height != height))
|
|
369 {
|
|
370 ScaleMatrix(&matrix, FixDiv(Long2Fix(d_width),Long2Fix(width)), FixDiv(Long2Fix(d_height),Long2Fix(height)), 0, 0);
|
|
371 }
|
12433
|
372
|
12432
|
373 switch (image_format)
|
|
374 {
|
|
375 case IMGFMT_RGB32:
|
12424
|
376 {
|
12432
|
377 ImageDescriptionHandle desc;
|
|
378
|
|
379 image_data = calloc(sizeof(image_size),1);
|
|
380 NewGWorldFromPtr (&imgGWorld, k32ARGBPixelFormat, &imgRect, 0, 0, 0, image_data, image_width * 4);
|
|
381 MakeImageDescriptionForPixMap(GetGWorldPixMap(imgGWorld), &desc);
|
|
382 DisposeGWorld(imgGWorld);
|
12424
|
383
|
12432
|
384 qterr = DecompressSequenceBeginS ( &seqId,
|
|
385 desc,
|
|
386 image_data,
|
|
387 image_size,
|
|
388 GetWindowPort(theWindow),
|
|
389 NULL,
|
|
390 NULL,
|
|
391 ((d_width != width) || (d_height != height)) ? &matrix : NULL,
|
|
392 srcCopy,
|
|
393 NULL,
|
|
394 0,
|
|
395 codecLosslessQuality,
|
|
396 bestSpeedCodec);
|
12424
|
397 if (qterr)
|
|
398 {
|
12432
|
399 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: DecompressSequenceBeginS (%d)\n", qterr);
|
12424
|
400 }
|
|
401 }
|
12432
|
402 break;
|
12424
|
403
|
12432
|
404 case IMGFMT_YV12:
|
|
405 case IMGFMT_IYUV:
|
|
406 case IMGFMT_I420:
|
|
407 case IMGFMT_UYVY:
|
|
408 case IMGFMT_YUY2:
|
12424
|
409 {
|
12432
|
410 yuv_qt_stuff.desc = (ImageDescriptionHandle)NewHandleClear( sizeof(ImageDescription) );
|
12424
|
411
|
12432
|
412 yuv_qt_stuff.extension_colr = NewHandleClear(sizeof(NCLCColorInfoImageDescriptionExtension));
|
|
413 ((NCLCColorInfoImageDescriptionExtension*)(*yuv_qt_stuff.extension_colr))->colorParamType = kVideoColorInfoImageDescriptionExtensionType;
|
|
414 ((NCLCColorInfoImageDescriptionExtension*)(*yuv_qt_stuff.extension_colr))->primaries = 2;
|
|
415 ((NCLCColorInfoImageDescriptionExtension*)(*yuv_qt_stuff.extension_colr))->transferFunction = 2;
|
|
416 ((NCLCColorInfoImageDescriptionExtension*)(*yuv_qt_stuff.extension_colr))->matrix = 2;
|
|
417
|
|
418 yuv_qt_stuff.extension_fiel = NewHandleClear(sizeof(FieldInfoImageDescriptionExtension));
|
|
419 ((FieldInfoImageDescriptionExtension*)(*yuv_qt_stuff.extension_fiel))->fieldCount = 1;
|
|
420 ((FieldInfoImageDescriptionExtension*)(*yuv_qt_stuff.extension_fiel))->fieldOrderings = 0;
|
12424
|
421
|
12432
|
422 yuv_qt_stuff.extension_clap = NewHandleClear(sizeof(CleanApertureImageDescriptionExtension));
|
|
423 ((CleanApertureImageDescriptionExtension*)(*yuv_qt_stuff.extension_clap))->cleanApertureWidthN = image_width;
|
|
424 ((CleanApertureImageDescriptionExtension*)(*yuv_qt_stuff.extension_clap))->cleanApertureWidthD = 1;
|
|
425 ((CleanApertureImageDescriptionExtension*)(*yuv_qt_stuff.extension_clap))->cleanApertureHeightN = image_height;
|
|
426 ((CleanApertureImageDescriptionExtension*)(*yuv_qt_stuff.extension_clap))->cleanApertureHeightD = 1;
|
|
427 ((CleanApertureImageDescriptionExtension*)(*yuv_qt_stuff.extension_clap))->horizOffN = 0;
|
|
428 ((CleanApertureImageDescriptionExtension*)(*yuv_qt_stuff.extension_clap))->horizOffD = 1;
|
|
429 ((CleanApertureImageDescriptionExtension*)(*yuv_qt_stuff.extension_clap))->vertOffN = 0;
|
|
430 ((CleanApertureImageDescriptionExtension*)(*yuv_qt_stuff.extension_clap))->vertOffD = 1;
|
|
431
|
|
432 yuv_qt_stuff.extension_pasp = NewHandleClear(sizeof(PixelAspectRatioImageDescriptionExtension));
|
|
433 ((PixelAspectRatioImageDescriptionExtension*)(*yuv_qt_stuff.extension_pasp))->hSpacing = 1;
|
|
434 ((PixelAspectRatioImageDescriptionExtension*)(*yuv_qt_stuff.extension_pasp))->vSpacing = 1;
|
|
435
|
|
436 (*yuv_qt_stuff.desc)->idSize = sizeof(ImageDescription);
|
|
437 (*yuv_qt_stuff.desc)->cType = image_qtcodec;
|
|
438 (*yuv_qt_stuff.desc)->version = 2;
|
|
439 (*yuv_qt_stuff.desc)->revisionLevel = 0;
|
|
440 (*yuv_qt_stuff.desc)->vendor = 'mpla';
|
|
441 (*yuv_qt_stuff.desc)->width = image_width;
|
|
442 (*yuv_qt_stuff.desc)->height = image_height;
|
|
443 (*yuv_qt_stuff.desc)->hRes = Long2Fix(72);
|
|
444 (*yuv_qt_stuff.desc)->vRes = Long2Fix(72);
|
|
445 (*yuv_qt_stuff.desc)->temporalQuality = 0;
|
|
446 (*yuv_qt_stuff.desc)->spatialQuality = codecLosslessQuality;
|
|
447 (*yuv_qt_stuff.desc)->frameCount = 1;
|
|
448 (*yuv_qt_stuff.desc)->dataSize = 0;
|
|
449 (*yuv_qt_stuff.desc)->depth = 24;
|
|
450 (*yuv_qt_stuff.desc)->clutID = -1;
|
12424
|
451
|
12432
|
452 qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_colr, kColorInfoImageDescriptionExtension);
|
|
453 if (qterr)
|
|
454 {
|
|
455 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: AddImageDescriptionExtension [colr] (%d)\n", qterr);
|
|
456 }
|
|
457
|
|
458 qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_fiel, kFieldInfoImageDescriptionExtension);
|
|
459 if (qterr)
|
|
460 {
|
|
461 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: AddImageDescriptionExtension [fiel] (%d)\n", qterr);
|
|
462 }
|
|
463
|
|
464 qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_clap, kCleanApertureImageDescriptionExtension);
|
|
465 if (qterr)
|
|
466 {
|
|
467 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: AddImageDescriptionExtension [clap] (%d)\n", qterr);
|
|
468 }
|
|
469
|
|
470 qterr = AddImageDescriptionExtension(yuv_qt_stuff.desc, yuv_qt_stuff.extension_pasp, kCleanApertureImageDescriptionExtension);
|
|
471 if (qterr)
|
|
472 {
|
|
473 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: AddImageDescriptionExtension [pasp] (%d)\n", qterr);
|
|
474 }
|
|
475
|
|
476 P = calloc(sizeof(PlanarPixmapInfoYUV420) + image_size, 1);
|
|
477 switch (image_format)
|
|
478 {
|
|
479 case IMGFMT_YV12:
|
|
480 case IMGFMT_IYUV:
|
|
481 case IMGFMT_I420:
|
|
482 P->componentInfoY.offset = sizeof(PlanarPixmapInfoYUV420);
|
|
483 P->componentInfoCb.offset = P->componentInfoY.offset + image_size / 2;
|
|
484 P->componentInfoCr.offset = P->componentInfoCb.offset + image_size / 4;
|
|
485 P->componentInfoY.rowBytes = image_width;
|
|
486 P->componentInfoCb.rowBytes = image_width / 2;
|
|
487 P->componentInfoCr.rowBytes = image_width / 2;
|
|
488 image_buffer_size = image_size + sizeof(PlanarPixmapInfoYUV420);
|
|
489 break;
|
|
490 case IMGFMT_UYVY:
|
|
491 case IMGFMT_YUY2:
|
|
492 image_buffer_size = image_size;
|
|
493 break;
|
|
494 }
|
12414
|
495
|
12432
|
496 qterr = DecompressSequenceBeginS(&seqId,
|
12414
|
497 yuv_qt_stuff.desc,
|
12432
|
498 (char *)P,
|
12414
|
499 image_buffer_size,
|
|
500 GetWindowPort(theWindow),
|
12432
|
501 NULL,
|
|
502 NULL,
|
12414
|
503 ((d_width != width) || (d_height != height)) ?
|
12432
|
504 &matrix : NULL,
|
12414
|
505 srcCopy,
|
12432
|
506 NULL,
|
|
507 0,
|
12414
|
508 codecLosslessQuality,
|
|
509 bestSpeedCodec);
|
12432
|
510
|
|
511 if (qterr)
|
|
512 {
|
|
513 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: DecompressSequenceBeginS (%d)\n", qterr);
|
|
514 }
|
12424
|
515 }
|
12432
|
516 break;
|
12414
|
517 }
|
|
518
|
12424
|
519 //Show window
|
|
520 RepositionWindow(theWindow, NULL, kWindowCascadeOnMainScreen);
|
12296
|
521 ShowWindow (theWindow);
|
|
522
|
|
523 if(vo_fs)
|
|
524 window_fullscreen();
|
|
525
|
|
526 if(vo_ontop)
|
|
527 window_ontop();
|
|
528
|
|
529 return 0;
|
12120
|
530 }
|
|
531
|
12296
|
532 static void check_events(void)
|
12120
|
533 {
|
12296
|
534 EventRef theEvent;
|
|
535 EventTargetRef theTarget;
|
|
536 OSStatus theErr;
|
|
537
|
|
538 //Get event
|
|
539 theTarget = GetEventDispatcherTarget();
|
|
540 theErr = ReceiveNextEvent(0, 0, kEventDurationNoWait,true, &theEvent);
|
|
541 if(theErr == noErr && theEvent != NULL)
|
|
542 {
|
|
543 SendEventToEventTarget (theEvent, theTarget);
|
|
544 ReleaseEvent(theEvent);
|
|
545 }
|
12120
|
546
|
12296
|
547 //update activity every 30 seconds to prevent
|
|
548 //screensaver from starting up.
|
|
549 DateTimeRec d;
|
|
550 unsigned long curTime;
|
|
551 static unsigned long lastTime = 0;
|
|
552
|
|
553 GetTime(&d);
|
|
554 DateToSeconds( &d, &curTime);
|
|
555
|
|
556 if( ( (curTime - lastTime) >= 30) || (lastTime == 0))
|
|
557 {
|
|
558 UpdateSystemActivity(UsrActivity);
|
|
559 lastTime = curTime;
|
|
560 }
|
|
561 }
|
12120
|
562
|
12296
|
563 static void draw_osd(void)
|
|
564 {
|
|
565 vo_draw_text(image_width,image_height,draw_alpha);
|
|
566 }
|
12120
|
567
|
12296
|
568 static void flip_page(void)
|
|
569 {
|
12432
|
570 switch (image_format)
|
|
571 {
|
|
572 case IMGFMT_RGB32:
|
|
573 {
|
|
574 if (EnterMoviesDone)
|
|
575 {
|
|
576 OSErr qterr;
|
|
577 CodecFlags flags = 0;
|
|
578
|
|
579 qterr = DecompressSequenceFrameWhen(seqId,
|
|
580 image_data,
|
|
581 image_size,
|
|
582 0,
|
|
583 &flags,
|
|
584 NULL,
|
|
585 NULL);
|
|
586
|
|
587 if (qterr)
|
|
588 {
|
|
589 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: DecompressSequenceFrameWhen in flip_page (%d) flags:0x%08x\n", qterr, flags);
|
|
590 }
|
|
591 }
|
|
592 }
|
|
593 break;
|
12414
|
594
|
12433
|
595 case IMGFMT_YV12:
|
|
596 case IMGFMT_IYUV:
|
|
597 case IMGFMT_I420:
|
|
598 case IMGFMT_UYVY:
|
|
599 case IMGFMT_YUY2:
|
|
600 if (EnterMoviesDone)
|
|
601 {
|
|
602 OSErr qterr;
|
|
603 CodecFlags flags = 0;
|
|
604 qterr = DecompressSequenceFrameWhen(seqId,
|
|
605 (char *)P,
|
|
606 image_buffer_size,
|
|
607 0, //codecFlagUseImageBuffer,
|
|
608 &flags,
|
|
609 NULL,
|
|
610 NULL);
|
|
611 if (qterr)
|
|
612 {
|
|
613 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: DecompressSequenceFrameWhen in flip_page (%d) flags:0x%08x\n", qterr, flags);
|
|
614 }
|
|
615 }
|
|
616 break;
|
|
617 }
|
12296
|
618 }
|
|
619
|
|
620 static uint32_t draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y)
|
|
621 {
|
12433
|
622 switch (image_format)
|
|
623 {
|
|
624 case IMGFMT_YV12:
|
|
625 case IMGFMT_I420:
|
|
626 memcpy_pic(((char*)P) + P->componentInfoY.offset + x + image_width * y, src[0], w, h, image_width, stride[0]);
|
|
627 x=x/2;y=y/2;w=w/2;h=h/2;
|
12414
|
628
|
12433
|
629 memcpy_pic(((char*)P) + P->componentInfoCb.offset + x + image_width / 2 * y, src[1], w, h, image_width / 2, stride[1]);
|
|
630 memcpy_pic(((char*)P) + P->componentInfoCr.offset + x + image_width / 2 * y, src[2], w, h, image_width / 2, stride[2]);
|
|
631 return 0;
|
|
632
|
|
633 case IMGFMT_IYUV:
|
|
634 memcpy_pic(((char*)P) + P->componentInfoY.offset + x + image_width * y, src[0], w, h, image_width, stride[0]);
|
|
635 x=x/2;y=y/2;w=w/2;h=h/2;
|
|
636
|
|
637 memcpy_pic(((char*)P) + P->componentInfoCr.offset + x + image_width / 2 * y, src[1], w, h, image_width / 2, stride[1]);
|
|
638 memcpy_pic(((char*)P) + P->componentInfoCb.offset + x + image_width / 2 * y, src[2], w, h, image_width / 2, stride[2]);
|
|
639 return 0;
|
|
640 }
|
12296
|
641 return -1;
|
|
642 }
|
|
643
|
|
644 static uint32_t draw_frame(uint8_t *src[])
|
|
645 {
|
12433
|
646 switch (image_format)
|
|
647 {
|
|
648 case IMGFMT_RGB32:
|
|
649 image_data = src[0];
|
|
650 return 0;
|
12432
|
651
|
12433
|
652 case IMGFMT_UYVY:
|
|
653 case IMGFMT_YUY2:
|
|
654 memcpy_pic(((char*)P), src[0], image_width * 2, image_height, image_width * 2, image_width * 2);
|
|
655 return 0;
|
|
656 }
|
|
657 return -1;
|
12296
|
658 }
|
12120
|
659
|
12296
|
660 static uint32_t query_format(uint32_t format)
|
|
661 {
|
|
662 image_format = format;
|
12432
|
663 image_qtcodec = 0;
|
|
664
|
|
665 if (format == IMGFMT_RGB32)
|
|
666 {
|
|
667 return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_SWSCALE;
|
|
668 }
|
12414
|
669
|
12424
|
670 if ((format == IMGFMT_YV12) || (format == IMGFMT_IYUV) || (format == IMGFMT_I420))
|
|
671 {
|
|
672 image_qtcodec = kMpegYUV420CodecType; //kYUV420CodecType ?;
|
|
673 return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_SWSCALE | VFCAP_ACCEPT_STRIDE;
|
12414
|
674 }
|
|
675
|
12424
|
676 if (format == IMGFMT_YUY2)
|
|
677 {
|
|
678 image_qtcodec = kComponentVideoUnsigned;
|
|
679 return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_SWSCALE;
|
12414
|
680 }
|
|
681
|
12424
|
682 if (format == IMGFMT_UYVY)
|
|
683 {
|
|
684 image_qtcodec = k422YpCbCr8CodecType;
|
|
685 return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_SWSCALE;
|
|
686 }
|
12414
|
687
|
12296
|
688 return 0;
|
|
689 }
|
12120
|
690
|
12296
|
691 static void uninit(void)
|
|
692 {
|
12432
|
693 OSErr qterr;
|
12424
|
694
|
12432
|
695 if (EnterMoviesDone)
|
|
696 {
|
|
697 qterr = CDSequenceEnd(seqId);
|
|
698 if (qterr)
|
|
699 {
|
|
700 mp_msg(MSGT_VO, MSGL_FATAL, "Quartz error: CDSequenceEnd (%d)\n", qterr);
|
12424
|
701 }
|
12414
|
702 }
|
12432
|
703
|
12296
|
704 ShowMenuBar();
|
|
705 }
|
12120
|
706
|
12296
|
707 static uint32_t preinit(const char *arg)
|
|
708 {
|
|
709 return 0;
|
12120
|
710 }
|
|
711
|
12424
|
712 static uint32_t draw_yuv_image(mp_image_t *mpi)
|
|
713 {
|
|
714 // ATM we're only called for planar IMGFMT
|
|
715 // drawing is done directly in P
|
|
716 // and displaying is in flip_page.
|
|
717 return VO_TRUE;
|
12414
|
718 }
|
|
719
|
12424
|
720 static uint32_t get_yuv_image(mp_image_t *mpi)
|
|
721 {
|
|
722 if(mpi->type!=MP_IMGTYPE_EXPORT) return VO_FALSE;
|
12414
|
723
|
12424
|
724 if(mpi->imgfmt!=image_format) return VO_FALSE;
|
12414
|
725
|
12424
|
726 if(mpi->flags&MP_IMGFLAG_PLANAR)
|
|
727 {
|
|
728 if (mpi->num_planes != 3)
|
|
729 {
|
|
730 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: only 3 planes allowed in get_yuv_image for planar (%d) \n", mpi->num_planes);
|
|
731 return VO_FALSE;
|
|
732 }
|
12414
|
733
|
12424
|
734 mpi->planes[0]=((char*)P) + P->componentInfoY.offset;
|
|
735 mpi->stride[0]=image_width;
|
|
736 mpi->width=image_width;
|
12414
|
737
|
12424
|
738 if(mpi->flags&MP_IMGFLAG_SWAPPED)
|
|
739 {
|
|
740 // I420
|
|
741 mpi->planes[1]=((char*)P) + P->componentInfoCb.offset;
|
|
742 mpi->planes[2]=((char*)P) + P->componentInfoCr.offset;
|
|
743 mpi->stride[1]=image_width/2;
|
|
744 mpi->stride[2]=image_width/2;
|
|
745 }
|
|
746 else
|
|
747 {
|
|
748 // YV12
|
|
749 mpi->planes[1]=((char*)P) + P->componentInfoCr.offset;
|
|
750 mpi->planes[2]=((char*)P) + P->componentInfoCb.offset;
|
|
751 mpi->stride[1]=image_width/2;
|
|
752 mpi->stride[2]=image_width/2;
|
|
753 }
|
|
754
|
|
755 mpi->flags|=MP_IMGFLAG_DIRECT;
|
|
756 return VO_TRUE;
|
|
757 }
|
|
758 else
|
12433
|
759 {
|
|
760 // doesn't work yet
|
12424
|
761 if (mpi->num_planes != 1)
|
|
762 {
|
|
763 mp_msg(MSGT_VO, MSGL_ERR, "Quartz error: only 1 plane allowed in get_yuv_image for packed (%d) \n", mpi->num_planes);
|
|
764 return VO_FALSE;
|
|
765 }
|
12414
|
766
|
12424
|
767 mpi->planes[0] = (char*)P;
|
|
768 mpi->stride[0] = image_width * 2;
|
|
769 mpi->width=image_width;
|
|
770 mpi->flags|=MP_IMGFLAG_DIRECT;
|
|
771 return VO_TRUE;
|
|
772 }
|
|
773 return VO_FALSE;
|
12414
|
774 }
|
|
775
|
12296
|
776 static uint32_t control(uint32_t request, void *data, ...)
|
12120
|
777 {
|
12424
|
778 switch (request)
|
|
779 {
|
|
780 case VOCTRL_PAUSE: return (int_pause=1);
|
|
781 case VOCTRL_RESUME: return (int_pause=0);
|
|
782 case VOCTRL_FULLSCREEN: window_fullscreen(); return VO_TRUE;
|
|
783 case VOCTRL_ONTOP: window_ontop(); return VO_TRUE;
|
|
784 case VOCTRL_QUERY_FORMAT: return query_format(*((uint32_t*)data));
|
|
785 case VOCTRL_GET_IMAGE:
|
|
786 switch (image_format)
|
|
787 {
|
|
788 case IMGFMT_YV12:
|
|
789 case IMGFMT_IYUV:
|
|
790 case IMGFMT_I420:
|
|
791 return get_yuv_image(data);
|
|
792 break;
|
|
793 }
|
|
794 case VOCTRL_DRAW_IMAGE:
|
|
795 switch (image_format)
|
|
796 {
|
|
797 case IMGFMT_YV12:
|
|
798 case IMGFMT_IYUV:
|
|
799 case IMGFMT_I420:
|
|
800 return draw_yuv_image(data);
|
|
801 break;
|
|
802 }
|
|
803 }
|
|
804 return VO_NOTIMPL;
|
12120
|
805 }
|
|
806
|
12296
|
807 void window_resized()
|
12120
|
808 {
|
12296
|
809 float aspectX;
|
|
810 float aspectY;
|
|
811
|
|
812 int padding;
|
|
813
|
|
814 uint32_t d_width;
|
|
815 uint32_t d_height;
|
|
816
|
|
817 GetWindowPortBounds(theWindow, &winRect);
|
12120
|
818
|
12296
|
819 aspect( &d_width, &d_height, A_NOZOOM);
|
|
820
|
|
821 aspectX = (float)((float)winRect.right/(float)d_width);
|
|
822 aspectY = (float)((float)winRect.bottom/(float)d_height);
|
|
823
|
|
824 if((d_height*aspectX)>winRect.bottom)
|
|
825 {
|
|
826 padding = (winRect.right - d_width*aspectY)/2;
|
|
827 SetRect(&dstRect, padding, 0, d_width*aspectY+padding, d_height*aspectY);
|
|
828 }
|
|
829 else
|
|
830 {
|
|
831 padding = (winRect.bottom - d_height*aspectX)/2;
|
|
832 SetRect(&dstRect, 0, padding, (d_width*aspectX), d_height*aspectX+padding);
|
|
833 }
|
12120
|
834
|
12296
|
835 //create a graphic context for the window
|
|
836 SetPortBounds(GetWindowPort(theWindow), &winRect);
|
|
837 CreateCGContextForPort(GetWindowPort(theWindow),&context);
|
|
838
|
|
839 //fill background with black
|
12425
|
840 CGRect winBounds = CGRectMake( winRect.top, winRect.left, winRect.right, winRect.bottom);
|
|
841 CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0);
|
|
842 CGContextFillRect(context, winBounds);
|
|
843 CGContextFlush(context);
|
12414
|
844
|
12432
|
845 long scale_X = FixDiv(Long2Fix(dstRect.right - dstRect.left),Long2Fix(image_width));
|
|
846 long scale_Y = FixDiv(Long2Fix(dstRect.bottom - dstRect.top),Long2Fix(image_height));
|
12414
|
847
|
12432
|
848 SetIdentityMatrix(&matrix);
|
|
849 if (((dstRect.right - dstRect.left) != image_width) || ((dstRect.bottom - dstRect.right) != image_height))
|
|
850 {
|
|
851 ScaleMatrix(&matrix, scale_X, scale_Y, 0, 0);
|
12414
|
852
|
12432
|
853 if (padding > 0)
|
|
854 {
|
|
855 TranslateMatrix(&matrix, Long2Fix(dstRect.left), Long2Fix(dstRect.top));
|
|
856 }
|
|
857 }
|
12424
|
858
|
12432
|
859 SetDSequenceMatrix(seqId, &matrix);
|
12120
|
860 }
|
|
861
|
12296
|
862 void window_ontop()
|
|
863 {
|
12432
|
864 if(vo_ontop)
|
12296
|
865 SetWindowClass( theWindow, kUtilityWindowClass);
|
|
866 else
|
|
867 SetWindowClass( theWindow, kDocumentWindowClass);
|
|
868
|
|
869 vo_ontop = (!(vo_ontop));
|
12120
|
870 }
|
|
871
|
12296
|
872 void window_fullscreen()
|
12120
|
873 {
|
12296
|
874 static Rect oldRect;
|
|
875 static Ptr *restoreState = nil;
|
|
876 short width=640;
|
|
877 short height=480;
|
|
878 RGBColor black={0,0,0};
|
|
879 GDHandle deviceHdl;
|
|
880 Rect deviceRect;
|
12120
|
881
|
12296
|
882 //go fullscreen
|
12432
|
883 if(vo_fs)
|
12296
|
884 {
|
|
885 //BeginFullScreen( &restoreState,nil,&width,&height,nil,&black,nil);
|
|
886 HideMenuBar();
|
12120
|
887
|
12296
|
888 //Get Main device info///////////////////////////////////////////////////
|
|
889 deviceHdl = GetMainDevice();
|
|
890 deviceRect = (*deviceHdl)->gdRect;
|
|
891
|
|
892 device_width = deviceRect.right;
|
|
893 device_height = deviceRect.bottom;
|
12120
|
894
|
12296
|
895 //save old window size
|
|
896 GetWindowPortBounds(theWindow, &oldRect);
|
|
897
|
|
898 //hide mouse cursor
|
|
899 HideCursor();
|
|
900
|
|
901 //go fullscreen
|
12432
|
902 //ChangeWindowAttributes(theWindow, 0, kWindowResizableAttribute);
|
12425
|
903
|
12296
|
904 MoveWindow (theWindow, 0, 0, 1);
|
|
905 SizeWindow(theWindow, device_width, device_height,1);
|
|
906 }
|
|
907 else //go back to windowed mode
|
|
908 {
|
|
909 //EndFullScreen( restoreState,0);
|
|
910 ShowMenuBar();
|
|
911
|
|
912 //Get Main device info///////////////////////////////////////////////////
|
|
913 deviceHdl = GetMainDevice();
|
|
914 deviceRect = (*deviceHdl)->gdRect;
|
|
915
|
|
916 device_width = deviceRect.right;
|
|
917 device_height = deviceRect.bottom;
|
12120
|
918
|
12296
|
919 //show mouse cursor
|
|
920 ShowCursor();
|
|
921
|
|
922 //revert window to previous setting
|
12432
|
923 //ChangeWindowAttributes(theWindow, kWindowResizableAttribute, 0);
|
12425
|
924
|
12296
|
925 SizeWindow(theWindow, oldRect.right, oldRect.bottom,1);
|
|
926 RepositionWindow(theWindow, NULL, kWindowCascadeOnMainScreen);
|
|
927 }
|
|
928
|
12432
|
929 vo_fs = (!(vo_fs));
|
|
930
|
12296
|
931 window_resized();
|
12120
|
932 }
|