1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2012 Sam Lantinga 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 19 Sam Lantinga 20 slouken (at) libsdl.org 21 */ 22 #include "SDL_config.h" 23 24 /* This is the QNX Realtime Platform version of SDL YUV video overlays */ 25 26 #include <errno.h> 27 28 #include <Ph.h> 29 #include <Pt.h> 30 31 #include "SDL_video.h" 32 #include "SDL_phyuv_c.h" 33 #include "../SDL_yuvfuncs.h" 34 35 #define OVERLAY_STATE_UNINIT 0 36 #define OVERLAY_STATE_ACTIVE 1 37 38 /* The functions are used to manipulate software video overlays */ 39 static struct private_yuvhwfuncs ph_yuvfuncs = 40 { 41 ph_LockYUVOverlay, 42 ph_UnlockYUVOverlay, 43 ph_DisplayYUVOverlay, 44 ph_FreeYUVOverlay 45 }; 46 47 int grab_ptrs2(PgVideoChannel_t* channel, FRAMEDATA* Frame0, FRAMEDATA* Frame1) 48 { 49 int planes = 0; 50 51 /* Buffers have moved; re-obtain the pointers */ 52 Frame0->Y = (unsigned char *)PdGetOffscreenContextPtr(channel->yplane1); 53 Frame1->Y = (unsigned char *)PdGetOffscreenContextPtr(channel->yplane2); 54 Frame0->U = (unsigned char *)PdGetOffscreenContextPtr(channel->vplane1); 55 Frame1->U = (unsigned char *)PdGetOffscreenContextPtr(channel->vplane2); 56 Frame0->V = (unsigned char *)PdGetOffscreenContextPtr(channel->uplane1); 57 Frame1->V = (unsigned char *)PdGetOffscreenContextPtr(channel->uplane2); 58 59 if (Frame0->Y) 60 planes++; 61 62 if (Frame0->U) 63 planes++; 64 65 if (Frame0->V) 66 planes++; 67 68 return planes; 69 } 70 71 SDL_Overlay* ph_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface* display) 72 { 73 SDL_Overlay* overlay; 74 struct private_yuvhwdata* hwdata; 75 int vidport; 76 int rtncode; 77 int planes; 78 int i=0; 79 PhPoint_t pos; 80 81 /* Create the overlay structure */ 82 overlay = SDL_calloc(1, sizeof(SDL_Overlay)); 83 84 if (overlay == NULL) 85 { 86 SDL_OutOfMemory(); 87 return NULL; 88 } 89 90 /* Fill in the basic members */ 91 overlay->format = format; 92 overlay->w = width; 93 overlay->h = height; 94 overlay->hwdata = NULL; 95 96 /* Set up the YUV surface function structure */ 97 overlay->hwfuncs = &ph_yuvfuncs; 98 99 /* Create the pixel data and lookup tables */ 100 hwdata = SDL_calloc(1, sizeof(struct private_yuvhwdata)); 101 102 if (hwdata == NULL) 103 { 104 SDL_OutOfMemory(); 105 SDL_FreeYUVOverlay(overlay); 106 return NULL; 107 } 108 109 overlay->hwdata = hwdata; 110 111 PhDCSetCurrent(0); 112 if (overlay->hwdata->channel == NULL) 113 { 114 if ((overlay->hwdata->channel = PgCreateVideoChannel(Pg_VIDEO_CHANNEL_SCALER, 0)) == NULL) 115 { 116 SDL_SetError("ph_CreateYUVOverlay(): Create channel failed: %s\n", strerror(errno)); 117 SDL_FreeYUVOverlay(overlay); 118 return NULL; 119 120 } 121 } 122 123 overlay->hwdata->forcedredraw=0; 124 125 PtGetAbsPosition(window, &pos.x, &pos.y); 126 overlay->hwdata->CurrentWindowPos.x = pos.x; 127 overlay->hwdata->CurrentWindowPos.y = pos.y; 128 overlay->hwdata->CurrentViewPort.pos.x = 0; 129 overlay->hwdata->CurrentViewPort.pos.y = 0; 130 overlay->hwdata->CurrentViewPort.size.w = width; 131 overlay->hwdata->CurrentViewPort.size.h = height; 132 overlay->hwdata->State = OVERLAY_STATE_UNINIT; 133 overlay->hwdata->FrameData0 = (FRAMEDATA *) SDL_calloc(1, sizeof(FRAMEDATA)); 134 overlay->hwdata->FrameData1 = (FRAMEDATA *) SDL_calloc(1, sizeof(FRAMEDATA)); 135 136 vidport = -1; 137 i=0; 138 139 overlay->hwdata->ischromakey=0; 140 141 do { 142 SDL_memset(&overlay->hwdata->caps, 0x00, sizeof(PgScalerCaps_t)); 143 overlay->hwdata->caps.size = sizeof(PgScalerCaps_t); 144 rtncode = PgGetScalerCapabilities(overlay->hwdata->channel, i, &overlay->hwdata->caps); 145 if (rtncode==0) 146 { 147 if (overlay->hwdata->caps.format==format) 148 { 149 if ((overlay->hwdata->caps.flags & Pg_SCALER_CAP_DST_CHROMA_KEY) == Pg_SCALER_CAP_DST_CHROMA_KEY) 150 { 151 overlay->hwdata->ischromakey=1; 152 } 153 vidport=1; 154 break; 155 } 156 } 157 else 158 { 159 break; 160 } 161 i++; 162 } while(1); 163 164 165 if (vidport == -1) 166 { 167 SDL_SetError("No available video ports for requested format\n"); 168 SDL_FreeYUVOverlay(overlay); 169 return NULL; 170 } 171 172 overlay->hwdata->format = format; 173 overlay->hwdata->props.format = format; 174 overlay->hwdata->props.size = sizeof(PgScalerProps_t); 175 overlay->hwdata->props.src_dim.w = width; 176 overlay->hwdata->props.src_dim.h = height; 177 178 /* overlay->hwdata->chromakey = PgGetOverlayChromaColor(); */ 179 overlay->hwdata->chromakey = PgRGB(12, 6, 12); /* very dark pink color */ 180 overlay->hwdata->props.color_key = overlay->hwdata->chromakey; 181 182 PhAreaToRect(&overlay->hwdata->CurrentViewPort, &overlay->hwdata->props.viewport); 183 184 overlay->hwdata->props.flags = Pg_SCALER_PROP_DOUBLE_BUFFER; 185 186 if ((overlay->hwdata->ischromakey)&&(overlay->hwdata->chromakey)) 187 { 188 overlay->hwdata->props.flags |= Pg_SCALER_PROP_CHROMA_ENABLE; 189 overlay->hwdata->props.flags |= Pg_SCALER_PROP_CHROMA_SPECIFY_KEY_MASK; 190 } 191 else 192 { 193 overlay->hwdata->props.flags &= ~Pg_SCALER_PROP_CHROMA_ENABLE; 194 } 195 196 rtncode = PgConfigScalerChannel(overlay->hwdata->channel, &overlay->hwdata->props); 197 198 switch(rtncode) 199 { 200 case -1: SDL_SetError("PgConfigScalerChannel failed\n"); 201 SDL_FreeYUVOverlay(overlay); 202 return NULL; 203 case 1: 204 case 0: 205 default: 206 break; 207 } 208 209 planes = grab_ptrs2(overlay->hwdata->channel, overlay->hwdata->FrameData0, overlay->hwdata->FrameData1); 210 211 if(overlay->hwdata->channel->yplane1 != NULL) 212 overlay->hwdata->YStride = overlay->hwdata->channel->yplane1->pitch; 213 if(overlay->hwdata->channel->vplane1 != NULL) 214 overlay->hwdata->UStride = overlay->hwdata->channel->vplane1->pitch; 215 if(overlay->hwdata->channel->uplane1 != NULL) 216 overlay->hwdata->VStride = overlay->hwdata->channel->uplane1->pitch; 217 218 /* check for the validness of all planes */ 219 if ((overlay->hwdata->channel->yplane1 == NULL) && 220 (overlay->hwdata->channel->uplane1 == NULL) && 221 (overlay->hwdata->channel->vplane1 == NULL)) 222 { 223 SDL_FreeYUVOverlay(overlay); 224 SDL_SetError("PgConfigScaler() returns all planes equal NULL\n"); 225 return NULL; 226 } 227 /* 228 overlay->hwdata->current = PgNextVideoFrame(overlay->hwdata->channel); 229 230 if (overlay->hwdata->current==0) 231 { 232 overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData0; 233 } 234 else 235 { 236 overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData1; 237 } 238 */ 239 overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData0; 240 241 /* 242 overlay->hwdata->locked = 1; 243 */ 244 245 /* Find the pitch and offset values for the overlay */ 246 overlay->planes = planes; 247 overlay->pitches = SDL_calloc(overlay->planes, sizeof(Uint16)); 248 overlay->pixels = SDL_calloc(overlay->planes, sizeof(Uint8*)); 249 if (!overlay->pitches || !overlay->pixels) 250 { 251 SDL_OutOfMemory(); 252 SDL_FreeYUVOverlay(overlay); 253 return(NULL); 254 } 255 256 if (overlay->planes > 0) 257 { 258 overlay->pitches[0] = overlay->hwdata->channel->yplane1->pitch; 259 overlay->pixels[0] = overlay->hwdata->CurrentFrameData->Y; 260 } 261 if (overlay->planes > 1) 262 { 263 overlay->pitches[1] = overlay->hwdata->channel->vplane1->pitch; 264 overlay->pixels[1] = overlay->hwdata->CurrentFrameData->U; 265 } 266 if (overlay->planes > 2) 267 { 268 overlay->pitches[2] = overlay->hwdata->channel->uplane1->pitch; 269 overlay->pixels[2] = overlay->hwdata->CurrentFrameData->V; 270 } 271 272 overlay->hwdata->State = OVERLAY_STATE_ACTIVE; 273 overlay->hwdata->scaler_on = 0; 274 overlay->hw_overlay = 1; 275 276 current_overlay=overlay; 277 278 return overlay; 279 } 280 281 int ph_LockYUVOverlay(_THIS, SDL_Overlay* overlay) 282 { 283 if (overlay == NULL) 284 { 285 return -1; 286 } 287 288 overlay->hwdata->locked = 1; 289 290 /* overlay->hwdata->current = PgNextVideoFrame(overlay->hwdata->channel); 291 if (overlay->hwdata->current == -1) 292 { 293 SDL_SetError("ph_LockYUVOverlay: PgNextFrame() failed, bailing out\n"); 294 SDL_FreeYUVOverlay(overlay); 295 return 0; 296 } 297 298 if (overlay->hwdata->current == 0) 299 { 300 overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData0; 301 } 302 else 303 { 304 overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData1; 305 } 306 307 if (overlay->planes > 0) 308 { 309 overlay->pitches[0] = overlay->hwdata->channel->yplane1->pitch; 310 overlay->pixels[0] = overlay->hwdata->CurrentFrameData->Y; 311 } 312 if (overlay->planes > 1) 313 { 314 overlay->pitches[1] = overlay->hwdata->channel->uplane1->pitch; 315 overlay->pixels[1] = overlay->hwdata->CurrentFrameData->U; 316 } 317 if (overlay->planes > 2) 318 { 319 overlay->pitches[2] = overlay->hwdata->channel->vplane1->pitch; 320 overlay->pixels[2] = overlay->hwdata->CurrentFrameData->V; 321 } 322 */ 323 324 return(0); 325 } 326 327 void ph_UnlockYUVOverlay(_THIS, SDL_Overlay* overlay) 328 { 329 if (overlay == NULL) 330 { 331 return; 332 } 333 334 overlay->hwdata->locked = 0; 335 } 336 337 int ph_DisplayYUVOverlay(_THIS, SDL_Overlay* overlay, SDL_Rect* src, SDL_Rect* dst) 338 { 339 int rtncode; 340 PhPoint_t pos; 341 SDL_Rect backrect; 342 PhRect_t windowextent; 343 int winchanged=0; 344 345 if ((overlay == NULL) || (overlay->hwdata==NULL)) 346 { 347 return -1; 348 } 349 350 if (overlay->hwdata->State == OVERLAY_STATE_UNINIT) 351 { 352 return -1; 353 } 354 355 PtGetAbsPosition(window, &pos.x, &pos.y); 356 if ((pos.x!=overlay->hwdata->CurrentWindowPos.x) || 357 (pos.y!=overlay->hwdata->CurrentWindowPos.y)) 358 { 359 winchanged=1; 360 overlay->hwdata->CurrentWindowPos.x=pos.x; 361 overlay->hwdata->CurrentWindowPos.y=pos.y; 362 } 363 364 /* If CurrentViewPort position/size has been changed, then move/resize the viewport */ 365 if ((overlay->hwdata->CurrentViewPort.pos.x != dst->x) || 366 (overlay->hwdata->CurrentViewPort.pos.y != dst->y) || 367 (overlay->hwdata->CurrentViewPort.size.w != dst->w) || 368 (overlay->hwdata->CurrentViewPort.size.h != dst->h) || 369 (overlay->hwdata->scaler_on==0) || (winchanged==1) || 370 (overlay->hwdata->forcedredraw==1)) 371 { 372 373 if (overlay->hwdata->ischromakey==1) 374 { 375 /* restore screen behind the overlay/chroma color. */ 376 backrect.x=overlay->hwdata->CurrentViewPort.pos.x; 377 backrect.y=overlay->hwdata->CurrentViewPort.pos.y; 378 backrect.w=overlay->hwdata->CurrentViewPort.size.w; 379 backrect.h=overlay->hwdata->CurrentViewPort.size.h; 380 this->UpdateRects(this, 1, &backrect); 381 382 /* Draw the new rectangle of the chroma color at the viewport position */ 383 PgSetFillColor(overlay->hwdata->chromakey); 384 PgDrawIRect(dst->x, dst->y, dst->x+dst->w-1, dst->y+dst->h-1, Pg_DRAW_FILL); 385 PgFlush(); 386 } 387 388 overlay->hwdata->props.flags |= Pg_SCALER_PROP_SCALER_ENABLE; 389 overlay->hwdata->scaler_on = 1; 390 391 PhWindowQueryVisible(Ph_QUERY_CONSOLE, 0, PtWidgetRid(window), &windowextent); 392 overlay->hwdata->CurrentViewPort.pos.x = pos.x-windowextent.ul.x+dst->x; 393 overlay->hwdata->CurrentViewPort.pos.y = pos.y-windowextent.ul.y+dst->y; 394 overlay->hwdata->CurrentViewPort.size.w = dst->w; 395 overlay->hwdata->CurrentViewPort.size.h = dst->h; 396 PhAreaToRect(&overlay->hwdata->CurrentViewPort, &overlay->hwdata->props.viewport); 397 overlay->hwdata->CurrentViewPort.pos.x = dst->x; 398 overlay->hwdata->CurrentViewPort.pos.y = dst->y; 399 400 rtncode = PgConfigScalerChannel(overlay->hwdata->channel, &(overlay->hwdata->props)); 401 402 switch(rtncode) 403 { 404 case -1: 405 SDL_SetError("PgConfigScalerChannel() function failed\n"); 406 SDL_FreeYUVOverlay(overlay); 407 return -1; 408 case 1: 409 grab_ptrs2(overlay->hwdata->channel, overlay->hwdata->FrameData0, overlay->hwdata->FrameData1); 410 break; 411 case 0: 412 default: 413 break; 414 } 415 } 416 417 418 /* 419 if (overlay->hwdata->locked==0) 420 { 421 overlay->hwdata->current = PgNextVideoFrame(overlay->hwdata->channel); 422 if (overlay->hwdata->current == -1) 423 { 424 SDL_SetError("ph_LockYUVOverlay: PgNextFrame() failed, bailing out\n"); 425 SDL_FreeYUVOverlay(overlay); 426 return 0; 427 } 428 429 if (overlay->hwdata->current == 0) 430 { 431 overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData0; 432 } 433 else 434 { 435 overlay->hwdata->CurrentFrameData = overlay->hwdata->FrameData1; 436 } 437 438 if (overlay->planes > 0) 439 { 440 overlay->pitches[0] = overlay->hwdata->channel->yplane1->pitch; 441 overlay->pixels[0] = overlay->hwdata->CurrentFrameData->Y; 442 } 443 if (overlay->planes > 1) 444 { 445 overlay->pitches[1] = overlay->hwdata->channel->uplane1->pitch; 446 overlay->pixels[1] = overlay->hwdata->CurrentFrameData->U; 447 } 448 if (overlay->planes > 2) 449 { 450 overlay->pitches[2] = overlay->hwdata->channel->vplane1->pitch; 451 overlay->pixels[2] = overlay->hwdata->CurrentFrameData->V; 452 } 453 } 454 */ 455 456 return 0; 457 } 458 459 void ph_FreeYUVOverlay(_THIS, SDL_Overlay *overlay) 460 { 461 SDL_Rect backrect; 462 463 if (overlay == NULL) 464 { 465 return; 466 } 467 468 if (overlay->hwdata == NULL) 469 { 470 return; 471 } 472 473 current_overlay=NULL; 474 475 /* restore screen behind the overlay/chroma color. */ 476 backrect.x=overlay->hwdata->CurrentViewPort.pos.x; 477 backrect.y=overlay->hwdata->CurrentViewPort.pos.y; 478 backrect.w=overlay->hwdata->CurrentViewPort.size.w; 479 backrect.h=overlay->hwdata->CurrentViewPort.size.h; 480 this->UpdateRects(this, 1, &backrect); 481 482 /* it is need for some buggy drivers, that can't hide overlay before */ 483 /* freeing buffer, so we got trash on the srceen */ 484 overlay->hwdata->props.flags &= ~Pg_SCALER_PROP_SCALER_ENABLE; 485 PgConfigScalerChannel(overlay->hwdata->channel, &(overlay->hwdata->props)); 486 487 overlay->hwdata->scaler_on = 0; 488 overlay->hwdata->State = OVERLAY_STATE_UNINIT; 489 490 if (overlay->hwdata->channel != NULL) 491 { 492 PgDestroyVideoChannel(overlay->hwdata->channel); 493 overlay->hwdata->channel = NULL; 494 return; 495 } 496 497 overlay->hwdata->CurrentFrameData = NULL; 498 499 SDL_free(overlay->hwdata->FrameData0); 500 SDL_free(overlay->hwdata->FrameData1); 501 overlay->hwdata->FrameData0 = NULL; 502 overlay->hwdata->FrameData1 = NULL; 503 SDL_free(overlay->hwdata); 504 } 505