/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*This contains all of the parameters that are needed to convert a row. Passingtheminastructinsteadofasindividualparameterssavestheneed
to continually push onto the stack the ones that are fixed for every row.*/ struct yuv2rgb565_row_scale_bilinear_ctx{
uint16_t *rgb_row; const uint8_t *y_row; const uint8_t *u_row; const uint8_t *v_row; int y_yweight; int y_pitch; int width; int source_x0_q16; int source_dx_q16; /*Not used for 4:4:4, except with chroma-nearest.*/ int source_uv_xoffs_q16; /*Not used for 4:4:4 or chroma-nearest.*/ int uv_pitch; /*Not used for 4:2:2, 4:4:4, or chroma-nearest.*/ int uv_yweight;
};
/*This contains all of the parameters that are needed to convert a row. Passingtheminastructinsteadofasindividualparameterssavestheneed
to continually push onto the stack the ones that are fixed for every row.*/ struct yuv2rgb565_row_scale_nearest_ctx{
uint16_t *rgb_row; const uint8_t *y_row; const uint8_t *u_row; const uint8_t *v_row; int width; int source_x0_q16; int source_dx_q16; /*Not used for 4:4:4.*/ int source_uv_xoffs_q16;
};
typedefvoid (*yuv2rgb565_row_scale_bilinear_func)( const yuv2rgb565_row_scale_bilinear_ctx *ctx, int dither);
typedefvoid (*yuv2rgb565_row_scale_nearest_func)( const yuv2rgb565_row_scale_nearest_ctx *ctx, int dither);
//TODO: fix NEON asm for iOS # ifdefined(MOZILLA_MAY_SUPPORT_NEON) && !defined(__APPLE__)
extern"C"void ScaleYCbCr42xToRGB565_BilinearY_Row_NEON( const yuv2rgb565_row_scale_bilinear_ctx *ctx, int dither);
void __attribute((noinline)) yuv42x_to_rgb565_row_neon(uint16_t *dst, const uint8_t *y, const uint8_t *u, const uint8_t *v, int n, int oddflag);
#endif
/*Bilinear interpolation of a single value. Thisusestheexactsameformulasastheasm,eventhoughitaddssomeextra
shifts that do nothing but reduce accuracy.*/ staticint bislerp(const uint8_t *row, int pitch, int source_x, int xweight, int yweight) { int a; int b; int c; int d;
a = row[source_x];
b = row[source_x+1];
c = row[source_x+pitch];
d = row[source_x+pitch+1];
a = ((a<<8)+(c-a)*yweight+128)>>8;
b = ((b<<8)+(d-b)*yweight+128)>>8; return ((a<<8)+(b-a)*xweight+128)>>8;
}
/*Convert a single pixel from Y'CbCr to RGB565. Thisusestheexactsameformulasastheasm,eventhoughwecouldmakethe
constants a lot more accurate with 32-bit wide registers.*/ static uint16_t yu2rgb565(int y, int u, int v, int dither) { /*This combines the constant offset that needs to be added during the Y'CbCr
conversion with a rounding offset that depends on the dither parameter.*/ staticconstint DITHER_BIAS[4][3]={
{-14240, 8704, -17696},
{-14240+128,8704+64, -17696+128},
{-14240+256,8704+128,-17696+256},
{-14240+384,8704+192,-17696+384}
}; int r; int g; int b;
r = std::clamp((74*y+102*v+DITHER_BIAS[dither][0])>>9, 0, 31);
g = std::clamp((74*y-25*u-52*v+DITHER_BIAS[dither][1])>>8, 0, 63);
b = std::clamp((74*y+129*u+DITHER_BIAS[dither][2])>>9, 0, 31); return (uint16_t)(r<<11 | g<<5 | b);
}
staticvoid ScaleYCbCr420ToRGB565_Bilinear_Row_C( const yuv2rgb565_row_scale_bilinear_ctx *ctx, int dither){ int x; int source_x_q16;
source_x_q16 = ctx->source_x0_q16; for (x = 0; x < ctx->width; x++) { int source_x; int xweight; int y; int u; int v;
xweight = ((source_x_q16&0xFFFF)+128)>>8;
source_x = source_x_q16>>16;
y = bislerp(ctx->y_row, ctx->y_pitch, source_x, xweight, ctx->y_yweight);
xweight = (((source_x_q16+ctx->source_uv_xoffs_q16)&0x1FFFF)+256)>>9;
source_x = (source_x_q16+ctx->source_uv_xoffs_q16)>>17;
source_x_q16 += ctx->source_dx_q16;
u = bislerp(ctx->u_row, ctx->uv_pitch, source_x, xweight, ctx->uv_yweight);
v = bislerp(ctx->v_row, ctx->uv_pitch, source_x, xweight, ctx->uv_yweight);
ctx->rgb_row[x] = yu2rgb565(y, u, v, dither);
dither ^= 3;
}
}
staticvoid ScaleYCbCr422ToRGB565_Bilinear_Row_C( const yuv2rgb565_row_scale_bilinear_ctx *ctx, int dither){ int x; int source_x_q16;
source_x_q16 = ctx->source_x0_q16; for (x = 0; x < ctx->width; x++) { int source_x; int xweight; int y; int u; int v;
xweight = ((source_x_q16&0xFFFF)+128)>>8;
source_x = source_x_q16>>16;
y = bislerp(ctx->y_row, ctx->y_pitch, source_x, xweight, ctx->y_yweight);
xweight = (((source_x_q16+ctx->source_uv_xoffs_q16)&0x1FFFF)+256)>>9;
source_x = (source_x_q16+ctx->source_uv_xoffs_q16)>>17;
source_x_q16 += ctx->source_dx_q16;
u = bislerp(ctx->u_row, ctx->uv_pitch, source_x, xweight, ctx->y_yweight);
v = bislerp(ctx->v_row, ctx->uv_pitch, source_x, xweight, ctx->y_yweight);
ctx->rgb_row[x] = yu2rgb565(y, u, v, dither);
dither ^= 3;
}
}
staticvoid ScaleYCbCr444ToRGB565_Bilinear_Row_C( const yuv2rgb565_row_scale_bilinear_ctx *ctx, int dither){ int x; int source_x_q16;
source_x_q16 = ctx->source_x0_q16; for (x = 0; x < ctx->width; x++) { int source_x; int xweight; int y; int u; int v;
xweight = ((source_x_q16&0xFFFF)+128)>>8;
source_x = source_x_q16>>16;
source_x_q16 += ctx->source_dx_q16;
y = bislerp(ctx->y_row, ctx->y_pitch, source_x, xweight, ctx->y_yweight);
u = bislerp(ctx->u_row, ctx->y_pitch, source_x, xweight, ctx->y_yweight);
v = bislerp(ctx->v_row, ctx->y_pitch, source_x, xweight, ctx->y_yweight);
ctx->rgb_row[x] = yu2rgb565(y, u, v, dither);
dither ^= 3;
}
}
staticvoid ScaleYCbCr42xToRGB565_BilinearY_Row_C( const yuv2rgb565_row_scale_bilinear_ctx *ctx, int dither){ int x; int source_x_q16;
source_x_q16 = ctx->source_x0_q16; for (x = 0; x < ctx->width; x++) { int source_x; int xweight; int y; int u; int v;
xweight = ((source_x_q16&0xFFFF)+128)>>8;
source_x = source_x_q16>>16;
y = bislerp(ctx->y_row, ctx->y_pitch, source_x, xweight, ctx->y_yweight);
source_x = (source_x_q16+ctx->source_uv_xoffs_q16)>>17;
source_x_q16 += ctx->source_dx_q16;
u = ctx->u_row[source_x];
v = ctx->v_row[source_x];
ctx->rgb_row[x] = yu2rgb565(y, u, v, dither);
dither ^= 3;
}
}
staticvoid ScaleYCbCr444ToRGB565_BilinearY_Row_C( const yuv2rgb565_row_scale_bilinear_ctx *ctx, int dither){ int x; int source_x_q16;
source_x_q16 = ctx->source_x0_q16; for (x = 0; x < ctx->width; x++) { int source_x; int xweight; int y; int u; int v;
xweight = ((source_x_q16&0xFFFF)+128)>>8;
source_x = source_x_q16>>16;
y = bislerp(ctx->y_row, ctx->y_pitch, source_x, xweight, ctx->y_yweight);
source_x = (source_x_q16+ctx->source_uv_xoffs_q16)>>16;
source_x_q16 += ctx->source_dx_q16;
u = ctx->u_row[source_x];
v = ctx->v_row[source_x];
ctx->rgb_row[x] = yu2rgb565(y, u, v, dither);
dither ^= 3;
}
}
staticvoid ScaleYCbCr42xToRGB565_Nearest_Row_C( const yuv2rgb565_row_scale_nearest_ctx *ctx, int dither){ int y; int u; int v; int x; int source_x_q16; int source_x;
source_x_q16 = ctx->source_x0_q16; for (x = 0; x < ctx->width; x++) {
source_x = source_x_q16>>16;
y = ctx->y_row[source_x];
source_x = (source_x_q16+ctx->source_uv_xoffs_q16)>>17;
source_x_q16 += ctx->source_dx_q16;
u = ctx->u_row[source_x];
v = ctx->v_row[source_x];
ctx->rgb_row[x] = yu2rgb565(y, u, v, dither);
dither ^= 3;
}
}
staticvoid ScaleYCbCr444ToRGB565_Nearest_Row_C( const yuv2rgb565_row_scale_nearest_ctx *ctx, int dither){ int y; int u; int v; int x; int source_x_q16; int source_x;
source_x_q16 = ctx->source_x0_q16; for (x = 0; x < ctx->width; x++) {
source_x = source_x_q16>>16;
source_x_q16 += ctx->source_dx_q16;
y = ctx->y_row[source_x];
u = ctx->u_row[source_x];
v = ctx->v_row[source_x];
ctx->rgb_row[x] = yu2rgb565(y, u, v, dither);
dither ^= 3;
}
}
void ScaleYCbCrToRGB565(const uint8_t *y_buf, const uint8_t *u_buf, const uint8_t *v_buf,
uint8_t *rgb_buf, int source_x0, int source_y0, int source_width, int source_height, int width, int height, int y_pitch, int uv_pitch, int rgb_pitch,
YUVType yuv_type,
ScaleFilter filter) { int source_x0_q16; int source_y0_q16; int source_dx_q16; int source_dy_q16; int source_uv_xoffs_q16; int source_uv_yoffs_q16; int x_shift; int y_shift; int ymin; int ymax; int uvmin; int uvmax; int dither; /*We don't support negative destination rectangles (just flip the source
instead), and for empty ones there's nothing to do.*/ if (width <= 0 || height <= 0) return; /*These bounds are required to avoid 16.16 fixed-point overflow.*/ if (!IsScaleYCbCrToRGB565BoundsValid(source_x0, source_y0, source_width,
source_height)) { return;
} /*We require the same stride for Y' and Cb and Cr for 4:4:4 content.*/
NS_ASSERTION(yuv_type != YV24 || y_pitch == uv_pitch, "ScaleYCbCrToRGB565 luma stride differs from chroma for 4:4:4 content."); /*We assume we can read outside the bounds of the input, because it makes thecodemuchsimpler(andinpracticeistrue:bothTheoraandVP8return paddedreferenceframes). Inpractice,wedonoteven_have_theactualboundsofthesource,as wearepassedacroprectanglefromit,andnotthedimensionsofthefull image. Thisassertionwillnotguaranteeourout-of-boundsreadsaresafe,butit
should at least catch the simple case of passing in an unpadded buffer.*/
NS_ASSERTION(abs(y_pitch) >= abs(source_width)+16, "ScaleYCbCrToRGB565 source image unpadded?"); /*The NEON code requires the pointers to be aligned to a 16-byte boundary at thestartofeachrow. Thisshouldbetrueforallofoursources. Wecouldtrytofixthisupifit'snottruebyadjustingsource_x0,but thatwouldrequirethemis-alignmenttobethesamefortheUandV
planes.*/
NS_ASSERTION((y_pitch&15) == 0 && (uv_pitch&15) == 0 &&
((y_buf-(uint8_t *)nullptr)&15) == 0 &&
((u_buf-(uint8_t *)nullptr)&15) == 0 &&
((v_buf-(uint8_t *)nullptr)&15) == 0, "ScaleYCbCrToRGB565 source image unaligned"); /*We take an area-based approach to pixel coverage to avoid shifting by small amounts(ornotsosmall,whenup-scalingordown-scalingbyalarge factor).
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.