changeset 30097:9d724e6def3e

Support all planar YUV formats in OpenGL vos.
author reimar
date Wed, 30 Dec 2009 11:32:24 +0000
parents 76c25bfa181b
children 834af9d1e3e9
files libvo/gl_common.c libvo/gl_common.h libvo/vo_gl.c libvo/vo_gl2.c
diffstat 4 files changed, 97 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/libvo/gl_common.c	Wed Dec 30 11:08:44 2009 +0000
+++ b/libvo/gl_common.c	Wed Dec 30 11:32:24 2009 +0000
@@ -234,6 +234,10 @@
   if (!gl_format) gl_format = &dummy2;
   if (!gl_type) gl_type = &dummy2;
 
+  // these are all the same for our purpose
+  if (mp_get_chroma_shift(fmt, NULL, NULL))
+    fmt = IMGFMT_YV12;
+
   *bpp = IMGFMT_IS_BGR(fmt)?IMGFMT_BGR_DEPTH(fmt):IMGFMT_RGB_DEPTH(fmt);
   *gl_texfmt = 3;
   switch (fmt) {
@@ -1323,9 +1327,9 @@
   add_scaler(YUV_LUM_SCALER(type), &prog_pos, &prog_remain, lum_scale_texs,
              '0', 'r', rect, texw, texh, params->filter_strength);
   add_scaler(YUV_CHROM_SCALER(type), &prog_pos, &prog_remain, chrom_scale_texs,
-             '1', 'g', rect, texw / 2, texh / 2, params->filter_strength);
+             '1', 'g', rect, params->chrom_texw, params->chrom_texh, params->filter_strength);
   add_scaler(YUV_CHROM_SCALER(type), &prog_pos, &prog_remain, chrom_scale_texs,
-             '2', 'b', rect, texw / 2, texh / 2, params->filter_strength);
+             '2', 'b', rect, params->chrom_texw, params->chrom_texh, params->filter_strength);
   get_yuv2rgb_coeffs(params, yuv2rgb);
   switch (YUV_CONVERSION(type)) {
     case YUV_CONVERSION_FRAGMENT:
@@ -1496,14 +1500,19 @@
  * \param sx width of texture in pixels
  * \param sy height of texture in pixels
  * \param rect_tex whether this texture uses texture_rectangle extension
- * \param is_yv12 if set, also draw the textures from units 1 and 2
+ * \param is_yv12 if != 0, also draw the textures from units 1 and 2,
+ *                bits 8 - 15 and 16 - 23 specify the x and y scaling of those textures
  * \param flip flip the texture upside down
  * \ingroup gltexture
  */
 void glDrawTex(GLfloat x, GLfloat y, GLfloat w, GLfloat h,
                GLfloat tx, GLfloat ty, GLfloat tw, GLfloat th,
                int sx, int sy, int rect_tex, int is_yv12, int flip) {
-  GLfloat tx2 = tx / 2, ty2 = ty / 2, tw2 = tw / 2, th2 = th / 2;
+  int chroma_x_shift = (is_yv12 >>  8) & 31;
+  int chroma_y_shift = (is_yv12 >> 16) & 31;
+  GLfloat xscale = 1 << chroma_x_shift;
+  GLfloat yscale = 1 << chroma_y_shift;
+  GLfloat tx2 = tx / xscale, ty2 = ty / yscale, tw2 = tw / xscale, th2 = th / yscale;
   if (!rect_tex) {
     tx /= sx; ty /= sy; tw /= sx; th /= sy;
     tx2 = tx, ty2 = ty, tw2 = tw, th2 = th;
--- a/libvo/gl_common.h	Wed Dec 30 11:08:44 2009 +0000
+++ b/libvo/gl_common.h	Wed Dec 30 11:32:24 2009 +0000
@@ -339,6 +339,8 @@
   float bgamma;
   int texw;
   int texh;
+  int chrom_texw;
+  int chrom_texh;
   float filter_strength;
 } gl_conversion_params_t;
 
--- a/libvo/vo_gl.c	Wed Dec 30 11:08:44 2009 +0000
+++ b/libvo/vo_gl.c	Wed Dec 30 11:32:24 2009 +0000
@@ -93,6 +93,7 @@
 #define MASK_NOT_COMBINERS (~((1 << YUV_CONVERSION_NONE) | (1 << YUV_CONVERSION_COMBINERS) | (1 << YUV_CONVERSION_COMBINERS_ATI)))
 #define MASK_GAMMA_SUPPORT (MASK_NOT_COMBINERS & ~(1 << YUV_CONVERSION_FRAGMENT))
 static int use_yuv;
+static int is_yuv;
 static int lscale;
 static int cscale;
 static float filter_strength;
@@ -206,6 +207,7 @@
 //! maximum size of custom fragment program
 #define MAX_CUSTOM_PROG_SIZE (1024 * 1024)
 static void update_yuvconv(void) {
+  int xs, ys;
   float bri = eq_bri / 100.0;
   float cont = (eq_cont + 100) / 100.0;
   float hue = eq_hue / 100.0 * 3.1415927;
@@ -215,7 +217,10 @@
   float bgamma = exp(log(8.0) * eq_bgamma / 100.0);
   gl_conversion_params_t params = {gl_target, yuvconvtype,
       bri, cont, hue, sat, rgamma, ggamma, bgamma,
-      texture_width, texture_height, filter_strength};
+      texture_width, texture_height, 0, 0, filter_strength};
+  mp_get_chroma_shift(image_format, &xs, &ys);
+  params.chrom_texw = params.texw >> xs;
+  params.chrom_texh = params.texh >> ys;
   glSetupYUVConversion(&params);
   if (custom_prog) {
     FILE *f = fopen(custom_prog, "r");
@@ -478,8 +483,10 @@
   mp_msg(MSGT_VO, MSGL_V, "[gl] Creating %dx%d texture...\n",
           texture_width, texture_height);
 
-  if (image_format == IMGFMT_YV12) {
+  if (is_yuv) {
     int i;
+    int xs, ys;
+    mp_get_chroma_shift(image_format, &xs, &ys);
     GenTextures(21, default_texs);
     default_texs[21] = 0;
     for (i = 0; i < 7; i++) {
@@ -490,18 +497,18 @@
     }
     ActiveTexture(GL_TEXTURE1);
     glCreateClearTex(gl_target, gl_texfmt, gl_format, gl_type, scale_type,
-                     texture_width / 2, texture_height / 2, 128);
+                     texture_width >> xs, texture_height >> ys, 128);
     if (mipmap_gen)
       TexParameteri(gl_target, GL_GENERATE_MIPMAP, GL_TRUE);
     ActiveTexture(GL_TEXTURE2);
     glCreateClearTex(gl_target, gl_texfmt, gl_format, gl_type, scale_type,
-                     texture_width / 2, texture_height / 2, 128);
+                     texture_width >> xs, texture_height >> ys, 128);
     if (mipmap_gen)
       TexParameteri(gl_target, GL_GENERATE_MIPMAP, GL_TRUE);
     ActiveTexture(GL_TEXTURE0);
     BindTexture(gl_target, 0);
   }
-  if (image_format == IMGFMT_YV12 || custom_prog)
+  if (is_yuv || custom_prog)
   {
     if ((MASK_NOT_COMBINERS & (1 << use_yuv)) || custom_prog) {
       if (!GenPrograms || !BindProgram) {
@@ -533,9 +540,12 @@
 static int
 config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format)
 {
+  int xs, ys;
   image_height = height;
   image_width = width;
   image_format = format;
+  is_yuv = mp_get_chroma_shift(image_format, &xs, &ys) > 0;
+  is_yuv |= (xs << 8) | (ys << 16);
   glFindFormat(format, NULL, &gl_texfmt, &gl_format, &gl_type);
 
   int_pause = 0;
@@ -712,14 +722,14 @@
 //  BindTexture(GL_TEXTURE_2D, texture_id);
 
   Color3f(1,1,1);
-  if (image_format == IMGFMT_YV12 || custom_prog)
+  if (is_yuv || custom_prog)
     glEnableYUVConversion(gl_target, yuvconvtype);
   glDrawTex(0, 0, image_width, image_height,
             0, 0, image_width, image_height,
             texture_width, texture_height,
-            use_rectangle == 1, image_format == IMGFMT_YV12,
+            use_rectangle == 1, is_yuv,
             mpi_flipped ^ vo_flipped);
-  if (image_format == IMGFMT_YV12 || custom_prog)
+  if (is_yuv || custom_prog)
     glDisableYUVConversion(gl_target, yuvconvtype);
 }
 
@@ -748,13 +758,15 @@
   mpi_flipped = stride[0] < 0;
   glUploadTex(gl_target, gl_format, gl_type, src[0], stride[0],
               x, y, w, h, slice_height);
-  if (image_format == IMGFMT_YV12) {
+  if (is_yuv) {
+    int xs, ys;
+    mp_get_chroma_shift(image_format, &xs, &ys);
     ActiveTexture(GL_TEXTURE1);
     glUploadTex(gl_target, gl_format, gl_type, src[1], stride[1],
-                x / 2, y / 2, w / 2, h / 2, slice_height);
+                x >> xs, y >> ys, w >> xs, h >> ys, slice_height);
     ActiveTexture(GL_TEXTURE2);
     glUploadTex(gl_target, gl_format, gl_type, src[2], stride[2],
-                x / 2, y / 2, w / 2, h / 2, slice_height);
+                x >> xs, y >> ys, w >> xs, h >> ys, slice_height);
     ActiveTexture(GL_TEXTURE0);
   }
   return 0;
@@ -812,14 +824,16 @@
     err_shown = 1;
     return VO_FALSE;
   }
-  if (mpi->imgfmt == IMGFMT_YV12) {
-    // YV12
+  if (is_yuv) {
+    // planar YUV
+    int xs, ys;
+    mp_get_chroma_shift(image_format, &xs, &ys);
     mpi->flags |= MP_IMGFLAG_COMMON_STRIDE | MP_IMGFLAG_COMMON_PLANE;
     mpi->stride[0] = mpi->width;
     mpi->planes[1] = mpi->planes[0] + mpi->stride[0] * mpi->height;
-    mpi->stride[1] = mpi->width >> 1;
-    mpi->planes[2] = mpi->planes[1] + mpi->stride[1] * (mpi->height >> 1);
-    mpi->stride[2] = mpi->width >> 1;
+    mpi->stride[1] = mpi->width >> xs;
+    mpi->planes[2] = mpi->planes[1] + mpi->stride[1] * (mpi->height >> ys);
+    mpi->stride[2] = mpi->width >> xs;
     if (ati_hack && !mesa_buffer) {
       mpi->flags &= ~MP_IMGFLAG_COMMON_PLANE;
       if (!gl_buffer_uv[0]) GenBuffers(2, gl_buffer_uv);
@@ -869,17 +883,19 @@
   mpi2.flags = 0; mpi2.type = MP_IMGTYPE_TEMP;
   mpi2.width = mpi2.w; mpi2.height = mpi2.h;
   if (force_pbo && !(mpi->flags & MP_IMGFLAG_DIRECT) && !gl_bufferptr && get_image(&mpi2) == VO_TRUE) {
-    int bpp = mpi->imgfmt == IMGFMT_YV12 ? 8 : mpi->bpp;
+    int bpp = is_yuv ? 8 : mpi->bpp;
+    int xs, ys;
+    mp_get_chroma_shift(image_format, &xs, &ys);
     memcpy_pic(mpi2.planes[0], mpi->planes[0], mpi->w * bpp / 8, mpi->h, mpi2.stride[0], mpi->stride[0]);
-    if (mpi->imgfmt == IMGFMT_YV12) {
-      memcpy_pic(mpi2.planes[1], mpi->planes[1], mpi->w >> 1, mpi->h >> 1, mpi2.stride[1], mpi->stride[1]);
-      memcpy_pic(mpi2.planes[2], mpi->planes[2], mpi->w >> 1, mpi->h >> 1, mpi2.stride[2], mpi->stride[2]);
+    if (is_yuv) {
+      memcpy_pic(mpi2.planes[1], mpi->planes[1], mpi->w >> xs, mpi->h >> ys, mpi2.stride[1], mpi->stride[1]);
+      memcpy_pic(mpi2.planes[2], mpi->planes[2], mpi->w >> xs, mpi->h >> ys, mpi2.stride[2], mpi->stride[2]);
     }
     if (ati_hack) { // since we have to do a full upload we need to clear the borders
       clear_border(mpi2.planes[0], mpi->w * bpp / 8, mpi2.stride[0], mpi->h, mpi2.height, 0);
-      if (mpi->imgfmt == IMGFMT_YV12) {
-        clear_border(mpi2.planes[1], mpi->w >> 1, mpi2.stride[1], mpi->h >> 1, mpi2.height >> 1, 128);
-        clear_border(mpi2.planes[2], mpi->w >> 1, mpi2.stride[2], mpi->h >> 1, mpi2.height >> 1, 128);
+      if (is_yuv) {
+        clear_border(mpi2.planes[1], mpi->w >> xs, mpi2.stride[1], mpi->h >> ys, mpi2.height >> ys, 128);
+        clear_border(mpi2.planes[2], mpi->w >> xs, mpi2.stride[2], mpi->h >> ys, mpi2.height >> ys, 128);
       }
     }
     mpi = &mpi2;
@@ -909,7 +925,9 @@
   }
   glUploadTex(gl_target, gl_format, gl_type, planes[0], stride[0],
               mpi->x, mpi->y, w, h, slice);
-  if (mpi->imgfmt == IMGFMT_YV12) {
+  if (is_yuv) {
+    int xs, ys;
+    mp_get_chroma_shift(image_format, &xs, &ys);
     if ((mpi->flags & MP_IMGFLAG_DIRECT) && !(mpi->flags & MP_IMGFLAG_COMMON_PLANE)) {
       BindBuffer(GL_PIXEL_UNPACK_BUFFER, gl_buffer_uv[0]);
       UnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
@@ -917,7 +935,7 @@
     }
     ActiveTexture(GL_TEXTURE1);
     glUploadTex(gl_target, gl_format, gl_type, planes[1], stride[1],
-                mpi->x / 2, mpi->y / 2, w / 2, h / 2, slice);
+                mpi->x >> xs, mpi->y >> ys, w >> xs, h >> ys, slice);
     if ((mpi->flags & MP_IMGFLAG_DIRECT) && !(mpi->flags & MP_IMGFLAG_COMMON_PLANE)) {
       BindBuffer(GL_PIXEL_UNPACK_BUFFER, gl_buffer_uv[1]);
       UnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
@@ -925,7 +943,7 @@
     }
     ActiveTexture(GL_TEXTURE2);
     glUploadTex(gl_target, gl_format, gl_type, planes[2], stride[2],
-                mpi->x / 2, mpi->y / 2, w / 2, h / 2, slice);
+                mpi->x >> xs, mpi->y >> ys, w >> xs, h >> ys, slice);
     ActiveTexture(GL_TEXTURE0);
   }
   if (mpi->flags & MP_IMGFLAG_DIRECT) {
@@ -953,7 +971,7 @@
       caps |= VFCAP_OSD | VFCAP_EOSD | (scaled_osd ? 0 : VFCAP_EOSD_UNSCALED);
     if (format == IMGFMT_RGB24 || format == IMGFMT_RGBA)
         return caps;
-    if (use_yuv && format == IMGFMT_YV12)
+    if (use_yuv && mp_get_chroma_shift(format, NULL, NULL))
         return caps;
     // HACK, otherwise we get only b&w with some filters (e.g. -vf eq)
     // ideally MPlayer should be fixed instead not to use Y800 when it has the choice
@@ -1184,7 +1202,7 @@
     resize(vo_dwidth, vo_dheight);
     return VO_TRUE;
   case VOCTRL_GET_EQUALIZER:
-    if (image_format == IMGFMT_YV12) {
+    if (is_yuv) {
       int i;
       va_list va;
       int *value;
@@ -1200,7 +1218,7 @@
     }
     break;
   case VOCTRL_SET_EQUALIZER:
-    if (image_format == IMGFMT_YV12) {
+    if (is_yuv) {
       int i;
       va_list va;
       int value;
--- a/libvo/vo_gl2.c	Wed Dec 30 11:08:44 2009 +0000
+++ b/libvo/vo_gl2.c	Wed Dec 30 11:32:24 2009 +0000
@@ -88,6 +88,7 @@
 static int      gl_bilinear=1;
 static int      gl_antialias=0;
 static int      use_yuv;
+static int      is_yuv;
 static int      use_glFinish;
 
 static void (*draw_alpha_fnc)
@@ -184,7 +185,7 @@
     s*=2;
   texture_height=s;
 
-  if (image_format != IMGFMT_YV12)
+  if (!is_yuv)
   gl_internal_format = getInternalFormat();
 
   /* Test the max texture size */
@@ -263,7 +264,7 @@
       glGenTextures (1, &(tsq->texobj));
 
       glBindTexture (GL_TEXTURE_2D, tsq->texobj);
-      if (image_format == IMGFMT_YV12) {
+      if (is_yuv) {
         glGenTextures(2, tsq->uvtexobjs);
         ActiveTexture(GL_TEXTURE1);
         glBindTexture (GL_TEXTURE_2D, tsq->uvtexobjs[0]);
@@ -276,13 +277,15 @@
                        texture_width, texture_height, 0);
 
       glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-      if (image_format == IMGFMT_YV12) {
+      if (is_yuv) {
+        int xs, ys;
+        mp_get_chroma_shift(image_format, &xs, &ys);
         ActiveTexture(GL_TEXTURE1);
         glCreateClearTex(GL_TEXTURE_2D, gl_internal_format, gl_bitmap_format,  gl_bitmap_type, GL_LINEAR,
-                         texture_width / 2, texture_height / 2, 128);
+                         texture_width >> xs, texture_height >> ys, 128);
         ActiveTexture(GL_TEXTURE2);
         glCreateClearTex(GL_TEXTURE_2D, gl_internal_format, gl_bitmap_format,  gl_bitmap_type, GL_LINEAR,
-                         texture_width / 2, texture_height / 2, 128);
+                         texture_width >> xs, texture_height >> ys, 128);
         ActiveTexture(GL_TEXTURE0);
       }
 
@@ -381,7 +384,7 @@
 
   glColor3f(1.0,1.0,1.0);
 
-  if (image_format == IMGFMT_YV12)
+  if (is_yuv)
     glEnableYUVConversion(GL_TEXTURE_2D, use_yuv);
   for (y = 0; y < texnumy; y++) {
     int thish = texture_height;
@@ -392,7 +395,7 @@
       if (x == texnumx - 1 && image_width % texture_width)
         thisw = image_width % texture_width;
       glBindTexture (GL_TEXTURE_2D, square->texobj);
-      if (image_format == IMGFMT_YV12) {
+      if (is_yuv) {
         ActiveTexture(GL_TEXTURE1);
         glBindTexture (GL_TEXTURE_2D, square->uvtexobjs[0]);
         ActiveTexture(GL_TEXTURE2);
@@ -409,11 +412,11 @@
       glDrawTex(square->fx, square->fy, square->fw, square->fh,
                 0, 0, texture_width, texture_height,
                 texture_width, texture_height,
-                0, image_format == IMGFMT_YV12, 0);
+                0, is_yuv, 0);
       square++;
     } /* for all texnumx */
   } /* for all texnumy */
-  if (image_format == IMGFMT_YV12)
+  if (is_yuv)
     glDisableYUVConversion(GL_TEXTURE_2D, use_yuv);
   texdirty = 0;
 }
@@ -565,10 +568,11 @@
   glDepthMask(GL_FALSE);
   glDisable(GL_CULL_FACE);
   glEnable (GL_TEXTURE_2D);
-  if (image_format == IMGFMT_YV12) {
+  if (is_yuv) {
+    int xs, ys;
     gl_conversion_params_t params = {GL_TEXTURE_2D, use_yuv,
           0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0,
-          texture_width, texture_height};
+          texture_width, texture_height, 0, 0, 0};
     switch (use_yuv) {
       case YUV_CONVERSION_FRAGMENT_LOOKUP:
         glGenTextures(1, &lookupTex);
@@ -586,6 +590,9 @@
         BindProgram(GL_FRAGMENT_PROGRAM, fragprog);
         break;
     }
+    mp_get_chroma_shift(image_format, &xs, &ys);
+    params.chrom_texw = params.texw >> xs;
+    params.chrom_texh = params.texh >> ys;
     glSetupYUVConversion(&params);
   }
 
@@ -613,11 +620,14 @@
 static int
 config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format)
 {
+  int xs, ys;
   const unsigned char * glVersion;
 
   image_height = height;
   image_width = width;
   image_format = format;
+  is_yuv = mp_get_chroma_shift(image_format, &xs, &ys) > 0;
+  is_yuv |= (xs << 8) | (ys << 16);
 
   int_pause = 0;
 
@@ -750,6 +760,8 @@
   int rem_h = h;
   struct TexSquare *texline = &texgrid[y / texture_height * texnumx];
   int subtex_y = y % texture_width;
+  int xs, ys;
+  mp_get_chroma_shift(image_format, &xs, &ys);
   while (rem_h > 0) {
     int rem_w = w;
     struct TexSquare *tsq = &texline[x / texture_width];
@@ -769,24 +781,24 @@
       ActiveTexture(GL_TEXTURE1);
       glBindTexture(GL_TEXTURE_2D, tsq->uvtexobjs[0]);
       glUploadTex(GL_TEXTURE_2D, gl_bitmap_format,  gl_bitmap_type,
-                  uptr, ustride, subtex_x / 2, subtex_y / 2,
-                  subtex_w / 2, subtex_h / 2, 0);
+                  uptr, ustride, subtex_x >> xs, subtex_y >> ys,
+                  subtex_w >> xs, subtex_h >> ys, 0);
       ActiveTexture(GL_TEXTURE2);
       glBindTexture(GL_TEXTURE_2D, tsq->uvtexobjs[1]);
       glUploadTex(GL_TEXTURE_2D, gl_bitmap_format,  gl_bitmap_type,
-                  vptr, vstride, subtex_x / 2, subtex_y / 2,
-                  subtex_w / 2, subtex_h / 2, 0);
+                  vptr, vstride, subtex_x >> xs, subtex_y >> ys,
+                  subtex_w >> xs, subtex_h >> ys, 0);
       subtex_x = 0;
       yptr += subtex_w;
-      uptr += subtex_w / 2;
-      vptr += subtex_w / 2;
+      uptr += subtex_w >> xs;
+      vptr += subtex_w >> xs;
       tsq++;
       rem_w -= subtex_w;
     }
     subtex_y = 0;
     yptr += subtex_h * ystride - w;
-    uptr += subtex_h / 2 * ustride - w / 2;
-    vptr += subtex_h / 2 * vstride - w / 2;
+    uptr += (subtex_h >> ys) * ustride - (w >> xs);
+    vptr += (subtex_h >> ys) * vstride - (w >> xs);
     texline += texnumx;
     rem_h -= subtex_h;
   }
@@ -797,7 +809,7 @@
 static int
 draw_frame(uint8_t *src[])
 {
-  if (image_format == IMGFMT_YV12) {
+  if (is_yuv) {
     mp_msg(MSGT_VO, MSGL_ERR, "[gl2] error: draw_frame called for YV12!\n");
     return 0;
   }
@@ -810,12 +822,10 @@
 static int
 query_format(uint32_t format)
 {
+  if (use_yuv && mp_get_chroma_shift(format, NULL, NULL))
+    return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD |
+           VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE;
   switch(format) {
-    case IMGFMT_YV12:
-      if (use_yuv)
-        return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD |
-               VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE;
-      break;
 #ifdef __APPLE__
     case IMGFMT_RGB32:
 #else