diff --git a/gst-libs/gst/video/video-color.c b/gst-libs/gst/video/video-color.c index cc89b11901..4e418d6a7c 100644 --- a/gst-libs/gst/video/video-color.c +++ b/gst-libs/gst/video/video-color.c @@ -25,6 +25,7 @@ #include #include +#include #include "video-color.h" @@ -314,3 +315,160 @@ gst_video_color_matrix_get_Kr_Kb (GstVideoColorMatrix matrix, gdouble * Kr, return res; } + +/** + * gst_video_color_transfer_encode: + * @func: a #GstVideoTransferFunction + * @val: a value + * + * Convert @val to its gamma encoded value. + * + * For a linear value L in the range [0..1], conversion to the non-linear + * (gamma encoded) L' is in general performed with a power function like: + * + * |[ + * L' = L ^ (1 / gamma) + * ]| + * + * Depending on @func, different formulas might be applied. Some formulas + * encode a linear segment in the lower range. + * + * Returns: the gamme encoded value of @val + * + * Since: 1.6 + */ +gdouble +gst_video_color_transfer_encode (GstVideoTransferFunction func, gdouble val) +{ + gdouble res; + + switch (func) { + case GST_VIDEO_TRANSFER_UNKNOWN: + case GST_VIDEO_TRANSFER_GAMMA10: + default: + res = val; + break; + case GST_VIDEO_TRANSFER_GAMMA18: + res = pow (val, 1.0 / 1.8); + break; + case GST_VIDEO_TRANSFER_GAMMA20: + res = pow (val, 1.0 / 2.0); + break; + case GST_VIDEO_TRANSFER_GAMMA22: + res = pow (val, 1.0 / 2.2); + break; + case GST_VIDEO_TRANSFER_BT709: + if (val < 0.018) + res = 4.5 * val; + else + res = 1.099 * pow (val, 0.45) - 0.099; + break; + case GST_VIDEO_TRANSFER_SMPTE240M: + if (val < 0.0228) + res = val * 4.0; + else + res = 1.1115 * pow (val, 0.45) - 0.1115; + break; + case GST_VIDEO_TRANSFER_SRGB: + if (val <= 0.0031308) + res = 12.92 * val; + else + res = 1.055 * pow (val, 1.0 / 2.4) - 0.055; + break; + case GST_VIDEO_TRANSFER_GAMMA28: + res = pow (val, 1 / 2.8); + break; + case GST_VIDEO_TRANSFER_LOG100: + if (val < 0.01) + res = 0.0; + else + res = 1.0 + log10 (val) / 2.0; + break; + case GST_VIDEO_TRANSFER_LOG316: + if (val < 0.0031622777) + res = 0.0; + else + res = 1.0 + log10 (val) / 2.5; + break; + } + return res; +} + +/** + * gst_video_color_transfer_decode: + * @func: a #GstVideoTransferFunction + * @val: a value + * + * Convert @val to its gamma decoded value. This is the inverse operation of + * @gst_video_color_transfer_encode(). + * + * For a non-linear value L' in the range [0..1], conversion to the linear + * L is in general performed with a power function like: + * + * |[ + * L = L' ^ gamma + * ]| + * + * Depending on @func, different formulas might be applied. Some formulas + * encode a linear segment in the lower range. + * + * Returns: the gamme decoded value of @val + * + * Since: 1.6 + */ +gdouble +gst_video_color_transfer_decode (GstVideoTransferFunction func, gdouble val) +{ + gdouble res; + + switch (func) { + case GST_VIDEO_TRANSFER_UNKNOWN: + case GST_VIDEO_TRANSFER_GAMMA10: + default: + res = val; + break; + case GST_VIDEO_TRANSFER_GAMMA18: + res = pow (val, 1.8); + break; + case GST_VIDEO_TRANSFER_GAMMA20: + res = pow (val, 2.0); + break; + case GST_VIDEO_TRANSFER_GAMMA22: + res = pow (val, 2.2); + break; + case GST_VIDEO_TRANSFER_BT709: + if (val < 0.081) + res = val / 4.5; + else + res = pow ((val + 0.099) / 1.099, 1.0 / 0.45); + break; + case GST_VIDEO_TRANSFER_SMPTE240M: + if (val < 0.0913) + res = val / 4.0; + else + res = pow ((val + 0.1115) / 1.1115, 1.0 / 0.45); + break; + case GST_VIDEO_TRANSFER_SRGB: + if (val <= 0.04045) + res = val / 12.92; + else + res = pow ((val + 0.055) / 1.055, 2.4); + break; + case GST_VIDEO_TRANSFER_GAMMA28: + res = pow (val, 2.8); + break; + case GST_VIDEO_TRANSFER_LOG100: + if (val == 0.0) + res = 0.0; + else + res = pow (10.0, 2.0 * (val - 1.0)); + break; + case GST_VIDEO_TRANSFER_LOG316: + if (val == 0.0) + res = 0.0; + else + res = pow (10.0, 2.5 * (val - 1.0)); + break; + } + return res; +} diff --git a/gst-libs/gst/video/video-color.h b/gst-libs/gst/video/video-color.h index fc0193e6d6..f0f78db4ab 100644 --- a/gst-libs/gst/video/video-color.h +++ b/gst-libs/gst/video/video-color.h @@ -101,6 +101,9 @@ typedef enum { GST_VIDEO_TRANSFER_LOG316 } GstVideoTransferFunction; +gdouble gst_video_color_transfer_encode (GstVideoTransferFunction func, gdouble val); +gdouble gst_video_color_transfer_decode (GstVideoTransferFunction func, gdouble val); + /** * GstVideoColorPrimaries: * @GST_VIDEO_COLOR_PRIMARIES_UNKNOWN: unknown color primaries diff --git a/tests/check/libs/video.c b/tests/check/libs/video.c index 7162890b77..6a8fb19f40 100644 --- a/tests/check/libs/video.c +++ b/tests/check/libs/video.c @@ -2251,6 +2251,32 @@ GST_END_TEST; #undef WIDTH #undef HEIGHT +GST_START_TEST (test_video_transfer) +{ + gint i, j; + + for (j = GST_VIDEO_TRANSFER_GAMMA10; j <= GST_VIDEO_TRANSFER_LOG316; j++) { + for (i = 0; i < 256; i++) { + gdouble val1, val2; + + val1 = gst_video_color_transfer_encode (j, i / 255.0); + fail_if (val1 < 0.0 || val1 > 1.0); + + val2 = gst_video_color_transfer_decode (j, val1); + fail_if (val2 < 0.0 || val2 > 1.0); + + GST_DEBUG ("%d: %d %f->%f->%f %d", j, i, i / 255.0, val1, val2, + (int) lrint (val2 * 255.0)); + if (val1 == 0.0) + fail_if (val2 != 0.0); + else + fail_if (lrint (val2 * 255.0) != i); + } + } +} + +GST_END_TEST; + static Suite * video_suite (void) { @@ -2279,6 +2305,7 @@ video_suite (void) tcase_add_test (tc_chain, test_video_scaler); tcase_add_test (tc_chain, test_video_color_convert); tcase_add_test (tc_chain, test_video_size_convert); + tcase_add_test (tc_chain, test_video_transfer); return s; }