Home | History | Annotate | Download | only in photon
      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