[retro-gtk] retro-gtk: Refactor video format conversion



commit 00e8d562b2e0e98882cb704874a71ee7f91c9ca9
Author: Adrien Plazas <kekun plazas laposte net>
Date:   Wed Feb 8 09:48:51 2017 +0100

    retro-gtk: Refactor video format conversion
    
    Completely refactor video-converter.c to make it more readable,
    maintainable and hopefully slightly faster.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=777489

 retro-gobject/video.vala                |    2 +-
 retro-gtk/Makefile.am                   |    3 +-
 retro-gtk/video/cairo-display.vala      |    6 +-
 retro-gtk/video/retro-video-converter.c |  161 +++++++++++++++++++++++++++++++
 retro-gtk/video/video-converter.c       |  150 ----------------------------
 retro-gtk/video/video-converter.h       |   22 ----
 6 files changed, 166 insertions(+), 178 deletions(-)
---
diff --git a/retro-gobject/video.vala b/retro-gobject/video.vala
index a6da3cb..2366e9b 100644
--- a/retro-gobject/video.vala
+++ b/retro-gobject/video.vala
@@ -23,7 +23,7 @@ public enum PixelFormat {
         * This pixel format is default for compatibility concerns only.
         * If a 15/16-bit pixel format is desired, consider using RGB565.
         */
-       ORGB1555,
+       XRGB1555,
 
        /**
         * XRGB8888, native endian. X bits are ignored.
diff --git a/retro-gtk/Makefile.am b/retro-gtk/Makefile.am
index e4d9eac..a592d7e 100644
--- a/retro-gtk/Makefile.am
+++ b/retro-gtk/Makefile.am
@@ -37,8 +37,7 @@ libretro_gtk_la_SOURCES = \
        input/virtual-gamepad.vala \
        \
        video/cairo-display.vala \
-       video/video-converter.c \
-       video/video-converter.h \
+       video/retro-video-converter.c \
        $(NULL)
 
 libretro_gtk_la_LDFLAGS =
diff --git a/retro-gtk/video/cairo-display.vala b/retro-gtk/video/cairo-display.vala
index c8a7843..a8608cc 100644
--- a/retro-gtk/video/cairo-display.vala
+++ b/retro-gtk/video/cairo-display.vala
@@ -15,8 +15,8 @@ public class RetroGtk.CairoDisplay : Gtk.DrawingArea {
                notify["pixbuf"].connect (queue_draw);
        }
 
-       [CCode (cname = "video_to_pixbuf", cheader_filename="video-converter.h")]
-       static extern Gdk.Pixbuf video_to_pixbuf ([CCode (array_length = false)] uint8[] data, uint width, 
uint height, size_t pitch, Retro.PixelFormat pixel_format);
+       [CCode (cname = "gdk_pixbuf_new_from_video")]
+       static extern Gdk.Pixbuf gdk_pixbuf_new_from_video ([CCode (array_length = false)] uint8[] data, uint 
width, uint height, size_t pitch, Retro.PixelFormat pixel_format);
 
        public void set_core (Retro.Core core) {
                if (this.core != null)
@@ -28,7 +28,7 @@ public class RetroGtk.CairoDisplay : Gtk.DrawingArea {
 
        private void on_video_output (uint8[] data, uint width, uint height, size_t pitch, Retro.PixelFormat 
pixel_format, float aspect_ratio) {
                this.aspect_ratio = aspect_ratio;
-               pixbuf = video_to_pixbuf (data, width, height, pitch, pixel_format);
+               pixbuf = gdk_pixbuf_new_from_video (data, width, height, pitch, pixel_format);
        }
 
        public void show_video () {
diff --git a/retro-gtk/video/retro-video-converter.c b/retro-gtk/video/retro-video-converter.c
new file mode 100644
index 0000000..ebb7a31
--- /dev/null
+++ b/retro-gtk/video/retro-video-converter.c
@@ -0,0 +1,161 @@
+// This file is part of RetroGtk. License: GPLv3
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <retro-gobject.h>
+
+typedef struct _xrgb1555 xrgb1555;
+struct _xrgb1555 {
+  guint16 b: 5;
+  guint16 g: 5;
+  guint16 r: 5;
+  guint16 x: 1;
+};
+
+typedef struct _xrgb8888 xrgb8888;
+struct _xrgb8888 {
+  guint32 b: 8;
+  guint32 g: 8;
+  guint32 r: 8;
+  guint32 x: 8;
+};
+
+typedef struct _rgb565 rgb565;
+struct _rgb565 {
+  guint16 b: 5;
+  guint16 g: 6;
+  guint16 r: 5;
+};
+
+typedef struct _rgba8888 rgba8888;
+struct _rgba8888 {
+  guint32 a: 8;
+  guint32 b: 8;
+  guint32 g: 8;
+  guint32 r: 8;
+};
+
+typedef rgba8888 (*GetRGBA8888) (const gpointer pixel);
+
+static rgba8888
+rgba8888_from_xrgb1555 (const gpointer data)
+{
+  xrgb1555 pixel = *(const xrgb1555 *) data;
+
+  return (rgba8888) { pixel.r << 3 | pixel.r >> 2, pixel.g << 3 | pixel.g >> 2, pixel.b << 3 | pixel.b >> 2, 
0xff };
+}
+
+static rgba8888
+rgba8888_from_xrgb8888 (const gpointer data)
+{
+  xrgb8888 pixel = *(const xrgb8888 *) data;
+
+  return (rgba8888) { pixel.r, pixel.g, pixel.b, 0xff };
+}
+
+static rgba8888
+rgba8888_from_rgb565 (const gpointer data)
+{
+  rgb565 pixel = *(const rgb565 *) data;
+
+  return (rgba8888) { pixel.r << 3 | pixel.r >> 2, pixel.g << 2 | pixel.g >> 4, pixel.b << 3 | pixel.b >> 2, 
0xff };
+}
+
+static gboolean
+get_interface_for_pixel_format (gint         pixel_format,
+                                GetRGBA8888 *get_pixel,
+                                gsize       *pixel_size)
+{
+  switch (pixel_format) {
+  case RETRO_PIXEL_FORMAT_XRGB1555:
+    *get_pixel = rgba8888_from_xrgb1555;
+    *pixel_size = sizeof (xrgb1555);
+
+    return TRUE;
+  case RETRO_PIXEL_FORMAT_XRGB8888:
+    *get_pixel = rgba8888_from_xrgb8888;
+    *pixel_size = sizeof (rgba8888);
+
+    return TRUE;
+  case RETRO_PIXEL_FORMAT_RGB565:
+    *get_pixel = rgba8888_from_rgb565;
+    *pixel_size = sizeof (rgb565);
+
+    return TRUE;
+  default:
+    return FALSE;
+  }
+}
+
+/**
+ * The destination buffer must be at least 'height * width * sizeof (rgba8888)' bytes long.
+ */
+static void
+rgba8888_from_video (const gpointer  src,
+                     rgba8888       *dst,
+                     size_t          pixel_size,
+                     guint           width,
+                     guint           height,
+                     gsize           pitch,
+                     GetRGBA8888     get_pixel)
+{
+  gsize row, src_row, dst_row, col, src_col;
+
+  for (row = 0 ; row < height ; row++) {
+    src_row = row * pitch;
+    dst_row = row * width;
+
+    for (col = 0 ; col < width ; col++) {
+      src_col = col * pixel_size;
+
+      dst[dst_row + col] = get_pixel (src_row + src_col + src);
+    }
+  }
+}
+
+static rgba8888 *
+new_rgba8888_from_video (const gpointer src,
+                         guint          width,
+                         guint          height,
+                         gsize          pitch,
+                         gint           pixel_format)
+{
+  GetRGBA8888 get_pixel;
+  gsize pixel_size;
+  rgba8888 *dst;
+
+  if (!get_interface_for_pixel_format (pixel_format, &get_pixel, &pixel_size))
+    return NULL;
+
+  dst = g_new (rgba8888, height * width);
+  rgba8888_from_video (src, dst, pixel_size, width, height, pitch, get_pixel);
+
+  return dst;
+}
+
+static void
+pixels_free (guchar *pixels, gpointer data) {
+  g_free (pixels);
+}
+
+GdkPixbuf *
+gdk_pixbuf_new_from_video (const gpointer src,
+                           guint          width,
+                           guint          height,
+                           gsize          pitch,
+                           gint           pixel_format)
+{
+  rgba8888 *dst;
+
+  dst = new_rgba8888_from_video (src, width, height, pitch, pixel_format);
+  if (dst == NULL)
+    return NULL;
+
+  GdkColorspace colorspace = GDK_COLORSPACE_RGB;
+  gboolean has_alpha = TRUE;
+  gint bits_per_sample = 8;
+  gint rowstride = width * sizeof (rgba8888);
+
+  GdkPixbuf *pb = gdk_pixbuf_new_from_data ((guchar *) dst, colorspace, has_alpha, bits_per_sample, width, 
height, rowstride, pixels_free, NULL);
+
+  return pb;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]