Rename avifRGBSpaceInfo to avifRGBColorSpaceInfo. (#1623) Same for YUV. Move 'mode' to avifYUVColorSpaceInfo. Change argument of avifReformatStateYToUNorm and avifReformatStateUVToUNorm to avifYUVColorSpaceInfo.
diff --git a/include/avif/internal.h b/include/avif/internal.h index 0afd5f7..895537c 100644 --- a/include/avif/internal.h +++ b/include/avif/internal.h
@@ -158,43 +158,45 @@ AVIF_ALPHA_MULTIPLY_MODE_UNMULTIPLY } avifAlphaMultiplyMode; -typedef struct avifRGBSpaceInfo +// Information about an RGB color space. +typedef struct avifRGBColorSpaceInfo { - uint32_t channelBytes; - uint32_t pixelBytes; - uint32_t offsetBytesR; - uint32_t offsetBytesG; - uint32_t offsetBytesB; - uint32_t offsetBytesA; + uint32_t channelBytes; // Number of bytes per channel. + uint32_t pixelBytes; // Number of bytes per pixel (= channelBytes * num channels). + uint32_t offsetBytesR; // Offset in bytes of the red channel in a pixel. + uint32_t offsetBytesG; // Offset in bytes of the green channel in a pixel. + uint32_t offsetBytesB; // Offset in bytes of the blue channel in a pixel. + uint32_t offsetBytesA; // Offset in bytes of the alpha channel in a pixel. - int maxChannel; - float maxChannelF; -} avifRGBSpaceInfo; + int maxChannel; // Maximum value for a channel (e.g. 255 for 8 bit). + float maxChannelF; // Same as maxChannel but as a float. +} avifRGBColorSpaceInfo; -typedef struct avifYUVSpaceInfo +// Information about a YUV color space. +typedef struct avifYUVColorSpaceInfo { - // YUV coefficients + // YUV coefficients. Y = kr*R + kg*G + kb*B. float kr; float kg; float kb; - uint32_t channelBytes; - uint32_t depth; - avifRange range; - int maxChannel; - float biasY; // minimum Y value - float biasUV; // the value of 0.5 for the appropriate bit depth [128, 512, 2048] - float rangeY; // difference between max and min Y - float rangeUV; // difference between max and min UV + uint32_t channelBytes; // Number of bytes per channel. + uint32_t depth; // Bit depth. + avifRange range; // Full or limited range. + int maxChannel; // Maximum value for a channel (e.g. 255 for 8 bit). + float biasY; // Minimum Y value. + float biasUV; // The value of 0.5 for the appropriate bit depth (128 for 8 bit, 512 for 10 bit, 2048 for 12 bit). + float rangeY; // Difference between max and min Y. + float rangeUV; // Difference between max and min UV. - avifPixelFormatInfo formatInfo; -} avifYUVSpaceInfo; + avifPixelFormatInfo formatInfo; // Chroma subsampling information. + avifReformatMode mode; // Appropriate RGB<->YUV conversion mode. +} avifYUVColorSpaceInfo; typedef struct avifReformatState { - avifRGBSpaceInfo rgb; - avifYUVSpaceInfo yuv; - avifReformatMode mode; + avifRGBColorSpaceInfo rgb; + avifYUVColorSpaceInfo yuv; } avifReformatState; // Returns:
diff --git a/src/reformat.c b/src/reformat.c index a403bd4..b4d63ba 100644 --- a/src/reformat.c +++ b/src/reformat.c
@@ -21,7 +21,7 @@ float v; }; -static avifBool avifGetRGBSpaceInfo(const avifRGBImage * rgb, avifRGBSpaceInfo * info) +static avifBool avifGetRGBColorSpaceInfo(const avifRGBImage * rgb, avifRGBColorSpaceInfo * info) { if ((rgb->depth != 8) && (rgb->depth != 10) && (rgb->depth != 12) && (rgb->depth != 16)) { return AVIF_FALSE; @@ -97,7 +97,7 @@ return AVIF_TRUE; } -static avifBool avifGetYUVSpaceInfo(const avifImage * image, avifYUVSpaceInfo * info) +static avifBool avifGetYUVColorSpaceInfo(const avifImage * image, avifYUVColorSpaceInfo * info) { #if defined(AVIF_ENABLE_EXPERIMENTAL_YCGCO_R) const avifBool useYCgCo = (image->matrixCoefficients == AVIF_MATRIX_COEFFICIENTS_YCGCO_RE) || @@ -167,24 +167,24 @@ } } - AVIF_CHECK(avifGetRGBSpaceInfo(rgb, &state->rgb)); - AVIF_CHECK(avifGetYUVSpaceInfo(image, &state->yuv)); + AVIF_CHECK(avifGetRGBColorSpaceInfo(rgb, &state->rgb)); + AVIF_CHECK(avifGetYUVColorSpaceInfo(image, &state->yuv)); - state->mode = AVIF_REFORMAT_MODE_YUV_COEFFICIENTS; + state->yuv.mode = AVIF_REFORMAT_MODE_YUV_COEFFICIENTS; if (image->matrixCoefficients == AVIF_MATRIX_COEFFICIENTS_IDENTITY) { - state->mode = AVIF_REFORMAT_MODE_IDENTITY; + state->yuv.mode = AVIF_REFORMAT_MODE_IDENTITY; } else if (image->matrixCoefficients == AVIF_MATRIX_COEFFICIENTS_YCGCO) { - state->mode = AVIF_REFORMAT_MODE_YCGCO; + state->yuv.mode = AVIF_REFORMAT_MODE_YCGCO; #if defined(AVIF_ENABLE_EXPERIMENTAL_YCGCO_R) } else if (useYCgCoRe) { - state->mode = AVIF_REFORMAT_MODE_YCGCO_RE; + state->yuv.mode = AVIF_REFORMAT_MODE_YCGCO_RE; } else if (useYCgCoRo) { - state->mode = AVIF_REFORMAT_MODE_YCGCO_RO; + state->yuv.mode = AVIF_REFORMAT_MODE_YCGCO_RO; #endif } - if (state->mode != AVIF_REFORMAT_MODE_YUV_COEFFICIENTS) { + if (state->yuv.mode != AVIF_REFORMAT_MODE_YUV_COEFFICIENTS) { state->yuv.kr = 0.0f; state->yuv.kg = 0.0f; state->yuv.kb = 0.0f; @@ -194,33 +194,32 @@ } // Formulas 20-31 from https://www.itu.int/rec/T-REC-H.273-201612-I/en -static int avifReformatStateYToUNorm(avifReformatState * state, float v) +static int avifYUVColorSpaceInfoYToUNorm(avifYUVColorSpaceInfo * info, float v) { - int unorm = (int)avifRoundf(v * state->yuv.rangeY + state->yuv.biasY); - return AVIF_CLAMP(unorm, 0, state->yuv.maxChannel); + int unorm = (int)avifRoundf(v * info->rangeY + info->biasY); + return AVIF_CLAMP(unorm, 0, info->maxChannel); } -static int avifReformatStateUVToUNorm(avifReformatState * state, float v) +static int avifYUVColorSpaceInfoUVToUNorm(avifYUVColorSpaceInfo * info, float v) { int unorm; // YCgCo performs limited-full range adjustment on R,G,B but the current implementation performs range adjustment // on Y,U,V. So YCgCo with limited range is unsupported. #if defined(AVIF_ENABLE_EXPERIMENTAL_YCGCO_R) - assert((state->mode != AVIF_REFORMAT_MODE_YCGCO && state->mode != AVIF_REFORMAT_MODE_YCGCO_RE && - state->mode != AVIF_REFORMAT_MODE_YCGCO_RO) || - (state->yuv.range == AVIF_RANGE_FULL)); + assert((info->mode != AVIF_REFORMAT_MODE_YCGCO && info->mode != AVIF_REFORMAT_MODE_YCGCO_RE && info->mode != AVIF_REFORMAT_MODE_YCGCO_RO) || + (info->range == AVIF_RANGE_FULL)); #else - assert((state->mode != AVIF_REFORMAT_MODE_YCGCO) || (state->yuv.range == AVIF_RANGE_FULL)); + assert((info->mode != AVIF_REFORMAT_MODE_YCGCO) || (info->range == AVIF_RANGE_FULL)); #endif - if (state->mode == AVIF_REFORMAT_MODE_IDENTITY) { - unorm = (int)avifRoundf(v * state->yuv.rangeY + state->yuv.biasY); + if (info->mode == AVIF_REFORMAT_MODE_IDENTITY) { + unorm = (int)avifRoundf(v * info->rangeY + info->biasY); } else { - unorm = (int)avifRoundf(v * state->yuv.rangeUV + state->yuv.biasUV); + unorm = (int)avifRoundf(v * info->rangeUV + info->biasUV); } - return AVIF_CLAMP(unorm, 0, state->yuv.maxChannel); + return AVIF_CLAMP(unorm, 0, info->maxChannel); } avifResult avifImageRGBToYUV(avifImage * image, const avifRGBImage * rgb) @@ -357,18 +356,18 @@ } // RGB -> YUV conversion - if (state.mode == AVIF_REFORMAT_MODE_IDENTITY) { + if (state.yuv.mode == AVIF_REFORMAT_MODE_IDENTITY) { // Formulas 41,42,43 from https://www.itu.int/rec/T-REC-H.273-201612-I/en yuvBlock[bI][bJ].y = rgbPixel[1]; // G yuvBlock[bI][bJ].u = rgbPixel[2]; // B yuvBlock[bI][bJ].v = rgbPixel[0]; // R - } else if (state.mode == AVIF_REFORMAT_MODE_YCGCO) { + } else if (state.yuv.mode == AVIF_REFORMAT_MODE_YCGCO) { // Formulas 44,45,46 from https://www.itu.int/rec/T-REC-H.273-201612-I/en yuvBlock[bI][bJ].y = 0.5f * rgbPixel[1] + 0.25f * (rgbPixel[0] + rgbPixel[2]); yuvBlock[bI][bJ].u = 0.5f * rgbPixel[1] - 0.25f * (rgbPixel[0] + rgbPixel[2]); yuvBlock[bI][bJ].v = 0.5f * (rgbPixel[0] - rgbPixel[2]); #if defined(AVIF_ENABLE_EXPERIMENTAL_YCGCO_R) - } else if (state.mode == AVIF_REFORMAT_MODE_YCGCO_RE || state.mode == AVIF_REFORMAT_MODE_YCGCO_RO) { + } else if (state.yuv.mode == AVIF_REFORMAT_MODE_YCGCO_RE || state.yuv.mode == AVIF_REFORMAT_MODE_YCGCO_RO) { // Formulas from JVET-U0093. const int R = (int)avifRoundf(AVIF_CLAMP(rgbPixel[0] * rgbMaxChannelF, 0.0f, rgbMaxChannelF)); const int G = (int)avifRoundf(AVIF_CLAMP(rgbPixel[1] * rgbMaxChannelF, 0.0f, rgbMaxChannelF)); @@ -389,23 +388,23 @@ if (state.yuv.channelBytes > 1) { uint16_t * pY = (uint16_t *)&yuvPlanes[AVIF_CHAN_Y][(i * 2) + (j * yuvRowBytes[AVIF_CHAN_Y])]; - *pY = (uint16_t)avifReformatStateYToUNorm(&state, yuvBlock[bI][bJ].y); + *pY = (uint16_t)avifYUVColorSpaceInfoYToUNorm(&state.yuv, yuvBlock[bI][bJ].y); if (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV444) { // YUV444, full chroma uint16_t * pU = (uint16_t *)&yuvPlanes[AVIF_CHAN_U][(i * 2) + (j * yuvRowBytes[AVIF_CHAN_U])]; - *pU = (uint16_t)avifReformatStateUVToUNorm(&state, yuvBlock[bI][bJ].u); + *pU = (uint16_t)avifYUVColorSpaceInfoUVToUNorm(&state.yuv, yuvBlock[bI][bJ].u); uint16_t * pV = (uint16_t *)&yuvPlanes[AVIF_CHAN_V][(i * 2) + (j * yuvRowBytes[AVIF_CHAN_V])]; - *pV = (uint16_t)avifReformatStateUVToUNorm(&state, yuvBlock[bI][bJ].v); + *pV = (uint16_t)avifYUVColorSpaceInfoUVToUNorm(&state.yuv, yuvBlock[bI][bJ].v); } } else { yuvPlanes[AVIF_CHAN_Y][i + (j * yuvRowBytes[AVIF_CHAN_Y])] = - (uint8_t)avifReformatStateYToUNorm(&state, yuvBlock[bI][bJ].y); + (uint8_t)avifYUVColorSpaceInfoYToUNorm(&state.yuv, yuvBlock[bI][bJ].y); if (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV444) { // YUV444, full chroma yuvPlanes[AVIF_CHAN_U][i + (j * yuvRowBytes[AVIF_CHAN_U])] = - (uint8_t)avifReformatStateUVToUNorm(&state, yuvBlock[bI][bJ].u); + (uint8_t)avifYUVColorSpaceInfoUVToUNorm(&state.yuv, yuvBlock[bI][bJ].u); yuvPlanes[AVIF_CHAN_V][i + (j * yuvRowBytes[AVIF_CHAN_V])] = - (uint8_t)avifReformatStateUVToUNorm(&state, yuvBlock[bI][bJ].v); + (uint8_t)avifYUVColorSpaceInfoUVToUNorm(&state.yuv, yuvBlock[bI][bJ].v); } } } @@ -435,14 +434,14 @@ int uvJ = outerJ >> chromaShiftY; if (state.yuv.channelBytes > 1) { uint16_t * pU = (uint16_t *)&yuvPlanes[AVIF_CHAN_U][(uvI * 2) + (uvJ * yuvRowBytes[AVIF_CHAN_U])]; - *pU = (uint16_t)avifReformatStateUVToUNorm(&state, avgU); + *pU = (uint16_t)avifYUVColorSpaceInfoUVToUNorm(&state.yuv, avgU); uint16_t * pV = (uint16_t *)&yuvPlanes[AVIF_CHAN_V][(uvI * 2) + (uvJ * yuvRowBytes[AVIF_CHAN_V])]; - *pV = (uint16_t)avifReformatStateUVToUNorm(&state, avgV); + *pV = (uint16_t)avifYUVColorSpaceInfoUVToUNorm(&state.yuv, avgV); } else { yuvPlanes[AVIF_CHAN_U][uvI + (uvJ * yuvRowBytes[AVIF_CHAN_U])] = - (uint8_t)avifReformatStateUVToUNorm(&state, avgU); + (uint8_t)avifYUVColorSpaceInfoUVToUNorm(&state.yuv, avgU); yuvPlanes[AVIF_CHAN_V][uvI + (uvJ * yuvRowBytes[AVIF_CHAN_V])] = - (uint8_t)avifReformatStateUVToUNorm(&state, avgV); + (uint8_t)avifYUVColorSpaceInfoUVToUNorm(&state.yuv, avgV); } } else if (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV422) { // YUV422, average 2 samples (1x2), twice @@ -463,14 +462,14 @@ int uvJ = outerJ + bJ; if (state.yuv.channelBytes > 1) { uint16_t * pU = (uint16_t *)&yuvPlanes[AVIF_CHAN_U][(uvI * 2) + (uvJ * yuvRowBytes[AVIF_CHAN_U])]; - *pU = (uint16_t)avifReformatStateUVToUNorm(&state, avgU); + *pU = (uint16_t)avifYUVColorSpaceInfoUVToUNorm(&state.yuv, avgU); uint16_t * pV = (uint16_t *)&yuvPlanes[AVIF_CHAN_V][(uvI * 2) + (uvJ * yuvRowBytes[AVIF_CHAN_V])]; - *pV = (uint16_t)avifReformatStateUVToUNorm(&state, avgV); + *pV = (uint16_t)avifYUVColorSpaceInfoUVToUNorm(&state.yuv, avgV); } else { yuvPlanes[AVIF_CHAN_U][uvI + (uvJ * yuvRowBytes[AVIF_CHAN_U])] = - (uint8_t)avifReformatStateUVToUNorm(&state, avgU); + (uint8_t)avifYUVColorSpaceInfoUVToUNorm(&state.yuv, avgU); yuvPlanes[AVIF_CHAN_V][uvI + (uvJ * yuvRowBytes[AVIF_CHAN_V])] = - (uint8_t)avifReformatStateUVToUNorm(&state, avgV); + (uint8_t)avifYUVColorSpaceInfoUVToUNorm(&state.yuv, avgV); } } } @@ -520,7 +519,7 @@ } if (unormFloatTableUV) { - if (state->mode == AVIF_REFORMAT_MODE_IDENTITY) { + if (state->yuv.mode == AVIF_REFORMAT_MODE_IDENTITY) { // Just reuse the luma table since the chroma values are the same. *unormFloatTableUV = *unormFloatTableY; } else { @@ -759,19 +758,19 @@ float R, G, B; if (hasColor) { - if (state->mode == AVIF_REFORMAT_MODE_IDENTITY) { + if (state->yuv.mode == AVIF_REFORMAT_MODE_IDENTITY) { // Identity (GBR): Formulas 41,42,43 from https://www.itu.int/rec/T-REC-H.273-201612-I/en G = Y; B = Cb; R = Cr; - } else if (state->mode == AVIF_REFORMAT_MODE_YCGCO) { + } else if (state->yuv.mode == AVIF_REFORMAT_MODE_YCGCO) { // YCgCo: Formulas 47,48,49,50 from https://www.itu.int/rec/T-REC-H.273-201612-I/en const float t = Y - Cb; G = Y + Cb; B = t - Cr; R = t + Cr; #if defined(AVIF_ENABLE_EXPERIMENTAL_YCGCO_R) - } else if (state->mode == AVIF_REFORMAT_MODE_YCGCO_RE || state->mode == AVIF_REFORMAT_MODE_YCGCO_RO) { + } else if (state->yuv.mode == AVIF_REFORMAT_MODE_YCGCO_RE || state->yuv.mode == AVIF_REFORMAT_MODE_YCGCO_RO) { const int YY = unormY; const int Cg = (int)avifRoundf(Cb * yuvMaxChannel); const int Co = (int)avifRoundf(Cr * yuvMaxChannel); @@ -790,7 +789,7 @@ G = Y - ((2 * ((kr * (1 - kr) * Cr) + (kb * (1 - kb) * Cb))) / kg); } } else { - // Monochrome: just populate all channels with luma (state->mode is irrelevant) + // Monochrome: just populate all channels with luma (state->yuv.mode is irrelevant) R = Y; G = Y; B = Y; @@ -1384,14 +1383,14 @@ // * None of these fast paths currently handle alpha (un)multiply, so avoid all of them // if we can't do alpha (un)multiply as a separated post step (destination format doesn't have alpha). - if (state->mode == AVIF_REFORMAT_MODE_IDENTITY) { + if (state->yuv.mode == AVIF_REFORMAT_MODE_IDENTITY) { if ((image->depth == 8) && (rgb->depth == 8) && (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV444) && (image->yuvRange == AVIF_RANGE_FULL)) { convertResult = avifImageIdentity8ToRGB8ColorFullRange(image, rgb, state); } // TODO: Add more fast paths for identity - } else if (state->mode == AVIF_REFORMAT_MODE_YUV_COEFFICIENTS) { + } else if (state->yuv.mode == AVIF_REFORMAT_MODE_YUV_COEFFICIENTS) { if (image->depth > 8) { // yuv:u16