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