From: Antonio Ospite Date: Thu, 24 Oct 2013 16:05:21 +0000 (+0200) Subject: Initial import, just a copy of fbdevsink from gst-plugins-bad X-Git-Url: https://git.ao2.it/gst-am7xxxsink.git/commitdiff_plain/f1a3a5249f8787af26802c4272571a46b4fa1079 Initial import, just a copy of fbdevsink from gst-plugins-bad --- f1a3a5249f8787af26802c4272571a46b4fa1079 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b864463 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +aclocal.m4 +autom4te.cache +autoregen.sh +config.* +configure +libtool +INSTALL +Makefile.in +depcomp +install-sh +ltmain.sh +missing +stamp-* +my-plugin-*.tar.* +*~ + diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..e3a294a --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Antonio Ospite diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..09ec995 --- /dev/null +++ b/COPYING @@ -0,0 +1,2 @@ +Put your license in here! + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..5ff2f58 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src + +EXTRA_DIST = autogen.sh diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..3474a99 --- /dev/null +++ b/NEWS @@ -0,0 +1 @@ +Nothing much yet. diff --git a/README b/README new file mode 100644 index 0000000..e69de29 diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..9df38d3 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# you can either set the environment variables AUTOCONF, AUTOHEADER, AUTOMAKE, +# ACLOCAL, AUTOPOINT and/or LIBTOOLIZE to the right versions, or leave them +# unset and get the defaults + +autoreconf --verbose --force --install --make || { + echo 'autogen.sh failed'; + exit 1; +} + +./configure || { + echo 'configure failed'; + exit 1; +} + +echo +echo "Now type 'make' to compile this module." +echo diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..ecd1a85 --- /dev/null +++ b/configure.ac @@ -0,0 +1,73 @@ +dnl required version of autoconf +AC_PREREQ([2.53]) + +AC_INIT([gst-fbdevsink],[0.1.0],[http://ao2.it],[gst-fbdevsink]) + +dnl required versions of gstreamer and plugins-base +GST_REQUIRED=1.0.0 +GSTPB_REQUIRED=1.0.0 + +AC_CONFIG_SRCDIR([src/gstfbdevsink.c]) +AC_CONFIG_HEADERS([config.h]) + +dnl required version of automake +AM_INIT_AUTOMAKE([1.10]) + +dnl enable mainainer mode by default +AM_MAINTAINER_MODE([enable]) + +dnl check for tools (compiler etc.) +AC_PROG_CC + +dnl required version of libtool +LT_PREREQ([2.2.6]) +LT_INIT + +dnl give error and exit if we don't have pkgconfig +AC_CHECK_PROG(HAVE_PKGCONFIG, pkg-config, [ ], [ + AC_MSG_ERROR([You need to have pkg-config installed!]) +]) + +PKG_CHECK_MODULES(GST, [ + gstreamer-1.0 >= $GST_REQUIRED + gstreamer-base-1.0 >= $GST_REQUIRED + gstreamer-controller-1.0 >= $GST_REQUIRED +], [ + AC_SUBST(GST_CFLAGS) + AC_SUBST(GST_LIBS) +], [ + AC_MSG_ERROR([ + You need to install or upgrade the GStreamer development + packages on your system. On debian-based systems these are + libgstreamer1.0-dev and libgstreamer-plugins-base1.0-dev. + on RPM-based systems gstreamer1.0-devel, libgstreamer1.0-devel + or similar. The minimum version required is $GST_REQUIRED. + ]) +]) + +dnl check if compiler understands -Wall (if yes, add -Wall to GST_CFLAGS) +AC_MSG_CHECKING([to see if compiler understands -Wall]) +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Wall" +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ ], [ ])], [ + GST_CFLAGS="$GST_CFLAGS -Wall" + AC_MSG_RESULT([yes]) +], [ + AC_MSG_RESULT([no]) +]) + +dnl set the plugindir where plugins should be installed (for src/Makefile.am) +if test "x${prefix}" = "x$HOME"; then + plugindir="$HOME/.gstreamer-1.0/plugins" +else + plugindir="\$(libdir)/gstreamer-1.0" +fi +AC_SUBST(plugindir) + +dnl set proper LDFLAGS for plugins +GST_PLUGIN_LDFLAGS='-module -avoid-version -export-symbols-regex [_]*\(gst_\|Gst\|GST_\).*' +AC_SUBST(GST_PLUGIN_LDFLAGS) + +AC_CONFIG_FILES([Makefile src/Makefile]) +AC_OUTPUT + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..06a03e0 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,15 @@ +# Note: plugindir is set in configure + +plugin_LTLIBRARIES = libgstfbdevsink.la + +# sources used to compile this plug-in +libgstfbdevsink_la_SOURCES = gstfbdevsink.c gstfbdevsink.h + +# compiler and linker flags used to compile this plugin, set in configure.ac +libgstfbdevsink_la_CFLAGS = $(GST_CFLAGS) +libgstfbdevsink_la_LIBADD = $(GST_LIBS) +libgstfbdevsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstfbdevsink_la_LIBTOOLFLAGS = --tag=disable-static + +# headers we need but don't want installed +noinst_HEADERS = gstfbdevsink.h diff --git a/src/gstfbdevsink.c b/src/gstfbdevsink.c new file mode 100644 index 0000000..31018aa --- /dev/null +++ b/src/gstfbdevsink.c @@ -0,0 +1,453 @@ +/* GStreamer fbdev plugin + * Copyright (C) 2007 Sean D'Epagnier + * + * 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 St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* currently the driver does not switch modes, instead uses current mode. + the video is centered and cropped if needed to fit onscreen. + Whatever bitdepth is set is used, and tested to work for 16, 24, 32 bits +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "gstfbdevsink.h" + +enum +{ + ARG_0, + ARG_DEVICE +}; + +#if 0 +static void gst_fbdevsink_get_times (GstBaseSink * basesink, + GstBuffer * buffer, GstClockTime * start, GstClockTime * end); +#endif + +static GstFlowReturn gst_fbdevsink_show_frame (GstVideoSink * videosink, + GstBuffer * buff); + +static gboolean gst_fbdevsink_start (GstBaseSink * bsink); +static gboolean gst_fbdevsink_stop (GstBaseSink * bsink); + +static GstCaps *gst_fbdevsink_getcaps (GstBaseSink * bsink, GstCaps * filter); +static gboolean gst_fbdevsink_setcaps (GstBaseSink * bsink, GstCaps * caps); + +static void gst_fbdevsink_finalize (GObject * object); +static void gst_fbdevsink_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); +static void gst_fbdevsink_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); +static GstStateChangeReturn gst_fbdevsink_change_state (GstElement * element, + GstStateChange transition); + +#define VIDEO_CAPS "{ RGB, BGR, BGRx, xBGR, RGB, RGBx, xRGB, RGB15, RGB16 }" + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (VIDEO_CAPS)) + ); + +#define parent_class gst_fbdevsink_parent_class +G_DEFINE_TYPE (GstFBDEVSink, gst_fbdevsink, GST_TYPE_VIDEO_SINK); + +static void +gst_fbdevsink_init (GstFBDEVSink * fbdevsink) +{ + /* nothing to do here yet */ +} + +#if 0 +static void +gst_fbdevsink_get_times (GstBaseSink * basesink, GstBuffer * buffer, + GstClockTime * start, GstClockTime * end) +{ + GstFBDEVSink *fbdevsink; + + fbdevsink = GST_FBDEVSINK (basesink); + + if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) { + *start = GST_BUFFER_TIMESTAMP (buffer); + if (GST_BUFFER_DURATION_IS_VALID (buffer)) { + *end = *start + GST_BUFFER_DURATION (buffer); + } else { + if (fbdevsink->fps_n > 0) { + *end = *start + + gst_util_uint64_scale_int (GST_SECOND, fbdevsink->fps_d, + fbdevsink->fps_n); + } + } + } +} +#endif + +static GstCaps * +gst_fbdevsink_getcaps (GstBaseSink * bsink, GstCaps * filter) +{ + GstFBDEVSink *fbdevsink; + GstVideoFormat format; + GstCaps *caps; + uint32_t rmask; + uint32_t gmask; + uint32_t bmask; + uint32_t tmask; + int endianness, depth, bpp; + + fbdevsink = GST_FBDEVSINK (bsink); + + caps = gst_static_pad_template_get_caps (&sink_template); + + /* FIXME: locking */ + if (!fbdevsink->framebuffer) + goto done; + + bpp = fbdevsink->varinfo.bits_per_pixel; + + rmask = ((1 << fbdevsink->varinfo.red.length) - 1) + << fbdevsink->varinfo.red.offset; + gmask = ((1 << fbdevsink->varinfo.green.length) - 1) + << fbdevsink->varinfo.green.offset; + bmask = ((1 << fbdevsink->varinfo.blue.length) - 1) + << fbdevsink->varinfo.blue.offset; + tmask = ((1 << fbdevsink->varinfo.transp.length) - 1) + << fbdevsink->varinfo.transp.offset; + + depth = fbdevsink->varinfo.red.length + fbdevsink->varinfo.green.length + + fbdevsink->varinfo.blue.length; + + switch (fbdevsink->varinfo.bits_per_pixel) { + case 32: + /* swap endianness of masks */ + rmask = GUINT32_SWAP_LE_BE (rmask); + gmask = GUINT32_SWAP_LE_BE (gmask); + bmask = GUINT32_SWAP_LE_BE (bmask); + tmask = GUINT32_SWAP_LE_BE (tmask); + depth += fbdevsink->varinfo.transp.length; + endianness = G_BIG_ENDIAN; + break; + case 24:{ + /* swap red and blue masks */ + tmask = rmask; + rmask = bmask; + bmask = tmask; + tmask = 0; + endianness = G_BIG_ENDIAN; + break; + } + case 15: + case 16: + tmask = 0; + endianness = G_LITTLE_ENDIAN; + break; + default: + goto unsupported_bpp; + } + + format = gst_video_format_from_masks (depth, bpp, endianness, rmask, gmask, + bmask, tmask); + + if (format == GST_VIDEO_FORMAT_UNKNOWN) + goto unknown_format; + + caps = gst_caps_make_writable (caps); + gst_caps_set_simple (caps, "format", G_TYPE_STRING, + gst_video_format_to_string (format), NULL); + +done: + + if (filter != NULL) { + GstCaps *icaps; + + icaps = gst_caps_intersect (caps, filter); + gst_caps_unref (caps); + caps = icaps; + } + + return caps; + +/* ERRORS */ +unsupported_bpp: + { + GST_WARNING_OBJECT (bsink, "unsupported bit depth: %d", bpp); + return NULL; + } +unknown_format: + { + GST_WARNING_OBJECT (bsink, "could not map fbdev format to GstVideoFormat: " + "depth=%u, bpp=%u, endianness=%u, rmask=0x%08x, gmask=0x%08x, " + "bmask=0x%08x, tmask=0x%08x", depth, bpp, endianness, rmask, gmask, + bmask, tmask); + return NULL; + } +} + +static gboolean +gst_fbdevsink_setcaps (GstBaseSink * bsink, GstCaps * vscapslist) +{ + GstFBDEVSink *fbdevsink; + GstStructure *structure; + const GValue *fps; + + fbdevsink = GST_FBDEVSINK (bsink); + + structure = gst_caps_get_structure (vscapslist, 0); + + fps = gst_structure_get_value (structure, "framerate"); + fbdevsink->fps_n = gst_value_get_fraction_numerator (fps); + fbdevsink->fps_d = gst_value_get_fraction_denominator (fps); + + gst_structure_get_int (structure, "width", &fbdevsink->width); + gst_structure_get_int (structure, "height", &fbdevsink->height); + + /* calculate centering and scanlengths for the video */ + fbdevsink->bytespp = fbdevsink->fixinfo.line_length / fbdevsink->varinfo.xres; + + fbdevsink->cx = ((int) fbdevsink->varinfo.xres - fbdevsink->width) / 2; + if (fbdevsink->cx < 0) + fbdevsink->cx = 0; + + fbdevsink->cy = ((int) fbdevsink->varinfo.yres - fbdevsink->height) / 2; + if (fbdevsink->cy < 0) + fbdevsink->cy = 0; + + fbdevsink->linelen = fbdevsink->width * fbdevsink->bytespp; + if (fbdevsink->linelen > fbdevsink->fixinfo.line_length) + fbdevsink->linelen = fbdevsink->fixinfo.line_length; + + fbdevsink->lines = fbdevsink->height; + if (fbdevsink->lines > fbdevsink->varinfo.yres) + fbdevsink->lines = fbdevsink->varinfo.yres; + + return TRUE; +} + + +static GstFlowReturn +gst_fbdevsink_show_frame (GstVideoSink * videosink, GstBuffer * buf) +{ + + GstFBDEVSink *fbdevsink; + GstMapInfo map; + int i; + + fbdevsink = GST_FBDEVSINK (videosink); + + /* optimization could remove this memcpy by allocating the buffer + in framebuffer memory, but would only work when xres matches + the video width */ + if (!gst_buffer_map (buf, &map, GST_MAP_READ)) + return GST_FLOW_ERROR; + + for (i = 0; i < fbdevsink->lines; i++) { + memcpy (fbdevsink->framebuffer + + (i + fbdevsink->cy) * fbdevsink->fixinfo.line_length + + fbdevsink->cx * fbdevsink->bytespp, + map.data + i * fbdevsink->width * fbdevsink->bytespp, + fbdevsink->linelen); + } + + gst_buffer_unmap (buf, &map); + + return GST_FLOW_OK; +} + +static gboolean +gst_fbdevsink_start (GstBaseSink * bsink) +{ + GstFBDEVSink *fbdevsink; + + fbdevsink = GST_FBDEVSINK (bsink); + + if (!fbdevsink->device) { + fbdevsink->device = g_strdup ("/dev/fb0"); + } + + fbdevsink->fd = open (fbdevsink->device, O_RDWR); + + if (fbdevsink->fd == -1) + return FALSE; + + /* get the fixed screen info */ + if (ioctl (fbdevsink->fd, FBIOGET_FSCREENINFO, &fbdevsink->fixinfo)) + return FALSE; + + /* get the variable screen info */ + if (ioctl (fbdevsink->fd, FBIOGET_VSCREENINFO, &fbdevsink->varinfo)) + return FALSE; + + /* map the framebuffer */ + fbdevsink->framebuffer = mmap (0, fbdevsink->fixinfo.smem_len, + PROT_WRITE, MAP_SHARED, fbdevsink->fd, 0); + if (fbdevsink->framebuffer == MAP_FAILED) + return FALSE; + + return TRUE; +} + +static gboolean +gst_fbdevsink_stop (GstBaseSink * bsink) +{ + GstFBDEVSink *fbdevsink; + + fbdevsink = GST_FBDEVSINK (bsink); + + if (munmap (fbdevsink->framebuffer, fbdevsink->fixinfo.smem_len)) + return FALSE; + + if (close (fbdevsink->fd)) + return FALSE; + + + return TRUE; +} + +static void +gst_fbdevsink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstFBDEVSink *fbdevsink; + + fbdevsink = GST_FBDEVSINK (object); + + switch (prop_id) { + case ARG_DEVICE:{ + g_free (fbdevsink->device); + fbdevsink->device = g_value_dup_string (value); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +static void +gst_fbdevsink_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstFBDEVSink *fbdevsink; + + fbdevsink = GST_FBDEVSINK (object); + + switch (prop_id) { + case ARG_DEVICE:{ + g_value_set_string (value, fbdevsink->device); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstStateChangeReturn +gst_fbdevsink_change_state (GstElement * element, GstStateChange transition) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + g_return_val_if_fail (GST_IS_FBDEVSINK (element), GST_STATE_CHANGE_FAILURE); + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + default: + break; + } + return ret; +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_element_register (plugin, "fbdevsink", GST_RANK_NONE, + GST_TYPE_FBDEVSINK)) + return FALSE; + + return TRUE; +} + +static void +gst_fbdevsink_class_init (GstFBDEVSinkClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSinkClass *basesink_class; + GstVideoSinkClass *videosink_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + basesink_class = (GstBaseSinkClass *) klass; + videosink_class = (GstVideoSinkClass *) klass; + + gobject_class->set_property = gst_fbdevsink_set_property; + gobject_class->get_property = gst_fbdevsink_get_property; + gobject_class->finalize = gst_fbdevsink_finalize; + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_fbdevsink_change_state); + + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEVICE, + g_param_spec_string ("device", "device", + "The framebuffer device eg: /dev/fb0", NULL, G_PARAM_READWRITE)); + + basesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_fbdevsink_setcaps); + basesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_fbdevsink_getcaps); +#if 0 + basesink_class->get_times = GST_DEBUG_FUNCPTR (gst_fbdevsink_get_times); +#endif + basesink_class->start = GST_DEBUG_FUNCPTR (gst_fbdevsink_start); + basesink_class->stop = GST_DEBUG_FUNCPTR (gst_fbdevsink_stop); + + videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_fbdevsink_show_frame); + + gst_element_class_set_static_metadata (gstelement_class, "fbdev video sink", + "Sink/Video", "Linux framebuffer videosink", + "Sean D'Epagnier "); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sink_template)); +} + +static void +gst_fbdevsink_finalize (GObject * object) +{ + GstFBDEVSink *fbdevsink = GST_FBDEVSINK (object); + + g_free (fbdevsink->device); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + fbdevsink, + "Linux framebuffer video sink", + plugin_init, VERSION, "LGPL", "gst-fbdevsink", "http://ao2.it") diff --git a/src/gstfbdevsink.h b/src/gstfbdevsink.h new file mode 100644 index 0000000..7998217 --- /dev/null +++ b/src/gstfbdevsink.h @@ -0,0 +1,73 @@ +/* GStreamer + * Copyright (C) 2007 Sean D'Epagnier sean@depagnier.com + * + * 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 St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef __GST_FBDEVSINK_H__ +#define __GST_FBDEVSINK_H__ + +#include +#include +#include + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_FBDEVSINK \ + (gst_fbdevsink_get_type()) +#define GST_FBDEVSINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FBDEVSINK,GstFBDEVSink)) +#define GST_FBDEVSINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FBDEVSINK,GstFBDEVSinkClass)) +#define GST_IS_FBDEVSINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FBDEVSINK)) +#define GST_IS_FBDEVSINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FBDEVSINK)) + +typedef struct _GstFBDEVSink GstFBDEVSink; +typedef struct _GstFBDEVSinkClass GstFBDEVSinkClass; + +struct _GstFBDEVSink { + GstVideoSink videosink; + + /*< private >*/ + struct fb_fix_screeninfo fixinfo; + struct fb_var_screeninfo varinfo; + + int fd; + unsigned char *framebuffer; + + char *device; + + int width, height; + int cx, cy, linelen, lines, bytespp; + + int fps_n, fps_d; +}; + +struct _GstFBDEVSinkClass { + GstVideoSinkClass videosink_class; + +}; + +GType gst_fbdevsink_get_type(void); + +G_END_DECLS + +#endif /* __GST_FBDEVSINK_H__ */