1/* 2 * Copyright (C) 2000-2003 the xine project 3 * 4 * This file is part of xine, a free video player. 5 * 6 * xine is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * xine is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 * 20 * This output driver makes use of xine's objective-c video_output 21 * classes located in the macosx folder. 22 */ 23 24#ifdef HAVE_CONFIG_H 25#include "config.h" 26#endif 27 28#include <stdio.h> 29#include <stdlib.h> 30#include <unistd.h> 31#include <string.h> 32 33#define LOG_MODULE "video_out_macosx" 34#define LOG_VERBOSE 35/* 36#define LOG 37*/ 38 39#include "xine.h" 40#include "xine/video_out.h" 41#include "xine/vo_scale.h" 42#include "xine/xine_internal.h" 43#include "xine/xineutils.h" 44 45#include "macosx/video_window.h" 46 47typedef struct { 48 vo_frame_t vo_frame; 49 int width; 50 int height; 51 double ratio; 52 int format; 53 xine_t *xine; 54} macosx_frame_t; 55 56typedef struct { 57 vo_driver_t vo_driver; 58 config_values_t *config; 59 int ratio; 60 xine_t *xine; 61 id view; 62 alphablend_t alphablend_extra_data; 63} macosx_driver_t; 64 65typedef struct { 66 video_driver_class_t driver_class; 67 config_values_t *config; 68 xine_t *xine; 69} macosx_class_t; 70 71 72static void free_framedata(macosx_frame_t* frame) { 73 if(frame->vo_frame.base[0]) { 74 free(frame->vo_frame.base[0]); 75 frame->vo_frame.base[0] = NULL; 76 frame->vo_frame.base[1] = NULL; 77 frame->vo_frame.base[2] = NULL; 78 } 79} 80 81static void macosx_frame_dispose(vo_frame_t *vo_frame) { 82 macosx_frame_t *frame = (macosx_frame_t *)vo_frame; 83 free_framedata(frame); 84 free (frame); 85} 86 87static void macosx_frame_field(vo_frame_t *vo_frame, int which_field) { 88 /* do nothing */ 89} 90 91static uint32_t macosx_get_capabilities(vo_driver_t *vo_driver) { 92 /* both styles, country and western */ 93 return VO_CAP_YV12 | VO_CAP_YUY2 | VO_CAP_UNSCALED_OVERLAY; 94} 95 96static vo_frame_t *macosx_alloc_frame(vo_driver_t *vo_driver) { 97 /* macosx_driver_t *this = (macosx_driver_t *) vo_driver; */ 98 macosx_frame_t *frame; 99 100 frame = calloc(1, sizeof(macosx_frame_t)); 101 if(!frame) 102 return NULL; 103 104 pthread_mutex_init(&frame->vo_frame.mutex, NULL); 105 106 frame->vo_frame.base[0] = NULL; 107 frame->vo_frame.base[1] = NULL; 108 frame->vo_frame.base[2] = NULL; 109 110 frame->vo_frame.proc_slice = NULL; 111 frame->vo_frame.proc_frame = NULL; 112 frame->vo_frame.field = macosx_frame_field; 113 frame->vo_frame.dispose = macosx_frame_dispose; 114 frame->vo_frame.driver = vo_driver; 115 116 return (vo_frame_t *)frame; 117} 118 119static void macosx_update_frame_format(vo_driver_t *vo_driver, vo_frame_t *vo_frame, 120 uint32_t width, uint32_t height, 121 double ratio, int format, int flags) { 122 macosx_driver_t *this = (macosx_driver_t *) vo_driver; 123 macosx_frame_t *frame = (macosx_frame_t *) vo_frame; 124 125 if((frame->width != width) || (frame->height != height) || 126 (frame->format != format)) { 127 128 NSSize video_size = NSMakeSize(width, height); 129 130 free_framedata(frame); 131 132 frame->width = width; 133 frame->height = height; 134 frame->format = format; 135 136 lprintf ("frame change, new height:%d width:%d (ratio:%lf) format:%d\n", 137 height, width, ratio, format); 138 139 switch(format) { 140 141 case XINE_IMGFMT_YV12: 142 { 143 int y_size, uv_size; 144 145 frame->vo_frame.pitches[0] = 8*((width + 7) / 8); 146 frame->vo_frame.pitches[1] = 8*((width + 15) / 16); 147 frame->vo_frame.pitches[2] = 8*((width + 15) / 16); 148 149 y_size = frame->vo_frame.pitches[0] * height; 150 uv_size = frame->vo_frame.pitches[1] * ((height+1)/2); 151 152 frame->vo_frame.base[0] = malloc (y_size + 2*uv_size); 153 frame->vo_frame.base[1] = frame->vo_frame.base[0]+y_size+uv_size; 154 frame->vo_frame.base[2] = frame->vo_frame.base[0]+y_size; 155 } 156 break; 157 158 case XINE_IMGFMT_YUY2: 159 frame->vo_frame.pitches[0] = 8*((width + 3) / 4); 160 frame->vo_frame.base[0] = malloc(frame->vo_frame.pitches[0] * height); 161 frame->vo_frame.base[1] = NULL; 162 frame->vo_frame.base[2] = NULL; 163 break; 164 165 default: 166 xprintf (this->xine, XINE_VERBOSITY_DEBUG, "video_out_macosx: unknown frame format %04x)\n", format); 167 break; 168 169 } 170 171 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 172 [this->view setVideoSize:video_size]; 173 [pool release]; 174 175 if((format == XINE_IMGFMT_YV12 176 && (frame->vo_frame.base[0] == NULL 177 || frame->vo_frame.base[1] == NULL 178 || frame->vo_frame.base[2] == NULL)) 179 || (format == XINE_IMGFMT_YUY2 && frame->vo_frame.base[0] == NULL)) { 180 xprintf (this->xine, XINE_VERBOSITY_DEBUG, 181 "video_out_macosx: error. (framedata allocation failed: out of memory)\n"); 182 free_framedata(frame); 183 } 184 } 185 186 frame->ratio = ratio; 187} 188 189static void macosx_display_frame(vo_driver_t *vo_driver, vo_frame_t *vo_frame) { 190 macosx_driver_t *driver = (macosx_driver_t *)vo_driver; 191 macosx_frame_t *frame = (macosx_frame_t *)vo_frame; 192 char *texture_buffer; 193 194 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 195 196 if ((texture_buffer = [driver->view textureBuffer]) != NULL) { 197 switch (vo_frame->format) { 198 case XINE_IMGFMT_YV12: 199 yv12_to_yuy2 (vo_frame->base[0], vo_frame->pitches[0], 200 vo_frame->base[1], vo_frame->pitches[1], 201 vo_frame->base[2], vo_frame->pitches[2], 202 (unsigned char *)texture_buffer, 203 vo_frame->width * 2, 204 vo_frame->width, vo_frame->height, 0); 205 206 [driver->view updateTexture]; 207 break; 208 case XINE_IMGFMT_YUY2: 209 xine_fast_memcpy (texture_buffer, vo_frame->base[0], 210 vo_frame->pitches[0] * vo_frame->height); 211 [driver->view updateTexture]; 212 break; 213 default: 214 /* unsupported frame format, do nothing. */ 215 break; 216 } 217 } 218 219 frame->vo_frame.free(&frame->vo_frame); 220 [pool release]; 221} 222 223static void macosx_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, 224 vo_overlay_t *overlay) { 225 macosx_driver_t *this = (macosx_driver_t *) this_gen; 226 macosx_frame_t *frame = (macosx_frame_t *) frame_gen; 227 228 this->alphablend_extra_data.offset_x = frame_gen->overlay_offset_x; 229 this->alphablend_extra_data.offset_y = frame_gen->overlay_offset_y; 230 231 /* TODO: should check here whether the overlay has changed or not: use a 232 * ovl_changed boolean variable similarly to video_out_xv */ 233 if (overlay->rle) { 234 if (frame->format == XINE_IMGFMT_YV12) 235 /* TODO: It may be possible to accelerate the blending via Quartz 236 * Extreme ... */ 237 _x_blend_yuv(frame->vo_frame.base, overlay, 238 frame->width, frame->height, frame->vo_frame.pitches, 239 &this->alphablend_extra_data); 240 else 241 _x_blend_yuy2(frame->vo_frame.base[0], overlay, 242 frame->width, frame->height, frame->vo_frame.pitches[0], 243 &this->alphablend_extra_data); 244 } 245} 246 247static int macosx_get_property(vo_driver_t *vo_driver, int property) { 248 macosx_driver_t *driver = (macosx_driver_t *)vo_driver; 249 250 switch(property) { 251 252 case VO_PROP_ASPECT_RATIO: 253 return driver->ratio; 254 break; 255 256 default: 257 break; 258 } 259 260 return 0; 261} 262 263static int macosx_set_property(vo_driver_t *vo_driver, int property, int value) { 264 macosx_driver_t *driver = (macosx_driver_t *)vo_driver; 265 266 switch(property) { 267 268 case VO_PROP_ASPECT_RATIO: 269 if(value >= XINE_VO_ASPECT_NUM_RATIOS) 270 value = XINE_VO_ASPECT_AUTO; 271 272 driver->ratio = value; 273 break; 274 275 default: 276 break; 277 } 278 return value; 279} 280 281static void macosx_get_property_min_max(vo_driver_t *vo_driver, 282 int property, int *min, int *max) { 283 *min = 0; 284 *max = 0; 285} 286 287static int macosx_gui_data_exchange(vo_driver_t *vo_driver, int data_type, void *data) { 288/* macosx_driver_t *this = (macosx_driver_t *) vo_driver; */ 289 290 switch (data_type) { 291 case XINE_GUI_SEND_COMPLETION_EVENT: 292 case XINE_GUI_SEND_DRAWABLE_CHANGED: 293 case XINE_GUI_SEND_EXPOSE_EVENT: 294 case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO: 295 case XINE_GUI_SEND_VIDEOWIN_VISIBLE: 296 case XINE_GUI_SEND_SELECT_VISUAL: 297 default: 298 lprintf("unknown GUI data type %d\n", data_type); 299 break; 300 } 301 302 return 0; 303} 304static void macosx_dispose(vo_driver_t *vo_driver) { 305 macosx_driver_t *this = (macosx_driver_t *) vo_driver; 306 307 _x_alphablend_free(&this->alphablend_extra_data); 308 [this->view releaseInMainThread]; 309 310 free(this); 311} 312 313static int macosx_redraw_needed(vo_driver_t *vo_driver) { 314 return 0; 315} 316 317 318static vo_driver_t *open_plugin(video_driver_class_t *driver_class, const void *visual) { 319 macosx_class_t *class = (macosx_class_t *) driver_class; 320 macosx_driver_t *driver; 321 XineOpenGLView *view = (XineOpenGLView *) visual; 322 323 driver = calloc(1, sizeof(macosx_driver_t)); 324 325 driver->config = class->config; 326 driver->xine = class->xine; 327 driver->ratio = XINE_VO_ASPECT_AUTO; 328 driver->view = [view retain]; 329 330 driver->vo_driver.get_capabilities = macosx_get_capabilities; 331 driver->vo_driver.alloc_frame = macosx_alloc_frame; 332 driver->vo_driver.update_frame_format = macosx_update_frame_format; 333 driver->vo_driver.overlay_begin = NULL; /* not used */ 334 driver->vo_driver.overlay_blend = macosx_overlay_blend; 335 driver->vo_driver.overlay_end = NULL; /* not used */ 336 driver->vo_driver.display_frame = macosx_display_frame; 337 driver->vo_driver.get_property = macosx_get_property; 338 driver->vo_driver.set_property = macosx_set_property; 339 driver->vo_driver.get_property_min_max = macosx_get_property_min_max; 340 driver->vo_driver.gui_data_exchange = macosx_gui_data_exchange; 341 driver->vo_driver.dispose = macosx_dispose; 342 driver->vo_driver.redraw_needed = macosx_redraw_needed; 343 344 _x_alphablend_init(&driver->alphablend_extra_data, class->xine); 345 346 return &driver->vo_driver; 347} 348 349/* 350 * Class related functions. 351 */ 352 353static void *init_class (xine_t *xine, void *visual) { 354 macosx_class_t *this; 355 356 this = calloc(1, sizeof(macosx_class_t)); 357 358 this->driver_class.open_plugin = open_plugin; 359 this->driver_class.identifier = "MacOSX"; 360 this->driver_class.description = N_("xine video output plugin for Mac OS X"); 361 this->driver_class.dispose = default_video_driver_class_dispose; 362 363 this->config = xine->config; 364 this->xine = xine; 365 366 return this; 367} 368 369static const vo_info_t vo_info_macosx = { 370 1, /* Priority */ 371 XINE_VISUAL_TYPE_MACOSX /* Visual type */ 372}; 373 374plugin_info_t xine_plugin_info[] EXPORTED = { 375 /* type, API, "name", version, special_info, init_function */ 376 /* work around the problem that dlclose() is not allowed to 377 * get rid of an image module which contains objective C code and simply 378 * crashes with a Trace/BPT trap when we try to do so */ 379 { PLUGIN_VIDEO_OUT | PLUGIN_NO_UNLOAD, 22, "macosx", XINE_VERSION_CODE, &vo_info_macosx, init_class }, 380 { PLUGIN_NONE, 0, NULL, 0, NULL, NULL } 381}; 382 383