video-color: add gamma encode/decode functions

Add functions to encode and decode gamma.
Add unit test to check that encode and decode are eachothers inverse
and that the limits are respected.
This commit is contained in:
Wim Taymans 2014-11-11 16:11:15 +01:00
parent 6711c50495
commit b73096ce8c
3 changed files with 188 additions and 0 deletions

View file

@ -25,6 +25,7 @@
#include <string.h>
#include <stdio.h>
#include <math.h>
#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;
}

View file

@ -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

View file

@ -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;
}