-/* GStreamer am7xxx plugin
- * Copyright (C) 2007 Sean D'Epagnier <sean@depagnier.com>
+/* GStreamer am7xxx sink plugin
+ * Copyright (C) 2013 Antonio Ospite <ospite@studenti.unina.it>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* 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 <signal.h>
-#include <string.h>
-#include <sys/time.h>
-#include <stdlib.h>
-
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <unistd.h>
-#include <stdint.h>
-
#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
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
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:
}
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
{
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;
+ }
}
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;
}
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;
}
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:
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:
GST_TYPE_AM7XXXSINK))
return FALSE;
+ GST_DEBUG_CATEGORY_INIT (am7xxxsink_debug, "am7xxxsink", 0,
+ "am7xxx video sink element");
+
return TRUE;
}
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);
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 <sean@depagnier.com>");
+ "Sink/Video", "A videosink for projectors supported by libam7xxx",
+ "Antonio Ospite <ospite@studenti.unina.it>");
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&sink_template));
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")