X-Git-Url: https://git.ao2.it/gst-am7xxxsink.git/blobdiff_plain/a4f104c73cff3ef6c9f637be33e9df351dd924e2..refs/heads/master:/src/gstam7xxxsink.c?ds=inline diff --git a/src/gstam7xxxsink.c b/src/gstam7xxxsink.c index cd25d21..bd3c2ef 100644 --- a/src/gstam7xxxsink.c +++ b/src/gstam7xxxsink.c @@ -1,5 +1,5 @@ -/* GStreamer am7xxx plugin - * Copyright (C) 2007 Sean D'Epagnier +/* GStreamer am7xxx sink plugin + * Copyright (C) 2013 Antonio Ospite * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -17,32 +17,20 @@ * 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 "gstam7xxxsink.h" +/* Debugging category */ +GST_DEBUG_CATEGORY_STATIC (am7xxxsink_debug); +#define GST_CAT_DEFAULT am7xxxsink_debug + enum { ARG_0, - ARG_DEVICE + ARG_DEVICE_INDEX }; #if 0 @@ -67,12 +55,12 @@ static void gst_am7xxxsink_get_property (GObject * object, static GstStateChangeReturn gst_am7xxxsink_change_state (GstElement * element, GstStateChange transition); -#define VIDEO_CAPS "{ RGB, BGR, BGRx, xBGR, RGB, RGBx, xRGB, RGB15, RGB16 }" +#define RAW_VIDEO_CAPS "{ NV12 }" static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (VIDEO_CAPS)) + GST_STATIC_CAPS ("image/jpeg;" GST_VIDEO_CAPS_MAKE (RAW_VIDEO_CAPS)) ); #define parent_class gst_am7xxxsink_parent_class @@ -112,73 +100,21 @@ static GstCaps * gst_am7xxxsink_getcaps (GstBaseSink * bsink, GstCaps * filter) { GstAM7XXXSink *am7xxxsink; - GstVideoFormat format; GstCaps *caps; - uint32_t rmask; - uint32_t gmask; - uint32_t bmask; - uint32_t tmask; - int endianness, depth, bpp; am7xxxsink = GST_AM7XXXSINK (bsink); caps = gst_static_pad_template_get_caps (&sink_template); - /* FIXME: locking */ - if (!am7xxxsink->framebuffer) + if (!am7xxxsink->dev) goto done; - bpp = am7xxxsink->varinfo.bits_per_pixel; - - rmask = ((1 << am7xxxsink->varinfo.red.length) - 1) - << am7xxxsink->varinfo.red.offset; - gmask = ((1 << am7xxxsink->varinfo.green.length) - 1) - << am7xxxsink->varinfo.green.offset; - bmask = ((1 << am7xxxsink->varinfo.blue.length) - 1) - << am7xxxsink->varinfo.blue.offset; - tmask = ((1 << am7xxxsink->varinfo.transp.length) - 1) - << am7xxxsink->varinfo.transp.offset; - - depth = am7xxxsink->varinfo.red.length + am7xxxsink->varinfo.green.length - + am7xxxsink->varinfo.blue.length; - - switch (am7xxxsink->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 += am7xxxsink->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; - + /* display size negotiation */ caps = gst_caps_make_writable (caps); - gst_caps_set_simple (caps, "format", G_TYPE_STRING, - gst_video_format_to_string (format), NULL); + gst_caps_set_simple (caps, + "width", GST_TYPE_INT_RANGE, 1, GST_VIDEO_SINK_WIDTH(am7xxxsink), + "height", GST_TYPE_INT_RANGE, 1, GST_VIDEO_SINK_HEIGHT(am7xxxsink), + "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL); done: @@ -191,21 +127,6 @@ done: } 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 am7xxx 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 @@ -213,39 +134,41 @@ gst_am7xxxsink_setcaps (GstBaseSink * bsink, GstCaps * vscapslist) { GstAM7XXXSink *am7xxxsink; GstStructure *structure; - const GValue *fps; + const gchar *mimetype; + GstVideoInfo vinfo; + int ret; am7xxxsink = GST_AM7XXXSINK (bsink); - structure = gst_caps_get_structure (vscapslist, 0); - - fps = gst_structure_get_value (structure, "framerate"); - am7xxxsink->fps_n = gst_value_get_fraction_numerator (fps); - am7xxxsink->fps_d = gst_value_get_fraction_denominator (fps); - - gst_structure_get_int (structure, "width", &am7xxxsink->width); - gst_structure_get_int (structure, "height", &am7xxxsink->height); - - /* calculate centering and scanlengths for the video */ - am7xxxsink->bytespp = am7xxxsink->fixinfo.line_length / am7xxxsink->varinfo.xres; - - am7xxxsink->cx = ((int) am7xxxsink->varinfo.xres - am7xxxsink->width) / 2; - if (am7xxxsink->cx < 0) - am7xxxsink->cx = 0; + ret = gst_video_info_from_caps (&vinfo, vscapslist); + if (!ret) + goto unknown_format; - am7xxxsink->cy = ((int) am7xxxsink->varinfo.yres - am7xxxsink->height) / 2; - if (am7xxxsink->cy < 0) - am7xxxsink->cy = 0; + structure = gst_caps_get_structure (vscapslist, 0); + mimetype = gst_structure_get_name (structure); - am7xxxsink->linelen = am7xxxsink->width * am7xxxsink->bytespp; - if (am7xxxsink->linelen > am7xxxsink->fixinfo.line_length) - am7xxxsink->linelen = am7xxxsink->fixinfo.line_length; + if (g_str_equal (mimetype, "image/jpeg")) { + am7xxxsink->format = AM7XXX_IMAGE_FORMAT_JPEG; + } else if (g_str_equal (mimetype, "video/x-raw")) { + if (GST_VIDEO_INFO_FORMAT (&vinfo) == GST_VIDEO_FORMAT_NV12) { + am7xxxsink->format = AM7XXX_IMAGE_FORMAT_NV12; + } else { + goto unknown_format; + } + } else { + goto unknown_format; + } - am7xxxsink->lines = am7xxxsink->height; - if (am7xxxsink->lines > am7xxxsink->varinfo.yres) - am7xxxsink->lines = am7xxxsink->varinfo.yres; + am7xxxsink->width = GST_VIDEO_INFO_WIDTH(&vinfo); + am7xxxsink->height = GST_VIDEO_INFO_HEIGHT(&vinfo); return TRUE; + +unknown_format: + { + GST_WARNING_OBJECT (am7xxxsink, "Could not figure format of input caps"); + return FALSE; + } } @@ -255,58 +178,52 @@ gst_am7xxxsink_show_frame (GstVideoSink * videosink, GstBuffer * buf) GstAM7XXXSink *am7xxxsink; GstMapInfo map; - int i; + int ret; am7xxxsink = GST_AM7XXXSINK (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)) + ret = gst_buffer_map (buf, &map, GST_MAP_READ); + if (!ret) return GST_FLOW_ERROR; - for (i = 0; i < am7xxxsink->lines; i++) { - memcpy (am7xxxsink->framebuffer - + (i + am7xxxsink->cy) * am7xxxsink->fixinfo.line_length - + am7xxxsink->cx * am7xxxsink->bytespp, - map.data + i * am7xxxsink->width * am7xxxsink->bytespp, - am7xxxsink->linelen); + ret = am7xxx_send_image_async(am7xxxsink->dev, am7xxxsink->format, + am7xxxsink->width, am7xxxsink->height, + map.data, map.size); + if (ret < 0) { + ret = GST_FLOW_ERROR; + goto out; } + ret = GST_FLOW_OK; + +out: gst_buffer_unmap (buf, &map); - return GST_FLOW_OK; + return ret; } static gboolean gst_am7xxxsink_start (GstBaseSink * bsink) { GstAM7XXXSink *am7xxxsink; + int ret; am7xxxsink = GST_AM7XXXSINK (bsink); - if (!am7xxxsink->device) { - am7xxxsink->device = g_strdup ("/dev/fb0"); - } - - am7xxxsink->fd = open (am7xxxsink->device, O_RDWR); - - if (am7xxxsink->fd == -1) + ret = am7xxx_init(&am7xxxsink->ctx); + if (ret < 0) return FALSE; - /* get the fixed screen info */ - if (ioctl (am7xxxsink->fd, FBIOGET_FSCREENINFO, &am7xxxsink->fixinfo)) + ret = am7xxx_open_device(am7xxxsink->ctx, &am7xxxsink->dev, am7xxxsink->device_index); + if (ret < 0) return FALSE; - /* get the variable screen info */ - if (ioctl (am7xxxsink->fd, FBIOGET_VSCREENINFO, &am7xxxsink->varinfo)) + ret = am7xxx_get_device_info(am7xxxsink->dev, &am7xxxsink->device_info); + if (ret < 0) return FALSE; - /* map the framebuffer */ - am7xxxsink->framebuffer = mmap (0, am7xxxsink->fixinfo.smem_len, - PROT_WRITE, MAP_SHARED, am7xxxsink->fd, 0); - if (am7xxxsink->framebuffer == MAP_FAILED) - return FALSE; + GST_VIDEO_SINK_WIDTH (am7xxxsink) = (am7xxxsink->device_info).native_width; + GST_VIDEO_SINK_HEIGHT (am7xxxsink) = (am7xxxsink->device_info).native_height; return TRUE; } @@ -318,12 +235,8 @@ gst_am7xxxsink_stop (GstBaseSink * bsink) am7xxxsink = GST_AM7XXXSINK (bsink); - if (munmap (am7xxxsink->framebuffer, am7xxxsink->fixinfo.smem_len)) - return FALSE; - - if (close (am7xxxsink->fd)) - return FALSE; - + /* open devices will be closed by am7xxx_shutdown() */ + am7xxx_shutdown(am7xxxsink->ctx); return TRUE; } @@ -337,9 +250,8 @@ gst_am7xxxsink_set_property (GObject * object, guint prop_id, am7xxxsink = GST_AM7XXXSINK (object); switch (prop_id) { - case ARG_DEVICE:{ - g_free (am7xxxsink->device); - am7xxxsink->device = g_value_dup_string (value); + case ARG_DEVICE_INDEX:{ + am7xxxsink->device_index = g_value_get_uint (value); break; } default: @@ -358,8 +270,8 @@ gst_am7xxxsink_get_property (GObject * object, guint prop_id, GValue * value, am7xxxsink = GST_AM7XXXSINK (object); switch (prop_id) { - case ARG_DEVICE:{ - g_value_set_string (value, am7xxxsink->device); + case ARG_DEVICE_INDEX:{ + g_value_set_uint (value, am7xxxsink->device_index); break; } default: @@ -391,6 +303,9 @@ plugin_init (GstPlugin * plugin) GST_TYPE_AM7XXXSINK)) return FALSE; + GST_DEBUG_CATEGORY_INIT (am7xxxsink_debug, "am7xxxsink", 0, + "am7xxx video sink element"); + return TRUE; } @@ -414,9 +329,9 @@ gst_am7xxxsink_class_init (GstAM7XXXSinkClass * klass) gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_am7xxxsink_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)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEVICE_INDEX, + g_param_spec_uint ("device-index", "device index", + "The am7xxx device index eg: 0", 0, G_MAXUINT, 0, G_PARAM_READWRITE)); basesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_am7xxxsink_setcaps); basesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_am7xxxsink_getcaps); @@ -429,8 +344,8 @@ gst_am7xxxsink_class_init (GstAM7XXXSinkClass * klass) videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_am7xxxsink_show_frame); gst_element_class_set_static_metadata (gstelement_class, "am7xxx video sink", - "Sink/Video", "Linux framebuffer videosink", - "Sean D'Epagnier "); + "Sink/Video", "A videosink for projectors supported by libam7xxx", + "Antonio Ospite "); gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&sink_template)); @@ -439,15 +354,11 @@ gst_am7xxxsink_class_init (GstAM7XXXSinkClass * klass) static void gst_am7xxxsink_finalize (GObject * object) { - GstAM7XXXSink *am7xxxsink = GST_AM7XXXSINK (object); - - g_free (am7xxxsink->device); - G_OBJECT_CLASS (parent_class)->finalize (object); } GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, am7xxxsink, - "Linux framebuffer video sink", + "libam7xxx video sink", plugin_init, VERSION, "LGPL", "gst-am7xxxsink", "http://ao2.it")