diff --git a/common/genicampixelformat.h b/common/genicampixelformat.h new file mode 100644 index 0000000..aa9f5ed --- /dev/null +++ b/common/genicampixelformat.h @@ -0,0 +1,240 @@ +/* GStreamer + * Copyright (c) 2018 outside US, United States Government, Joshua M. Doe + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Suite 500, + * Boston, MA 02110-1335, USA. + */ + +#define GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER8(format) \ + "video/x-bayer, " \ + "format = (string) { " format " }, " \ + "width = " GST_VIDEO_SIZE_RANGE ", " \ + "height = " GST_VIDEO_SIZE_RANGE ", " \ + "framerate = " GST_VIDEO_FPS_RANGE + +#define GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16(format,endianness) \ + "video/x-bayer, " \ + "format = (string) { " format " }, " \ + "endianness = (int) { " endianness " }, " \ + "bpp = (int) {16, 14, 12, 10}, " \ + "width = " GST_VIDEO_SIZE_RANGE ", " \ + "height = " GST_VIDEO_SIZE_RANGE ", " \ + "framerate = " GST_VIDEO_FPS_RANGE + +typedef struct +{ + const char *pixel_format; + int endianness; + const char *gst_caps_string; + int bpp; + int depth; + int row_multiple; +} GstGenicamPixelFormatInfo; + +GstGenicamPixelFormatInfo gst_genicam_pixel_format_infos[] = { + {"Mono 8", 0, GST_VIDEO_CAPS_MAKE ("GRAY8"), 8, 8, 4} + , + {"Mono 10", G_LITTLE_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_LE"), 10, 16, 4} + , + {"Mono 10", G_BIG_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_BE"), 10, 16, 4} + , + {"Mono 12", G_LITTLE_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_LE"), 12, 16, 4} + , + {"Mono 12", G_BIG_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_BE"), 12, 16, 4} + , + {"Mono 14", G_LITTLE_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_LE"), 14, 16, 4} + , + {"Mono 14", G_BIG_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_BE"), 14, 16, 4} + , + {"Mono 16", G_LITTLE_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_LE"), 16, 16, 4} + , + {"Mono 16", G_BIG_ENDIAN, GST_VIDEO_CAPS_MAKE ("GRAY16_BE"), 16, 16, 4} + , + {"BGRA 8 Packed", 0, GST_VIDEO_CAPS_MAKE ("BGRA"), 32, 32, 4} + , + {"YUV 422 Packed", 0, GST_VIDEO_CAPS_MAKE ("UYVY"), 16, 16, 4} + , + {"Bayer BG 8", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER8 ("bggr"), 8, 8, 1} + , + {"Bayer GR 8", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER8 ("grbg"), 8, 8, 1} + , + {"Bayer RG 8", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER8 ("rggb"), 8, 8, 1} + , + {"Bayer GB 8", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER8 ("gbrg"), 8, 8, 1} + , + //TODO: make sure we use standard caps strings for 16-bit Bayer + {"Bayer BG 10", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16 ("bggr16", "1234"), 10, 16, 1} + , + {"Bayer GR 10", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16 ("grbg16", "1234"), 10, 16, 1} + , + {"Bayer RG 10", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16 ("rggb16", "1234"), 10, 16, 1} + , + {"Bayer GB 10", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16 ("gbrg16", "1234"), 10, 16, 1} + , + {"Bayer BG 12", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16 ("bggr16", "1234"), 12, 16, 1} + , + {"Bayer GR 12", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16 ("grbg16", "1234"), 12, 16, 1} + , + {"Bayer RG 12", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16 ("rggb16", "1234"), 12, 16, 1} + , + {"Bayer GB 12", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16 ("gbrg16", "1234"), 12, 16, 1} + , + {"Bayer BG 14", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16 ("bggr16", "1234"), 14, 16, 1} + , + {"Bayer GR 14", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16 ("grbg16", "1234"), 14, 16, 1} + , + {"Bayer RG 14", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16 ("rggb16", "1234"), 14, 16, 1} + , + {"Bayer GB 14", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16 ("gbrg16", "1234"), 14, 16, 1} + , + {"Bayer BG 16", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16 ("bggr16", "1234"), 16, 16, 1} + , + {"Bayer GR 16", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16 ("grbg16", "1234"), 16, 16, 1} + , + {"Bayer RG 16", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16 ("rggb16", "1234"), 16, 16, 1} + , + {"Bayer GB 16", 0, GST_GENICAM_PIXEL_FORMAT_MAKE_BAYER16 ("gbrg16", "1234"), 16, 16, 1} + , + {"JPEG", 0, "image/jpeg", 8, 8, 1} +}; + +int strcmp_ignore_whitespace (const char *s1, const char *s2) +{ + const char *p1 = s1, *p2 = s2; + + while (TRUE) { + /* skip all whitespace characters in both strings */ + while (g_ascii_isspace(*p1)) ++p1; + if (!*p1) break; + + while (g_ascii_isspace(*p2)) ++p2; + if (!*p2) return 1; + + if (*p2 > *p1) return -1; + if (*p1 > *p2) return 1; + + ++p1; + ++p2; + } + + if (*p2) return -1; + + return 0; +} + + +static const GstGenicamPixelFormatInfo * +gst_genicam_pixel_format_get_info (const char *pixel_format, int endianness) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS (gst_genicam_pixel_format_infos); i++) { + GstGenicamPixelFormatInfo *info = &gst_genicam_pixel_format_infos[i]; + if (strcmp_ignore_whitespace (pixel_format, info->pixel_format) == 0 && + (info->endianness == endianness || info->endianness == 0)) + return info; + } + + GST_WARNING ("PixelFormat '%s' is not supported", pixel_format); + return NULL; +} + +static const char * +gst_genicam_pixel_format_to_caps_string (const char *pixel_format, + int endianness) +{ + const GstGenicamPixelFormatInfo *info = + gst_genicam_pixel_format_get_info (pixel_format, endianness); + + if (!info) + return NULL; + + return info->gst_caps_string; +} + +static const char * +gst_genicam_pixel_format_from_caps (const GstCaps * caps, int *endianness) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS (gst_genicam_pixel_format_infos); i++) { + GstCaps *super_caps; + super_caps = gst_caps_from_string (gst_genicam_pixel_format_infos[i].gst_caps_string); + if (gst_caps_is_subset (caps, super_caps)) { + *endianness = gst_genicam_pixel_format_infos[i].endianness; + return gst_genicam_pixel_format_infos[i].pixel_format; + } + } + + return NULL; +} + +static int +gst_genicam_pixel_format_get_depth (const char *pixel_format, + int endianness) +{ + const GstGenicamPixelFormatInfo *info = + gst_genicam_pixel_format_get_info (pixel_format, endianness); + + if (!info) + return 0; + + return info->depth; +} + +static int +gst_genicam_pixel_format_get_stride (const char *pixel_format, + int endianness, int width) +{ + return width * gst_genicam_pixel_format_get_depth (pixel_format, + endianness) / 8; +} + +static GstCaps * +gst_genicam_pixel_format_caps_from_pixel_format (const char *pixel_format, + int endianness, int width, int height, int framerate_n, int framerate_d, + int par_n, int par_d) +{ + const char *caps_string; + GstCaps *caps; + GstStructure *structure; + + GST_DEBUG + ("Trying to create caps from: %s, endianness=%d, %dx%d, fps=%d/%d, par=%d/%d", + pixel_format, endianness, width, height, framerate_n, framerate_d, par_n, + par_d); + + caps_string = + gst_genicam_pixel_format_to_caps_string (pixel_format, endianness); + if (caps_string == NULL) + return NULL; + + GST_DEBUG ("Got caps string: %s", caps_string); + + structure = gst_structure_from_string (caps_string, NULL); + if (structure == NULL) + return NULL; + + gst_structure_set (structure, + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, + "framerate", GST_TYPE_FRACTION, framerate_n, framerate_d, + "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d, NULL); + + caps = gst_caps_new_empty (); + gst_caps_append_structure (caps, structure); + + return caps; +} \ No newline at end of file