From e45f85fc956d8e763759b6f16df0de42a08ad89d Mon Sep 17 00:00:00 2001 From: "Joshua M. Doe" Date: Wed, 10 Jan 2018 09:34:47 -0500 Subject: [PATCH] misb: add new plugin with elements to pack/unpack MISB IR over SDI data --- gst/CMakeLists.txt | 1 + gst/misb/CMakeLists.txt | 31 +++ gst/misb/gstmisb.c | 59 ++++++ gst/misb/gstmisbirpack.c | 397 +++++++++++++++++++++++++++++++++++++ gst/misb/gstmisbirpack.h | 75 +++++++ gst/misb/gstmisbirunpack.c | 342 ++++++++++++++++++++++++++++++++ gst/misb/gstmisbirunpack.h | 75 +++++++ 7 files changed, 980 insertions(+) create mode 100644 gst/misb/CMakeLists.txt create mode 100644 gst/misb/gstmisb.c create mode 100644 gst/misb/gstmisbirpack.c create mode 100644 gst/misb/gstmisbirpack.h create mode 100644 gst/misb/gstmisbirunpack.c create mode 100644 gst/misb/gstmisbirunpack.h diff --git a/gst/CMakeLists.txt b/gst/CMakeLists.txt index b037213..accf79e 100644 --- a/gst/CMakeLists.txt +++ b/gst/CMakeLists.txt @@ -3,4 +3,5 @@ if (OPENCV_FOUND) endif (OPENCV_FOUND) add_subdirectory (extractcolor) +add_subdirectory (misb) add_subdirectory (videoadjust) diff --git a/gst/misb/CMakeLists.txt b/gst/misb/CMakeLists.txt new file mode 100644 index 0000000..12402d5 --- /dev/null +++ b/gst/misb/CMakeLists.txt @@ -0,0 +1,31 @@ +set (SOURCES + gstmisb.c + gstmisbirpack.c + gstmisbirunpack.c + ) + +set (HEADERS + gstmisbirpack.h + gstmisbirunpack.h) + +include_directories (AFTER + ${ORC_INCLUDE_DIR}) + +set (libname libgstmisb) + +add_library (${libname} MODULE + ${SOURCES} + ${HEADERS}) + +target_link_libraries (${libname} + ${ORC_LIBRARIES} + ${GLIB2_LIBRARIES} + ${GOBJECT_LIBRARIES} + ${GSTREAMER_LIBRARY} + ${GSTREAMER_BASE_LIBRARY} + ${GSTREAMER_VIDEO_LIBRARY}) + +set (pdbfile "${CMAKE_CURRENT_BINARY_DIR}/\${CMAKE_INSTALL_CONFIG_NAME}/${libname}.pdb") +install (FILES ${pdbfile} DESTINATION lib/gstreamer-1.0 COMPONENT pdb) +install(TARGETS ${libname} + LIBRARY DESTINATION lib/gstreamer-1.0) diff --git a/gst/misb/gstmisb.c b/gst/misb/gstmisb.c new file mode 100644 index 0000000..072399b --- /dev/null +++ b/gst/misb/gstmisb.c @@ -0,0 +1,59 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) <2003> David Schleef + * Copyright (C) 2003 Arwed v. Merkatz + * Copyright (C) 2006 Mark Nauwelaerts + * Copyright (C) 2018 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstmisbirpack.h" +#include "gstmisbirunpack.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "misb", 0, + "debug category for misb"); + + GST_DEBUG ("plugin_init"); + + GST_CAT_INFO (GST_CAT_DEFAULT, "registering misbirpack element"); + if (!gst_element_register (plugin, "misbirpack", GST_RANK_NONE, + GST_TYPE_MISB_IR_PACK)) { + return FALSE; + } + + GST_CAT_INFO (GST_CAT_DEFAULT, "registering misbirunpack element"); + if (!gst_element_register (plugin, "misbirunpack", GST_RANK_NONE, + GST_TYPE_MISB_IR_UNPACK)) { + return FALSE; + } + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + misb, + "MISB related filters", + plugin_init, GST_PACKAGE_VERSION, GST_PACKAGE_LICENSE, GST_PACKAGE_NAME, + GST_PACKAGE_ORIGIN); diff --git a/gst/misb/gstmisbirpack.c b/gst/misb/gstmisbirpack.c new file mode 100644 index 0000000..8be430d --- /dev/null +++ b/gst/misb/gstmisbirpack.c @@ -0,0 +1,397 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) <2003> David Schleef + * Copyright (C) 2003 Arwed v. Merkatz + * Copyright (C) 2006 Mark Nauwelaerts + * Copyright (C) 2018 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** +* SECTION:element-misbirpack +* +* Pack GRAY16 to MISB IR packed video. +* +* +* Example launch line +* |[ +* gst-launch videotestsrc ! misbirpack ! misbirpack ! ffmpegcolorspace ! autovideosink +* ]| +* +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstmisbirpack.h" + +#include + +//#include "gstextractcolororc-dist.h" + +/* GstMisbIrPack signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_OFFSET, + PROP_LAST +}; + +#define DEFAULT_PROP_OFFSET 64 + +/* the capabilities of the inputs and outputs */ +static GstStaticPadTemplate gst_misb_ir_pack_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("GRAY16_LE")) + ); + +static GstStaticPadTemplate gst_misb_ir_pack_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("v210")) + ); + + +/* GObject vmethod declarations */ +static void gst_misb_ir_pack_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_misb_ir_pack_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_misb_ir_pack_dispose (GObject * object); + +/* GstBaseTransform vmethod declarations */ +static GstCaps *gst_misb_ir_pack_transform_caps (GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps, GstCaps * filter_caps); + +/* GstVideoFilter vmethod declarations */ +static gboolean gst_misb_ir_pack_set_info (GstVideoFilter * filter, + GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps, + GstVideoInfo * out_info); +static GstFlowReturn gst_misb_ir_pack_transform_frame (GstVideoFilter * filter, + GstVideoFrame * in_frame, GstVideoFrame * out_frame); + +/* GstMisbIrPack method declarations */ +static void gst_misb_ir_pack_reset (GstMisbIrPack * filter); + +/* setup debug */ +GST_DEBUG_CATEGORY_STATIC (misb_ir_pack_debug); +#define GST_CAT_DEFAULT misb_ir_pack_debug + +G_DEFINE_TYPE (GstMisbIrPack, gst_misb_ir_pack, GST_TYPE_VIDEO_FILTER); + +/************************************************************************/ +/* GObject vmethod implementations */ +/************************************************************************/ + +/** + * gst_misb_ir_pack_dispose: + * @object: #GObject. + * + */ +static void +gst_misb_ir_pack_dispose (GObject * object) +{ + GstMisbIrPack *misb_ir_pack = GST_MISB_IR_PACK (object); + + GST_DEBUG ("dispose"); + + gst_misb_ir_pack_reset (misb_ir_pack); + + /* chain up to the parent class */ + G_OBJECT_CLASS (gst_misb_ir_pack_parent_class)->dispose (object); +} + +/** + * gst_misb_ir_pack_class_init: + * @object: #GstMisbIrPackClass. + * + */ +static void +gst_misb_ir_pack_class_init (GstMisbIrPackClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + GstBaseTransformClass *gstbasetransform_class = + GST_BASE_TRANSFORM_CLASS (klass); + GstVideoFilterClass *gstvideofilter_class = GST_VIDEO_FILTER_CLASS (klass); + + GST_DEBUG ("class init"); + + /* Register GObject vmethods */ + gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_misb_ir_pack_dispose); + gobject_class->set_property = + GST_DEBUG_FUNCPTR (gst_misb_ir_pack_set_property); + gobject_class->get_property = + GST_DEBUG_FUNCPTR (gst_misb_ir_pack_get_property); + + /* Install GObject properties */ + g_object_class_install_property (G_OBJECT_CLASS (klass), + PROP_OFFSET, g_param_spec_int ("offset", + "Offset value", + "Offset value to apply during packing", 0, 1023, + DEFAULT_PROP_OFFSET, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_misb_ir_pack_sink_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_misb_ir_pack_src_template)); + + gst_element_class_set_static_metadata (gstelement_class, + "Pack to MISB IR video", "Filter/Effect/Video", + "Pack GRAY16 to MISB IR video according to ST 0402.2 Method 2", + "Joshua M. Doe "); + + /* Register GstBaseTransform vmethods */ + gstbasetransform_class->transform_caps = + GST_DEBUG_FUNCPTR (gst_misb_ir_pack_transform_caps); + + gstvideofilter_class->set_info = + GST_DEBUG_FUNCPTR (gst_misb_ir_pack_set_info); + gstvideofilter_class->transform_frame = + GST_DEBUG_FUNCPTR (gst_misb_ir_pack_transform_frame); +} + +static void +gst_misb_ir_pack_init (GstMisbIrPack * filt) +{ + GST_DEBUG_OBJECT (filt, "init class instance"); + + filt->offset_value = DEFAULT_PROP_OFFSET; + gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filt), FALSE); + + gst_misb_ir_pack_reset (filt); +} + +static void +gst_misb_ir_pack_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstMisbIrPack *filt = GST_MISB_IR_PACK (object); + + GST_DEBUG_OBJECT (filt, "setting property %s", pspec->name); + + switch (prop_id) { + case PROP_OFFSET: + filt->offset_value = g_value_get_enum (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_misb_ir_pack_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstMisbIrPack *filt = GST_MISB_IR_PACK (object); + + GST_DEBUG_OBJECT (filt, "getting property %s", pspec->name); + + switch (prop_id) { + case PROP_OFFSET: + g_value_set_enum (value, filt->offset_value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +GstCaps * +gst_misb_ir_pack_transform_caps (GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps, GstCaps * filter_caps) +{ + GstMisbIrPack *filt = GST_MISB_IR_PACK (trans); + GstStructure *structure, *newstruct; + GstCaps *newcaps; + guint i, n; + + GST_LOG_OBJECT (filt, "transforming caps from %" GST_PTR_FORMAT, caps); + + newcaps = gst_caps_new_empty (); + n = gst_caps_get_size (caps); + for (i = 0; i < n; ++i) { + structure = gst_caps_get_structure (caps, i); + if (direction == GST_PAD_SINK) { + newstruct = gst_structure_new_from_string ("video/x-raw,format=v210"); + } else { + newstruct = + gst_structure_new_from_string ("video/x-raw,format=GRAY16_LE"); + } + + gst_structure_set_value (newstruct, "width", + gst_structure_get_value (structure, "width")); + gst_structure_set_value (newstruct, "height", + gst_structure_get_value (structure, "height")); + gst_structure_set_value (newstruct, "framerate", + gst_structure_get_value (structure, "framerate")); + + gst_caps_append_structure (newcaps, newstruct); + } + + + if (!gst_caps_is_empty (newcaps) && filter_caps) { + GstCaps *tmp = gst_caps_intersect_full (filter_caps, newcaps, + GST_CAPS_INTERSECT_FIRST); + gst_caps_replace (&newcaps, tmp); + gst_caps_unref (tmp); + } + + GST_LOG_OBJECT (filt, "transformed caps to %" GST_PTR_FORMAT, newcaps); + + return newcaps; +} + +static gboolean +gst_misb_ir_pack_set_info (GstVideoFilter * filter, GstCaps * incaps, + GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info) +{ + GstMisbIrPack *filt = GST_MISB_IR_PACK (filter); + gboolean res = TRUE; + + GST_DEBUG_OBJECT (filt, + "set_caps: in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps, outcaps); + + memcpy (&filt->info_in, in_info, sizeof (GstVideoInfo)); + memcpy (&filt->info_out, out_info, sizeof (GstVideoInfo)); + + return res; +} + +static GstFlowReturn +gst_misb_ir_pack_transform_frame (GstVideoFilter * filter, + GstVideoFrame * in_frame, GstVideoFrame * out_frame) +{ + GstMisbIrPack *filt = GST_MISB_IR_PACK (filter); + GTimer *timer = NULL; + guint offset = filt->offset_value; + gint y; + guint16 *src, *src_end; + guint32 *dst; + guint32 word0; + guint32 word1; + guint16 luma0, chroma0, luma1, chroma1, luma2, chroma2; + + GST_LOG_OBJECT (filt, "Performing non-inplace transform"); + +#if 0 + timer = g_timer_new (); +#endif + + for (y = 0; y < GST_VIDEO_FRAME_COMP_HEIGHT (in_frame, 0); y++) { + src = (guint16 *) (GST_VIDEO_FRAME_COMP_DATA (in_frame, 0) + + y * GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0)); + src_end = src + GST_VIDEO_FRAME_COMP_WIDTH (in_frame, 0); + dst = (guint32 *) (GST_VIDEO_FRAME_COMP_DATA (out_frame, 0) + + y * GST_VIDEO_FRAME_COMP_STRIDE (out_frame, 0)); + + while (src + 2 < src_end) { + chroma0 = (*src & 0xff) + offset; + luma0 = ((*src & 0xff00) >> 8) + offset; + src++; + chroma1 = (*src & 0xff) + offset; + luma1 = ((*src & 0xff00) >> 8) + offset; + src++; + chroma2 = (*src & 0xff) + offset; + luma2 = ((*src & 0xff00) >> 8) + offset; + src++; + + word0 = chroma0 | luma0 << 10 | chroma1 << 20; + word1 = luma1 | chroma2 << 10 | luma2 << 20; + + *dst++ = word0; + *dst++ = word1; + } + + /* handle the last one or two pixels if they exist */ + if (src_end - src) { + chroma0 = (*src & 0xff) + offset; + luma0 = ((*src & 0xff00) >> 8) + offset; + src++; + if (src_end - src) { + chroma1 = (*src & 0xff) + offset; + luma1 = ((*src & 0xff00) >> 8) + offset; + } else { + chroma1 = luma1 = 0; + } + chroma2 = luma2 = 0; + + word0 = chroma0 | luma0 << 10 | chroma1 << 20; + word1 = luma1 | chroma2 << 10 | luma2 << 20; + + *dst++ = word0; + *dst++ = word1; + } + } + + //for (y = 0; y < GST_VIDEO_FRAME_COMP_HEIGHT (in_frame, 0); y++) { + // src = (guint16 *) (GST_VIDEO_FRAME_COMP_DATA (in_frame, 0) + + // y * GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0)); + // dst = (guint32 *) (GST_VIDEO_FRAME_COMP_DATA (out_frame, 0) + + // y * GST_VIDEO_FRAME_COMP_STRIDE (out_frame, 0)); + // for (x = 0; x < GST_VIDEO_FRAME_COMP_WIDTH (in_frame, 0); ) { + // guint32 word0; + // guint32 word1; + // guint16 luma0, chroma0, luma1, chroma1, luma2, chroma2; + + // chroma0 = *src & 0xff + offset; + // luma0 = (*src & 0xff00) >> 8 + offset; + // src++; + // chroma1 = *src & 0xff + offset; + // luma1 = (*src & 0xff00) >> 8 + offset; + // src++; + // chroma2 = *src & 0xff + offset; + // luma2 = (*src & 0xff00) >> 8 + offset; + // src++; + + // word0 = 0; + // word0 = chroma0 | luma0 << 10 | chroma1 << 20; + // word1 = 0; + // word1 = luma1 | chroma2 << 10 | luma2 << 20; + + // dst[x++] = word0; + // dst[x++] = word1; + // } + //} + +#if 0 + GST_LOG_OBJECT (filt, "Processing took %.3f ms", g_timer_elapsed (timer, + NULL) * 1000); + g_timer_destroy (timer); +#endif + + return GST_FLOW_OK; +} + + +static void +gst_misb_ir_pack_reset (GstMisbIrPack * misb_ir_pack) +{ + gst_video_info_init (&misb_ir_pack->info_in); + gst_video_info_init (&misb_ir_pack->info_out); +} diff --git a/gst/misb/gstmisbirpack.h b/gst/misb/gstmisbirpack.h new file mode 100644 index 0000000..039423b --- /dev/null +++ b/gst/misb/gstmisbirpack.h @@ -0,0 +1,75 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) <2003> David Schleef + * Copyright (C) 2003 Arwed v. Merkatz + * Copyright (C) 2006 Mark Nauwelaerts + * Copyright (C) 2018 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_MISB_IR_PACK_H__ +#define __GST_MISB_IR_PACK_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_MISB_IR_PACK \ + (gst_misb_ir_pack_get_type()) +#define GST_MISB_IR_PACK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MISB_IR_PACK,GstMisbIrPack)) +#define GST_MISB_IR_PACK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MISB_IR_PACK,GstMisbIrPackClass)) +#define GST_IS_MISB_IR_PACK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MISB_IR_PACK)) +#define GST_IS_MISB_IR_PACK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MISB_IR_PACK)) + +typedef struct _GstMisbIrPack GstMisbIrPack; +typedef struct _GstMisbIrPackClass GstMisbIrPackClass; + +/** +* GstMisbIrPack: +* @element: the parent element. +* +* +* The opaque GstMisbIrPack data structure. +*/ +struct _GstMisbIrPack +{ + GstVideoFilter element; + + /* format */ + GstVideoInfo info_in; + GstVideoInfo info_out; + + /* properties */ + guint offset_value; +}; + +struct _GstMisbIrPackClass +{ + GstVideoFilterClass parent_class; +}; + +GType gst_misb_ir_pack_get_type(void); + +G_END_DECLS + +#endif /* __GST_MISB_IR_PACK_H__ */ diff --git a/gst/misb/gstmisbirunpack.c b/gst/misb/gstmisbirunpack.c new file mode 100644 index 0000000..dfb9d0a --- /dev/null +++ b/gst/misb/gstmisbirunpack.c @@ -0,0 +1,342 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) <2003> David Schleef + * Copyright (C) 2003 Arwed v. Merkatz + * Copyright (C) 2006 Mark Nauwelaerts + * Copyright (C) 2018 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** +* SECTION:element-misbirunpack +* +* Unpack MISB IR packed video to GRAY16. +* +* +* Example launch line +* |[ +* gst-launch videotestsrc ! misbirpack ! misbirunpack ! ffmpegcolorspace ! autovideosink +* ]| +* +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstmisbirunpack.h" + +#include + +//#include "gstextractcolororc-dist.h" + +/* GstMisbIrUnpack signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_OFFSET, + PROP_LAST +}; + +#define DEFAULT_PROP_OFFSET 64 + +/* the capabilities of the inputs and outputs */ +static GstStaticPadTemplate gst_misb_ir_unpack_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("v210")) + ); + +static GstStaticPadTemplate gst_misb_ir_unpack_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("GRAY16_LE")) + ); + + +/* GObject vmethod declarations */ +static void gst_misb_ir_unpack_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_misb_ir_unpack_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_misb_ir_unpack_dispose (GObject * object); + +/* GstBaseTransform vmethod declarations */ +static GstCaps *gst_misb_ir_unpack_transform_caps (GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps, GstCaps * filter_caps); + +/* GstVideoFilter vmethod declarations */ +static gboolean gst_misb_ir_unpack_set_info (GstVideoFilter * filter, + GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps, + GstVideoInfo * out_info); +static GstFlowReturn gst_misb_ir_unpack_transform_frame (GstVideoFilter * + filter, GstVideoFrame * in_frame, GstVideoFrame * out_frame); + +/* GstMisbIrUnpack method declarations */ +static void gst_misb_ir_unpack_reset (GstMisbIrUnpack * filter); + +/* setup debug */ +GST_DEBUG_CATEGORY_STATIC (misb_ir_unpack_debug); +#define GST_CAT_DEFAULT misb_ir_unpack_debug + +G_DEFINE_TYPE (GstMisbIrUnpack, gst_misb_ir_unpack, GST_TYPE_VIDEO_FILTER); + +/************************************************************************/ +/* GObject vmethod implementations */ +/************************************************************************/ + +/** + * gst_misb_ir_unpack_dispose: + * @object: #GObject. + * + */ +static void +gst_misb_ir_unpack_dispose (GObject * object) +{ + GstMisbIrUnpack *misb_ir_unpack = GST_MISB_IR_UNPACK (object); + + GST_DEBUG ("dispose"); + + gst_misb_ir_unpack_reset (misb_ir_unpack); + + /* chain up to the parent class */ + G_OBJECT_CLASS (gst_misb_ir_unpack_parent_class)->dispose (object); +} + +/** + * gst_misb_ir_unpack_class_init: + * @object: #GstMisbIrUnpackClass. + * + */ +static void +gst_misb_ir_unpack_class_init (GstMisbIrUnpackClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + GstBaseTransformClass *gstbasetransform_class = + GST_BASE_TRANSFORM_CLASS (klass); + GstVideoFilterClass *gstvideofilter_class = GST_VIDEO_FILTER_CLASS (klass); + + GST_DEBUG ("class init"); + + /* Register GObject vmethods */ + gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_misb_ir_unpack_dispose); + gobject_class->set_property = + GST_DEBUG_FUNCPTR (gst_misb_ir_unpack_set_property); + gobject_class->get_property = + GST_DEBUG_FUNCPTR (gst_misb_ir_unpack_get_property); + + /* Install GObject properties */ + g_object_class_install_property (G_OBJECT_CLASS (klass), + PROP_OFFSET, g_param_spec_int ("offset", + "Offset value", + "Offset value to apply during unpacking", 0, 1023, + DEFAULT_PROP_OFFSET, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE)); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_misb_ir_unpack_sink_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&gst_misb_ir_unpack_src_template)); + + gst_element_class_set_static_metadata (gstelement_class, + "Unpack MISB IR video", "Filter/Effect/Video", + "Unpack MISB IR video according to ST 0402.2 Method 2", + "Joshua M. Doe "); + + /* Register GstBaseTransform vmethods */ + gstbasetransform_class->transform_caps = + GST_DEBUG_FUNCPTR (gst_misb_ir_unpack_transform_caps); + + gstvideofilter_class->set_info = + GST_DEBUG_FUNCPTR (gst_misb_ir_unpack_set_info); + gstvideofilter_class->transform_frame = + GST_DEBUG_FUNCPTR (gst_misb_ir_unpack_transform_frame); +} + +static void +gst_misb_ir_unpack_init (GstMisbIrUnpack * filt) +{ + GST_DEBUG_OBJECT (filt, "init class instance"); + + filt->offset_value = DEFAULT_PROP_OFFSET; + gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filt), FALSE); + + gst_misb_ir_unpack_reset (filt); +} + +static void +gst_misb_ir_unpack_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstMisbIrUnpack *filt = GST_MISB_IR_UNPACK (object); + + GST_DEBUG_OBJECT (filt, "setting property %s", pspec->name); + + switch (prop_id) { + case PROP_OFFSET: + filt->offset_value = g_value_get_enum (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_misb_ir_unpack_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstMisbIrUnpack *filt = GST_MISB_IR_UNPACK (object); + + GST_DEBUG_OBJECT (filt, "getting property %s", pspec->name); + + switch (prop_id) { + case PROP_OFFSET: + g_value_set_enum (value, filt->offset_value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +GstCaps * +gst_misb_ir_unpack_transform_caps (GstBaseTransform * trans, + GstPadDirection direction, GstCaps * caps, GstCaps * filter_caps) +{ + GstMisbIrUnpack *filt = GST_MISB_IR_UNPACK (trans); + GstStructure *structure, *newstruct; + GstCaps *newcaps; + guint i, n; + + GST_LOG_OBJECT (filt, "transforming caps from %" GST_PTR_FORMAT, caps); + + newcaps = gst_caps_new_empty (); + n = gst_caps_get_size (caps); + for (i = 0; i < n; ++i) { + structure = gst_caps_get_structure (caps, i); + if (direction == GST_PAD_SINK) { + newstruct = + gst_structure_new_from_string ("video/x-raw,format=GRAY16_LE"); + } else { + newstruct = gst_structure_new_from_string ("video/x-raw,format=v210"); + } + + gst_structure_set_value (newstruct, "width", + gst_structure_get_value (structure, "width")); + gst_structure_set_value (newstruct, "height", + gst_structure_get_value (structure, "height")); + gst_structure_set_value (newstruct, "framerate", + gst_structure_get_value (structure, "framerate")); + + gst_caps_append_structure (newcaps, newstruct); + } + + + if (!gst_caps_is_empty (newcaps) && filter_caps) { + GstCaps *tmp = gst_caps_intersect_full (filter_caps, newcaps, + GST_CAPS_INTERSECT_FIRST); + gst_caps_replace (&newcaps, tmp); + gst_caps_unref (tmp); + } + + GST_LOG_OBJECT (filt, "transformed caps to %" GST_PTR_FORMAT, newcaps); + + return newcaps; +} + +static gboolean +gst_misb_ir_unpack_set_info (GstVideoFilter * filter, GstCaps * incaps, + GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info) +{ + GstMisbIrUnpack *filt = GST_MISB_IR_UNPACK (filter); + gboolean res = TRUE; + + GST_DEBUG_OBJECT (filt, + "set_caps: in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps, outcaps); + + memcpy (&filt->info_in, in_info, sizeof (GstVideoInfo)); + memcpy (&filt->info_out, out_info, sizeof (GstVideoInfo)); + + return res; +} + +static GstFlowReturn +gst_misb_ir_unpack_transform_frame (GstVideoFilter * filter, + GstVideoFrame * in_frame, GstVideoFrame * out_frame) +{ + GstMisbIrUnpack *filt = GST_MISB_IR_UNPACK (filter); + GTimer *timer = NULL; + guint offset = filt->offset_value; + gint x, y; + guint32 *src; + guint16 *dst; + + GST_LOG_OBJECT (filt, "Performing non-inplace transform"); + +#if 0 + timer = g_timer_new (); +#endif + + for (y = 0; y < GST_VIDEO_FRAME_COMP_HEIGHT (in_frame, 0); y++) { + src = (guint32 *) (GST_VIDEO_FRAME_COMP_DATA (in_frame, 0) + + y * GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0)); + dst = (guint16 *) (GST_VIDEO_FRAME_COMP_DATA (out_frame, 0) + + y * GST_VIDEO_FRAME_COMP_STRIDE (out_frame, 0)); + for (x = 0; x < GST_VIDEO_FRAME_COMP_WIDTH (in_frame, 0);) { + guint32 word0 = *src++; + guint32 word1 = *src++; + guint16 luma, chroma; + + chroma = word0 & 0x3ff; + luma = (word0 & 0xffc00) >> 10; + dst[x++] = ((chroma - offset) & 0xff) | (((luma - offset) & 0xff) << 8); + + chroma = (word0 & 0x3ff00000) >> 20; + luma = word1 & 0x3ff; + dst[x++] = (chroma - offset) & 0xff | ((luma - offset) & 0xff) << 8; + + chroma = (word1 & 0xffc00) >> 10; + luma = (word1 & 0x3ff00000) >> 20; + dst[x++] = (chroma - offset) & 0xff | ((luma - offset) & 0xff) << 8; + } + } + +#if 0 + GST_LOG_OBJECT (filt, "Processing took %.3f ms", g_timer_elapsed (timer, + NULL) * 1000); + g_timer_destroy (timer); +#endif + + return GST_FLOW_OK; +} + + +static void +gst_misb_ir_unpack_reset (GstMisbIrUnpack * misb_ir_unpack) +{ + gst_video_info_init (&misb_ir_unpack->info_in); + gst_video_info_init (&misb_ir_unpack->info_out); +} diff --git a/gst/misb/gstmisbirunpack.h b/gst/misb/gstmisbirunpack.h new file mode 100644 index 0000000..5360cd0 --- /dev/null +++ b/gst/misb/gstmisbirunpack.h @@ -0,0 +1,75 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) <2003> David Schleef + * Copyright (C) 2003 Arwed v. Merkatz + * Copyright (C) 2006 Mark Nauwelaerts + * Copyright (C) 2018 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_MISB_IR_UNPACK_H__ +#define __GST_MISB_IR_UNPACK_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_MISB_IR_UNPACK \ + (gst_misb_ir_unpack_get_type()) +#define GST_MISB_IR_UNPACK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MISB_IR_UNPACK,GstMisbIrUnpack)) +#define GST_MISB_IR_UNPACK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MISB_IR_UNPACK,GstMisbIrUnpackClass)) +#define GST_IS_MISB_IR_UNPACK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MISB_IR_UNPACK)) +#define GST_IS_MISB_IR_UNPACK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MISB_IR_UNPACK)) + +typedef struct _GstMisbIrUnpack GstMisbIrUnpack; +typedef struct _GstMisbIrUnpackClass GstMisbIrUnpackClass; + +/** +* GstMisbIrUnpack: +* @element: the parent element. +* +* +* The opaque GstMisbIrUnpack data structure. +*/ +struct _GstMisbIrUnpack +{ + GstVideoFilter element; + + /* format */ + GstVideoInfo info_in; + GstVideoInfo info_out; + + /* properties */ + guint offset_value; +}; + +struct _GstMisbIrUnpackClass +{ + GstVideoFilterClass parent_class; +}; + +GType gst_misb_ir_unpack_get_type(void); + +G_END_DECLS + +#endif /* __GST_MISB_IR_UNPACK_H__ */