Update AC_PREREQ as suggested by autoupdate
[gst-am7xxxsink.git] / src / gstam7xxxsink.c
index cd25d21..bd3c2ef 100644 (file)
@@ -1,5 +1,5 @@
-/* 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
@@ -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 <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));
@@ -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")