diff --git a/src/render/SDL_yuv_sw.c b/src/render/SDL_yuv_sw.c index 9d202e0e7..49fce6db2 100644 --- a/src/render/SDL_yuv_sw.c +++ b/src/render/SDL_yuv_sw.c @@ -265,7 +265,18 @@ Color32DitherYV12Mod1X(int *colortab, Uint32 * rgb_2_pix, int cr_r; int crb_g; int cb_b; - int cols_2 = cols / 2; + int cols_2 = (cols + 1) / 2; + /* not even dimensions */ + int skip_last_col = 0; + int skip_last_row = 0; + + if ( (cols & 0x1) ) { + skip_last_col = 1; + } + + if ( (rows & 0x1) ) { + skip_last_row = 1; + } row1 = (unsigned int *) out; row2 = row1 + cols + mod; @@ -273,7 +284,7 @@ Color32DitherYV12Mod1X(int *colortab, Uint32 * rgb_2_pix, mod += cols + mod; - y = rows / 2; + y = (rows + 1) / 2; while (y--) { x = cols_2; while (x--) { @@ -290,20 +301,27 @@ Color32DitherYV12Mod1X(int *colortab, Uint32 * rgb_2_pix, *row1++ = (rgb_2_pix[L + cr_r] | rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]); + if (!(x == 0 && skip_last_col)) { L = *lum++; *row1++ = (rgb_2_pix[L + cr_r] | rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]); + } /* skip col */ + if (!(y == 0 && skip_last_row)) { + /* Now, do second row. */ L = *lum2++; *row2++ = (rgb_2_pix[L + cr_r] | rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]); + if (!(x == 1 && skip_last_col)) { L = *lum2++; *row2++ = (rgb_2_pix[L + cr_r] | rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]); + } /* skip col */ + } /* skip row */ } /* @@ -670,7 +688,12 @@ Color32DitherYUY2Mod1X(int *colortab, Uint32 * rgb_2_pix, int cr_r; int crb_g; int cb_b; - int cols_2 = cols / 2; + int cols_2 = (cols + 1) / 2; + /* not even dimensions */ + int skip_last_col = 0; + if ( (cols & 0x1) ) { + skip_last_col = 1; + } row = (unsigned int *) out; y = rows; @@ -693,9 +716,11 @@ Color32DitherYUY2Mod1X(int *colortab, Uint32 * rgb_2_pix, L = *lum; lum += 2; + + if (!(x == 0 && skip_last_col)) { *row++ = (rgb_2_pix[L + cr_r] | rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]); - + } /* skip col */ } row += mod; @@ -1022,6 +1047,13 @@ SDL_SW_SetupYUVDisplay(SDL_SW_YUVTexture * swdata, Uint32 target_format) swdata->Display2X = Color32DitherYUY2Mod2X; } break; + case SDL_PIXELFORMAT_NV21: + case SDL_PIXELFORMAT_NV12: + /* no Display{1,2}X function */ + swdata->Display1X = NULL; + swdata->Display2X = NULL; + break; + default: /* We should never get here (caught above) */ break; @@ -1049,6 +1081,8 @@ SDL_SW_CreateYUVTexture(Uint32 format, int w, int h) case SDL_PIXELFORMAT_YUY2: case SDL_PIXELFORMAT_UYVY: case SDL_PIXELFORMAT_YVYU: + case SDL_PIXELFORMAT_NV12: + case SDL_PIXELFORMAT_NV21: break; default: SDL_SetError("Unsupported YUV format"); @@ -1065,7 +1099,35 @@ SDL_SW_CreateYUVTexture(Uint32 format, int w, int h) swdata->target_format = SDL_PIXELFORMAT_UNKNOWN; swdata->w = w; swdata->h = h; - swdata->pixels = (Uint8 *) SDL_malloc(w * h * 2); + { + const int sz_plane = w * h; + const int sz_plane_chroma = ((w + 1) / 2) * ((h + 1) / 2); + const int sz_plane_packed = ((w + 1) / 2) * h; + int dst_size = 0; + switch(format) + { + case SDL_PIXELFORMAT_YV12: /**< Planar mode: Y + V + U (3 planes) */ + case SDL_PIXELFORMAT_IYUV: /**< Planar mode: Y + U + V (3 planes) */ + dst_size = sz_plane + sz_plane_chroma + sz_plane_chroma; + break; + + case SDL_PIXELFORMAT_YUY2: /**< Packed mode: Y0+U0+Y1+V0 (1 plane) */ + case SDL_PIXELFORMAT_UYVY: /**< Packed mode: U0+Y0+V0+Y1 (1 plane) */ + case SDL_PIXELFORMAT_YVYU: /**< Packed mode: Y0+V0+Y1+U0 (1 plane) */ + dst_size = 4 * sz_plane_packed; + break; + + case SDL_PIXELFORMAT_NV12: /**< Planar mode: Y + U/V interleaved (2 planes) */ + case SDL_PIXELFORMAT_NV21: /**< Planar mode: Y + V/U interleaved (2 planes) */ + dst_size = sz_plane + sz_plane_chroma + sz_plane_chroma; + break; + + default: + SDL_assert(0 && "We should never get here (caught above)"); + break; + } + swdata->pixels = (Uint8 *) SDL_malloc(dst_size); + } swdata->colortab = (int *) SDL_malloc(4 * 256 * sizeof(int)); swdata->rgb_2_pix = (Uint32 *) SDL_malloc(3 * 768 * sizeof(Uint32)); if (!swdata->pixels || !swdata->colortab || !swdata->rgb_2_pix) { @@ -1095,18 +1157,27 @@ SDL_SW_CreateYUVTexture(Uint32 format, int w, int h) case SDL_PIXELFORMAT_YV12: case SDL_PIXELFORMAT_IYUV: swdata->pitches[0] = w; - swdata->pitches[1] = swdata->pitches[0] / 2; - swdata->pitches[2] = swdata->pitches[0] / 2; + swdata->pitches[1] = (swdata->pitches[0] + 1) / 2; + swdata->pitches[2] = (swdata->pitches[0] + 1) / 2; swdata->planes[0] = swdata->pixels; swdata->planes[1] = swdata->planes[0] + swdata->pitches[0] * h; - swdata->planes[2] = swdata->planes[1] + swdata->pitches[1] * h / 2; + swdata->planes[2] = swdata->planes[1] + swdata->pitches[1] * ((h + 1) / 2); break; case SDL_PIXELFORMAT_YUY2: case SDL_PIXELFORMAT_UYVY: case SDL_PIXELFORMAT_YVYU: - swdata->pitches[0] = w * 2; + swdata->pitches[0] = ((w + 1) / 2) * 4; swdata->planes[0] = swdata->pixels; break; + + case SDL_PIXELFORMAT_NV12: + case SDL_PIXELFORMAT_NV21: + swdata->pitches[0] = w; + swdata->pitches[1] = 2 * ((swdata->pitches[0] + 1) / 2); + swdata->planes[0] = swdata->pixels; + swdata->planes[1] = swdata->planes[0] + swdata->pitches[0] * h; + break; + default: SDL_assert(0 && "We should never get here (caught above)"); break; @@ -1135,7 +1206,7 @@ SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect, if (rect->x == 0 && rect->y == 0 && rect->w == swdata->w && rect->h == swdata->h) { SDL_memcpy(swdata->pixels, pixels, - (swdata->h * swdata->w) + (swdata->h * swdata->w) / 2); + (swdata->h * swdata->w) + 2* ((swdata->h + 1) /2) * ((swdata->w + 1) / 2)); } else { Uint8 *src, *dst; int row; @@ -1150,28 +1221,28 @@ SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect, src += pitch; dst += swdata->w; } - + /* Copy the next plane */ src = (Uint8 *) pixels + rect->h * pitch; dst = swdata->pixels + swdata->h * swdata->w; - dst += rect->y/2 * swdata->w/2 + rect->x/2; - length = rect->w / 2; - for (row = 0; row < rect->h/2; ++row) { + dst += rect->y/2 * ((swdata->w + 1) / 2) + rect->x/2; + length = (rect->w + 1) / 2; + for (row = 0; row < (rect->h + 1)/2; ++row) { SDL_memcpy(dst, src, length); - src += pitch/2; - dst += swdata->w/2; + src += (pitch + 1)/2; + dst += (swdata->w + 1)/2; } /* Copy the next plane */ - src = (Uint8 *) pixels + rect->h * pitch + (rect->h * pitch) / 4; + src = (Uint8 *) pixels + rect->h * pitch + ((rect->h + 1) / 2) * ((pitch + 1) / 2); dst = swdata->pixels + swdata->h * swdata->w + - (swdata->h * swdata->w) / 4; - dst += rect->y/2 * swdata->w/2 + rect->x/2; - length = rect->w / 2; - for (row = 0; row < rect->h/2; ++row) { + ((swdata->h + 1)/2) * ((swdata->w+1) / 2); + dst += rect->y/2 * ((swdata->w + 1)/2) + rect->x/2; + length = (rect->w + 1) / 2; + for (row = 0; row < (rect->h + 1)/2; ++row) { SDL_memcpy(dst, src, length); - src += pitch/2; - dst += swdata->w/2; + src += (pitch + 1)/2; + dst += (swdata->w + 1)/2; } } break; @@ -1187,7 +1258,7 @@ SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect, dst = swdata->planes[0] + rect->y * swdata->pitches[0] + rect->x * 2; - length = rect->w * 2; + length = 4 * ((rect->w + 1) / 2); for (row = 0; row < rect->h; ++row) { SDL_memcpy(dst, src, length); src += pitch; @@ -1195,6 +1266,42 @@ SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect, } } break; + case SDL_PIXELFORMAT_NV12: + case SDL_PIXELFORMAT_NV21: + { + if (rect->x == 0 && rect->y == 0 && rect->w == swdata->w && rect->h == swdata->h) { + SDL_memcpy(swdata->pixels, pixels, + (swdata->h * swdata->w) + 2* ((swdata->h + 1) /2) * ((swdata->w + 1) / 2)); + } else { + + Uint8 *src, *dst; + int row; + size_t length; + + /* Copy the Y plane */ + src = (Uint8 *) pixels; + dst = swdata->pixels + rect->y * swdata->w + rect->x; + length = rect->w; + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, src, length); + src += pitch; + dst += swdata->w; + } + + /* Copy the next plane */ + src = (Uint8 *) pixels + rect->h * pitch; + dst = swdata->pixels + swdata->h * swdata->w; + dst += 2 * ((rect->y + 1)/2) * ((swdata->w + 1) / 2) + 2 * (rect->x/2); + length = 2 * ((rect->w + 1) / 2); + for (row = 0; row < (rect->h + 1)/2; ++row) { + SDL_memcpy(dst, src, length); + src += 2 * ((pitch + 1)/2); + dst += 2 * ((swdata->w + 1)/2); + } + } + } + break; + } return 0; } @@ -1226,14 +1333,14 @@ SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect, dst = swdata->pixels + swdata->h * swdata->w; } else { dst = swdata->pixels + swdata->h * swdata->w + - (swdata->h * swdata->w) / 4; + ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2); } - dst += rect->y/2 * swdata->w/2 + rect->x/2; - length = rect->w / 2; - for (row = 0; row < rect->h/2; ++row) { + dst += rect->y/2 * ((swdata->w + 1)/2) + rect->x/2; + length = (rect->w + 1) / 2; + for (row = 0; row < (rect->h + 1)/2; ++row) { SDL_memcpy(dst, src, length); src += Upitch; - dst += swdata->w/2; + dst += (swdata->w + 1)/2; } /* Copy the V plane */ @@ -1242,14 +1349,14 @@ SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect, dst = swdata->pixels + swdata->h * swdata->w; } else { dst = swdata->pixels + swdata->h * swdata->w + - (swdata->h * swdata->w) / 4; + ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2); } - dst += rect->y/2 * swdata->w/2 + rect->x/2; - length = rect->w / 2; - for (row = 0; row < rect->h/2; ++row) { + dst += rect->y/2 * ((swdata->w + 1)/2) + rect->x/2; + length = (rect->w + 1) / 2; + for (row = 0; row < (rect->h + 1)/2; ++row) { SDL_memcpy(dst, src, length); src += Vpitch; - dst += swdata->w/2; + dst += (swdata->w + 1)/2; } return 0; } @@ -1261,11 +1368,13 @@ SDL_SW_LockYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect, switch (swdata->format) { case SDL_PIXELFORMAT_YV12: case SDL_PIXELFORMAT_IYUV: + case SDL_PIXELFORMAT_NV12: + case SDL_PIXELFORMAT_NV21: if (rect && (rect->x != 0 || rect->y != 0 || rect->w != swdata->w || rect->h != swdata->h)) { return SDL_SetError - ("YV12 and IYUV textures only support full surface locks"); + ("YV12, IYUV, NV12, NV21 textures only support full surface locks"); } break; } @@ -1383,6 +1492,12 @@ SDL_SW_CopyYUVToRGB(SDL_SW_YUVTexture * swdata, const SDL_Rect * srcrect, Cr = lum + 1; Cb = lum + 3; break; + case SDL_PIXELFORMAT_NV12: + case SDL_PIXELFORMAT_NV21: + return SDL_ConvertPixels(swdata->w, swdata->h, + swdata->format, swdata->planes[0], swdata->pitches[0], + target_format, pixels, pitch); + break; default: return SDL_SetError("Unsupported YUV format in copy"); } diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c index 305a744a0..a950d8b81 100644 --- a/src/render/opengl/SDL_render_gl.c +++ b/src/render/opengl/SDL_render_gl.c @@ -752,12 +752,12 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) if (texture->format == SDL_PIXELFORMAT_YV12 || texture->format == SDL_PIXELFORMAT_IYUV) { /* Need to add size for the U and V planes */ - size += (2 * (texture->h * data->pitch) / 4); + size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2); } if (texture->format == SDL_PIXELFORMAT_NV12 || texture->format == SDL_PIXELFORMAT_NV21) { /* Need to add size for the U/V plane */ - size += ((texture->h * data->pitch) / 2); + size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2); } data->pixels = SDL_calloc(1, size); if (!data->pixels) { @@ -875,8 +875,8 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) GL_CLAMP_TO_EDGE); renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2, - texture_h/2, 0, format, type, NULL); + renderdata->glTexImage2D(data->type, 0, internalFormat, (texture_w+1)/2, + (texture_h+1)/2, 0, format, type, NULL); renderdata->glBindTexture(data->type, data->vtexture); renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER, @@ -887,8 +887,8 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) GL_CLAMP_TO_EDGE); renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2, - texture_h/2, 0, format, type, NULL); + renderdata->glTexImage2D(data->type, 0, internalFormat, (texture_w+1)/2, + (texture_h+1)/2, 0, format, type, NULL); renderdata->glDisable(data->type); } @@ -909,8 +909,8 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) GL_CLAMP_TO_EDGE); renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - renderdata->glTexImage2D(data->type, 0, GL_LUMINANCE_ALPHA, texture_w/2, - texture_h/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL); + renderdata->glTexImage2D(data->type, 0, GL_LUMINANCE_ALPHA, (texture_w+1)/2, + (texture_h+1)/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL); renderdata->glDisable(data->type); } @@ -937,7 +937,7 @@ GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, rect->h, data->format, data->formattype, pixels); if (data->yuv) { - renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / 2)); + renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, ((pitch + 1) / 2)); /* Skip to the correct offset into the next texture */ pixels = (const void*)((const Uint8*)pixels + rect->h * pitch); @@ -947,29 +947,29 @@ GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, renderdata->glBindTexture(data->type, data->utexture); } renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2, - rect->w/2, rect->h/2, + (rect->w+1)/2, (rect->h+1)/2, data->format, data->formattype, pixels); /* Skip to the correct offset into the next texture */ - pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4); + pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2)); if (texture->format == SDL_PIXELFORMAT_YV12) { renderdata->glBindTexture(data->type, data->utexture); } else { renderdata->glBindTexture(data->type, data->vtexture); } renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2, - rect->w/2, rect->h/2, + (rect->w+1)/2, (rect->h+1)/2, data->format, data->formattype, pixels); } if (data->nv12) { - renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / 2)); + renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, ((pitch + 1) / 2)); /* Skip to the correct offset into the next texture */ pixels = (const void*)((const Uint8*)pixels + rect->h * pitch); renderdata->glBindTexture(data->type, data->utexture); renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2, - rect->w/2, rect->h/2, + (rect->w + 1)/2, (rect->h + 1)/2, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels); } renderdata->glDisable(data->type); @@ -1000,13 +1000,13 @@ GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture, renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Upitch); renderdata->glBindTexture(data->type, data->utexture); renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2, - rect->w/2, rect->h/2, + (rect->w + 1)/2, (rect->h + 1)/2, data->format, data->formattype, Uplane); renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Vpitch); renderdata->glBindTexture(data->type, data->vtexture); renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2, - rect->w/2, rect->h/2, + (rect->w + 1)/2, (rect->h + 1)/2, data->format, data->formattype, Vplane); renderdata->glDisable(data->type); diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c index 0e87f2aa2..d5d42c343 100644 --- a/src/render/opengles2/SDL_render_gles2.c +++ b/src/render/opengles2/SDL_render_gles2.c @@ -619,11 +619,11 @@ GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) size = texture->h * data->pitch; if (data->yuv) { /* Need to add size for the U and V planes */ - size += (2 * (texture->h * data->pitch) / 4); + size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2); } if (data->nv12) { /* Need to add size for the U/V plane */ - size += ((texture->h * data->pitch) / 2); + size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2); } data->pixel_data = SDL_calloc(1, size); if (!data->pixel_data) { @@ -646,7 +646,7 @@ GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode); renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - renderdata->glTexImage2D(data->texture_type, 0, format, texture->w / 2, texture->h / 2, 0, format, type, NULL); + renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL); renderdata->glGenTextures(1, &data->texture_u); if (GL_CheckError("glGenTexures()", renderer) < 0) { @@ -658,7 +658,7 @@ GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode); renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - renderdata->glTexImage2D(data->texture_type, 0, format, texture->w / 2, texture->h / 2, 0, format, type, NULL); + renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL); if (GL_CheckError("glTexImage2D()", renderer) < 0) { return -1; } @@ -675,7 +675,7 @@ GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode); renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - renderdata->glTexImage2D(data->texture_type, 0, GL_LUMINANCE_ALPHA, texture->w / 2, texture->h / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL); + renderdata->glTexImage2D(data->texture_type, 0, GL_LUMINANCE_ALPHA, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL); if (GL_CheckError("glTexImage2D()", renderer) < 0) { return -1; } @@ -775,14 +775,15 @@ GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect GLES2_TexSubImage2D(data, tdata->texture_type, rect->x / 2, rect->y / 2, - rect->w / 2, - rect->h / 2, + (rect->w + 1) / 2, + (rect->h + 1) / 2, tdata->pixel_format, tdata->pixel_type, - pixels, pitch / 2, 1); + pixels, (pitch + 1) / 2, 1); + /* Skip to the correct offset into the next texture */ - pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4); + pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1)/2)); if (texture->format == SDL_PIXELFORMAT_YV12) { data->glBindTexture(tdata->texture_type, tdata->texture_u); } else { @@ -791,11 +792,11 @@ GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect GLES2_TexSubImage2D(data, tdata->texture_type, rect->x / 2, rect->y / 2, - rect->w / 2, - rect->h / 2, + (rect->w + 1) / 2, + (rect->h + 1) / 2, tdata->pixel_format, tdata->pixel_type, - pixels, pitch / 2, 1); + pixels, (pitch + 1) / 2, 1); } if (tdata->nv12) { @@ -805,11 +806,11 @@ GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect GLES2_TexSubImage2D(data, tdata->texture_type, rect->x / 2, rect->y / 2, - rect->w / 2, - rect->h / 2, + (rect->w + 1) / 2, + (rect->h + 1) / 2, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, - pixels, pitch, 2); + pixels, 2 * ((pitch + 1) / 2), 2); } return GL_CheckError("glTexSubImage2D()", renderer); @@ -836,8 +837,8 @@ GLES2_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture, GLES2_TexSubImage2D(data, tdata->texture_type, rect->x / 2, rect->y / 2, - rect->w / 2, - rect->h / 2, + (rect->w + 1) / 2, + (rect->h + 1) / 2, tdata->pixel_format, tdata->pixel_type, Vplane, Vpitch, 1); @@ -846,8 +847,8 @@ GLES2_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture, GLES2_TexSubImage2D(data, tdata->texture_type, rect->x / 2, rect->y / 2, - rect->w / 2, - rect->h / 2, + (rect->w + 1) / 2, + (rect->h + 1) / 2, tdata->pixel_format, tdata->pixel_type, Uplane, Upitch, 1); diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c index 721c47740..21fe1c010 100644 --- a/src/video/SDL_surface.c +++ b/src/video/SDL_surface.c @@ -26,6 +26,17 @@ #include "SDL_RLEaccel_c.h" #include "SDL_pixels_c.h" +/* Private routines */ +static int +SDL_ConvertPixels_YUV_to_ARGB8888(int width, int height, + Uint32 src_format, const void *src, + void *dst, int dst_pitch); + +static int +SDL_ConvertPixels_ARGB8888_to_YUV(int width, int height, + const void *src, int src_pitch, + Uint32 dst_format, void *dst); + /* Public routines */ /* @@ -1124,58 +1135,133 @@ int SDL_ConvertPixels(int width, int height, /* Fast path for same format copy */ if (src_format == dst_format) { - int bpp, i; + int i; if (SDL_ISPIXELFORMAT_FOURCC(src_format)) { switch (src_format) { case SDL_PIXELFORMAT_YUY2: case SDL_PIXELFORMAT_UYVY: case SDL_PIXELFORMAT_YVYU: - bpp = 2; + /* Packed planes */ + width = 4 * ((width + 1) / 2); + for (i = height; i--;) { + SDL_memcpy(dst, src, width); + src = (const Uint8*)src + src_pitch; + dst = (Uint8*)dst + dst_pitch; + } break; case SDL_PIXELFORMAT_YV12: case SDL_PIXELFORMAT_IYUV: case SDL_PIXELFORMAT_NV12: case SDL_PIXELFORMAT_NV21: - bpp = 1; + { + /* Y plane */ + for (i = height; i--;) { + SDL_memcpy(dst, src, width); + src = (const Uint8*)src + src_pitch; + dst = (Uint8*)dst + dst_pitch; + } + + /* not sure the pitch is relevant here. + this also works to add the size of two chroma planes */ +#if 0 + SDL_memcpy(dst, src, 2 * ((width + 1)/2) * ((height+1)/2)); +#else + + if (src_format == SDL_PIXELFORMAT_YV12 || src_format == SDL_PIXELFORMAT_IYUV) { + /* U and V planes are a quarter the size of the Y plane */ + width = (width + 1) / 2; + height = (height + 1) / 2; + src_pitch = (src_pitch + 1) / 2; + dst_pitch = (dst_pitch + 1) / 2; + for (i = height * 2; i--;) { + SDL_memcpy(dst, src, width); + src = (Uint8*)src + src_pitch; + dst = (Uint8*)dst + dst_pitch; + } + } else if (src_format == SDL_PIXELFORMAT_NV12 || src_format == SDL_PIXELFORMAT_NV21) { + /* U/V plane is half the height of the Y plane */ + height = (height + 1) / 2; + width = (width + 1) / 2; + src_pitch = (src_pitch + 1) / 2; + dst_pitch = (dst_pitch + 1) / 2; + for (i = height; i--;) { + SDL_memcpy(dst, src, 2 * width); + src = (Uint8*)src + 2 * src_pitch; + dst = (Uint8*)dst + 2 * dst_pitch; + } + } +#endif + } break; default: return SDL_SetError("Unknown FOURCC pixel format"); } } else { - bpp = SDL_BYTESPERPIXEL(src_format); - } - width *= bpp; - - for (i = height; i--;) { - SDL_memcpy(dst, src, width); - src = (Uint8*)src + src_pitch; - dst = (Uint8*)dst + dst_pitch; - } - - if (src_format == SDL_PIXELFORMAT_YV12 || src_format == SDL_PIXELFORMAT_IYUV) { - /* U and V planes are a quarter the size of the Y plane */ - width /= 2; - height /= 2; - src_pitch /= 2; - dst_pitch /= 2; - for (i = height * 2; i--;) { - SDL_memcpy(dst, src, width); - src = (Uint8*)src + src_pitch; - dst = (Uint8*)dst + dst_pitch; - } - } else if (src_format == SDL_PIXELFORMAT_NV12 || src_format == SDL_PIXELFORMAT_NV21) { - /* U/V plane is half the height of the Y plane */ - height /= 2; + const int bpp = SDL_BYTESPERPIXEL(src_format); + width *= bpp; for (i = height; i--;) { SDL_memcpy(dst, src, width); - src = (Uint8*)src + src_pitch; + src = (const Uint8*)src + src_pitch; dst = (Uint8*)dst + dst_pitch; } } return 0; } + /* FOURCC to Any */ + if (SDL_ISPIXELFORMAT_FOURCC(src_format)) { + /* FOURCC to ARGB8888 */ + if (dst_format == SDL_PIXELFORMAT_ARGB8888) { + SDL_ConvertPixels_YUV_to_ARGB8888(width, height, src_format, src, dst, dst_pitch); + return 0; + } + else /* FOURCC to not(ARGB8888) : need an intermediate conversion */ + { + int ret; + void *tmp = SDL_malloc(width * height * 4); + if (tmp == NULL) { + return -1; + } + + /* convert src/FOURCC to tmp/ARGB8888 */ + SDL_ConvertPixels_YUV_to_ARGB8888(width, height, src_format, src, tmp, width * 4); + + /* convert tmp/ARGB8888 to dst/dst_format */ + ret = SDL_ConvertPixels(width, height, SDL_PIXELFORMAT_ARGB8888, tmp, width * 4, dst_format, dst, dst_pitch); + SDL_free(tmp); + return ret; + } + } + + /* Any to FOURCC */ + if (SDL_ISPIXELFORMAT_FOURCC(dst_format)) { + /* ARGB8888 to FOURCC */ + if (src_format == SDL_PIXELFORMAT_ARGB8888) { + SDL_ConvertPixels_ARGB8888_to_YUV(width, height, src, src_pitch, dst_format, dst); + return 0; + } + else /* not(ARGB8888) to FOURCC : need an intermediate conversion */ + { + int ret; + void *tmp = SDL_malloc(width * height * 4); + if (tmp == NULL) { + return -1; + } + /* convert src/src_format to tmp/ARGB8888 */ + ret = SDL_ConvertPixels(width, height, src_format, src, src_pitch, SDL_PIXELFORMAT_ARGB8888, tmp, width * 4); + if (ret == -1) { + SDL_free(tmp); + return ret; + } + /* convert tmp/ARGB8888 to dst/FOURCC */ + SDL_ConvertPixels_ARGB8888_to_YUV(width, height, tmp, width * 4, dst_format, dst); + + SDL_free(tmp); + return 0; + } + } + if (!SDL_CreateSurfaceOnStack(width, height, src_format, nonconst_src, src_pitch, &src_surface, &src_fmt, &src_blitmap)) { @@ -1231,4 +1317,472 @@ SDL_FreeSurface(SDL_Surface * surface) SDL_free(surface); } + +/* YUV-RGB conversion */ +#define CLAMP(val) ((val) > 0 ? ((val) < 255 ? (val) : 255) : 0) + +#define MAKE_Y(r, g, b) ((( 66 * (r) + 129 * (g) + 25 * (b) + 128) >> 8) + 16) +#define MAKE_U(r, g, b) ((( -38 * (r) - 74 * (g) + 112 * (b) + 128) >> 8) + 128) +#define MAKE_V(r, g, b) ((( 112 * (r) - 94 * (g) - 18 * (b) + 128) >> 8) + 128) + + +#define MAKE_R(y, u, v) CLAMP(( 298 * ((y) - 16) + 409 * ((v) - 128) + 128) >> 8) +#define MAKE_G(y, u, v) CLAMP(( 298 * ((y) - 16) - 100 * ((u) - 128) - 208 * ((v) - 128) + 128) >> 8) +#define MAKE_B(y, u, v) CLAMP(( 298 * ((y) - 16) + 516 * ((u) - 128) + 128) >> 8) + +static int +SDL_ConvertPixels_YUV_to_ARGB8888(int width, int height, + Uint32 src_format, const void *src, + void *dst, int dst_pitch) +{ + const int sz_plane = width * height; + const int sz_plane_chroma = ((width + 1) / 2) * ((height + 1) / 2); + const int width_remainder = (width & 0x1); + const int width_half = width / 2; + const int curr_row_padding = dst_pitch - 4 * width; + int i, j; + Uint8 *curr_row = (Uint8*)dst; + + // SDL_Log("SDL_ConvertPixels_YUV_to_ARGB8888 (from %s)", SDL_GetPixelFormatName(src_format)); + +#define WRITE_RGB_PIXEL(y, u, v) \ + *((Uint32*)curr_row) = \ + (MAKE_B((y), (u), (v)) \ + | (MAKE_G((y), (u), (v)) << 8) \ + | (MAKE_R((y), (u), (v)) << 16) \ + | 0xff000000); \ + curr_row += 4; \ + + switch (src_format) + { + case SDL_PIXELFORMAT_YV12: + case SDL_PIXELFORMAT_IYUV: + case SDL_PIXELFORMAT_NV12: + case SDL_PIXELFORMAT_NV21: + { + const Uint8 *plane_y = (const Uint8*)src; + + if (src_format == SDL_PIXELFORMAT_YV12 || src_format == SDL_PIXELFORMAT_IYUV) + { + const Uint8 *plane_u = (src_format == SDL_PIXELFORMAT_YV12 ? plane_y + sz_plane + sz_plane_chroma : plane_y + sz_plane); + const Uint8 *plane_v = (src_format == SDL_PIXELFORMAT_YV12 ? plane_y + sz_plane : plane_y + sz_plane + sz_plane_chroma); + + for (j = 0; j < height; j++) { + for (i = 0; i < width_half; i++) { + const Uint8 u = *plane_u++; + const Uint8 v = *plane_v++; + const Uint8 y = *plane_y++; + const Uint8 y1 = *plane_y++; + WRITE_RGB_PIXEL(y, u, v); + WRITE_RGB_PIXEL(y1, u, v); + } + if (width_remainder) { + const Uint8 u = *plane_u++; + const Uint8 v = *plane_v++; + const Uint8 y = *plane_y++; + WRITE_RGB_PIXEL(y, u, v); + } + /* Re-use the same line of chroma planes */ + if ((j & 0x1) == 0x0) { + plane_u -= width_half + width_remainder; + plane_v -= width_half + width_remainder; + } + curr_row += curr_row_padding; + } + } + else if (src_format == SDL_PIXELFORMAT_NV12) + { + const Uint8 *plane_interleaved_uv = plane_y + sz_plane; + for (j = 0; j < height; j++) { + for (i = 0; i < width_half; i++) { + const Uint8 y = *plane_y++; + const Uint8 y1 = *plane_y++; + const Uint8 u = *plane_interleaved_uv++; + const Uint8 v = *plane_interleaved_uv++; + WRITE_RGB_PIXEL(y, u, v); + WRITE_RGB_PIXEL(y1, u, v); + } + if (width_remainder) { + const Uint8 y = *plane_y++; + const Uint8 u = *plane_interleaved_uv++; + const Uint8 v = *plane_interleaved_uv++; + WRITE_RGB_PIXEL(y, u, v); + } + /* Re-use the same line of chroma planes */ + if ((j & 0x1) == 0x0) { + plane_interleaved_uv -= 2 * (width_half + width_remainder); + } + curr_row += curr_row_padding; + } + } + else /* src_format == SDL_PIXELFORMAT_NV21 */ + { + const Uint8 *plane_interleaved_uv = plane_y + sz_plane; + for (j = 0; j < height; j++) { + for (i = 0; i < width_half; i++) { + const Uint8 y = *plane_y++; + const Uint8 y1 = *plane_y++; + const Uint8 v = *plane_interleaved_uv++; + const Uint8 u = *plane_interleaved_uv++; + WRITE_RGB_PIXEL(y, u, v); + WRITE_RGB_PIXEL(y1, u, v); + } + if (width_remainder) { + const Uint8 y = *plane_y++; + const Uint8 v = *plane_interleaved_uv++; + const Uint8 u = *plane_interleaved_uv++; + WRITE_RGB_PIXEL(y, u, v); + } + /* Re-use the same line of chroma planes */ + if ((j & 0x1) == 0x0) { + plane_interleaved_uv -= 2 * (width_half + width_remainder); + } + curr_row += curr_row_padding; + } + } + } + break; + + case SDL_PIXELFORMAT_YUY2: + case SDL_PIXELFORMAT_UYVY: + case SDL_PIXELFORMAT_YVYU: + { + const Uint8 *plane = (const Uint8 *)src; + +#define READ_PACKED_YUV(var1, var2, var3, var4) \ + const Uint8 var1 = plane[0]; \ + const Uint8 var2 = plane[1]; \ + const Uint8 var3 = plane[2]; \ + const Uint8 var4 = plane[3]; \ + plane += 4; \ + + if (src_format == SDL_PIXELFORMAT_YUY2) /* Y U Y1 V */ + { + for (j = 0; j < height; j++) { + for (i = 0; i < width_half; i++) { + READ_PACKED_YUV(y, u, y1, v); + WRITE_RGB_PIXEL(y, u, v); + WRITE_RGB_PIXEL(y1, u, v); + } + if (width_remainder) { + READ_PACKED_YUV(y, u, y1, v); /* y1 unused */ + WRITE_RGB_PIXEL(y, u, v); + } + curr_row += curr_row_padding; + } + } + else if (src_format == SDL_PIXELFORMAT_UYVY) /* U Y V Y1 */ + { + for (j = 0; j < height; j++) { + for (i = 0; i < width_half; i++) { + READ_PACKED_YUV(u, y, v, y1); + WRITE_RGB_PIXEL(y, u, v); + WRITE_RGB_PIXEL(y1, u, v); + } + if (width_remainder) { + READ_PACKED_YUV(u, y, v, y1); /* y1 unused */ + WRITE_RGB_PIXEL(y, u, v); + } + curr_row += curr_row_padding; + } + } + else if (src_format == SDL_PIXELFORMAT_YVYU) /* Y V Y1 U */ + { + for (j = 0; j < height; j++) { + for (i = 0; i < width_half; i++) { + READ_PACKED_YUV(y, v, y1, u); + WRITE_RGB_PIXEL(y, u, v); + WRITE_RGB_PIXEL(y1, u, v); + } + if (width_remainder) { + READ_PACKED_YUV(y, v, y1, u); /* y1 unused */ + WRITE_RGB_PIXEL(y, u, v); + } + curr_row += curr_row_padding; + } + } +#undef READ_PACKED_YUV + } + break; + } +#undef WRITE_RGB_PIXEL + return 0; +} + +static int +SDL_ConvertPixels_ARGB8888_to_YUV(int width, int height, const void *src, int src_pitch, Uint32 dst_format, void *dst) +{ + const int src_pitch_x_2 = src_pitch * 2; + const int sz_plane = width * height; + const int sz_plane_chroma = ((width + 1) / 2) * ((height + 1) / 2); + const int height_half = height / 2; + const int height_remainder = (height & 0x1); + const int width_half = width / 2; + const int width_remainder = (width & 0x1); + int i, j; + + // SDL_Log("SDL_ConvertPixels_ARGB8888_to_YUV (to %s)", SDL_GetPixelFormatName(dst_format)); + + switch (dst_format) + { + case SDL_PIXELFORMAT_YV12: + case SDL_PIXELFORMAT_IYUV: + case SDL_PIXELFORMAT_NV12: + case SDL_PIXELFORMAT_NV21: + { + const Uint8 *curr_row, *next_row; + + Uint8 *plane_y = (Uint8*) dst; + Uint8 *plane_u = (dst_format == SDL_PIXELFORMAT_YV12 ? plane_y + sz_plane + sz_plane_chroma : plane_y + sz_plane); + Uint8 *plane_v = (dst_format == SDL_PIXELFORMAT_YV12 ? plane_y + sz_plane : plane_y + sz_plane + sz_plane_chroma); + Uint8 *plane_interleaved_uv = plane_y + sz_plane; + + curr_row = (const Uint8*)src; + + /* Write Y plane */ + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + const Uint8 b = curr_row[4 * i + 0]; + const Uint8 g = curr_row[4 * i + 1]; + const Uint8 r = curr_row[4 * i + 2]; + *plane_y++ = MAKE_Y(r, g, b); + } + curr_row += src_pitch; + } + + curr_row = (const Uint8*)src; + next_row = (const Uint8*)src; + next_row += src_pitch; + +#if 1 +/* slightly faster */ +#define READ_2x2_PIXELS \ + const Uint32 p1 = ((Uint32 *)curr_row)[2 * i]; \ + const Uint32 p2 = ((Uint32 *)curr_row)[2 * i + 1]; \ + const Uint32 p3 = ((Uint32 *)next_row)[2 * i]; \ + const Uint32 p4 = ((Uint32 *)next_row)[2 * i + 1]; \ + const Uint32 b = ((p1 & 0x000000ff) + (p2 & 0x000000ff) + (p3 & 0x000000ff) + (p4 & 0x000000ff)) >> 2; \ + const Uint32 g = ((p1 & 0x0000ff00) + (p2 & 0x0000ff00) + (p3 & 0x0000ff00) + (p4 & 0x0000ff00)) >> 10; \ + const Uint32 r = ((p1 & 0x00ff0000) + (p2 & 0x00ff0000) + (p3 & 0x00ff0000) + (p4 & 0x00ff0000)) >> 18; \ + +#else + +#define READ_2x2_PIXELS \ + const Uint8 b = (curr_row[8 * i + 0] + curr_row[8 * i + 4] \ + + next_row[8 * i + 0] + next_row[8 * i + 4] ) >> 2; \ + const Uint8 g = (curr_row[8 * i + 1] + curr_row[8 * i + 5] \ + + next_row[8 * i + 1] + next_row[8 * i + 5] ) >> 2; \ + const Uint8 r = (curr_row[8 * i + 2] + curr_row[8 * i + 6] \ + + next_row[8 * i + 2] + next_row[8 * i + 6] ) >> 2; \ + +#endif + +#define READ_2x1_PIXELS \ + const Uint8 b = (curr_row[8 * i + 0] + next_row[8 * i + 0]) >> 1; \ + const Uint8 g = (curr_row[8 * i + 1] + next_row[8 * i + 1]) >> 1; \ + const Uint8 r = (curr_row[8 * i + 2] + next_row[8 * i + 2]) >> 1; \ + +#define READ_1x2_PIXELS \ + const Uint8 b = (curr_row[8 * i + 0] + curr_row[8 * i + 4]) >> 1; \ + const Uint8 g = (curr_row[8 * i + 1] + curr_row[8 * i + 5]) >> 1; \ + const Uint8 r = (curr_row[8 * i + 2] + curr_row[8 * i + 6]) >> 1; \ + +#define READ_1x1_PIXEL \ + const Uint8 b = curr_row[8 * i + 0]; \ + const Uint8 g = curr_row[8 * i + 1]; \ + const Uint8 r = curr_row[8 * i + 2]; \ + + if (dst_format == SDL_PIXELFORMAT_YV12 || dst_format == SDL_PIXELFORMAT_IYUV) + { + /* Write UV planes, not interleaved */ + for (j = 0; j < height_half; j++) { + for (i = 0; i < width_half; i++) { + READ_2x2_PIXELS; + *plane_u++ = MAKE_U(r, g, b); + *plane_v++ = MAKE_V(r, g, b); + } + if (width_remainder) { + READ_2x1_PIXELS; + *plane_u++ = MAKE_U(r, g, b); + *plane_v++ = MAKE_V(r, g, b); + } + curr_row += src_pitch_x_2; + next_row += src_pitch_x_2; + } + if (height_remainder) { + for (i = 0; i < width_half; i++) { + READ_1x2_PIXELS; + *plane_u++ = MAKE_U(r, g, b); + *plane_v++ = MAKE_V(r, g, b); + } + if (width_remainder) { + READ_1x1_PIXEL; + *plane_u++ = MAKE_U(r, g, b); + *plane_v++ = MAKE_V(r, g, b); + } + } + } + else if (dst_format == SDL_PIXELFORMAT_NV12) + { + for (j = 0; j < height_half; j++) { + for (i = 0; i < width_half; i++) { + READ_2x2_PIXELS; + *plane_interleaved_uv++ = MAKE_U(r, g, b); + *plane_interleaved_uv++ = MAKE_V(r, g, b); + } + if (width_remainder) { + READ_2x1_PIXELS; + *plane_interleaved_uv++ = MAKE_U(r, g, b); + *plane_interleaved_uv++ = MAKE_V(r, g, b); + } + curr_row += src_pitch_x_2; + next_row += src_pitch_x_2; + } + if (height_remainder) { + for (i = 0; i < width_half; i++) { + READ_1x2_PIXELS; + *plane_interleaved_uv++ = MAKE_U(r, g, b); + *plane_interleaved_uv++ = MAKE_V(r, g, b); + } + if (width_remainder) { + READ_1x1_PIXEL; + *plane_interleaved_uv++ = MAKE_U(r, g, b); + *plane_interleaved_uv++ = MAKE_V(r, g, b); + } + } + } + else /* dst_format == SDL_PIXELFORMAT_NV21 */ + { + for (j = 0; j < height_half; j++) { + for (i = 0; i < width_half; i++) { + READ_2x2_PIXELS; + *plane_interleaved_uv++ = MAKE_V(r, g, b); + *plane_interleaved_uv++ = MAKE_U(r, g, b); + } + if (width_remainder) { + READ_2x1_PIXELS; + *plane_interleaved_uv++ = MAKE_V(r, g, b); + *plane_interleaved_uv++ = MAKE_U(r, g, b); + } + curr_row += src_pitch_x_2; + next_row += src_pitch_x_2; + } + if (height_remainder) { + for (i = 0; i < width_half; i++) { + READ_1x2_PIXELS; + *plane_interleaved_uv++ = MAKE_V(r, g, b); + *plane_interleaved_uv++ = MAKE_U(r, g, b); + } + if (width_remainder) { + READ_1x1_PIXEL; + *plane_interleaved_uv++ = MAKE_V(r, g, b); + *plane_interleaved_uv++ = MAKE_U(r, g, b); + } + } + } +#undef READ_2x2_PIXELS +#undef READ_2x1_PIXELS +#undef READ_1x2_PIXELS +#undef READ_1x1_PIXEL + } + break; + + case SDL_PIXELFORMAT_YUY2: + case SDL_PIXELFORMAT_UYVY: + case SDL_PIXELFORMAT_YVYU: + { + const Uint8 *curr_row = (const Uint8*) src; + Uint8 *plane = (Uint8*) dst; + +#define READ_TWO_RGB_PIXELS \ + const Uint8 b = curr_row[8 * i + 0]; \ + const Uint8 g = curr_row[8 * i + 1]; \ + const Uint8 r = curr_row[8 * i + 2]; \ + const Uint8 b1 = curr_row[8 * i + 4]; \ + const Uint8 g1 = curr_row[8 * i + 5]; \ + const Uint8 r1 = curr_row[8 * i + 6]; \ + const Uint8 B = (b + b1) >> 1; \ + const Uint8 G = (g + g1) >> 1; \ + const Uint8 R = (r + r1) >> 1; \ + +#define READ_ONE_RGB_PIXEL \ + const Uint8 b = curr_row[8 * i + 0]; \ + const Uint8 g = curr_row[8 * i + 1]; \ + const Uint8 r = curr_row[8 * i + 2]; \ + + /* Write YUV plane, packed */ + if (dst_format == SDL_PIXELFORMAT_YUY2) + { + for (j = 0; j < height; j++) { + for (i = 0; i < width_half; i++) { + READ_TWO_RGB_PIXELS; + /* Y U Y1 V */ + *plane++ = MAKE_Y(r, g, b); + *plane++ = MAKE_U(R, G, B); + *plane++ = MAKE_Y(r1, g1, b1); + *plane++ = MAKE_V(R, G, B); + } + if (width_remainder) { + READ_ONE_RGB_PIXEL; + /* Y U Y V */ + *plane++ = MAKE_Y(r, g, b); + *plane++ = MAKE_U(r, g, b); + *plane++ = MAKE_Y(r, g, b); + *plane++ = MAKE_V(r, g, b); + } + curr_row += src_pitch; + } + } + else if (dst_format == SDL_PIXELFORMAT_UYVY) + { + for (j = 0; j < height; j++) { + for (i = 0; i < width_half; i++) { + READ_TWO_RGB_PIXELS; + /* U Y V Y1 */ + *plane++ = MAKE_U(R, G, B); + *plane++ = MAKE_Y(r, g, b); + *plane++ = MAKE_V(R, G, B); + *plane++ = MAKE_Y(r1, g1, b1); + } + if (width_remainder) { + READ_ONE_RGB_PIXEL; + /* U Y V Y */ + *plane++ = MAKE_U(r, g, b); + *plane++ = MAKE_Y(r, g, b); + *plane++ = MAKE_V(r, g, b); + *plane++ = MAKE_Y(r, g, b); + } + curr_row += src_pitch; + } + } + else if (dst_format == SDL_PIXELFORMAT_YVYU) + { + for (j = 0; j < height; j++) { + for (i = 0; i < width_half; i++) { + READ_TWO_RGB_PIXELS; + /* Y V Y1 U */ + *plane++ = MAKE_Y(r, g, b); + *plane++ = MAKE_V(R, G, B); + *plane++ = MAKE_Y(r1, g1, b1); + *plane++ = MAKE_U(R, G, B); + } + if (width_remainder) { + READ_ONE_RGB_PIXEL; + /* Y V Y U */ + *plane++ = MAKE_Y(r, g, b); + *plane++ = MAKE_V(r, g, b); + *plane++ = MAKE_Y(r, g, b); + *plane++ = MAKE_U(r, g, b); + } + curr_row += src_pitch; + } + } +#undef READ_TWO_RGB_PIXELS +#undef READ_ONE_RGB_PIXEL + } + break; + } + return 0; +} + /* vi: set ts=4 sw=4 expandtab: */