videolevels: support GRAY8 input

This commit is contained in:
Joshua M. Doe 2017-08-10 10:18:34 -04:00
parent ff8376b9d2
commit 45bc0f24aa
3 changed files with 85 additions and 22 deletions

View File

@ -30,4 +30,5 @@ GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR, GST_VERSION_MINOR,
videoadjust, videoadjust,
"Filters that apply transform from 16-bit to 8-bit video", "Filters that apply transform from 16-bit to 8-bit video",
plugin_init, PACKAGE_VERSION, GST_LICENSE, PACKAGE_NAME, GST_PACKAGE_ORIGIN); plugin_init, PACKAGE_VERSION, GST_LICENSE, PACKAGE_NAME,
GST_PACKAGE_ORIGIN);

View File

@ -75,7 +75,7 @@ static GstStaticPadTemplate gst_videolevels_src_template =
GST_STATIC_PAD_TEMPLATE ("sink", GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_SINK,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ GRAY16_LE, GRAY16_BE }")) GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ GRAY16_LE, GRAY16_BE, GRAY8 }"))
//";" //";"
// "video/x-bayer,format=(string){bggr16,grbg16,gbrg16,rggb16}," // "video/x-bayer,format=(string){bggr16,grbg16,gbrg16,rggb16},"
// "bpp=(int){10,12,14,16},endianness={1234,4321}," // "bpp=(int){10,12,14,16},endianness={1234,4321},"
@ -136,6 +136,7 @@ static gboolean gst_videolevels_calculate_histogram (GstVideoLevels *
videolevels, guint16 * data); videolevels, guint16 * data);
static gboolean gst_videolevels_auto_adjust (GstVideoLevels * videolevels, static gboolean gst_videolevels_auto_adjust (GstVideoLevels * videolevels,
guint16 * data); guint16 * data);
static void gst_videolevels_check_passthrough (GstVideoLevels * videolevels);
/* setup debug */ /* setup debug */
GST_DEBUG_CATEGORY_STATIC (videolevels_debug); GST_DEBUG_CATEGORY_STATIC (videolevels_debug);
@ -255,6 +256,7 @@ gst_videolevels_init (GstVideoLevels * videolevels)
{ {
GST_DEBUG_OBJECT (videolevels, "init class instance"); GST_DEBUG_OBJECT (videolevels, "init class instance");
videolevels->passthrough = FALSE;
gst_videolevels_reset (videolevels); gst_videolevels_reset (videolevels);
} }
@ -385,8 +387,8 @@ gst_videolevels_transform_caps (GstBaseTransform * trans,
if (direction == GST_PAD_SRC) { if (direction == GST_PAD_SRC) {
newst = newst =
gst_structure_from_string ("video/x-raw,format={GRAY16_LE,GRAY16_BE}", gst_structure_from_string
NULL); ("video/x-raw,format={GRAY16_LE,GRAY16_BE,GRAY8}", NULL);
} else { } else {
newst = gst_structure_from_string ("video/x-raw,format=GRAY8", NULL); newst = gst_structure_from_string ("video/x-raw,format=GRAY8", NULL);
} }
@ -428,8 +430,16 @@ gst_videolevels_set_info (GstVideoFilter * filter, GstCaps * incaps,
memcpy (&levels->info_out, out_info, sizeof (GstVideoInfo)); memcpy (&levels->info_out, out_info, sizeof (GstVideoInfo));
s = gst_caps_get_structure (incaps, 0); s = gst_caps_get_structure (incaps, 0);
if (!gst_structure_get_int (s, "bpp", &levels->bpp_in))
levels->bpp_in = 16; if (levels->info_in.finfo->format == GST_VIDEO_FORMAT_GRAY8) {
levels->bpp_in = 8;
levels->nbins = 256;
} else {
if (!gst_structure_get_int (s, "bpp", &levels->bpp_in)) {
levels->bpp_in = 16;
}
levels->nbins = 4096;
}
g_assert (levels->bpp_in >= 1 && levels->bpp_in <= 16); g_assert (levels->bpp_in >= 1 && levels->bpp_in <= 16);
res = gst_videolevels_calculate_lut (levels); res = gst_videolevels_calculate_lut (levels);
@ -488,17 +498,32 @@ gst_videolevels_transform_frame (GstVideoFilter * filter,
out_stride = GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0); out_stride = GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0);
lut = videolevels->lookup_table; lut = videolevels->lookup_table;
for (r = 0; r < in_frame->info.height; r++) { if (videolevels->bpp_in > 8) {
guint16 *src = (guint16 *) in_data; for (r = 0; r < in_frame->info.height; r++) {
guint8 *dst = out_data; guint16 *src = (guint16 *) in_data;
guint8 *dst = out_data;
for (c = 0; c < in_frame->info.width; c++) { for (c = 0; c < in_frame->info.width; c++) {
//GST_LOG_OBJECT (videolevels, "Converting pixel (%d, %d), %d->%d", c, r, *src, lut[*src]); //GST_LOG_OBJECT (videolevels, "Converting pixel (%d, %d), %d->%d", c, r, *src, lut[*src]);
*dst++ = lut[*src++]; *dst++ = lut[*src++];
}
in_data += in_stride;
out_data += out_stride;
} }
} else {
for (r = 0; r < in_frame->info.height; r++) {
guint8 *src = (guint8 *) in_data;
guint8 *dst = out_data;
in_data += in_stride; for (c = 0; c < in_frame->info.width; c++) {
out_data += out_stride; //GST_LOG_OBJECT (videolevels, "Converting pixel (%d, %d), %d->%d", c, r, *src, lut[*src]);
*dst++ = lut[*src++];
}
in_data += in_stride;
out_data += out_stride;
}
} }
GST_LOG_OBJECT (videolevels, "Processing took %" G_GINT64_FORMAT "ms", GST_LOG_OBJECT (videolevels, "Processing took %" G_GINT64_FORMAT "ms",
@ -540,6 +565,7 @@ gst_videolevels_reset (GstVideoLevels * videolevels)
videolevels->lower_pix_sat = 0.01f; videolevels->lower_pix_sat = 0.01f;
videolevels->upper_pix_sat = 0.01f; videolevels->upper_pix_sat = 0.01f;
/* if GRAY8, this will be set in set_info */
videolevels->nbins = 4096; videolevels->nbins = 4096;
g_free (videolevels->histogram); g_free (videolevels->histogram);
@ -549,6 +575,7 @@ gst_videolevels_reset (GstVideoLevels * videolevels)
#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: rename this, as this handles uint8_to_uint8 as well */
static void static void
gst_videolevels_calculate_lut_uint16_to_uint8 (GstVideoLevels * videolevels, gst_videolevels_calculate_lut_uint16_to_uint8 (GstVideoLevels * videolevels,
gint endianness) gint endianness)
@ -569,10 +596,12 @@ gst_videolevels_calculate_lut_uint16_to_uint8 (GstVideoLevels * videolevels,
g_object_notify_by_pspec (G_OBJECT (videolevels), properties[PROP_LOWIN]); g_object_notify_by_pspec (G_OBJECT (videolevels), properties[PROP_LOWIN]);
} }
if (videolevels->upper_input < 0 || videolevels->upper_input > max_in) { if (videolevels->upper_input < 0 || videolevels->upper_input > max_in) {
videolevels->lower_input = max_in; videolevels->upper_input = max_in;
g_object_notify_by_pspec (G_OBJECT (videolevels), properties[PROP_HIGHIN]); g_object_notify_by_pspec (G_OBJECT (videolevels), properties[PROP_HIGHIN]);
} }
gst_videolevels_check_passthrough (videolevels);
low_in = videolevels->lower_input; low_in = videolevels->lower_input;
high_in = videolevels->upper_input; high_in = videolevels->upper_input;
@ -613,6 +642,11 @@ gst_videolevels_calculate_lut (GstVideoLevels * videolevels)
case GST_VIDEO_FORMAT_UNKNOWN: case GST_VIDEO_FORMAT_UNKNOWN:
/* no format set yet, don't do anything */ /* no format set yet, don't do anything */
break; break;
case GST_VIDEO_FORMAT_GRAY8:
GST_LOG_OBJECT (videolevels, "Calculating lookup table uint8 -> uint8");
gst_videolevels_calculate_lut_uint16_to_uint8 (videolevels,
G_LITTLE_ENDIAN);
break;
case GST_VIDEO_FORMAT_GRAY16_LE: case GST_VIDEO_FORMAT_GRAY16_LE:
GST_LOG_OBJECT (videolevels, GST_LOG_OBJECT (videolevels,
"Calculating lookup table uint16le -> uint8"); "Calculating lookup table uint16le -> uint8");
@ -659,7 +693,6 @@ gst_videolevels_calculate_histogram (GstVideoLevels * videolevels,
else else
endianness = G_BYTE_ORDER; endianness = G_BYTE_ORDER;
factor = (nbins - 1.0) / maxVal; factor = (nbins - 1.0) / maxVal;
if (videolevels->histogram == NULL) { if (videolevels->histogram == NULL) {
@ -674,17 +707,26 @@ gst_videolevels_calculate_histogram (GstVideoLevels * videolevels,
memset (hist, 0, sizeof (gint) * nbins); memset (hist, 0, sizeof (gint) * nbins);
GST_LOG_OBJECT (videolevels, "Calculating histogram"); GST_LOG_OBJECT (videolevels, "Calculating histogram");
if (endianness == G_BYTE_ORDER) { if (videolevels->bpp_in > 8) {
for (r = 0; r < videolevels->info_in.height; r++) { if (endianness == G_BYTE_ORDER) {
for (c = 0; c < videolevels->info_in.width; c++) { for (r = 0; r < videolevels->info_in.height; r++) {
hist[GINT_CLAMP (data[c + r * stride / 2] * factor, 0, nbins - 1)]++; for (c = 0; c < videolevels->info_in.width; c++) {
hist[GINT_CLAMP (data[c + r * stride / 2] * factor, 0, nbins - 1)]++;
}
}
} else {
for (r = 0; r < videolevels->info_in.height; r++) {
for (c = 0; c < videolevels->info_in.width; c++) {
hist[GINT_CLAMP (GUINT16_FROM_BE (data[c +
r * stride / 2]) * factor, 0, nbins - 1)]++;
}
} }
} }
} else { } else {
guint8 *data8 = (guint8 *) data;
for (r = 0; r < videolevels->info_in.height; r++) { for (r = 0; r < videolevels->info_in.height; r++) {
for (c = 0; c < videolevels->info_in.width; c++) { for (c = 0; c < videolevels->info_in.width; c++) {
hist[GINT_CLAMP (GUINT16_FROM_BE (data[c + hist[GINT_CLAMP (data8[c + r * stride / 2] * factor, 0, nbins - 1)]++;
r * stride / 2]) * factor, 0, nbins - 1)]++;
} }
} }
} }
@ -747,3 +789,21 @@ gst_videolevels_auto_adjust (GstVideoLevels * videolevels, guint16 * data)
return TRUE; return TRUE;
} }
static void
gst_videolevels_check_passthrough (GstVideoLevels * levels)
{
gboolean passthrough;
if (levels->info_in.finfo->format == GST_VIDEO_FORMAT_GRAY8 &&
levels->lower_input == levels->lower_output &&
levels->upper_input == levels->upper_output) {
passthrough = TRUE;
} else {
passthrough = FALSE;
}
if (passthrough != levels->passthrough) {
levels->passthrough = passthrough;
gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (levels),
levels->passthrough);
}
}

View File

@ -91,6 +91,8 @@ struct _GstVideoLevels
gint * histogram; gint * histogram;
guint64 last_auto_timestamp; guint64 last_auto_timestamp;
gboolean passthrough;
}; };
struct _GstVideoLevelsClass struct _GstVideoLevelsClass