videolevels: use lut for conversion (again)
Faster, but could maybe be faster still using orc.
This commit is contained in:
parent
d6fe385cb9
commit
5d5d1085b7
@ -130,7 +130,7 @@ static GstFlowReturn gst_videolevels_prepare_output_buffer (GstBaseTransform *
|
|||||||
|
|
||||||
/* GstVideoLevels method declarations */
|
/* GstVideoLevels method declarations */
|
||||||
static void gst_videolevels_reset (GstVideoLevels * filter);
|
static void gst_videolevels_reset (GstVideoLevels * filter);
|
||||||
static void gst_videolevels_calculate_tables (GstVideoLevels * videolevels);
|
static gboolean gst_videolevels_calculate_lut (GstVideoLevels * videolevels);
|
||||||
static gboolean gst_videolevels_do_levels (GstVideoLevels * videolevels,
|
static gboolean gst_videolevels_do_levels (GstVideoLevels * videolevels,
|
||||||
gpointer indata, gpointer outdata);
|
gpointer indata, gpointer outdata);
|
||||||
static gboolean gst_videolevels_calculate_histogram (GstVideoLevels *
|
static gboolean gst_videolevels_calculate_histogram (GstVideoLevels *
|
||||||
@ -281,19 +281,19 @@ gst_videolevels_set_property (GObject * object, guint prop_id,
|
|||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_LOWIN:
|
case PROP_LOWIN:
|
||||||
videolevels->lower_input = g_value_get_double (value);
|
videolevels->lower_input = g_value_get_double (value);
|
||||||
//gst_videolevels_calculate_tables (videolevels);
|
gst_videolevels_calculate_lut (videolevels);
|
||||||
break;
|
break;
|
||||||
case PROP_HIGHIN:
|
case PROP_HIGHIN:
|
||||||
videolevels->upper_input = g_value_get_double (value);
|
videolevels->upper_input = g_value_get_double (value);
|
||||||
//gst_videolevels_calculate_tables (videolevels);
|
gst_videolevels_calculate_lut (videolevels);
|
||||||
break;
|
break;
|
||||||
case PROP_LOWOUT:
|
case PROP_LOWOUT:
|
||||||
videolevels->lower_output = g_value_get_double (value);
|
videolevels->lower_output = g_value_get_double (value);
|
||||||
//gst_videolevels_calculate_tables (videolevels);
|
gst_videolevels_calculate_lut (videolevels);
|
||||||
break;
|
break;
|
||||||
case PROP_HIGHOUT:
|
case PROP_HIGHOUT:
|
||||||
videolevels->upper_output = g_value_get_double (value);
|
videolevels->upper_output = g_value_get_double (value);
|
||||||
//gst_videolevels_calculate_tables (videolevels);
|
gst_videolevels_calculate_lut (videolevels);
|
||||||
break;
|
break;
|
||||||
case PROP_AUTO:{
|
case PROP_AUTO:{
|
||||||
videolevels->auto_adjust = g_value_get_enum (value);
|
videolevels->auto_adjust = g_value_get_enum (value);
|
||||||
@ -443,10 +443,14 @@ gst_videolevels_set_caps (GstBaseTransform * base, GstCaps * incaps,
|
|||||||
structure = gst_caps_get_structure (outcaps, 0);
|
structure = gst_caps_get_structure (outcaps, 0);
|
||||||
res &= gst_structure_get_int (structure, "bpp", &levels->bpp_out);
|
res &= gst_structure_get_int (structure, "bpp", &levels->bpp_out);
|
||||||
|
|
||||||
if (!res) {
|
levels->framesize = gst_video_format_get_size (levels->format_out,
|
||||||
|
levels->width, levels->height);
|
||||||
|
|
||||||
|
if (!res || levels->framesize <= 0) {
|
||||||
GST_ERROR_OBJECT (levels, "Failed to parse caps");
|
GST_ERROR_OBJECT (levels, "Failed to parse caps");
|
||||||
}
|
}
|
||||||
//gst_videolevels_calculate_tables (levels);
|
|
||||||
|
gst_videolevels_calculate_lut (levels);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -592,78 +596,17 @@ gst_videolevels_reset (GstVideoLevels * videolevels)
|
|||||||
videolevels->histogram = NULL;
|
videolevels->histogram = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_videolevels_calculate_tables
|
|
||||||
* @videolevels: #GstVideoLevels
|
|
||||||
*
|
|
||||||
* Calculate lookup tables based on input and output levels
|
|
||||||
*/
|
|
||||||
/*static void
|
|
||||||
gst_videolevels_calculate_tables (GstVideoLevels * videolevels)
|
|
||||||
{
|
|
||||||
gint i;
|
|
||||||
guint16 loIn, hiIn;
|
|
||||||
guint8 loOut, hiOut;
|
|
||||||
gdouble slope;
|
|
||||||
guint8 * lut;
|
|
||||||
|
|
||||||
GST_DEBUG ("calculating lookup table");
|
|
||||||
|
|
||||||
if (!videolevels->lookup_table) {
|
|
||||||
videolevels->lookup_table = g_new (guint8, 65536);
|
|
||||||
}
|
|
||||||
lut = (guint8*) videolevels->lookup_table;
|
|
||||||
|
|
||||||
loIn = (guint16) (videolevels->lower_input * G_MAXUINT16);
|
|
||||||
hiIn = (guint16) (videolevels->upper_input * G_MAXUINT16);
|
|
||||||
loOut = (guint8) (videolevels->lower_output * G_MAXUINT8);
|
|
||||||
hiOut = (guint8) (videolevels->upper_output * G_MAXUINT8);
|
|
||||||
|
|
||||||
GST_DEBUG ("input levels (%.3f, %.3f), output levels (%.3f, %.3f)",videolevels->lower_input,videolevels->upper_input,videolevels->lower_output,videolevels->upper_output);
|
|
||||||
|
|
||||||
GST_DEBUG ("input levels (%d, %d), output levels (%d, %d)",loIn,hiIn,loOut,hiOut);
|
|
||||||
if (hiIn == loIn)
|
|
||||||
slope = 0;
|
|
||||||
else
|
|
||||||
slope = (videolevels->upper_output - videolevels->lower_output) /
|
|
||||||
(videolevels->upper_input - videolevels->lower_input);
|
|
||||||
|
|
||||||
GST_DEBUG ("slope = %f", slope);
|
|
||||||
|
|
||||||
if (videolevels->endianness_in == G_BYTE_ORDER) {
|
|
||||||
for (i = 0; i < loIn; i++)
|
|
||||||
lut[i] = loOut;
|
|
||||||
for (i = loIn; i < hiIn; i++)
|
|
||||||
lut[i] = loOut + (guint8) ( (i - loIn) * slope);
|
|
||||||
for (i = hiIn; i < 65536; i++)
|
|
||||||
lut[i] = hiOut;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (i = 0; i < loIn; i++)
|
|
||||||
lut[GUINT16_SWAP_LE_BE(i)] = loOut;
|
|
||||||
for (i = loIn; i < hiIn; i++)
|
|
||||||
lut[GUINT16_SWAP_LE_BE(i)] = loOut + (guint8) ((GUINT16_SWAP_LE_BE(i) - loIn) * slope);
|
|
||||||
for (i = hiIn; i < 65536; i++)
|
|
||||||
lut[GUINT16_SWAP_LE_BE(i)] = hiOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < 65536; i += 128)
|
|
||||||
GST_DEBUG ("lut[%d / %d] = %d", i, GUINT16_SWAP_LE_BE(i), lut[i]);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
#define GINT_CLAMP(x, low, high) ((gint)(CLAMP((x),(low),(high))))
|
#define GINT_CLAMP(x, low, high) ((gint)(CLAMP((x),(low),(high))))
|
||||||
#define GUINT8_CLAMP(x, low, high) ((guint8)(CLAMP((x),(low),(high))))
|
#define GUINT8_CLAMP(x, low, high) ((guint8)(CLAMP((x),(low),(high))))
|
||||||
|
|
||||||
/* TODO: use orc/lut */
|
static void
|
||||||
void
|
gst_videolevels_calculate_lut_uint16_to_uint8 (GstVideoLevels * videolevels,
|
||||||
gst_videolevels_convert_uint16le_to_uint8 (GstVideoLevels * videolevels,
|
gint endianness)
|
||||||
guint16 * in, guint8 * out)
|
|
||||||
{
|
{
|
||||||
gint i;
|
gint i;
|
||||||
const gint size = gst_video_format_get_size (videolevels->format_out,
|
|
||||||
videolevels->width, videolevels->height);
|
|
||||||
gdouble m;
|
gdouble m;
|
||||||
gdouble b;
|
gdouble b;
|
||||||
|
guint8 *lut = (guint8 *) videolevels->lookup_table;
|
||||||
const guint16 max_in = (1 << videolevels->bpp_in) - 1;
|
const guint16 max_in = (1 << videolevels->bpp_in) - 1;
|
||||||
const guint16 low_in = (guint16) (videolevels->lower_input * max_in);
|
const guint16 low_in = (guint16) (videolevels->lower_input * max_in);
|
||||||
const guint16 high_in = (guint16) (videolevels->upper_input * max_in);
|
const guint16 high_in = (guint16) (videolevels->upper_input * max_in);
|
||||||
@ -682,39 +625,40 @@ gst_videolevels_convert_uint16le_to_uint8 (GstVideoLevels * videolevels,
|
|||||||
|
|
||||||
b = low_out - m * low_in;
|
b = low_out - m * low_in;
|
||||||
|
|
||||||
for (i = 0; i < size; i++)
|
if (endianness == G_LITTLE_ENDIAN)
|
||||||
out[i] = GUINT8_CLAMP (m * GUINT16_FROM_LE (in[i]) + b, low_out, high_out);
|
for (i = 0; i < G_MAXUINT16; i++)
|
||||||
|
lut[i] = GUINT8_CLAMP (m * GUINT16_FROM_LE (i) + b, low_out, high_out);
|
||||||
|
else if (endianness == G_BIG_ENDIAN)
|
||||||
|
for (i = 0; i < G_MAXUINT16; i++)
|
||||||
|
lut[i] = GUINT8_CLAMP (m * GUINT16_FROM_BE (i) + b, low_out, high_out);
|
||||||
|
else
|
||||||
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: use orc/lut */
|
/**
|
||||||
void
|
* gst_videolevels_calculate_lut
|
||||||
gst_videolevels_convert_uint16be_to_uint8 (GstVideoLevels * videolevels,
|
* @videolevels: #GstVideoLevels
|
||||||
guint16 * in, guint8 * out)
|
*
|
||||||
|
* Update lookup tables based on input and output levels
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
gst_videolevels_calculate_lut (GstVideoLevels * videolevels)
|
||||||
{
|
{
|
||||||
gint i;
|
if (!videolevels->lookup_table) {
|
||||||
const gint size = gst_video_format_get_size (videolevels->format_out,
|
videolevels->lookup_table = g_new (guint8, G_MAXUINT16);
|
||||||
videolevels->width, videolevels->height);
|
}
|
||||||
gdouble m;
|
|
||||||
gdouble b;
|
|
||||||
const guint16 max_in = (1 << videolevels->bpp_in) - 1;
|
|
||||||
const guint16 low_in = (guint16) (videolevels->lower_input * max_in);
|
|
||||||
const guint16 high_in = (guint16) (videolevels->upper_input * max_in);
|
|
||||||
const guint8 max_out = (1 << videolevels->bpp_out) - 1;
|
|
||||||
const guint8 low_out = (guint8) (videolevels->lower_output * max_out);
|
|
||||||
const guint8 high_out = (guint8) (videolevels->upper_output * max_out);
|
|
||||||
|
|
||||||
GST_DEBUG ("Applying linear mapping (%d, %d) -> (%d, %d)",
|
if (videolevels->format_in == GST_VIDEO_FORMAT_GRAY16_LE) {
|
||||||
low_in, high_in, low_out, high_out);
|
GST_DEBUG ("Calculating lookup table uint16le -> uint8");
|
||||||
|
gst_videolevels_calculate_lut_uint16_to_uint8 (videolevels,
|
||||||
|
G_LITTLE_ENDIAN);
|
||||||
|
} else if (videolevels->format_in == GST_VIDEO_FORMAT_GRAY16_BE) {
|
||||||
|
GST_DEBUG ("Calculating lookup table uint16be -> uint8");
|
||||||
|
gst_videolevels_calculate_lut_uint16_to_uint8 (videolevels, G_BIG_ENDIAN);
|
||||||
|
} else
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
if (low_in == high_in)
|
return TRUE;
|
||||||
m = 0.0;
|
|
||||||
else
|
|
||||||
m = (high_out - low_out) / (gdouble) (high_in - low_in);
|
|
||||||
|
|
||||||
b = low_out - m * low_in;
|
|
||||||
|
|
||||||
for (i = 0; i < size; i++)
|
|
||||||
out[i] = GUINT8_CLAMP (m * GUINT16_FROM_BE (in[i]) + b, low_out, high_out);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -728,31 +672,19 @@ gst_videolevels_convert_uint16be_to_uint8 (GstVideoLevels * videolevels,
|
|||||||
*
|
*
|
||||||
* Returns: TRUE on success
|
* Returns: TRUE on success
|
||||||
*/
|
*/
|
||||||
gboolean
|
static gboolean
|
||||||
gst_videolevels_do_levels (GstVideoLevels * videolevels, gpointer indata,
|
gst_videolevels_do_levels (GstVideoLevels * videolevels, gpointer indata,
|
||||||
gpointer outdata)
|
gpointer outdata)
|
||||||
{
|
{
|
||||||
if (videolevels->format_in == GST_VIDEO_FORMAT_GRAY16_LE)
|
guint8 *dst = (guint8 *) outdata;
|
||||||
gst_videolevels_convert_uint16le_to_uint8 (videolevels, indata, outdata);
|
guint16 *src = (guint16 *) indata;
|
||||||
else if (videolevels->format_in == GST_VIDEO_FORMAT_GRAY16_BE)
|
guint8 *lut = (guint8 *) videolevels->lookup_table;
|
||||||
gst_videolevels_convert_uint16be_to_uint8 (videolevels, indata, outdata);
|
int i;
|
||||||
else
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
return TRUE;
|
GST_DEBUG ("Converting frame using LUT");
|
||||||
//guint8 * dst = outdata;
|
|
||||||
//guint16 * src = indata;
|
|
||||||
//gint r = 0, c = 0;
|
|
||||||
//guint8 * lut = (guint8 *) videolevels->lookup_table;
|
|
||||||
|
|
||||||
//GST_DEBUG ("Converting frame using LUT");
|
for (i = 0; i < videolevels->framesize; i++)
|
||||||
//
|
dst[i] = lut[src[i]];
|
||||||
//for (r = 0; r < videolevels->height; r++) {
|
|
||||||
// for (c = 0; c < videolevels->width; c++) {
|
|
||||||
// dst[c+r*videolevels->stride_out] =
|
|
||||||
// lut[src[c+r*videolevels->stride_in/2]];
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -866,6 +798,8 @@ gst_videolevels_auto_adjust (GstVideoLevels * videolevels, guint16 * data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_videolevels_calculate_lut (videolevels);
|
||||||
|
|
||||||
GST_DEBUG ("Contrast stretch with npixsat=%d, (%.6f, %.6f)", npixsat,
|
GST_DEBUG ("Contrast stretch with npixsat=%d, (%.6f, %.6f)", npixsat,
|
||||||
videolevels->lower_input, videolevels->upper_input);
|
videolevels->lower_input, videolevels->upper_input);
|
||||||
|
|
||||||
|
|||||||
@ -72,6 +72,7 @@ struct _GstVideoLevels
|
|||||||
/* format */
|
/* format */
|
||||||
gint width;
|
gint width;
|
||||||
gint height;
|
gint height;
|
||||||
|
int framesize;
|
||||||
|
|
||||||
GstVideoFormat format_in;
|
GstVideoFormat format_in;
|
||||||
GstVideoFormat format_out;
|
GstVideoFormat format_out;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user