}
if (ycbcr_format.full_range) {
+ // TODO: Use num_levels.
offset[0] = 0.0 / 255.0;
offset[1] = 128.0 / 255.0;
offset[2] = 128.0 / 255.0;
scale[2] = 1.0;
} else {
// Rec. 601, page 4; Rec. 709, page 19; Rec. 2020, page 4.
+ // TODO: Use num_levels.
offset[0] = 16.0 / 255.0;
offset[1] = 128.0 / 255.0;
offset[2] = 128.0 / 255.0;
#define _MOVIT_YCBCR_H 1
// Shared utility functions between YCbCrInput and YCbCr422InterleavedInput.
+//
+// Conversion from integer to floating-point representation in case of
+// Y'CbCr is seemingly tricky:
+//
+// BT.601 page 8 has a table that says that for luma, black is at 16.00_d and
+// white is at 235.00_d. _d seemingly means “on a floating-point scale from 0
+// to 255.75”, see §2.4. The .75 is because BT.601 wants to support 10-bit,
+// but all values are scaled for 8-bit since that's the most common; it is
+// specified that conversion from 8-bit to 10-bit is done by inserting two
+// binary zeroes at the end (not repeating bits as one would often do
+// otherwise). It would seem that BT.601 lives in a world where the idealized
+// range is really [0,256), not [0,255].
+//
+// However, GPUs (and by extension Movit) don't work this way. For them,
+// typically 1.0 maps to the largest possible representable value in the
+// framebuffer, ie., the range [0.0,1.0] maps to [0,255] for 8-bit
+// and to [0,1023] (or [0_d,255.75_d] in BT.601 parlance) for 10-bit.
+//
+// BT.701 (page 5) seems to agree with BT.601; it specifies range 16–235 for
+// 8-bit luma, and 64–940 for 10-bit luma. This would indicate, for a GPU,
+// that that for 8-bit mode, the range would be 16/255 to 235/255
+// (0.06275 to 0.92157), while for 10-bit, it should be 64/1023 to 940/1023
+// (0.06256 to 0.91887). There's no good compromise here; if you select 8-bit
+// range, 10-bit goes out of range (white gets to 942), while if you select
+// 10-bit range, 8-bit gets only to 234, making true white impossible.
+//
+// We currently support the 8-bit ranges only, since all of our Y'CbCr
+// handling effects happen to support only 8-bit at the moment. We will need
+// to fix this eventually, though, with an added field to YCbCrFormat.
#include "image_format.h"
// JPEG uses the Rec. 601 luma coefficients, but full range.
bool full_range;
+ // Currently unused, but should be set to 256 for future expansion,
+ // indicating 8-bit interpretation (see file-level comment).
+ int num_levels;
+
// Sampling factors for chroma components. For no subsampling (4:4:4),
// set both to 1.
unsigned chroma_subsampling_x, chroma_subsampling_y;
YCbCrFormat ycbcr_format;
ycbcr_format.luma_coefficients = YCBCR_REC_601;
ycbcr_format.full_range = false;
+ ycbcr_format.num_levels = 256;
ycbcr_format.chroma_subsampling_x = 2;
ycbcr_format.chroma_subsampling_y = 1;
ycbcr_format.cb_x_position = 0.0f; // Doesn't really matter here, since Y is constant.
YCbCrFormat ycbcr_format;
ycbcr_format.luma_coefficients = YCBCR_REC_601;
ycbcr_format.full_range = false;
+ ycbcr_format.num_levels = 256;
ycbcr_format.chroma_subsampling_x = 2;
ycbcr_format.chroma_subsampling_y = 1;
ycbcr_format.cb_x_position = 0.0f; // Doesn't really matter here, since U/V are constant.
YCbCrFormat ycbcr_format;
ycbcr_format.luma_coefficients = YCBCR_REC_601;
ycbcr_format.full_range = false;
+ ycbcr_format.num_levels = 256;
ycbcr_format.chroma_subsampling_x = 2;
ycbcr_format.chroma_subsampling_y = 1;
ycbcr_format.cb_x_position = 0.0f;
YCbCrFormat ycbcr_format;
ycbcr_format.luma_coefficients = YCBCR_REC_601;
ycbcr_format.full_range = false;
+ ycbcr_format.num_levels = 256;
ycbcr_format.chroma_subsampling_x = 2;
ycbcr_format.chroma_subsampling_y = 1;
ycbcr_format.cb_x_position = 0.0f; // Doesn't really matter here, since Y is constant.
YCbCrFormat ycbcr_format;
ycbcr_format.luma_coefficients = YCBCR_REC_601;
ycbcr_format.full_range = false;
+ ycbcr_format.num_levels = 256;
ycbcr_format.chroma_subsampling_x = 1;
ycbcr_format.chroma_subsampling_y = 1;
ycbcr_format.cb_x_position = 0.5f;
YCbCrFormat ycbcr_format;
ycbcr_format.luma_coefficients = YCBCR_REC_601;
ycbcr_format.full_range = true;
+ ycbcr_format.num_levels = 256;
ycbcr_format.chroma_subsampling_x = 1;
ycbcr_format.chroma_subsampling_y = 1;
ycbcr_format.cb_x_position = 0.5f;
YCbCrFormat ycbcr_format;
ycbcr_format.luma_coefficients = YCBCR_REC_709;
ycbcr_format.full_range = false;
+ ycbcr_format.num_levels = 256;
ycbcr_format.chroma_subsampling_x = 1;
ycbcr_format.chroma_subsampling_y = 1;
ycbcr_format.cb_x_position = 0.5f;
YCbCrFormat ycbcr_format;
ycbcr_format.luma_coefficients = YCBCR_REC_2020;
ycbcr_format.full_range = false;
+ ycbcr_format.num_levels = 256;
ycbcr_format.chroma_subsampling_x = 1;
ycbcr_format.chroma_subsampling_y = 1;
ycbcr_format.cb_x_position = 0.5f;
YCbCrFormat ycbcr_format;
ycbcr_format.luma_coefficients = YCBCR_REC_601;
ycbcr_format.full_range = false;
+ ycbcr_format.num_levels = 256;
ycbcr_format.chroma_subsampling_x = 2;
ycbcr_format.chroma_subsampling_y = 2;
ycbcr_format.cb_x_position = 0.5f;
YCbCrFormat ycbcr_format;
ycbcr_format.luma_coefficients = YCBCR_REC_601;
ycbcr_format.full_range = false;
+ ycbcr_format.num_levels = 256;
ycbcr_format.chroma_subsampling_x = 2;
ycbcr_format.chroma_subsampling_y = 2;
ycbcr_format.cb_x_position = 0.0f;
YCbCrFormat ycbcr_format;
ycbcr_format.luma_coefficients = YCBCR_REC_601;
ycbcr_format.full_range = false;
+ ycbcr_format.num_levels = 256;
ycbcr_format.chroma_subsampling_x = 2;
ycbcr_format.chroma_subsampling_y = 1;
ycbcr_format.cb_x_position = 0.0f;
YCbCrFormat ycbcr_format;
ycbcr_format.luma_coefficients = YCBCR_REC_601;
ycbcr_format.full_range = false;
+ ycbcr_format.num_levels = 256;
ycbcr_format.chroma_subsampling_x = 1;
ycbcr_format.chroma_subsampling_y = 1;
ycbcr_format.cb_x_position = 0.5f;