Home | History | Annotate | Download | only in test
      1 /*
      2  * Copyright (c) 2008-2009 Intel Corporation. All Rights Reserved.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the
      6  * "Software"), to deal in the Software without restriction, including
      7  * without limitation the rights to use, copy, modify, merge, publish,
      8  * distribute, sub license, and/or sell copies of the Software, and to
      9  * permit persons to whom the Software is furnished to do so, subject to
     10  * the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the
     13  * next paragraph) shall be included in all copies or substantial portions
     14  * of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     19  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
     20  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     21  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     22  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 #include "loadsurface_yuv.h"
     25 
     26 static int scale_2dimage(unsigned char *src_img, int src_imgw, int src_imgh,
     27                          unsigned char *dst_img, int dst_imgw, int dst_imgh)
     28 {
     29     int row=0, col=0;
     30 
     31     for (row=0; row<dst_imgh; row++) {
     32         for (col=0; col<dst_imgw; col++) {
     33             *(dst_img + row * dst_imgw + col) = *(src_img + (row * src_imgh/dst_imgh) * src_imgw + col * src_imgw/dst_imgw);
     34         }
     35     }
     36 
     37     return 0;
     38 }
     39 
     40 
     41 static int YUV_blend_with_pic(int width, int height,
     42                               unsigned char *Y_start, int Y_pitch,
     43                               unsigned char *U_start, int U_pitch,
     44                               unsigned char *V_start, int V_pitch,
     45                               unsigned int fourcc, int fixed_alpha)
     46 {
     47     /* PIC YUV format */
     48     unsigned char *pic_y_old = yuvga_pic;
     49     unsigned char *pic_u_old = pic_y_old + 640*480;
     50     unsigned char *pic_v_old = pic_u_old + 640*480/4;
     51     unsigned char *pic_y, *pic_u, *pic_v;
     52 
     53     int alpha_values[] = {100,90,80,70,60,50,40,30,20,30,40,50,60,70,80,90};
     54 
     55     static int alpha_idx = 0;
     56     int alpha;
     57     int allocated = 0;
     58 
     59     int row, col;
     60 
     61     if (fixed_alpha == 0) {
     62         alpha = alpha_values[alpha_idx % 16 ];
     63         alpha_idx ++;
     64     } else
     65         alpha = fixed_alpha;
     66 
     67     //alpha = 0;
     68 
     69     pic_y = pic_y_old;
     70     pic_u = pic_u_old;
     71     pic_v = pic_v_old;
     72 
     73     if (width != 640 || height != 480) { /* need to scale the pic */
     74         pic_y = (unsigned char *)malloc(width * height);
     75         pic_u = (unsigned char *)malloc(width * height/4);
     76         pic_v = (unsigned char *)malloc(width * height/4);
     77 
     78         allocated = 1;
     79 
     80         scale_2dimage(pic_y_old, 640, 480,
     81                       pic_y, width, height);
     82         scale_2dimage(pic_u_old, 320, 240,
     83                       pic_u, width/2, height/2);
     84         scale_2dimage(pic_v_old, 320, 240,
     85                       pic_v, width/2, height/2);
     86     }
     87 
     88     /* begin blend */
     89 
     90     /* Y plane */
     91     int Y_pixel_stride = 1;
     92     if (fourcc == VA_FOURCC_YUY2)
     93         Y_pixel_stride = 2;
     94 
     95     for (row=0; row<height; row++) {
     96         unsigned char *p = Y_start + row * Y_pitch;
     97         unsigned char *q = pic_y + row * width;
     98         for (col=0; col<width; col++, q++) {
     99             *p  = *p * (100 - alpha) / 100 + *q * alpha/100;
    100             p += Y_pixel_stride;
    101         }
    102     }
    103 
    104     /* U/V plane */
    105     int U_pixel_stride = 0, V_pixel_stride = 0;
    106     int v_factor_to_nv12 = 1;
    107     switch (fourcc) {
    108     case VA_FOURCC_YV12:
    109         U_pixel_stride = V_pixel_stride = 1;
    110         break;
    111     case VA_FOURCC_NV12:
    112         U_pixel_stride = V_pixel_stride = 2;
    113         break;
    114     case VA_FOURCC_YUY2:
    115         U_pixel_stride = V_pixel_stride = 4;
    116         v_factor_to_nv12 = 2;
    117         break;
    118     default:
    119         break;
    120     }
    121     for (row=0; row<height/2*v_factor_to_nv12; row++) {
    122         unsigned char *pU = U_start + row * U_pitch;
    123         unsigned char *pV = V_start + row * V_pitch;
    124         unsigned char *qU = pic_u + row/v_factor_to_nv12 * width/2;
    125         unsigned char *qV = pic_v + row/v_factor_to_nv12 * width/2;
    126 
    127         for (col=0; col<width/2; col++, qU++, qV++) {
    128             *pU  = *pU * (100 - alpha) / 100 + *qU * alpha/100;
    129             *pV  = *pV * (100 - alpha) / 100 + *qV * alpha/100;
    130 
    131             pU += U_pixel_stride;
    132             pV += V_pixel_stride;
    133         }
    134     }
    135 
    136 
    137     if (allocated) {
    138         free(pic_y);
    139         free(pic_u);
    140         free(pic_v);
    141     }
    142 
    143     return 0;
    144 }
    145 
    146 static int yuvgen_planar(int width, int height,
    147                          unsigned char *Y_start, int Y_pitch,
    148                          unsigned char *U_start, int U_pitch,
    149                          unsigned char *V_start, int V_pitch,
    150                          unsigned int fourcc, int box_width, int row_shift,
    151                          int field)
    152 {
    153     int row, alpha;
    154     unsigned char uv_value = 0x80;
    155 
    156     /* copy Y plane */
    157     int y_factor = 1;
    158     if (fourcc == VA_FOURCC_YUY2) y_factor = 2;
    159     for (row=0;row<height;row++) {
    160         unsigned char *Y_row = Y_start + row * Y_pitch;
    161         int jj, xpos, ypos;
    162 
    163         ypos = (row / box_width) & 0x1;
    164 
    165         /* fill garbage data into the other field */
    166         if (((field == VA_TOP_FIELD) && (row &1))
    167             || ((field == VA_BOTTOM_FIELD) && ((row &1)==0))) {
    168             memset(Y_row, 0xff, width);
    169             continue;
    170         }
    171 
    172         for (jj=0; jj<width; jj++) {
    173             xpos = ((row_shift + jj) / box_width) & 0x1;
    174             if (xpos == ypos)
    175                 Y_row[jj*y_factor] = 0xeb;
    176             else
    177                 Y_row[jj*y_factor] = 0x10;
    178 
    179             if (fourcc == VA_FOURCC_YUY2) {
    180                 Y_row[jj*y_factor+1] = uv_value; // it is for UV
    181             }
    182         }
    183     }
    184 
    185     /* copy UV data */
    186     for( row =0; row < height/2; row++) {
    187 
    188         /* fill garbage data into the other field */
    189         if (((field == VA_TOP_FIELD) && (row &1))
    190             || ((field == VA_BOTTOM_FIELD) && ((row &1)==0))) {
    191             uv_value = 0xff;
    192         }
    193 
    194         unsigned char *U_row = U_start + row * U_pitch;
    195         unsigned char *V_row = V_start + row * V_pitch;
    196         switch (fourcc) {
    197         case VA_FOURCC_NV12:
    198             memset(U_row, uv_value, width);
    199             break;
    200         case VA_FOURCC_YV12:
    201             memset (U_row,uv_value,width/2);
    202             memset (V_row,uv_value,width/2);
    203             break;
    204         case VA_FOURCC_YUY2:
    205             // see above. it is set with Y update.
    206             break;
    207         default:
    208             printf("unsupported fourcc in loadsurface.h\n");
    209             assert(0);
    210         }
    211     }
    212 
    213     if (getenv("AUTO_UV") == 0)
    214         return 0;
    215 
    216     if (getenv("AUTO_ALPHA"))
    217         alpha = 0;
    218     else
    219         alpha = 70;
    220 
    221     YUV_blend_with_pic(width,height,
    222                        Y_start, Y_pitch,
    223                        U_start, U_pitch,
    224                        V_start, V_pitch,
    225                        fourcc, alpha);
    226 
    227     return 0;
    228 }
    229 
    230 static int upload_surface(VADisplay va_dpy, VASurfaceID surface_id,
    231                           int box_width, int row_shift,
    232                           int field)
    233 {
    234     VAImage surface_image;
    235     void *surface_p=NULL, *U_start = NULL,*V_start = NULL;
    236     VAStatus va_status;
    237     unsigned int pitches[3]={0,0,0};
    238 
    239     va_status = vaDeriveImage(va_dpy,surface_id,&surface_image);
    240     CHECK_VASTATUS(va_status,"vaDeriveImage");
    241 
    242     vaMapBuffer(va_dpy,surface_image.buf,&surface_p);
    243     assert(VA_STATUS_SUCCESS == va_status);
    244 
    245     pitches[0] = surface_image.pitches[0];
    246     switch (surface_image.format.fourcc) {
    247     case VA_FOURCC_NV12:
    248         U_start = (char *)surface_p + surface_image.offsets[1];
    249         V_start = (char *)U_start + 1;
    250         pitches[1] = surface_image.pitches[1];
    251         pitches[2] = surface_image.pitches[1];
    252         break;
    253     case VA_FOURCC_IYUV:
    254         U_start = (char *)surface_p + surface_image.offsets[1];
    255         V_start = (char *)surface_p + surface_image.offsets[2];
    256         pitches[1] = surface_image.pitches[1];
    257         pitches[2] = surface_image.pitches[2];
    258         break;
    259     case VA_FOURCC_YV12:
    260         U_start = (char *)surface_p + surface_image.offsets[2];
    261         V_start = (char *)surface_p + surface_image.offsets[1];
    262         pitches[1] = surface_image.pitches[2];
    263         pitches[2] = surface_image.pitches[1];
    264         break;
    265     case VA_FOURCC_YUY2:
    266         U_start = (char *)surface_p + 1;
    267         V_start = (char *)surface_p + 3;
    268         pitches[1] = surface_image.pitches[0];
    269         pitches[2] = surface_image.pitches[0];
    270         break;
    271     default:
    272         assert(0);
    273     }
    274 
    275     /* assume surface is planar format */
    276     yuvgen_planar(surface_image.width, surface_image.height,
    277                   (unsigned char *)surface_p, pitches[0],
    278                   (unsigned char *)U_start, pitches[1],
    279                   (unsigned char *)V_start, pitches[2],
    280                   surface_image.format.fourcc,
    281                   box_width, row_shift, field);
    282 
    283     vaUnmapBuffer(va_dpy,surface_image.buf);
    284 
    285     vaDestroyImage(va_dpy,surface_image.image_id);
    286 
    287     return 0;
    288 }
    289 
    290 /*
    291  * Upload YUV data from memory into a surface
    292  * if src_fourcc == NV12, assume the buffer pointed by src_U
    293  * is UV interleaved (src_V is ignored)
    294  */
    295 static int upload_surface_yuv(VADisplay va_dpy, VASurfaceID surface_id,
    296                               int src_fourcc, int src_width, int src_height,
    297                               unsigned char *src_Y, unsigned char *src_U, unsigned char *src_V)
    298 {
    299     VAImage surface_image;
    300     unsigned char *surface_p=NULL, *Y_start=NULL, *U_start=NULL, *V_start=NULL;
    301     int Y_pitch=0, U_pitch=0, V_pitch=0, row;
    302     VAStatus va_status;
    303 
    304     va_status = vaDeriveImage(va_dpy,surface_id, &surface_image);
    305     CHECK_VASTATUS(va_status,"vaDeriveImage");
    306 
    307     vaMapBuffer(va_dpy,surface_image.buf,(void **)&surface_p);
    308     assert(VA_STATUS_SUCCESS == va_status);
    309 
    310     Y_start = surface_p;
    311     Y_pitch = surface_image.pitches[0];
    312     switch (surface_image.format.fourcc) {
    313     case VA_FOURCC_NV12:
    314         U_start = (unsigned char *)surface_p + surface_image.offsets[1];
    315         V_start = U_start + 1;
    316         U_pitch = surface_image.pitches[1];
    317         V_pitch = surface_image.pitches[1];
    318         break;
    319     case VA_FOURCC_IYUV:
    320         U_start = (unsigned char *)surface_p + surface_image.offsets[1];
    321         V_start = (unsigned char *)surface_p + surface_image.offsets[2];
    322         U_pitch = surface_image.pitches[1];
    323         V_pitch = surface_image.pitches[2];
    324         break;
    325     case VA_FOURCC_YV12:
    326         U_start = (unsigned char *)surface_p + surface_image.offsets[2];
    327         V_start = (unsigned char *)surface_p + surface_image.offsets[1];
    328         U_pitch = surface_image.pitches[2];
    329         V_pitch = surface_image.pitches[1];
    330         break;
    331     case VA_FOURCC_YUY2:
    332         U_start = surface_p + 1;
    333         V_start = surface_p + 3;
    334         U_pitch = surface_image.pitches[0];
    335         V_pitch = surface_image.pitches[0];
    336         break;
    337     default:
    338         assert(0);
    339     }
    340 
    341     /* copy Y plane */
    342     for (row=0;row<src_height;row++) {
    343         unsigned char *Y_row = Y_start + row * Y_pitch;
    344         memcpy(Y_row, src_Y + row*src_width, src_width);
    345     }
    346 
    347     for (row =0; row < src_height/2; row++) {
    348         unsigned char *U_row = U_start + row * U_pitch;
    349         unsigned char *u_ptr = NULL, *v_ptr=NULL;
    350         int j;
    351         switch (surface_image.format.fourcc) {
    352         case VA_FOURCC_NV12:
    353             if (src_fourcc == VA_FOURCC_NV12) {
    354                 memcpy(U_row, src_U + row * src_width, src_width);
    355                 break;
    356             } else if (src_fourcc == VA_FOURCC_IYUV) {
    357                 u_ptr = src_U + row * (src_width/2);
    358                 v_ptr = src_V + row * (src_width/2);
    359             } else if (src_fourcc == VA_FOURCC_YV12) {
    360                 v_ptr = src_U + row * (src_width/2);
    361                 u_ptr = src_V + row * (src_width/2);
    362             }
    363             for(j = 0; j < src_width/2; j++) {
    364                 U_row[2*j] = u_ptr[j];
    365                 U_row[2*j+1] = v_ptr[j];
    366             }
    367             break;
    368         case VA_FOURCC_IYUV:
    369         case VA_FOURCC_YV12:
    370         case VA_FOURCC_YUY2:
    371         default:
    372             printf("unsupported fourcc in load_surface_yuv\n");
    373             assert(0);
    374         }
    375     }
    376 
    377     vaUnmapBuffer(va_dpy,surface_image.buf);
    378 
    379     vaDestroyImage(va_dpy,surface_image.image_id);
    380 
    381     return 0;
    382 }
    383 
    384 /*
    385  * Download YUV data from a surface into memory
    386  * Some hardward doesn't have a aperture for linear access of
    387  * tiled surface, thus use vaGetImage to expect the implemnetion
    388  * to do tile to linear convert
    389  *
    390  * if dst_fourcc == NV12, assume the buffer pointed by dst_U
    391  * is UV interleaved (src_V is ignored)
    392  */
    393 static int download_surface_yuv(VADisplay va_dpy, VASurfaceID surface_id,
    394                                 int dst_fourcc, int dst_width, int dst_height,
    395                                 unsigned char *dst_Y, unsigned char *dst_U, unsigned char *dst_V)
    396 {
    397     VAImage surface_image;
    398     unsigned char *surface_p=NULL, *Y_start=NULL, *U_start=NULL,*V_start=NULL;
    399     int Y_pitch=0, U_pitch=0, V_pitch=0, row;
    400     VAStatus va_status;
    401 
    402     va_status = vaDeriveImage(va_dpy,surface_id, &surface_image);
    403     CHECK_VASTATUS(va_status,"vaDeriveImage");
    404 
    405     vaMapBuffer(va_dpy,surface_image.buf,(void **)&surface_p);
    406     assert(VA_STATUS_SUCCESS == va_status);
    407 
    408     Y_start = surface_p;
    409     Y_pitch = surface_image.pitches[0];
    410     switch (surface_image.format.fourcc) {
    411     case VA_FOURCC_NV12:
    412         U_start = (unsigned char *)surface_p + surface_image.offsets[1];
    413         V_start = U_start + 1;
    414         U_pitch = surface_image.pitches[1];
    415         V_pitch = surface_image.pitches[1];
    416         break;
    417     case VA_FOURCC_IYUV:
    418         U_start = (unsigned char *)surface_p + surface_image.offsets[1];
    419         V_start = (unsigned char *)surface_p + surface_image.offsets[2];
    420         U_pitch = surface_image.pitches[1];
    421         V_pitch = surface_image.pitches[2];
    422         break;
    423     case VA_FOURCC_YV12:
    424         U_start = (unsigned char *)surface_p + surface_image.offsets[2];
    425         V_start = (unsigned char *)surface_p + surface_image.offsets[1];
    426         U_pitch = surface_image.pitches[2];
    427         V_pitch = surface_image.pitches[1];
    428         break;
    429     case VA_FOURCC_YUY2:
    430         U_start = surface_p + 1;
    431         V_start = surface_p + 3;
    432         U_pitch = surface_image.pitches[0];
    433         V_pitch = surface_image.pitches[0];
    434         break;
    435     default:
    436         assert(0);
    437     }
    438 
    439     /* copy Y plane */
    440     for (row=0;row<dst_height;row++) {
    441         unsigned char *Y_row = Y_start + row * Y_pitch;
    442         memcpy(dst_Y + row*dst_width, Y_row, dst_width);
    443     }
    444 
    445     for (row =0; row < dst_height/2; row++) {
    446         unsigned char *U_row = U_start + row * U_pitch;
    447         unsigned char *u_ptr = NULL, *v_ptr = NULL;
    448         int j;
    449         switch (surface_image.format.fourcc) {
    450         case VA_FOURCC_NV12:
    451             if (dst_fourcc == VA_FOURCC_NV12) {
    452                 memcpy(dst_U + row * dst_width, U_row, dst_width);
    453                 break;
    454             } else if (dst_fourcc == VA_FOURCC_IYUV) {
    455                 u_ptr = dst_U + row * (dst_width/2);
    456                 v_ptr = dst_V + row * (dst_width/2);
    457             } else if (dst_fourcc == VA_FOURCC_YV12) {
    458                 v_ptr = dst_U + row * (dst_width/2);
    459                 u_ptr = dst_V + row * (dst_width/2);
    460             }
    461             for(j = 0; j < dst_width/2; j++) {
    462                 u_ptr[j] = U_row[2*j];
    463                 v_ptr[j] = U_row[2*j+1];
    464             }
    465             break;
    466         case VA_FOURCC_IYUV:
    467         case VA_FOURCC_YV12:
    468         case VA_FOURCC_YUY2:
    469         default:
    470             printf("unsupported fourcc in load_surface_yuv\n");
    471             assert(0);
    472         }
    473     }
    474 
    475     vaUnmapBuffer(va_dpy,surface_image.buf);
    476 
    477     vaDestroyImage(va_dpy,surface_image.image_id);
    478 
    479     return 0;
    480 }
    481