Remove weston virtual screen
authorronan <ronan.lemartret@gmail.com>
Fri, 9 Feb 2018 13:34:14 +0000 (14:34 +0100)
committerronan <ronan.lemartret@gmail.com>
Tue, 13 Feb 2018 16:22:38 +0000 (17:22 +0100)
Change-Id: I027a46a0cbe2ff3c46102d781158e2a979c07282
Signed-off-by: ronan <ronan.lemartret@gmail.com>
recipes-graphics/wayland/weston/0001-Add-virtual-output-support.patch [deleted file]
recipes-graphics/wayland/weston/0002-Add-gst-recorder-for-h264-output-streaming.patch [deleted file]
recipes-graphics/wayland/weston/0003-gst-recorder-Use-USERPTR-instead-of-DMABUF-for-VSP-o.patch [deleted file]
recipes-graphics/wayland/weston/0004-gst-record-Specify-bytesused-and-length-of-VSP-input.patch [deleted file]
recipes-graphics/wayland/weston_2.0.0.bbappend [deleted file]

diff --git a/recipes-graphics/wayland/weston/0001-Add-virtual-output-support.patch b/recipes-graphics/wayland/weston/0001-Add-virtual-output-support.patch
deleted file mode 100644 (file)
index 211fb73..0000000
+++ /dev/null
@@ -1,470 +0,0 @@
-From b6d084f68434fea7402d4989d4d8344523b1a939 Mon Sep 17 00:00:00 2001
-From: Harunobu Kurokawa <harunobu.kurokawa.dn@renesas.com>
-Date: Thu, 10 Aug 2017 15:42:38 +0900
-Subject: [PATCH 1/4] Add virtual output support
-
-This patch is ported to weston 2.0.0.
-
-----------
-Author: Damian Hobson-Garcia <dhobsong@igel.co.jp>
-Date:   Thu Apr 27 16:47:00 2017 +0900
-
-Following patch ported to Weston 1.11 with minor updates
-  ----------
-  Author: Grigory Kletsko <grigory.kletsko@cogentembedded.com>
-  Date:   Wed Nov 2 17:14:43 2016 +0300
-
-  To enable virtual output set "virtual" property in core section
-  to desirable number of virtual outputs. Then add settings to
-  each virtual output in output sections. Name of the outputs
-  will be virtual1, virtual2... etc.
-  ------------
----
- libweston/compositor-drm.c | 352 +++++++++++++++++++++++++++++++++++++++++++++
- libweston/compositor-drm.h |   1 +
- 2 files changed, 353 insertions(+)
-
-diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
-index 1d38f05..d0f07e9 100644
---- a/libweston/compositor-drm.c
-+++ b/libweston/compositor-drm.c
-@@ -182,6 +182,11 @@ struct drm_output {
-       struct vaapi_recorder *recorder;
-       struct wl_listener recorder_frame_listener;
-+
-+      /* not real output device */
-+      int virtual;
-+      /* Timer for updating frame */
-+      struct wl_event_source *virtual_finish_frame_timer;
- };
- /*
-@@ -211,6 +216,9 @@ struct drm_sprite {
- static struct gl_renderer_interface *gl_renderer;
-+static int
-+recorder_enable(struct drm_backend *b, struct drm_output *output);
-+
- static const char default_seat[] = "seat0";
- static inline struct drm_output *
-@@ -2347,6 +2355,99 @@ connector_get_current_mode(drmModeConnector *connector, int drm_fd,
- }
- static int
-+virtual_output_set_mode(struct weston_output *base,
-+                  enum weston_drm_backend_output_mode mode,
-+                  const char *modeline)
-+{
-+      struct drm_output *output = to_drm_output(base);
-+      struct drm_backend *b = to_drm_backend(base->compositor);
-+      struct weston_config *config = wet_get_config(b->compositor);
-+
-+      struct drm_mode *drm_mode, *next, *current;
-+      char *s;
-+      int valid_mode;
-+      int recorded_output;
-+      int width, height, scale, fps;
-+      struct weston_config_section *section;
-+      uint32_t transform;
-+      drmModeModeInfo crtc_mode;
-+
-+      output->base.make = "CogentEmbedded,Inc";
-+
-+      section = weston_config_get_section(config, "output", "name",
-+                                          output->base.name);
-+
-+      weston_config_section_get_bool(section, "recorder", &recorded_output, 0);
-+
-+      if (recorded_output) {
-+              output->base.model = "Virtual RTP Display";
-+      } else {
-+              output->base.model = "Virtual Display";
-+      }
-+
-+      output->base.serial_number = "";
-+      wl_list_init(&output->base.mode_list);
-+
-+      if (mode == WESTON_DRM_BACKEND_OUTPUT_PREFERRED) {
-+              if (modeline && sscanf(modeline, "%dx%d@%d", &width, &height, &fps) >= 3)
-+                      valid_mode = 1;
-+      }
-+
-+      weston_config_section_get_int(section, "scale", &scale, 1);
-+      weston_config_section_get_string(section, "transform", &s, "normal");
-+      if (weston_parse_transform(s, &transform) < 0)
-+              weston_log("Invalid transform \"%s\" for output %s\n",
-+                         s, output->base.name);
-+      free(s);
-+
-+      weston_config_section_get_string(section, "seat", &s, "");
-+      free(s);
-+
-+      output->original_crtc = NULL;
-+      output->dpms_prop = NULL;
-+
-+      /* set static mode */
-+      if (valid_mode) {
-+              /* TODO: calculate proper mode settings to get desirable framerate */
-+              drmModeModeInfo static_drm_mode = {
-+                      width * height * fps,
-+                      width, 0, 0, width, width,
-+                      height, 0, 0, height, height,
-+                      fps * 1000,
-+                      0, //flags
-+                      0, //type
-+                      "virtual"
-+              };
-+              drm_mode = drm_output_add_mode(output, &static_drm_mode);
-+              if (!drm_mode)
-+                      goto err_free;
-+
-+              drm_mode->base.refresh = fps * 1000;
-+      }
-+
-+      current = drm_output_choose_initial_mode(b, output, mode, &modeline,
-+                                               &crtc_mode);
-+      if (!current)
-+              goto err_free;
-+      output->base.current_mode = &current->base;
-+      output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
-+
-+      return 0;
-+
-+err_free:
-+      drmModeFreeCrtc(output->original_crtc);
-+      output->original_crtc = NULL;
-+
-+      wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
-+                                                      base.link) {
-+              wl_list_remove(&drm_mode->base.link);
-+              free(drm_mode);
-+      }
-+
-+      return -1;
-+}
-+
-+static int
- drm_output_set_mode(struct weston_output *base,
-                   enum weston_drm_backend_output_mode mode,
-                   const char *modeline)
-@@ -2357,6 +2458,8 @@ drm_output_set_mode(struct weston_output *base,
-       struct drm_mode *drm_mode, *next, *current;
-       drmModeModeInfo crtc_mode;
-       int i;
-+      if ( output->virtual == 1 )
-+              return virtual_output_set_mode(base, mode, modeline);
-       output->base.make = "unknown";
-       output->base.model = "unknown";
-@@ -2453,6 +2556,10 @@ drm_output_enable(struct weston_output *base)
-               weston_log("Failed to initialize backlight\n");
-       }
-+      /* enable GST recording-streaming */
-+      if (b->enable_recorder)
-+              recorder_enable(b, output);
-+
-       output->base.start_repaint_loop = drm_output_start_repaint_loop;
-       output->base.repaint = drm_output_repaint;
-       output->base.assign_planes = drm_assign_planes;
-@@ -2630,6 +2737,227 @@ create_output_for_connector(struct drm_backend *b,
- }
- static void
-+virtual_output_deinit(struct weston_output *base)
-+{
-+      struct drm_output *output = to_drm_output(base);
-+      struct drm_backend *b = to_drm_backend(base->compositor);
-+
-+      if (b->use_pixman)
-+              drm_output_fini_pixman(output);
-+      else
-+              drm_output_fini_egl(output);
-+
-+      weston_plane_release(&output->fb_plane);
-+      weston_plane_release(&output->cursor_plane);
-+}
-+
-+static void
-+virtual_output_destroy(struct weston_output *base)
-+{
-+      struct drm_output *output = to_drm_output(base);
-+
-+      if (output->base.enabled)
-+              virtual_output_deinit(&output->base);
-+
-+      weston_output_destroy(&output->base);
-+
-+      free(output);
-+}
-+
-+static void
-+virtual_output_start_repaint_loop(struct weston_output *output)
-+{
-+      struct timespec now;
-+
-+      weston_compositor_read_presentation_clock(output->compositor, &now);
-+      weston_output_finish_frame(output, &now, WP_PRESENTATION_FEEDBACK_INVALID);
-+}
-+
-+
-+static int
-+virtual_output_repaint(struct weston_output *output_base,
-+                 pixman_region32_t *damage)
-+{
-+      struct drm_output *output = (struct drm_output *) output_base;
-+      struct timespec ts;
-+      uint32_t msec_next;
-+      uint32_t msec_current;
-+
-+      msec_next = (output->base.frame_time + 1000000UL / output->base.current_mode->refresh) ;
-+
-+      if (output->disable_pending || output->destroy_pending)
-+              return -1;
-+
-+      if (!output->next)
-+              drm_output_render(output, damage);
-+      if (!output->next)
-+              return -1;
-+
-+      drm_output_set_cursor(output);
-+
-+      output->page_flip_pending = 1;
-+
-+      weston_compositor_read_presentation_clock(output_base->compositor, &ts);
-+
-+      msec_current = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
-+
-+      /*
-+       * If we somehow late with updating frame, then fireup timer immediately (1 msec)
-+       */
-+      wl_event_source_timer_update(output->virtual_finish_frame_timer, (msec_next > msec_current)  ?
-+                                   msec_next - msec_current : 1);
-+
-+      return 0;
-+}
-+
-+static int
-+virtual_finish_frame_handler(void *data)
-+{
-+      struct drm_output *output = (struct drm_output *) data;
-+      struct timespec ts;
-+
-+      /* We don't set page_flip_pending on start_repaint_loop, in that case
-+       * we just want to page flip to the current buffer to get an accurate
-+       * timestamp */
-+      if (output->page_flip_pending) {
-+              drm_output_release_fb(output, output->current);
-+              output->current = output->next;
-+              output->next = NULL;
-+      }
-+
-+      output->page_flip_pending = 0;
-+
-+      if (output->destroy_pending)
-+              drm_output_destroy(&output->base);
-+      else if (!output->vblank_pending) {
-+              weston_compositor_read_presentation_clock(output->base.compositor, &ts);
-+
-+              weston_output_finish_frame(&output->base, &ts,
-+                      WP_PRESENTATION_FEEDBACK_INVALID);
-+
-+              /* We can't call this from frame_notify, because the output's
-+               * repaint needed flag is cleared just after that */
-+              if (output->recorder)
-+                      weston_output_schedule_repaint(&output->base);
-+      }
-+
-+      return 1;
-+}
-+
-+static int
-+virtual_output_enable(struct weston_output *base)
-+{
-+      struct drm_output *output = to_drm_output(base);
-+      struct drm_backend *b = to_drm_backend(base->compositor);
-+      struct weston_mode *m;
-+
-+      if (b->use_pixman) {
-+              if (drm_output_init_pixman(output, b) < 0) {
-+                      weston_log("Failed to init output pixman state\n");
-+                      goto err_free;
-+              }
-+      } else if (drm_output_init_egl(output, b) < 0) {
-+              weston_log("Failed to init output gl state\n");
-+              goto err_free;
-+      }
-+
-+      output->base.start_repaint_loop = virtual_output_start_repaint_loop;
-+      output->base.repaint = virtual_output_repaint;
-+      output->base.assign_planes = NULL;
-+      output->base.set_dpms = NULL;
-+      output->base.switch_mode = drm_output_switch_mode;
-+
-+      output->base.gamma_size = 0;
-+      output->base.set_gamma = drm_output_set_gamma;
-+
-+      output->base.subpixel = WL_OUTPUT_SUBPIXEL_NONE; //drm_subpixel_to_wayland(connector->subpixel);
-+
-+      weston_plane_init(&output->cursor_plane, b->compositor,
-+                        INT32_MIN, INT32_MIN);
-+      weston_plane_init(&output->fb_plane, b->compositor, 0, 0);
-+
-+      weston_compositor_stack_plane(b->compositor, &output->cursor_plane, NULL);
-+      weston_compositor_stack_plane(b->compositor, &output->fb_plane,
-+                                    &b->compositor->primary_plane);
-+
-+      weston_log("Output %s, ()\n",
-+                 output->base.name);
-+      wl_list_for_each(m, &output->base.mode_list, link)
-+              weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f\n",
-+                                  m->width, m->height, m->refresh / 1000.0);
-+
-+      /* enable GST recording-streaming */
-+      if (b->enable_recorder)
-+              recorder_enable(b, output);
-+
-+      return 0;
-+
-+err_free:
-+
-+      return -1;
-+}
-+
-+
-+static int
-+virtual_output_disable(struct weston_output *base)
-+{
-+      struct drm_output *output = to_drm_output(base);
-+
-+      if (output->base.enabled)
-+              virtual_output_deinit(&output->base);
-+
-+      output->disable_pending = 0;
-+
-+      weston_log("Disabling output %s\n", output->base.name);
-+
-+      return 0;
-+}
-+
-+/*
-+ * Virtual output connector that could be used for simulating output
-+ * device for clients and/or streaming of video
-+ */
-+static int
-+create_output_for_virtual_connector(struct drm_backend *b,
-+                                  struct udev_device *drm_device)
-+{
-+      struct wl_event_loop *loop;
-+      struct drm_output *output;
-+      static int virtual_id = 1; /* as other outputs numbered */
-+      char name[32], *s;
-+
-+      output = zalloc(sizeof *output);
-+      if (output == NULL)
-+              return -1;
-+
-+      output->pipe = 0;
-+      output->connector_id = 0;
-+
-+      /* this is virtual output */
-+      output->virtual = 1;
-+
-+      output->backlight = NULL;
-+
-+      loop = wl_display_get_event_loop(b->compositor->wl_display);
-+      output->virtual_finish_frame_timer = wl_event_loop_add_timer(loop, virtual_finish_frame_handler, output);
-+
-+      output->base.enable = virtual_output_enable;
-+      output->base.destroy = virtual_output_destroy;
-+      output->base.disable = virtual_output_disable;
-+
-+      output->destroy_pending = 0;
-+      output->disable_pending = 0;
-+      output->original_crtc = NULL;
-+      snprintf(name, 32, "virtual%d", virtual_id++);
-+      output->base.name = strdup(name);
-+
-+      weston_output_init(&output->base, b->compositor);
-+      weston_compositor_add_pending_output(&output->base, b->compositor);
-+
-+      return 0;
-+}
-+
-+static void
- create_sprites(struct drm_backend *b)
- {
-       struct drm_sprite *sprite;
-@@ -2701,9 +3029,12 @@ destroy_sprites(struct drm_backend *backend)
- static int
- create_outputs(struct drm_backend *b, struct udev_device *drm_device)
- {
-+      struct weston_config_section *section;
-+      struct weston_config *config = wet_get_config(b->compositor);
-       drmModeConnector *connector;
-       drmModeRes *resources;
-       int i;
-+      int virtual;
-       resources = drmModeGetResources(b->drm.fd);
-       if (!resources) {
-@@ -2735,6 +3066,14 @@ create_outputs(struct drm_backend *b, struct udev_device *drm_device)
-               }
-       }
-+      section = weston_config_get_section(config, "core", NULL, NULL);
-+      weston_config_section_get_int(section, "virtual", &virtual, 0);
-+
-+      for (i = 0; i < virtual; i++) {
-+              if (create_output_for_virtual_connector(b, drm_device) < 0)
-+                      continue;
-+      }
-+
-       if (wl_list_empty(&b->compositor->output_list) &&
-           wl_list_empty(&b->compositor->pending_output_list))
-               weston_log("No currently active connector found.\n");
-@@ -3181,6 +3520,12 @@ renderer_switch_binding(struct weston_keyboard *keyboard, uint32_t time,
-       switch_to_gl_renderer(b);
- }
-+static const struct weston_drm_output_api virtual_api = {
-+      virtual_output_set_mode,
-+      drm_output_set_gbm_format,
-+      drm_output_set_seat,
-+};
-+
- static const struct weston_drm_output_api api = {
-       drm_output_set_mode,
-       drm_output_set_gbm_format,
-@@ -3346,6 +3691,13 @@ drm_backend_create(struct weston_compositor *compositor,
-               goto err_udev_monitor;
-       }
-+      ret = weston_plugin_api_register(compositor, WESTON_DRM_VIRTUAL_OUTPUT_API_NAME,
-+                                       &virtual_api, sizeof(virtual_api));
-+
-+      if (ret < 0) {
-+              weston_log("Failed to register output API.\n");
-+              goto err_udev_monitor;
-+      }
-       return b;
- err_udev_monitor:
-diff --git a/libweston/compositor-drm.h b/libweston/compositor-drm.h
-index 2e2995a..00171c8 100644
---- a/libweston/compositor-drm.h
-+++ b/libweston/compositor-drm.h
-@@ -53,6 +53,7 @@ enum weston_drm_backend_output_mode {
- };
- #define WESTON_DRM_OUTPUT_API_NAME "weston_drm_output_api_v1"
-+#define WESTON_DRM_VIRTUAL_OUTPUT_API_NAME "weston_virtual_output_api_v1"
- struct weston_drm_output_api {
-       /** The mode to be used by the output. Refer to the documentation
--- 
-2.9.2
-
diff --git a/recipes-graphics/wayland/weston/0002-Add-gst-recorder-for-h264-output-streaming.patch b/recipes-graphics/wayland/weston/0002-Add-gst-recorder-for-h264-output-streaming.patch
deleted file mode 100644 (file)
index 71a45ff..0000000
+++ /dev/null
@@ -1,4214 +0,0 @@
-From c953d91f8d7e4bca5dd68246c763fd4c4e354287 Mon Sep 17 00:00:00 2001
-From: Harunobu Kurokawa <harunobu.kurokawa.dn@renesas.com>
-Date: Thu, 10 Aug 2017 15:49:14 +0900
-Subject: [PATCH 2/4] Add gst-recorder for h264 output streaming
-
-This patch is ported to weston 2.0.0.
---------
-Author: Damian Hobson-Garcia <dhobsong@igel.co.jp>
-Date:   Thu Apr 27 16:47:00 2017 +0900
-
-  Following patch ported to Weston 1.11 with minor updates
-  --------
-  To use gst-recorder run weston with arg --gst-record. Add
-  recorder=true property to output section of one of the outputs
-  (real or virtual). Use properties ip, port to set host of RTP
-  stream. Use property bitrate to set desirable maximum h264 bitrate.
-  --------
----
- Makefile.am                         |   17 +
- compositor/main.c                   |    4 +-
- configure.ac                        |   13 +
- libweston/compositor-drm.c          |  203 +++++-
- libweston/compositor-drm.h          |    3 +
- libweston/gst-recorder.c            | 1213 +++++++++++++++++++++++++++++++++++
- libweston/gst-recorder.h            |   58 ++
- libweston/media-ctl/libmediactl.c   |  955 +++++++++++++++++++++++++++
- libweston/media-ctl/libv4l2subdev.c |  759 ++++++++++++++++++++++
- libweston/media-ctl/mediactl-priv.h |   64 ++
- libweston/media-ctl/mediactl.h      |  423 ++++++++++++
- libweston/media-ctl/tools.h         |   32 +
- libweston/media-ctl/v4l2subdev.h    |  258 ++++++++
- 13 files changed, 4000 insertions(+), 2 deletions(-)
- create mode 100644 libweston/gst-recorder.c
- create mode 100644 libweston/gst-recorder.h
- create mode 100644 libweston/media-ctl/libmediactl.c
- create mode 100644 libweston/media-ctl/libv4l2subdev.c
- create mode 100644 libweston/media-ctl/mediactl-priv.h
- create mode 100644 libweston/media-ctl/mediactl.h
- create mode 100644 libweston/media-ctl/tools.h
- create mode 100644 libweston/media-ctl/v4l2subdev.h
-
-diff --git a/Makefile.am b/Makefile.am
-index cdf82ab..9fb9ba0 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -386,6 +386,23 @@ drm_backend_la_LIBADD += $(LIBVA_LIBS)
- drm_backend_la_LDFLAGS += -pthread
- drm_backend_la_CFLAGS += $(LIBVA_CFLAGS)
- endif
-+
-+if ENABLE_GST_RECORDER
-+drm_backend_la_SOURCES +=                     \
-+      libweston/gst-recorder.c                        \
-+      libweston/gst-recorder.h                        \
-+      libweston/v4l2-device.h                 \
-+      libweston/media-ctl/libmediactl.c               \
-+      libweston/media-ctl/libv4l2subdev.c             \
-+      libweston/media-ctl/mediactl-priv.h             \
-+      libweston/media-ctl/mediactl.h          \
-+      libweston/media-ctl/tools.h                     \
-+      libweston/media-ctl/v4l2subdev.h
-+drm_backend_la_LIBADD += $(LIBVA_LIBS)                \
-+      -lgstallocators-1.0                     \
-+      -lgstvideo-1.0
-+drm_backend_la_CFLAGS += $(LIBVA_CFLAGS)
-+endif
- endif
- if ENABLE_WAYLAND_COMPOSITOR
-diff --git a/compositor/main.c b/compositor/main.c
-index 72c3cd1..6a8ca7f 100644
---- a/compositor/main.c
-+++ b/compositor/main.c
-@@ -566,7 +566,8 @@ usage(int error_code)
-               "  --seat=SEAT\t\tThe seat that weston should run on\n"
-               "  --tty=TTY\t\tThe tty to use\n"
-               "  --use-pixman\t\tUse the pixman (CPU) renderer\n"
--              "  --current-mode\tPrefer current KMS mode over EDID preferred mode\n\n");
-+              "  --current-mode\tPrefer current KMS mode over EDID preferred mode\n"
-+              "  --gst-record\t\tEnable GStreamer recording\n\n");
- #endif
- #if defined(BUILD_FBDEV_COMPOSITOR)
-@@ -1227,6 +1228,7 @@ load_drm_backend(struct weston_compositor *c,
-               { WESTON_OPTION_INTEGER, "tty", 0, &config.tty },
-               { WESTON_OPTION_BOOLEAN, "current-mode", 0, &wet->drm_use_current_mode },
-               { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &config.use_pixman },
-+              { WESTON_OPTION_BOOLEAN, "gst-record", 0, &config.enable_recorder },
-       };
-       parse_options(options, ARRAY_LENGTH(options), argc, argv);
-diff --git a/configure.ac b/configure.ac
-index a36a516..3cc7501 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -242,6 +242,18 @@ if test x$enable_headless_compositor = xyes; then
- fi
-+AC_ARG_ENABLE(gst-recorder, [  --enable-gst-recorder],,
-+            enable_gst_recorder=yes)
-+if test x$enable_gst_recorder != xno; then
-+  AC_DEFINE([BUILD_GST_RECORDER], [1], [Build the gst recorder])
-+  PKG_CHECK_MODULES(GSTREAMER, [gstreamer-1.0 >= 1.0])
-+
-+  CPPFLAGS="$CPPFLAGS $GSTREAMER_CFLAGS"
-+  LIBS="$LIBS $GSTREAMER_LIBS -lgstapp-1.0"
-+fi
-+AM_CONDITIONAL(ENABLE_GST_RECORDER, test "x$enable_gst_recorder" != xno)
-+
-+
- AC_ARG_ENABLE([fbdev-compositor], [  --enable-fbdev-compositor],,
-               enable_fbdev_compositor=yes)
- AM_CONDITIONAL([ENABLE_FBDEV_COMPOSITOR],
-@@ -724,4 +736,5 @@ AC_MSG_RESULT([
-       libwebp Support                 ${have_webp}
-       libunwind Support               ${have_libunwind}
-       VA H.264 encoding Support       ${have_libva}
-+      GStreamer H.264 enc. Support    ${enable_gst_recorder}
- ])
-diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
-index d0f07e9..0b9643f 100644
---- a/libweston/compositor-drm.c
-+++ b/libweston/compositor-drm.c
-@@ -58,9 +58,11 @@
- #include "libinput-seat.h"
- #include "launcher-util.h"
- #include "vaapi-recorder.h"
-+#include "gst-recorder.h"
- #include "presentation-time-server-protocol.h"
- #include "linux-dmabuf.h"
- #include "linux-dmabuf-unstable-v1-server-protocol.h"
-+#include "compositor/weston.h"
- #ifndef DRM_CAP_TIMESTAMP_MONOTONIC
- #define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
-@@ -113,6 +115,8 @@ struct drm_backend {
-       int use_pixman;
-+      int enable_recorder;
-+
-       struct udev_input input;
-       int32_t cursor_width;
-@@ -180,7 +184,12 @@ struct drm_output {
-       int current_image;
-       pixman_region32_t previous_damage;
-+#ifdef BUILD_VAAPI_RECORDER
-       struct vaapi_recorder *recorder;
-+#endif
-+#ifdef BUILD_GST_RECORDER
-+      struct gst_recorder *recorder;
-+#endif
-       struct wl_listener recorder_frame_listener;
-       /* not real output device */
-@@ -239,6 +248,9 @@ drm_output_set_cursor(struct drm_output *output);
- static void
- drm_output_update_msc(struct drm_output *output, unsigned int seq);
-+static void
-+recorders_enable(struct drm_backend *b);
-+
- static int
- drm_sprite_crtc_supported(struct drm_output *output, struct drm_sprite *sprite)
- {
-@@ -2197,6 +2209,23 @@ parse_modeline(const char *s, drmModeModeInfo *mode)
-       return 0;
- }
-+static int parse_crop_rect(const char *s, struct v4l2_rect* crop)
-+{
-+      crop->left = 0;
-+      crop->top = 0;
-+      crop->width = 0;
-+      crop->height = 0;
-+
-+      if (sscanf(s, "%dx%d@%dx%d",
-+                 &crop->width,
-+                 &crop->height,
-+                 &crop->top,
-+                 &crop->left) != 4)
-+              return -1;
-+
-+      return 0;
-+}
-+
- static void
- setup_output_seat_constraint(struct drm_backend *b,
-                            struct weston_output *output,
-@@ -3457,7 +3486,173 @@ recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
-               recorder_destroy(output);
-       }
- }
--#else
-+#endif
-+
-+#ifdef BUILD_GST_RECORDER
-+static void
-+recorder_destroy(struct drm_output *output)
-+{
-+      wl_list_remove(&output->recorder_frame_listener.link);
-+
-+      gst_recorder_destroy(output->recorder);
-+      output->recorder = NULL;
-+
-+      output->base.disable_planes--;
-+
-+      weston_log("[gst recorder] done\n");
-+}
-+
-+static void
-+recorder_frame_notify(struct wl_listener *listener, void *data)
-+{
-+      int ret = 0;
-+      struct drm_output *output;
-+      struct drm_backend *b;
-+      int fd;
-+
-+      output = container_of(listener, struct drm_output,
-+                            recorder_frame_listener);
-+      b = to_drm_backend(output->base.compositor);
-+
-+      if (!output->recorder) {
-+              weston_log("%s: output have no recorder enabled\n",
-+                      output->base.name);
-+              return;
-+      }
-+
-+      if (!output->current) {
-+              weston_log("%s: frame notify while current frame == NULL\n",
-+                         output->base.name);
-+              return;
-+      }
-+
-+      ret = drmPrimeHandleToFD(b->drm.fd, output->current->handle,
-+                               DRM_CLOEXEC, &fd);
-+      if (!ret) {
-+              ret = gst_recorder_frame_dmafd(output->recorder, fd,
-+                                             output->current->stride);
-+      }
-+
-+      if (ret < 0) {
-+              weston_log("[gst recorder] aborted: %m\n");
-+              recorder_destroy(output);
-+      }
-+}
-+
-+static int
-+recorder_enable(struct drm_backend *b, struct drm_output *output)
-+{
-+      int enable_recorder = 0;
-+      struct gst_recorder_settings *settings;
-+      struct weston_config_section *section;
-+      struct weston_config *config = wet_get_config(b->compositor);
-+      char* s;
-+      struct v4l2_rect crop = { .width = output->base.current_mode->width,
-+                                .height = output->base.current_mode->height,
-+                                .top = 0,
-+                                .left = 0 };
-+
-+      if (output->recorder)
-+              return -1;
-+
-+      section = weston_config_get_section(config, "output", "name",
-+                                          output->base.name);
-+
-+      weston_config_section_get_bool(section, "recorder", &enable_recorder, 0);
-+
-+      if (!enable_recorder)
-+              return 0;
-+
-+      /* TODO: add support for NV16 or NV12 */
-+      if (output->gbm_format != GBM_FORMAT_XRGB8888) {
-+              weston_log("[gst recorder] %s: "
-+                         "output format not supported\n", output->base.name);
-+              return -1;
-+      }
-+
-+      settings = malloc(sizeof(* settings));
-+      weston_config_section_get_string(section, "ip", &settings->ip, NULL);
-+      if (!settings->ip)
-+              goto err;
-+      weston_config_section_get_int(section, "port", &settings->port, -1);
-+      /* default gives about 16 Mbit/s at 1280x720@60FPS */
-+      weston_config_section_get_int(section, "bitrate", &settings->bitrate, 300000);
-+
-+      settings->width = output->base.current_mode->width;
-+      settings->height = output->base.current_mode->height;
-+
-+      settings->crop = crop;
-+
-+      weston_config_section_get_string(section, "crop", &s, NULL);
-+      if (s) {
-+              if (parse_crop_rect(s, &settings->crop)) {
-+                      weston_log("[gst recorder] %s:"
-+                                 " failed to parse crop parameter\n",
-+                                 output->base.name);
-+                      goto err;
-+              }
-+      }
-+
-+
-+      output->recorder =
-+              gst_recorder_create(settings);
-+      if (!output->recorder) {
-+              weston_log("[gst recorder] %s:"
-+                      " failed to create gst recorder\n",
-+                      output->base.name);
-+              goto err;
-+      }
-+
-+      output->base.disable_planes++;
-+
-+      output->recorder_frame_listener.notify = recorder_frame_notify;
-+      wl_signal_add(&output->base.frame_signal,
-+                    &output->recorder_frame_listener);
-+
-+      weston_output_schedule_repaint(&output->base);
-+
-+      weston_log("[gst recorder] %s:"
-+              " recorder initialized\n",
-+              output->base.name);
-+
-+      return 0;
-+err:
-+      weston_log("[gst recorder] %s:"
-+              " invalid settings\n",
-+              output->base.name);
-+      free(settings);
-+      return -1;
-+}
-+
-+static void
-+recorders_enable(struct drm_backend *b)
-+{
-+      struct drm_output *output;
-+
-+      wl_list_for_each(output, &b->compositor->output_list, base.link) {
-+              recorder_enable(b, output);
-+      }
-+}
-+
-+static void
-+recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
-+               void *data)
-+{
-+      struct drm_backend *b = data;
-+      struct drm_output *output;
-+
-+      /* fix this */
-+      wl_list_for_each(output, &b->compositor->output_list, base.link) {
-+              if (!output->recorder)
-+                      recorder_enable(b, output);
-+              else
-+                      recorder_destroy(output);
-+      }
-+}
-+#endif
-+
-+#if !defined(BUILD_VAAPI_RECORDER) && !defined(BUILD_GST_RECORDER)
-+
- static void
- recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
-                void *data)
-@@ -3562,6 +3757,7 @@ drm_backend_create(struct weston_compositor *compositor,
-       b->sprites_are_broken = 1;
-       b->compositor = compositor;
-       b->use_pixman = config->use_pixman;
-+      b->enable_recorder = config->enable_recorder;
-       if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
-               goto err_compositor;
-@@ -3611,6 +3807,11 @@ drm_backend_create(struct weston_compositor *compositor,
-               }
-       }
-+#ifdef BUILD_GST_RECORDER
-+      if (b->enable_recorder)
-+              gst_recorder_init();
-+#endif
-+
-       b->base.destroy = drm_destroy;
-       b->base.restore = drm_restore;
-diff --git a/libweston/compositor-drm.h b/libweston/compositor-drm.h
-index 00171c8..4eb6097 100644
---- a/libweston/compositor-drm.h
-+++ b/libweston/compositor-drm.h
-@@ -111,6 +111,9 @@ struct weston_drm_backend_config {
-       /** Whether to use the pixman renderer instead of the OpenGL ES renderer. */
-       bool use_pixman;
-+      /** Whether to use the v4l2 renderer insted of the OpenGL ES renderer. */
-+      bool enable_recorder;
-+
-       /** The seat to be used for input and output.
-        *
-        * If NULL the default "seat0" will be used.  The backend will
-diff --git a/libweston/gst-recorder.c b/libweston/gst-recorder.c
-new file mode 100644
-index 0000000..d46d4f0
---- /dev/null
-+++ b/libweston/gst-recorder.c
-@@ -0,0 +1,1213 @@
-+/*
-+ * Copyright Â© 2016 Cogent Embedded Inc
-+ *
-+ * Permission to use, copy, modify, distribute, and sell this software and
-+ * its documentation for any purpose is hereby granted without fee, provided
-+ * that the above copyright notice appear in all copies and that both that
-+ * copyright notice and this permission notice appear in supporting
-+ * documentation, and that the name of the copyright holders not be used in
-+ * advertising or publicity pertaining to distribution of the software
-+ * without specific, written prior permission.  The copyright holders make
-+ * no representations about the suitability of this software for any
-+ * purpose.  It is provided "as is" without express or implied warranty.
-+ *
-+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
-+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
-+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
-+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
-+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+/*
-+ * TODO:
-+ * 1) Add format parameter to virtual display to render in another format
-+ * with v4l2-renderer
-+ * 2) Add capability to use already NV12 rendered frame
-+ */
-+#include "config.h"
-+
-+#include <stdlib.h>
-+#include <stdint.h>
-+#include <string.h>
-+#include <unistd.h>
-+#include <assert.h>
-+#include <errno.h>
-+
-+#include <sys/types.h>
-+#include <sys/stat.h>
-+#include <sys/mman.h>
-+#include <sys/ioctl.h>
-+#include <fcntl.h>
-+
-+#include <pthread.h>
-+
-+#include "compositor.h"
-+#include "gst-recorder.h"
-+
-+/* Gstreamer includes */
-+#include <gst/gst.h>
-+#include <gst/app/gstappsrc.h>
-+#include <gst/rtp/gstrtpbuffer.h>
-+
-+#include <gst/video/video.h>
-+#include <gst/video/gstvideometa.h>
-+#include <gst/video/gstvideopool.h>
-+#include <gst/allocators/gstdmabuf.h>
-+
-+struct vsp_data;
-+
-+#define DEFAULT_FPS           60
-+
-+typedef enum _vsp_port_n {
-+      VSP_PORT_INPUT  = 0,
-+      VSP_PORT_INPUT0 = VSP_PORT_INPUT,
-+      VSP_PORT_INPUT1,
-+      VSP_PORT_INPUT2,
-+      VSP_PORT_INPUT3,
-+      VSP_PORT_OUTPUT
-+} vsp_port_n;
-+
-+struct gst_recorder {
-+      struct gst_recorder_settings *set;
-+      int frame_count;
-+      int input_count;
-+
-+      int error;
-+      int destroying;
-+      pthread_t worker_thread;
-+      pthread_mutex_t mutex;
-+      pthread_cond_t input_cond;
-+
-+      struct {
-+              int valid;
-+              int prime_fd, stride;
-+      } input;
-+
-+      /* GLib */
-+      GMainContext *gcontext;
-+      /* Gstreamer stuff */
-+      GstElement *pipeline;
-+      /* AppSrc */
-+      GstAppSrc *appsrc;
-+      /* ...and source pad */
-+      GstPad *appsrc_pad;
-+      /* OMX encoder buffer pool */
-+      GstBufferPool *omx_pool;
-+      /* bus */
-+      GstBus *bus;
-+      /* timestamp */
-+      GstClock   *clock;
-+      GstClockTime timestamp;
-+      GstClockTime ts_last_frame;
-+      /* to be removed */
-+      guint callback_tag;
-+
-+      struct vsp_data *vsp;
-+};
-+
-+/*******************************************************************************
-+ * VSP related code
-+ ******************************************************************************/
-+
-+#define VSP_OUTPUT_BUFFERS_PLANE      2
-+
-+/* #define VSP_OUTPUT_NV16                    1 */
-+
-+/* ...number of input/output pads (WPF1-3 are not implemented) */
-+#define VSP_PADS_NUM                    1
-+
-+/*******************************************************************************
-+ * Local types definition
-+ ******************************************************************************/
-+
-+struct vsp_media_pad
-+{
-+      struct media_pad           *infmt_pad;
-+      struct media_pad           *outfmt_pad;
-+      struct media_entity        *entity;
-+      int                     fd;
-+};
-+
-+typedef struct vsp_media_pad vsp_media_pad_t;
-+
-+struct vsp_data
-+{
-+      /* ...media device */
-+      struct media_device *media;
-+
-+      /* ...VSP input/output pads */
-+      vsp_media_pad_t input, output;
-+
-+      /* mutex */
-+      pthread_mutex_t mutex;
-+
-+      /* user count */
-+      int users;
-+};
-+
-+struct vsp_data *vsp_g = NULL;
-+
-+/* ...type declarations */
-+typedef struct vsp_data vsp_data_t;
-+
-+static int
-+gst_recorder_process_dmafd(struct gst_recorder *r, int fd, int stride);
-+
-+/* ...module initialization (a bit of salami) */
-+static vsp_data_t *
-+vsp_init(const char *devname)
-+{
-+      vsp_data_t                     *vsp;
-+      struct media_device            *media;
-+      const struct media_device_info *info;
-+      const char                     *dev;
-+      char                            buf[256];
-+      char                           *endp, *p;
-+      struct media_entity            *entity;
-+
-+      /* ...create data structure */
-+      if ((vsp = malloc(sizeof(*vsp))) == NULL)
-+      {
-+              weston_log("failed to allocate memory\n");
-+              errno = ENOMEM;
-+              return NULL;
-+      }
-+      memset(vsp, 0, sizeof(*vsp));
-+
-+      pthread_mutex_init(&vsp->mutex, NULL);
-+
-+      /* ...create media device */
-+      if ((vsp->media = media = media_device_new(devname)) == NULL)
-+      {
-+              weston_log("failed to open device '%s'\n", devname);
-+              goto error;
-+      }
-+      else if ((errno = -media_device_enumerate(media)) != 0)
-+      {
-+              weston_log("failed to enumerate device '%s'\n", devname);
-+              goto error_media;
-+      }
-+      else if ((info = media_get_info(media)) == NULL)
-+      {
-+              weston_log("failed to get media info data\n");
-+              goto error_media;
-+      }
-+      else
-+      {
-+              dev = ((p = strchr(info->bus_info, ':')) ? p + 1 : info->bus_info);
-+              weston_log("open media device: %s (%s)\n", info->bus_info, dev);
-+      }
-+
-+      /* ...reset links */
-+      if (media_reset_links(media) != 0)
-+      {
-+              weston_log("failed to reset media device\n");
-+              goto error_media;
-+      }
-+
-+      /* ...setup RPF.0:1 -> WPF.0:0 link */
-+      snprintf(buf, sizeof(buf), "'%s rpf.0':1 -> '%s wpf.0':0 [1]", dev, dev);
-+      if (media_parse_setup_link(media, buf, &endp) != 0)
-+      {
-+              weston_log("failed to setup link '%s'\n", buf);
-+              errno = EINVAL;
-+              goto error_media;
-+      }
-+
-+      /* ...setup WPF.0:1 -> WPF.0 output link */
-+      snprintf(buf, sizeof(buf), "'%s wpf.0':1 -> '%s wpf.0 output':0 [1]", dev, dev);
-+      if (media_parse_setup_link(media, buf, &endp) != 0)
-+      {
-+              weston_log("failed to setup link '%s'\n", buf);
-+              errno = EINVAL;
-+              goto error_media;
-+      }
-+
-+      /* ...specify input/output-format of RPF pad */
-+      snprintf(buf, sizeof(buf), "'%s rpf.0':0", dev);
-+      if ((vsp->input.infmt_pad = media_parse_pad(media, buf, NULL)) == NULL)
-+      {
-+              weston_log("failed to parse pad '%s'\n", buf);
-+              errno = EINVAL;
-+              goto error_media;
-+      }
-+
-+      snprintf(buf, sizeof(buf), "'%s rpf.0':1", dev);
-+      if ((vsp->input.outfmt_pad = media_parse_pad(media, buf, NULL)) == NULL)
-+      {
-+              weston_log("failed to parse pad '%s'\n", buf);
-+              errno = EINVAL;
-+              goto error_media;
-+      }
-+
-+      snprintf(buf, sizeof(buf), "%s rpf.0", dev);
-+      if ((vsp->input.entity = media_get_entity_by_name(media, buf, strlen(buf))) == NULL)
-+      {
-+              weston_log("failed to parse entity '%s'\n", buf);
-+              errno = EINVAL;
-+              goto error_media;
-+      }
-+
-+      /* ...get input file-descriptor */
-+      snprintf(buf, sizeof(buf), "%s rpf.0 input", dev);
-+      if ((entity = media_get_entity_by_name(media, buf, strlen(buf))) == NULL)
-+      {
-+              weston_log("entity '%s' not found\n", buf);
-+              errno = EINVAL;
-+              goto error_media;
-+      }
-+      else if (v4l2_subdev_open(entity) != 0)
-+      {
-+              weston_log("failed to open subdev '%s'\n", buf);
-+              goto error_media;
-+      }
-+      else if ((vsp->input.fd = open(media_entity_get_devname(entity), O_RDWR/* | O_NONBLOCK*/)) < 0)
-+      {
-+              weston_log("failed to open device '%s'\n", media_entity_get_devname(entity));
-+              goto error_media;
-+      }
-+      else
-+      {
-+              weston_log("input pad setup ('%s':'%s')\n", buf, media_entity_get_devname(entity));
-+      }
-+
-+      /* ...specify input/output formats of WPF pad */
-+      snprintf(buf, sizeof(buf), "'%s wpf.0':0", dev);
-+      if ((vsp->output.infmt_pad = media_parse_pad(media, buf, NULL)) == NULL)
-+      {
-+              weston_log("failed to parse pad '%s'\n", buf);
-+              errno = EINVAL;
-+              goto error_media;
-+      }
-+
-+      snprintf(buf, sizeof(buf), "'%s wpf.0':1", dev);
-+      if ((vsp->output.outfmt_pad = media_parse_pad(media, buf, NULL)) == NULL)
-+      {
-+              weston_log("failed to parse pad '%s'\n", buf);
-+              errno = EINVAL;
-+              goto error_media;
-+      }
-+
-+      snprintf(buf, sizeof(buf), "%s wpf.0", dev);
-+      if ((vsp->output.entity = media_get_entity_by_name(media, buf, strlen(buf))) == NULL)
-+      {
-+              weston_log("failed to parse entity '%s'\n", buf);
-+              errno = EINVAL;
-+              goto error_media;
-+      }
-+
-+      /* ...get a file descriptor for the output */
-+      snprintf(buf, sizeof(buf), "%s wpf.0 output", dev);
-+      if ((entity = media_get_entity_by_name(media, buf, strlen(buf))) == NULL)
-+      {
-+              weston_log("failed to get entity '%s'\n", buf);
-+              errno = EINVAL;
-+              goto error_media;
-+      }
-+      else if (v4l2_subdev_open(entity) != 0)
-+      {
-+              weston_log("failed to open subdev '%s'\n", buf);
-+              goto error_media;
-+      }
-+      else if ((vsp->output.fd = open(media_entity_get_devname(entity), O_RDWR | O_NONBLOCK)) < 0)
-+      {
-+              weston_log("failed to open device '%s'\n", media_entity_get_devname(entity));
-+              goto error_media;
-+      }
-+      else
-+      {
-+              weston_log("output pad setup (%s:%s)\n", buf, media_entity_get_devname(entity));
-+      }
-+
-+      weston_log("vsp-device '%s' created\n", devname);
-+
-+      return vsp;
-+
-+error_media:
-+      /* ...destroy media device and all associated structures */
-+      media_device_unref(vsp->media);
-+
-+error:
-+      /* ...destroy data structure */
-+      free(vsp);
-+      return NULL;
-+}
-+
-+static void
-+vsp_deinit(vsp_data_t *vsp)
-+{
-+      /* ...destroy media device and all associated structures */
-+      media_device_unref(vsp->media);
-+
-+      /* ...destroy data structure */
-+      free(vsp);
-+}
-+
-+/* ...set V4L2 device format */
-+static int
-+vsp_set_format(int fd, struct v4l2_format *fmt)
-+{
-+      /* ...set format */
-+      if (ioctl(fd, VIDIOC_S_FMT, fmt) < 0) {
-+              weston_log("format set (fd=%d) failed: %d\n",
-+                      fd, errno);
-+      }
-+
-+      return 0;
-+}
-+
-+/* ...start streaming on specific V4L2 device */
-+static int
-+vsp_streaming_enable(vsp_data_t *vsp, vsp_port_n port, int enable)
-+{
-+      vsp_media_pad_t *pad = (port == VSP_PORT_INPUT) ? &vsp->input : &vsp->output;
-+      int fd = pad->fd;
-+      int type = (port == VSP_PORT_INPUT) ?
-+              V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-+
-+      return ioctl(fd, (enable ? VIDIOC_STREAMON : VIDIOC_STREAMOFF), &type);
-+}
-+
-+/* ...prepare VSP filter for operation */
-+static int
-+vsp_set_formats(vsp_data_t *vsp, int width, int height, struct v4l2_rect* crop)
-+{
-+      vsp_media_pad_t *input = &vsp->input, *output = &vsp->output;
-+      struct v4l2_mbus_framefmt mfmt = { .width = width, .height = height };
-+      struct v4l2_format format;
-+
-+      /* ...configure RPF input pads; specify pixel format and size (one of YUV variants) */
-+      mfmt.width = width;
-+      mfmt.height = height;
-+      mfmt.code = V4L2_MBUS_FMT_ARGB8888_1X32;
-+      if (v4l2_subdev_set_format(input->infmt_pad->entity,
-+              &mfmt, input->infmt_pad->index, V4L2_SUBDEV_FORMAT_ACTIVE) < 0) {
-+              weston_log("VSP: input pad in format set failed: %d\n", errno);
-+              return -1;
-+      }
-+
-+       /* set a crop paramters */
-+      if (v4l2_subdev_set_selection(input->infmt_pad->entity, crop, input->infmt_pad->index,
-+                                    V4L2_SEL_TGT_CROP, V4L2_SUBDEV_FORMAT_ACTIVE)) {
-+              weston_log("set crop parameter failed: %dx%d@(%d,%d).\n",
-+                         crop->width, crop->height, crop->left, crop->top);
-+              return -1;
-+      }
-+
-+      /* ...output is NV12 or NV16 or I420*/
-+      mfmt.width = crop->width;
-+      mfmt.height = crop->height;
-+      mfmt.code = V4L2_MBUS_FMT_AYUV8_1X32;
-+      if (v4l2_subdev_set_format(input->outfmt_pad->entity,
-+              &mfmt, input->outfmt_pad->index, V4L2_SUBDEV_FORMAT_ACTIVE) < 0) {
-+              weston_log("VSP: input pad out format set failed: %d\n", errno);
-+              return -1;
-+      }
-+
-+      /* ...specify input format */
-+      memset(&format, 0, sizeof(format));
-+      format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-+      format.fmt.pix_mp.width = /* crop-> */width;
-+      format.fmt.pix_mp.height = /* crop-> */height;
-+      format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_ABGR32;
-+      format.fmt.pix_mp.num_planes = 1;
-+      /* ...set input port format */
-+      if (vsp_set_format(input->fd, &format) < 0) {
-+              weston_log("VSP: input set format failed: %d\n", errno);
-+              return -1;
-+      }
-+
-+      /* ...both input and output are ARGB8888 always (now effective) */
-+      if (v4l2_subdev_set_format(output->infmt_pad->entity,
-+              &mfmt, output->infmt_pad->index, V4L2_SUBDEV_FORMAT_ACTIVE) < 0) {
-+              weston_log("VSP: output pad in format set failed: %d\n", errno);
-+              return -1;
-+      }
-+
-+      /* ...specify cropping area, probably? - tbd */
-+      if (v4l2_subdev_set_format(output->outfmt_pad->entity,
-+              &mfmt, output->outfmt_pad->index, V4L2_SUBDEV_FORMAT_ACTIVE) < 0) {
-+              weston_log("VSP: output pad in format set failed: %d\n", errno);
-+              return -1;
-+      }
-+
-+      /* ...setup output pads */
-+      memset(&format, 0, sizeof(format));
-+      format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-+      format.fmt.pix_mp.width = crop->width;
-+      format.fmt.pix_mp.height = crop->height;
-+#ifdef VSP_OUTPUT_NV16
-+      format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV16M;
-+#else
-+      format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M;
-+#endif
-+      format.fmt.pix_mp.num_planes = VSP_OUTPUT_BUFFERS_PLANE;
-+      /* ...set output buffer format */
-+      if (vsp_set_format(output->fd, &format) < 0) {
-+              weston_log("VSP: output set format failed: %d\n", errno);
-+              return -1;
-+      }
-+
-+      return 0;
-+}
-+
-+static int
-+vsp_request_buffers(vsp_data_t *vsp, vsp_port_n port, unsigned int num)
-+{
-+      vsp_media_pad_t *pad = (port == VSP_PORT_INPUT) ? &vsp->input : &vsp->output;
-+      struct v4l2_requestbuffers reqbuf;
-+      int fd = pad->fd;
-+
-+      /* ...input buffers are DMA-fd, output buffers allocated by kernel */
-+      memset(&reqbuf, 0, sizeof(reqbuf));
-+      reqbuf.type = (port == VSP_PORT_INPUT) ?
-+              V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-+      reqbuf.memory = V4L2_MEMORY_DMABUF;
-+      reqbuf.count = num;
-+      if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
-+              weston_log("VSP: %s REQBUFS failed: %d\n",
-+                      (port == VSP_PORT_INPUT) ? "input" : "output", errno);
-+              return -1;
-+      }
-+
-+      if (reqbuf.count != num) {
-+              weston_log("VSP: %s failed to request %d (!= %d) bufs\n",
-+                      (port == VSP_PORT_INPUT) ? "input" : "output", num, reqbuf.count);
-+              return -1;
-+      }
-+      return 0;
-+}
-+
-+
-+/* ...enqueue dmafd buffer */
-+static int
-+vsp_input_buffer_queue_dmafd(vsp_data_t *vsp, int i, int dmafd)
-+{
-+      vsp_media_pad_t    *pad = &vsp->input;
-+      struct v4l2_buffer  buf;
-+      struct v4l2_plane   planes[1];
-+
-+      /* ...set buffer parameters */
-+      memset(&buf, 0, sizeof(buf));
-+      memset(planes, 0, sizeof(planes));
-+      buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-+      buf.memory = V4L2_MEMORY_DMABUF;
-+      buf.index = i;
-+      buf.m.planes = planes;
-+      buf.length = 1;
-+      buf.m.planes[0].m.fd = dmafd;
-+
-+      /* ...submit buffer */
-+      if (ioctl(pad->fd, VIDIOC_QBUF, &buf) < 0) {
-+              weston_log("VSP: input dmafd (%d) buffer (%i) queue failed: %d\n",
-+                      dmafd, i, errno);
-+              return -1;
-+      }
-+
-+      return 0;
-+}
-+
-+/* ...dequeue dmafd buffer */
-+static int
-+vsp_input_buffer_dequeue_dmafd(vsp_data_t *vsp)
-+{
-+      vsp_media_pad_t    *pad = &vsp->input;
-+      struct v4l2_buffer  buf;
-+      struct v4l2_plane   planes[1];
-+
-+      /* ...set buffer parameters */
-+      memset(&buf, 0, sizeof(buf));
-+      memset(planes, 0, sizeof(planes));
-+      buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-+      buf.memory = V4L2_MEMORY_DMABUF;
-+      buf.m.planes = planes;
-+      buf.length = 1;
-+
-+      if (ioctl(pad->fd, VIDIOC_DQBUF, &buf) < 0) {
-+              weston_log("VSP: input dmafd buffer de-queue failed: %d\n", errno);
-+              return -1;
-+      }
-+
-+      /* ...return buffer index */
-+      return buf.index;
-+}
-+
-+/* ...enqueue output buffer */
-+static int
-+vsp_output_buffer_queue_dmafd(vsp_data_t *vsp, int i, int dmafd[])
-+{
-+      vsp_media_pad_t    *pad = &vsp->output;
-+      struct v4l2_plane   planes[2];
-+      struct v4l2_buffer  buf;
-+
-+      /* ...set buffer parameters (single-plane ARGB always) */
-+      memset(&buf, 0, sizeof(buf));
-+      memset(planes, 0, sizeof(planes));
-+      buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-+      buf.memory = V4L2_MEMORY_DMABUF;
-+      buf.index = i;
-+      buf.m.planes = planes;
-+      buf.length = VSP_OUTPUT_BUFFERS_PLANE;
-+      buf.m.planes[0].m.fd = dmafd[0];
-+      buf.m.planes[1].m.fd = dmafd[1];
-+
-+      /* ...submit buffer */
-+      if (ioctl(pad->fd, VIDIOC_QBUF, &buf) < 0) {
-+              weston_log("VSP: output dmafd queue failed: %d\n", errno);
-+              return -1;
-+      }
-+
-+      return 0;
-+}
-+
-+/* ...dequeue output buffer */
-+static int
-+vsp_output_buffer_dequeue_dmafd(vsp_data_t *vsp)
-+{
-+      vsp_media_pad_t    *pad = &vsp->output;
-+      struct v4l2_buffer  buf;
-+      struct v4l2_plane   planes[2];
-+
-+      /* ...set buffer parameters */
-+      memset(&buf, 0, sizeof(buf));
-+      memset(planes, 0, sizeof(planes));
-+      buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-+      buf.memory = V4L2_MEMORY_DMABUF;
-+      buf.m.planes = planes;
-+      buf.length = VSP_OUTPUT_BUFFERS_PLANE;
-+
-+      if (ioctl(pad->fd, VIDIOC_DQBUF, &buf) < 0) {
-+              weston_log("VSP: output dmafd de-queue failed: %d\n", errno);
-+              return -1;
-+      }
-+
-+      /* ...return dequeue buffer index */
-+      return buf.index;
-+}
-+
-+/* ...get capturing interface file descriptor */
-+static int
-+vsp_capture_fd(vsp_data_t *vsp)
-+{
-+      return vsp->output.fd;
-+}
-+
-+/*******************************************************************************
-+ * Gstreamer stuff
-+ ******************************************************************************/
-+
-+static void
-+print_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
-+{
-+      int i, num;
-+
-+      num = gst_tag_list_get_tag_size (list, tag);
-+      for (i = 0; i < num; ++i) {
-+              const GValue *val;
-+
-+              /* Note: when looking for specific tags, use the gst_tag_list_get_xyz() API,
-+               * we only use the GValue approach here because it is more generic */
-+              val = gst_tag_list_get_value_index (list, tag, i);
-+              if (G_VALUE_HOLDS_STRING (val)) {
-+                      weston_log("\t%20s : %s\n", tag, g_value_get_string (val));
-+              } else if (G_VALUE_HOLDS_UINT (val)) {
-+                      weston_log("\t%20s : %u\n", tag, g_value_get_uint (val));
-+              } else if (G_VALUE_HOLDS_DOUBLE (val)) {
-+                      weston_log("\t%20s : %g\n", tag, g_value_get_double (val));
-+              } else if (G_VALUE_HOLDS_BOOLEAN (val)) {
-+                      weston_log("\t%20s : %s\n", tag,
-+                                      (g_value_get_boolean (val)) ? "true" : "false");
-+              } else if (GST_VALUE_HOLDS_BUFFER (val)) {
-+                      GstBuffer *buf = gst_value_get_buffer (val);
-+                      guint buffer_size = gst_buffer_get_size (buf);
-+
-+                      weston_log("\t%20s : buffer of size %u\n", tag, buffer_size);
-+              } else if (GST_VALUE_HOLDS_DATE_TIME (val)) {
-+                      GstDateTime *dt = g_value_get_boxed (val);
-+                      gchar *dt_str = gst_date_time_to_iso8601_string (dt);
-+
-+                      weston_log("\t%20s : %s\n", tag, dt_str);
-+                      g_free (dt_str);
-+              } else {
-+                      weston_log("\t%20s : tag of type '%s'\n", tag, G_VALUE_TYPE_NAME (val));
-+              }
-+      }
-+}
-+
-+static gboolean
-+gst_bus_callback(GstBus *bus, GstMessage *message, gpointer user_data)
-+{
-+      GTimeVal time;
-+      struct gst_recorder *r = user_data;
-+
-+      if (!r->pipeline) {
-+              weston_log("gst_pipeline: unexpected gst bus callback event, while pipeline==null\n");
-+              return TRUE;
-+      }
-+
-+      g_get_current_time(&time);
-+
-+      switch (GST_MESSAGE_TYPE(message))
-+      {
-+              case GST_MESSAGE_QOS:
-+                      {
-+                              GstFormat format;
-+                              guint64 processed;
-+                              guint64 dropped;
-+
-+                              gst_message_parse_qos_stats (message, &format, &processed, &dropped);
-+                              weston_log("gst_pipeline: qos from: %s processed %lud, dropped %lud\n",
-+                                      GST_OBJECT_NAME (message->src),
-+                                      processed, dropped);
-+                      }
-+              break;
-+              case GST_MESSAGE_STREAM_STATUS:
-+                      {
-+                              const GValue *val;
-+
-+                              val = gst_message_get_stream_status_object (message);
-+                              weston_log("gst_pipeline: stream status type %s, value %p\n",
-+                                      G_VALUE_TYPE_NAME(val),
-+                                      g_value_get_object(val));
-+                      }
-+              break;
-+              case GST_MESSAGE_TAG:
-+                      {
-+                              GstTagList *tags = NULL;
-+
-+                              gst_message_parse_tag (message, &tags);
-+                              weston_log("gst_pipeline: tag from element %s:\n",
-+                                      GST_OBJECT_NAME (message->src));
-+                              gst_tag_list_foreach (tags, print_one_tag, NULL);
-+                              weston_log("\n");
-+                      }
-+              break;
-+              case GST_MESSAGE_STATE_CHANGED:
-+                      {
-+                              GstState oldstate, newstate;
-+
-+                              gst_message_parse_state_changed(message, &oldstate, &newstate, NULL);
-+                              weston_log("gst_pipeline: element %s changed state from %s to %s.\n",
-+                                      GST_OBJECT_NAME (message->src),
-+                                      gst_element_state_get_name (oldstate),
-+                                      gst_element_state_get_name (newstate));
-+
-+                              /* if gstreamer become ready */
-+                              if ((GST_MESSAGE_SRC(message) == GST_OBJECT(r->appsrc)) &&
-+                                      (newstate == GST_STATE_PAUSED)) {
-+                                      weston_log("gst_pipeline: pipeline ready\n");
-+                              }
-+                      }
-+              break;
-+              case GST_MESSAGE_ERROR:
-+                      {
-+                              GError *err;
-+                              gchar *debug_info;
-+                              gst_message_parse_error(message, &err, &debug_info);
-+                              weston_log("gst_pipeline: error received from element %s: %s\n",
-+                                      GST_OBJECT_NAME(message->src), err->message);
-+                              weston_log("gst_pipeline: debugging information: %s\n",
-+                                      debug_info ? debug_info : "none");
-+                              g_clear_error (&err);
-+                              g_free (debug_info);
-+                      }
-+              break;
-+              case GST_MESSAGE_WARNING:
-+                      {
-+                              GError *err;
-+                              gchar *debug_info;
-+                              gst_message_parse_warning(message, &err, &debug_info);
-+                              weston_log("gst_pipeline: warning received from element %s: %s\n",
-+                                      GST_OBJECT_NAME(message->src), err->message);
-+                              weston_log("gst_pipeline: debugging information: %s\n",
-+                                      debug_info ? debug_info : "none");
-+                              g_clear_error (&err);
-+                              g_free (debug_info);
-+                      }
-+              break;
-+              default:
-+                      weston_log("gst_pipeline: %s from %s\n",
-+                              GST_MESSAGE_TYPE_NAME(message), GST_OBJECT_NAME (message->src));
-+              break;
-+      }
-+      return TRUE;
-+}
-+
-+static void *
-+worker_thread_function(void *data)
-+{
-+      GstMessage *msg;
-+      struct gst_recorder *r = data;
-+
-+      pthread_mutex_lock(&r->mutex);
-+
-+      while (!r->destroying) {
-+              if (!r->input.valid)
-+                      pthread_cond_wait(&r->input_cond, &r->mutex);
-+
-+              /* If the thread is awaken by destroy_worker_thread(),
-+               * there might not be valid input */
-+              if (!r->input.valid)
-+                      continue;
-+
-+              /* TODO: move it to separate thread? */
-+              g_main_context_iteration(r->gcontext, FALSE);
-+
-+              do {
-+                      msg = gst_bus_pop_filtered(r->bus,
-+                                                 GST_MESSAGE_ANY);
-+                      if (msg) {
-+                              gst_bus_callback(r->bus, msg, r);
-+                      }
-+              } while (msg);
-+
-+              /* check input */
-+              gst_recorder_process_dmafd(r, r->input.prime_fd, r->input.stride);
-+
-+              r->input.valid = 0;
-+      }
-+
-+      pthread_mutex_unlock(&r->mutex);
-+
-+      return NULL;
-+}
-+
-+static int
-+setup_worker_thread(struct gst_recorder *r)
-+{
-+      r->gcontext = g_main_context_new();
-+      pthread_mutex_init(&r->mutex, NULL);
-+      pthread_cond_init(&r->input_cond, NULL);
-+      pthread_create(&r->worker_thread, NULL, worker_thread_function, r);
-+
-+      return 1;
-+}
-+
-+static void
-+destroy_worker_thread(struct gst_recorder *r)
-+{
-+      /* Make sure the worker thread finishes */
-+      r->destroying = 1;
-+
-+      pthread_cond_signal(&r->input_cond);
-+
-+      pthread_join(r->worker_thread, NULL);
-+
-+      pthread_mutex_destroy(&r->mutex);
-+      pthread_cond_destroy(&r->input_cond);
-+}
-+
-+void weston_debug_function(GstDebugCategory* category, GstDebugLevel level,
-+                          const gchar* file, const char* function,
-+                          gint line, GObject* object, GstDebugMessage* message,
-+                          gpointer data)
-+{
-+      weston_log("[GST]:%s %s:%d %s\n", file, function, line, gst_debug_message_get(message));
-+}
-+
-+void
-+gst_recorder_init(void)
-+{
-+      gst_init(NULL, 0);
-+
-+      /* VSP init */
-+      vsp_g = vsp_init("/dev/media0");
-+      if (!vsp_g)
-+              weston_log("[gst recorder] VSP init failed\n");
-+}
-+
-+static int
-+gst_recorder_find_omx_pool(struct gst_recorder *r)
-+{
-+      int ret = 0;
-+      GstCaps *caps;
-+      GstQuery *query;
-+      GstBufferPool *pool;
-+      GstStructure *config;
-+      guint size, min, max;
-+
-+      caps = gst_caps_new_simple (    "video/x-raw",
-+#ifdef VSP_OUTPUT_NV16
-+                                      "format", G_TYPE_STRING, "NV16",
-+#else
-+                                      "format", G_TYPE_STRING, "NV12",
-+#endif
-+                                      "width", G_TYPE_INT, r->set->crop.width,
-+                                      "height", G_TYPE_INT, r->set->crop.height,
-+                                      "framerate", GST_TYPE_FRACTION, 0, DEFAULT_FPS,
-+                                      NULL);
-+
-+      /* find a pool for the negotiated caps now */
-+      query = gst_query_new_allocation (caps, TRUE);
-+
-+      if (!gst_pad_peer_query (r->appsrc_pad, query)) {
-+              /* query failed, not a problem, we use the query defaults */
-+              weston_log("allocation query failed\n");
-+              ret = -1;
-+              goto err;
-+      }
-+
-+      weston_log("goot %d pools\n", gst_query_get_n_allocation_pools (query));
-+      if (gst_query_get_n_allocation_pools (query) > 0) {
-+              /* we got configuration from our peer, parse them */
-+              gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
-+              weston_log(" pool settings size %d, min %d, max %d\n", size, min, max);
-+      } else {
-+              weston_log("no pool queried\n");
-+              ret = -1;
-+              goto err;
-+      }
-+
-+      config = gst_buffer_pool_get_config (pool);
-+      gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
-+      gst_buffer_pool_config_set_params (config, caps, size, min, max);
-+      gst_buffer_pool_set_config (pool, config);
-+
-+      /* and activate */
-+      gst_buffer_pool_set_active (pool, TRUE);
-+
-+      r->omx_pool = pool;
-+
-+err:
-+      gst_query_unref (query);
-+      return ret;
-+}
-+
-+static int
-+gst_recorder_omx_buffer_acquire(struct gst_recorder *r, GstBuffer **ret_buf, int fd[])
-+{
-+      unsigned int i;
-+      GstFlowReturn ret;
-+      GstBuffer *buf;
-+      guint n_mem;
-+      GstMemory *mem;
-+
-+      ret = gst_buffer_pool_acquire_buffer(r->omx_pool, &buf, NULL);
-+      if (ret != GST_FLOW_OK) {
-+              weston_log("OMX buffer acquire failed\n");
-+              return -1;
-+      }
-+
-+      n_mem = gst_buffer_n_memory(buf);
-+      if (n_mem < 1) {
-+              weston_log("Buffer with no mem!\n");
-+              goto err_release;
-+      }
-+
-+      for (i = 0; i < n_mem; i++) {
-+              mem = gst_buffer_peek_memory (buf, i);
-+              if (!gst_is_dmabuf_memory (mem)) {
-+                      weston_log("Mem not dmabuf\n");
-+                      goto err_release;
-+              }
-+              fd[i] = gst_dmabuf_memory_get_fd (mem);
-+      }
-+
-+      *ret_buf = buf;
-+
-+      return 0;
-+err_release:
-+      gst_buffer_pool_release_buffer(r->omx_pool, buf);
-+      return -1;
-+}
-+
-+static int
-+gst_recorder_omx_buffer_release(struct gst_recorder *r, GstBuffer *buf)
-+{
-+      gst_buffer_pool_release_buffer(r->omx_pool, buf);
-+
-+      return 0;
-+}
-+
-+struct gst_recorder *
-+gst_recorder_create(struct gst_recorder_settings *settings)
-+{
-+      struct gst_recorder *r;
-+      char gst_pipe[1024];
-+      char *ptr = gst_pipe;
-+      GError *perror = NULL;
-+
-+      weston_log("gst_recorder_create (%dx%d) crop %dx%d at %d,%d\n",
-+                 settings->width, settings->height, settings->crop.width,
-+                 settings->crop.height, settings->crop.top, settings->crop.left);
-+
-+      if (!vsp_g) {
-+              weston_log("gst_recorder_create: no VSP\n");
-+              return NULL;
-+      }
-+
-+      r = calloc(1, sizeof *r);
-+      if (!r)
-+              return NULL;
-+      memset(r, 0, sizeof *r);
-+
-+      r->set = settings;
-+      r->timestamp = 0;
-+
-+      r->vsp = vsp_g;
-+      vsp_g->users++;
-+
-+      /* GST init */
-+      /* source (GST_FORMAT_BYTES) */
-+      ptr += sprintf(ptr,
-+              "appsrc name=src ! ");
-+
-+      /* omx */
-+      ptr += sprintf(ptr,
-+              "omxh264enc target-bitrate=%d control-rate=2 name=my_encoder ! "
-+              "video/x-h264,width=%d,height=%d ! ",
-+              r->set->bitrate, r->set->crop.width, r->set->crop.height);
-+
-+      /* rtp payloader */
-+      ptr += sprintf(ptr,
-+              "rtph264pay config-interval=1 name=my_h264pay ! queue  ! ");
-+
-+      /* usp sink */
-+      ptr += sprintf(ptr,
-+              "udpsink host=%s ", r->set->ip);
-+      if (r->set->port > 0)
-+              ptr += sprintf(ptr,
-+                      " port=%d name=my_udpsink", r->set->port);
-+
-+      weston_log("gst_pipeline: starting: %s\n", gst_pipe);
-+
-+      /* launch */
-+      r->pipeline = gst_parse_launch (gst_pipe, &perror);
-+      if (!r->pipeline) {
-+              weston_log("gst_pipeline: can not start pipeline: %s\n", perror->message);
-+              goto err_gst;
-+      }
-+
-+      /* get appsrc */
-+      r->appsrc = gst_bin_get_by_name(GST_BIN (r->pipeline), "src");
-+      if (!r->appsrc) {
-+              weston_log("gst_pipeline: can not get appsrc\n");
-+              goto err_gst;
-+      }
-+
-+      /* get bus */
-+      r->bus = gst_pipeline_get_bus (GST_PIPELINE(r->pipeline));
-+      if (!r->bus) {
-+              weston_log("gst_pipeline: can not get bus\n");
-+              goto err_gst;
-+      }
-+
-+      setup_worker_thread(r);
-+
-+      /* setup caps */
-+      g_object_set(G_OBJECT(r->appsrc), "caps",
-+              gst_caps_new_simple (   "video/x-raw",
-+#ifdef VSP_OUTPUT_NV16
-+                                      "format", G_TYPE_STRING, "NV16",
-+#else
-+                                      "format", G_TYPE_STRING, "NV12",
-+#endif
-+                                      "width", G_TYPE_INT, r->set->crop.width,
-+                                      "height", G_TYPE_INT, r->set->crop.height,
-+                                      "framerate", GST_TYPE_FRACTION, 0, DEFAULT_FPS,
-+                                      NULL), NULL);
-+
-+      r->appsrc_pad = gst_element_get_static_pad(GST_ELEMENT_CAST(r->appsrc), "src");
-+      if (!r->appsrc_pad)
-+              weston_log("Failed to get src0 pad of appsrc\n");
-+
-+      /* set playing */
-+      if (gst_element_set_state (r->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
-+              weston_log("gst_pipeline: can not change state to PLAYING\n");
-+              goto err_gst;
-+      }
-+
-+      if (gst_recorder_find_omx_pool(r) != 0) {
-+              weston_log("failed to find OMX buffer pool\n");
-+              goto err_gst_stop;
-+      }
-+
-+      /* set clock time */
-+      r->clock = gst_element_get_clock (GST_ELEMENT_CAST (r->appsrc));
-+
-+      weston_log("gst_recorder_create done\n");
-+
-+      return r;
-+
-+err_gst_stop:
-+      gst_element_set_state (r->pipeline, GST_STATE_NULL);
-+      destroy_worker_thread(r);
-+err_gst:
-+      free(r->pipeline);
-+      free(r);
-+
-+      return NULL;
-+}
-+
-+void
-+gst_recorder_destroy(struct gst_recorder *r)
-+{
-+      r->vsp->users--;
-+
-+      if (r->pipeline) {
-+              gst_element_set_state (r->pipeline, GST_STATE_NULL);
-+              gst_object_unref(r->omx_pool);
-+
-+              destroy_worker_thread(r);
-+
-+              gst_object_unref(GST_OBJECT(r->bus));
-+              gst_object_unref (r->pipeline);
-+              r->pipeline = NULL;
-+      }
-+      free(r);
-+}
-+
-+static int
-+gst_recorder_set_timestamp(struct gst_recorder *r, GstBuffer *buffer)
-+{
-+      GstClockTime cur_time = gst_clock_get_time(r->clock);
-+
-+      if (r->timestamp == 0) {
-+              /* first frame assume around DEFAULT_FPS FPS */
-+              GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale_int(1, GST_SECOND, DEFAULT_FPS);
-+      } else {
-+              GstClockTime delta = cur_time - r->ts_last_frame;
-+              /* delta in nS */
-+              GST_BUFFER_DURATION(buffer) = delta;
-+      }
-+
-+      r->timestamp += GST_BUFFER_DURATION(buffer);
-+      GST_BUFFER_PTS(buffer) = r->timestamp;
-+      GST_BUFFER_DTS(buffer) = r->timestamp;
-+
-+      r->ts_last_frame = cur_time;
-+
-+      return 0;
-+}
-+
-+
-+static int
-+gst_recorder_process_dmafd(struct gst_recorder *r, int fd, int stride)
-+{
-+      int ret;
-+      GstBuffer *buf;
-+      int omx_fd[2];
-+
-+        /* get GST buffer */
-+      if (gst_recorder_omx_buffer_acquire(r, &buf, omx_fd) < 0) {
-+              weston_log("VSP: can not acquire GST buffer, dropping frame\n");
-+              return 0;
-+      }
-+
-+      pthread_mutex_lock(&r->vsp->mutex);
-+      /* setup vsp */
-+      if (vsp_set_formats(r->vsp, r->set->width, r->set->height, &r->set->crop) < 0) {
-+              weston_log("VSP: format set failed\n");
-+              goto err;
-+      }
-+
-+      /* input */
-+      if (vsp_request_buffers(r->vsp, VSP_PORT_INPUT, 1) < 0) {
-+              weston_log("VSP: input buffer allocation failed\n");
-+              goto err_vsp;
-+      }
-+
-+      /* output */
-+      if (vsp_request_buffers(r->vsp, VSP_PORT_OUTPUT, 1) < 0) {
-+              weston_log("VSP: output buffer allocation failed\n");
-+              goto err_vsp;
-+      }
-+
-+      /* queue output biffer */
-+      if (vsp_output_buffer_queue_dmafd(r->vsp, 0, omx_fd) < 0) {
-+              weston_log("can not queue OMX buffer %d to VSP\n", 0);
-+              gst_recorder_omx_buffer_release(r, buf);
-+              goto err_vsp;
-+      }
-+
-+      /* queue input vsp buffer */
-+      if (vsp_input_buffer_queue_dmafd(r->vsp, 0, fd) < 0) {
-+              weston_log("VSP: failed to queue input buffer\n");
-+              goto err_vsp;
-+      }
-+
-+      /* start input */
-+      if (vsp_streaming_enable(r->vsp, VSP_PORT_INPUT, 1) < 0) {
-+              weston_log("VSP: failed to start input\n");
-+              goto err_vsp;
-+      }
-+
-+      /* start output */
-+      if (vsp_streaming_enable(r->vsp, VSP_PORT_OUTPUT, 1) < 0) {
-+              weston_log("VSP: failed to start output\n");
-+              goto err_vsp;
-+      }
-+
-+      /* dequeue input (do we need this?) */
-+      if (vsp_input_buffer_dequeue_dmafd(r->vsp) < 0) {
-+              weston_log("VSP: failed to dequeue input buffer\n");
-+              /* don't care */
-+      }
-+
-+      /* dequeue output */
-+      if (vsp_output_buffer_dequeue_dmafd(r->vsp) < 0) {
-+              weston_log("VSP: failed to dequeu output buffer\n");
-+              gst_recorder_omx_buffer_release(r, buf);
-+              /* fall through */
-+      } else {
-+              /* set timestamp */
-+              gst_recorder_set_timestamp(r, buf);
-+
-+              ret = gst_app_src_push_buffer(r->appsrc, buf);
-+              r->frame_count++;
-+
-+              if (ret != GST_FLOW_OK) {
-+                      /* some error, stop sending data */
-+                      weston_log("gst_pipeline: some error %d\n", ret);
-+              }
-+
-+      }
-+      /* stop input */
-+      vsp_streaming_enable(r->vsp, VSP_PORT_INPUT, 0);
-+      /* stop output */
-+      vsp_streaming_enable(r->vsp, VSP_PORT_OUTPUT, 0);
-+
-+      /* deinit */
-+      vsp_request_buffers(r->vsp, VSP_PORT_INPUT, 0);
-+      vsp_request_buffers(r->vsp, VSP_PORT_OUTPUT, 0);
-+
-+      pthread_mutex_unlock(&r->vsp->mutex);
-+      return 0;
-+
-+err_vsp:
-+      /* drop gst buffer */
-+      /* finish vsp here */
-+err:
-+      pthread_mutex_unlock(&r->vsp->mutex);
-+      return -1;
-+}
-+
-+int
-+gst_recorder_frame_dmafd(struct gst_recorder *r, int fd, int stride)
-+{
-+      int ret = 0;
-+      
-+      pthread_mutex_lock(&r->mutex);
-+
-+      if (r->error) {
-+              errno = r->error;
-+              ret = -1;
-+              goto unlock;
-+      }
-+              
-+      /* The mutex is never released while encoding, so this point should
-+       * never be reached if input.valid is true. */
-+      assert(!r->input.valid);
-+
-+      r->input.prime_fd = fd;
-+      r->input.stride = stride;
-+      r->input.valid = 1;
-+      pthread_cond_signal(&r->input_cond);
-+
-+unlock:
-+      pthread_mutex_unlock(&r->mutex);
-+
-+      return 0;
-+}
-diff --git a/libweston/gst-recorder.h b/libweston/gst-recorder.h
-new file mode 100644
-index 0000000..78290c1
---- /dev/null
-+++ b/libweston/gst-recorder.h
-@@ -0,0 +1,58 @@
-+/*
-+ * Copyright Â© 2016 Cogent Embedded Inc
-+ *
-+ * Permission to use, copy, modify, distribute, and sell this software and
-+ * its documentation for any purpose is hereby granted without fee, provided
-+ * that the above copyright notice appear in all copies and that both that
-+ * copyright notice and this permission notice appear in supporting
-+ * documentation, and that the name of the copyright holders not be used in
-+ * advertising or publicity pertaining to distribution of the software
-+ * without specific, written prior permission.  The copyright holders make
-+ * no representations about the suitability of this software for any
-+ * purpose.  It is provided "as is" without express or implied warranty.
-+ *
-+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
-+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
-+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
-+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
-+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+#ifndef _GST_RECORDER_H_
-+#define _GST_RECORDER_H_
-+
-+/* VSP includes */
-+#include <media-ctl/mediactl.h>
-+#include <media-ctl/v4l2subdev.h>
-+
-+struct gst_recorder;
-+
-+struct gst_recorder_settings {
-+      int width;
-+      int height;
-+      int bitrate;
-+      char *ip;
-+      int port;
-+      int latency_test;
-+      int refresh_ratio;
-+
-+      /* Cropping */
-+      struct v4l2_rect crop;
-+};
-+
-+void
-+gst_recorder_init(void);
-+struct gst_recorder *
-+gst_recorder_create(struct gst_recorder_settings *settings);
-+void
-+gst_recorder_destroy(struct gst_recorder *r);
-+int
-+gst_recorder_frame(struct gst_recorder *r, int fd, int stride);
-+int
-+gst_recorder_frame_mmap(struct gst_recorder *r, void *data, int stride);
-+int
-+gst_recorder_frame_dmafd(struct gst_recorder *r, int fd, int stride);
-+
-+#endif /* _GST_RECORDER_H_ */
-diff --git a/libweston/media-ctl/libmediactl.c b/libweston/media-ctl/libmediactl.c
-new file mode 100644
-index 0000000..f15b1a3
---- /dev/null
-+++ b/libweston/media-ctl/libmediactl.c
-@@ -0,0 +1,955 @@
-+/*
-+ * Media controller interface library
-+ *
-+ * Copyright (C) 2010-2014 Ideas on board SPRL
-+ *
-+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU Lesser General Public License as published
-+ * by the Free Software Foundation; either version 2.1 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program 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 Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include "config.h"
-+
-+#include <sys/ioctl.h>
-+#include <sys/stat.h>
-+#include <sys/types.h>
-+
-+#include <ctype.h>
-+#include <errno.h>
-+#include <fcntl.h>
-+#include <stdbool.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <unistd.h>
-+
-+#include <linux/media.h>
-+#include <linux/videodev2.h>
-+
-+#include "mediactl.h"
-+#include "mediactl-priv.h"
-+#include "tools.h"
-+
-+/* -----------------------------------------------------------------------------
-+ * Graph access
-+ */
-+
-+struct media_pad *media_entity_remote_source(struct media_pad *pad)
-+{
-+      unsigned int i;
-+
-+      if (!(pad->flags & MEDIA_PAD_FL_SINK))
-+              return NULL;
-+
-+      for (i = 0; i < pad->entity->num_links; ++i) {
-+              struct media_link *link = &pad->entity->links[i];
-+
-+              if (!(link->flags & MEDIA_LNK_FL_ENABLED))
-+                      continue;
-+
-+              if (link->sink == pad)
-+                      return link->source;
-+      }
-+
-+      return NULL;
-+}
-+
-+struct media_entity *media_get_entity_by_name(struct media_device *media,
-+                                            const char *name, size_t length)
-+{
-+      unsigned int i;
-+
-+      /* A match is impossible if the entity name is longer than the maximum
-+       * size we can get from the kernel.
-+       */
-+      if (length >= FIELD_SIZEOF(struct media_entity_desc, name))
-+              return NULL;
-+
-+      for (i = 0; i < media->entities_count; ++i) {
-+              struct media_entity *entity = &media->entities[i];
-+
-+              if (strncmp(entity->info.name, name, length) == 0 &&
-+                  entity->info.name[length] == '\0')
-+                      return entity;
-+      }
-+
-+      return NULL;
-+}
-+
-+struct media_entity *media_get_entity_by_id(struct media_device *media,
-+                                          __u32 id)
-+{
-+      bool next = id & MEDIA_ENT_ID_FLAG_NEXT;
-+      unsigned int i;
-+
-+      id &= ~MEDIA_ENT_ID_FLAG_NEXT;
-+
-+      for (i = 0; i < media->entities_count; ++i) {
-+              struct media_entity *entity = &media->entities[i];
-+
-+              if ((entity->info.id == id && !next) ||
-+                  (entity->info.id > id && next))
-+                      return entity;
-+      }
-+
-+      return NULL;
-+}
-+
-+unsigned int media_get_entities_count(struct media_device *media)
-+{
-+      return media->entities_count;
-+}
-+
-+struct media_entity *media_get_entity(struct media_device *media, unsigned int index)
-+{
-+      if (index >= media->entities_count)
-+              return NULL;
-+
-+      return &media->entities[index];
-+}
-+
-+const struct media_pad *media_entity_get_pad(struct media_entity *entity, unsigned int index)
-+{
-+      if (index >= entity->info.pads)
-+              return NULL;
-+
-+      return &entity->pads[index];
-+}
-+
-+unsigned int media_entity_get_links_count(struct media_entity *entity)
-+{
-+      return entity->num_links;
-+}
-+
-+const struct media_link *media_entity_get_link(struct media_entity *entity, unsigned int index)
-+{
-+      if (index >= entity->num_links)
-+              return NULL;
-+
-+      return &entity->links[index];
-+}
-+
-+const char *media_entity_get_devname(struct media_entity *entity)
-+{
-+      return entity->devname[0] ? entity->devname : NULL;
-+}
-+
-+struct media_entity *media_get_default_entity(struct media_device *media,
-+                                            unsigned int type)
-+{
-+      switch (type) {
-+      case MEDIA_ENT_T_DEVNODE_V4L:
-+              return media->def.v4l;
-+      case MEDIA_ENT_T_DEVNODE_FB:
-+              return media->def.fb;
-+      case MEDIA_ENT_T_DEVNODE_ALSA:
-+              return media->def.alsa;
-+      case MEDIA_ENT_T_DEVNODE_DVB:
-+              return media->def.dvb;
-+      }
-+
-+      return NULL;
-+}
-+
-+const struct media_device_info *media_get_info(struct media_device *media)
-+{
-+      return &media->info;
-+}
-+
-+const char *media_get_devnode(struct media_device *media)
-+{
-+      return media->devnode;
-+}
-+
-+const struct media_entity_desc *media_entity_get_info(struct media_entity *entity)
-+{
-+      return &entity->info;
-+}
-+
-+/* -----------------------------------------------------------------------------
-+ * Open/close
-+ */
-+
-+static int media_device_open(struct media_device *media)
-+{
-+      int ret;
-+
-+      if (media->fd != -1)
-+              return 0;
-+
-+      media_dbg(media, "Opening media device %s\n", media->devnode);
-+
-+      media->fd = open(media->devnode, O_RDWR);
-+      if (media->fd < 0) {
-+              ret = -errno;
-+              media_dbg(media, "%s: Can't open media device %s\n",
-+                        __func__, media->devnode);
-+              return ret;
-+      }
-+
-+      return 0;
-+}
-+
-+static void media_device_close(struct media_device *media)
-+{
-+      if (media->fd != -1) {
-+              close(media->fd);
-+              media->fd = -1;
-+      }
-+}
-+
-+/* -----------------------------------------------------------------------------
-+ * Link setup
-+ */
-+
-+int media_setup_link(struct media_device *media,
-+                   struct media_pad *source,
-+                   struct media_pad *sink,
-+                   __u32 flags)
-+{
-+      struct media_link *link;
-+      struct media_link_desc ulink;
-+      unsigned int i;
-+      int ret;
-+
-+      ret = media_device_open(media);
-+      if (ret < 0)
-+              goto done;
-+
-+      for (i = 0; i < source->entity->num_links; i++) {
-+              link = &source->entity->links[i];
-+
-+              if (link->source->entity == source->entity &&
-+                  link->source->index == source->index &&
-+                  link->sink->entity == sink->entity &&
-+                  link->sink->index == sink->index)
-+                      break;
-+      }
-+
-+      if (i == source->entity->num_links) {
-+              media_dbg(media, "%s: Link not found\n", __func__);
-+              ret = -ENOENT;
-+              goto done;
-+      }
-+
-+      /* source pad */
-+      ulink.source.entity = source->entity->info.id;
-+      ulink.source.index = source->index;
-+      ulink.source.flags = MEDIA_PAD_FL_SOURCE;
-+
-+      /* sink pad */
-+      ulink.sink.entity = sink->entity->info.id;
-+      ulink.sink.index = sink->index;
-+      ulink.sink.flags = MEDIA_PAD_FL_SINK;
-+
-+      ulink.flags = flags | (link->flags & MEDIA_LNK_FL_IMMUTABLE);
-+
-+      ret = ioctl(media->fd, MEDIA_IOC_SETUP_LINK, &ulink);
-+      if (ret == -1) {
-+              ret = -errno;
-+              media_dbg(media, "%s: Unable to setup link (%s)\n",
-+                        __func__, strerror(errno));
-+              goto done;
-+      }
-+
-+      link->flags = ulink.flags;
-+      link->twin->flags = ulink.flags;
-+
-+      ret = 0;
-+
-+done:
-+      return ret;
-+}
-+
-+int media_reset_links(struct media_device *media)
-+{
-+      unsigned int i, j;
-+      int ret;
-+
-+      for (i = 0; i < media->entities_count; ++i) {
-+              struct media_entity *entity = &media->entities[i];
-+
-+              for (j = 0; j < entity->num_links; j++) {
-+                      struct media_link *link = &entity->links[j];
-+
-+                      if (link->flags & MEDIA_LNK_FL_IMMUTABLE ||
-+                          link->source->entity != entity)
-+                              continue;
-+
-+                      ret = media_setup_link(media, link->source, link->sink,
-+                                             link->flags & ~MEDIA_LNK_FL_ENABLED);
-+                      if (ret < 0)
-+                              return ret;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+/* -----------------------------------------------------------------------------
-+ * Entities, pads and links enumeration
-+ */
-+
-+static struct media_link *media_entity_add_link(struct media_entity *entity)
-+{
-+      if (entity->num_links >= entity->max_links) {
-+              struct media_link *links = entity->links;
-+              unsigned int max_links = entity->max_links * 2;
-+              unsigned int i;
-+
-+              links = realloc(links, max_links * sizeof *links);
-+              if (links == NULL)
-+                      return NULL;
-+
-+              for (i = 0; i < entity->num_links; ++i)
-+                      links[i].twin->twin = &links[i];
-+
-+              entity->max_links = max_links;
-+              entity->links = links;
-+      }
-+
-+      return &entity->links[entity->num_links++];
-+}
-+
-+static int media_enum_links(struct media_device *media)
-+{
-+      __u32 id;
-+      int ret = 0;
-+
-+      for (id = 1; id <= media->entities_count; id++) {
-+              struct media_entity *entity = &media->entities[id - 1];
-+              struct media_links_enum links;
-+              unsigned int i;
-+
-+              links.entity = entity->info.id;
-+              links.pads = calloc(entity->info.pads, sizeof(struct media_pad_desc));
-+              links.links = calloc(entity->info.links, sizeof(struct media_link_desc));
-+
-+              if (ioctl(media->fd, MEDIA_IOC_ENUM_LINKS, &links) < 0) {
-+                      ret = -errno;
-+                      media_dbg(media,
-+                                "%s: Unable to enumerate pads and links (%s).\n",
-+                                __func__, strerror(errno));
-+                      free(links.pads);
-+                      free(links.links);
-+                      return ret;
-+              }
-+
-+              for (i = 0; i < entity->info.pads; ++i) {
-+                      entity->pads[i].entity = entity;
-+                      entity->pads[i].index = links.pads[i].index;
-+                      entity->pads[i].flags = links.pads[i].flags;
-+              }
-+
-+              for (i = 0; i < entity->info.links; ++i) {
-+                      struct media_link_desc *link = &links.links[i];
-+                      struct media_link *fwdlink;
-+                      struct media_link *backlink;
-+                      struct media_entity *source;
-+                      struct media_entity *sink;
-+
-+                      source = media_get_entity_by_id(media, link->source.entity);
-+                      sink = media_get_entity_by_id(media, link->sink.entity);
-+
-+                      if (source == NULL || sink == NULL) {
-+                              media_dbg(media,
-+                                        "WARNING entity %u link %u from %u/%u to %u/%u is invalid!\n",
-+                                        id, i, link->source.entity,
-+                                        link->source.index,
-+                                        link->sink.entity,
-+                                        link->sink.index);
-+                              ret = -EINVAL;
-+                      } else {
-+                              fwdlink = media_entity_add_link(source);
-+                              fwdlink->source = &source->pads[link->source.index];
-+                              fwdlink->sink = &sink->pads[link->sink.index];
-+                              fwdlink->flags = link->flags;
-+
-+                              backlink = media_entity_add_link(sink);
-+                              backlink->source = &source->pads[link->source.index];
-+                              backlink->sink = &sink->pads[link->sink.index];
-+                              backlink->flags = link->flags;
-+
-+                              fwdlink->twin = backlink;
-+                              backlink->twin = fwdlink;
-+                      }
-+              }
-+
-+              free(links.pads);
-+              free(links.links);
-+      }
-+
-+      return ret;
-+}
-+
-+#ifdef HAVE_LIBUDEV
-+
-+#include <libudev.h>
-+
-+static inline int media_udev_open(struct udev **udev)
-+{
-+      *udev = udev_new();
-+      if (*udev == NULL)
-+              return -ENOMEM;
-+      return 0;
-+}
-+
-+static inline void media_udev_close(struct udev *udev)
-+{
-+      if (udev != NULL)
-+              udev_unref(udev);
-+}
-+
-+static int media_get_devname_udev(struct udev *udev,
-+              struct media_entity *entity)
-+{
-+      struct udev_device *device;
-+      dev_t devnum;
-+      const char *p;
-+      int ret = -ENODEV;
-+
-+      if (udev == NULL)
-+              return -EINVAL;
-+
-+      devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor);
-+      media_dbg(entity->media, "looking up device: %u:%u\n",
-+                major(devnum), minor(devnum));
-+      device = udev_device_new_from_devnum(udev, 'c', devnum);
-+      if (device) {
-+              p = udev_device_get_devnode(device);
-+              if (p) {
-+                      strncpy(entity->devname, p, sizeof(entity->devname));
-+                      entity->devname[sizeof(entity->devname) - 1] = '\0';
-+              }
-+              ret = 0;
-+      }
-+
-+      udev_device_unref(device);
-+
-+      return ret;
-+}
-+
-+#else /* HAVE_LIBUDEV */
-+
-+struct udev;
-+
-+static inline int media_udev_open(struct udev **udev) { return 0; }
-+
-+static inline void media_udev_close(struct udev *udev) { }
-+
-+static inline int media_get_devname_udev(struct udev *udev,
-+              struct media_entity *entity)
-+{
-+      return -ENOTSUP;
-+}
-+
-+#endif        /* HAVE_LIBUDEV */
-+
-+static int media_get_devname_sysfs(struct media_entity *entity)
-+{
-+      struct stat devstat;
-+      char devname[32];
-+      char sysname[32];
-+      char target[1024];
-+      char *p;
-+      int ret;
-+
-+      sprintf(sysname, "/sys/dev/char/%u:%u", entity->info.v4l.major,
-+              entity->info.v4l.minor);
-+      ret = readlink(sysname, target, sizeof(target) - 1);
-+      if (ret < 0)
-+              return -errno;
-+
-+      target[ret] = '\0';
-+      p = strrchr(target, '/');
-+      if (p == NULL)
-+              return -EINVAL;
-+
-+      sprintf(devname, "/dev/%s", p + 1);
-+      ret = stat(devname, &devstat);
-+      if (ret < 0)
-+              return -errno;
-+
-+      /* Sanity check: udev might have reordered the device nodes.
-+       * Make sure the major/minor match. We should really use
-+       * libudev.
-+       */
-+      if (major(devstat.st_rdev) == entity->info.v4l.major &&
-+          minor(devstat.st_rdev) == entity->info.v4l.minor)
-+              strcpy(entity->devname, devname);
-+
-+      return 0;
-+}
-+
-+static int media_enum_entities(struct media_device *media)
-+{
-+      struct media_entity *entity;
-+      struct udev *udev;
-+      unsigned int size;
-+      __u32 id;
-+      int ret;
-+
-+      ret = media_udev_open(&udev);
-+      if (ret < 0)
-+              media_dbg(media, "Can't get udev context\n");
-+
-+      for (id = 0, ret = 0; ; id = entity->info.id) {
-+              size = (media->entities_count + 1) * sizeof(*media->entities);
-+              media->entities = realloc(media->entities, size);
-+
-+              entity = &media->entities[media->entities_count];
-+              memset(entity, 0, sizeof(*entity));
-+              entity->fd = -1;
-+              entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
-+              entity->media = media;
-+
-+              ret = ioctl(media->fd, MEDIA_IOC_ENUM_ENTITIES, &entity->info);
-+              if (ret < 0) {
-+                      ret = errno != EINVAL ? -errno : 0;
-+                      break;
-+              }
-+
-+              /* Number of links (for outbound links) plus number of pads (for
-+               * inbound links) is a good safe initial estimate of the total
-+               * number of links.
-+               */
-+              entity->max_links = entity->info.pads + entity->info.links;
-+
-+              entity->pads = malloc(entity->info.pads * sizeof(*entity->pads));
-+              entity->links = malloc(entity->max_links * sizeof(*entity->links));
-+              if (entity->pads == NULL || entity->links == NULL) {
-+                      ret = -ENOMEM;
-+                      break;
-+              }
-+
-+              media->entities_count++;
-+
-+              if (entity->info.flags & MEDIA_ENT_FL_DEFAULT) {
-+                      switch (entity->info.type) {
-+                      case MEDIA_ENT_T_DEVNODE_V4L:
-+                              media->def.v4l = entity;
-+                              break;
-+                      case MEDIA_ENT_T_DEVNODE_FB:
-+                              media->def.fb = entity;
-+                              break;
-+                      case MEDIA_ENT_T_DEVNODE_ALSA:
-+                              media->def.alsa = entity;
-+                              break;
-+                      case MEDIA_ENT_T_DEVNODE_DVB:
-+                              media->def.dvb = entity;
-+                              break;
-+                      }
-+              }
-+
-+              /* Find the corresponding device name. */
-+              if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE &&
-+                  media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV)
-+                      continue;
-+
-+              /* Try to get the device name via udev */
-+              if (!media_get_devname_udev(udev, entity))
-+                      continue;
-+
-+              /* Fall back to get the device name via sysfs */
-+              media_get_devname_sysfs(entity);
-+      }
-+
-+      media_udev_close(udev);
-+      return ret;
-+}
-+
-+int media_device_enumerate(struct media_device *media)
-+{
-+      int ret;
-+
-+      if (media->entities)
-+              return 0;
-+
-+      ret = media_device_open(media);
-+      if (ret < 0)
-+              return ret;
-+
-+      ret = ioctl(media->fd, MEDIA_IOC_DEVICE_INFO, &media->info);
-+      if (ret < 0) {
-+              ret = -errno;
-+              media_dbg(media, "%s: Unable to retrieve media device "
-+                        "information for device %s (%s)\n", __func__,
-+                        media->devnode, strerror(errno));
-+              goto done;
-+      }
-+
-+      media_dbg(media, "Enumerating entities\n");
-+
-+      ret = media_enum_entities(media);
-+      if (ret < 0) {
-+              media_dbg(media,
-+                        "%s: Unable to enumerate entities for device %s (%s)\n",
-+                        __func__, media->devnode, strerror(-ret));
-+              goto done;
-+      }
-+
-+      media_dbg(media, "Found %u entities\n", media->entities_count);
-+      media_dbg(media, "Enumerating pads and links\n");
-+
-+      ret = media_enum_links(media);
-+      if (ret < 0) {
-+              media_dbg(media,
-+                        "%s: Unable to enumerate pads and linksfor device %s\n",
-+                        __func__, media->devnode);
-+              goto done;
-+      }
-+
-+      ret = 0;
-+
-+done:
-+      return ret;
-+}
-+
-+/* -----------------------------------------------------------------------------
-+ * Create/destroy
-+ */
-+
-+static void media_debug_default(void *ptr, ...)
-+{
-+}
-+
-+void media_debug_set_handler(struct media_device *media,
-+                           void (*debug_handler)(void *, ...),
-+                           void *debug_priv)
-+{
-+      if (debug_handler) {
-+              media->debug_handler = debug_handler;
-+              media->debug_priv = debug_priv;
-+      } else {
-+              media->debug_handler = media_debug_default;
-+              media->debug_priv = NULL;
-+      }
-+}
-+
-+static struct media_device *__media_device_new(void)
-+{
-+      struct media_device *media;
-+
-+      media = calloc(1, sizeof(*media));
-+      if (media == NULL)
-+              return NULL;
-+
-+      media->fd = -1;
-+      media->refcount = 1;
-+
-+      media_debug_set_handler(media, NULL, NULL);
-+
-+      return media;
-+}
-+
-+struct media_device *media_device_new(const char *devnode)
-+{
-+      struct media_device *media;
-+
-+      media = __media_device_new();
-+      if (media == NULL)
-+              return NULL;
-+
-+      media->devnode = strdup(devnode);
-+      if (media->devnode == NULL) {
-+              media_device_unref(media);
-+              return NULL;
-+      }
-+
-+      return media;
-+}
-+
-+struct media_device *media_device_new_emulated(struct media_device_info *info)
-+{
-+      struct media_device *media;
-+
-+      media = __media_device_new();
-+      if (media == NULL)
-+              return NULL;
-+
-+      media->info = *info;
-+
-+      return media;
-+}
-+
-+struct media_device *media_device_ref(struct media_device *media)
-+{
-+      media->refcount++;
-+      return media;
-+}
-+
-+void media_device_unref(struct media_device *media)
-+{
-+      unsigned int i;
-+
-+      media->refcount--;
-+      if (media->refcount > 0)
-+              return;
-+
-+      for (i = 0; i < media->entities_count; ++i) {
-+              struct media_entity *entity = &media->entities[i];
-+
-+              free(entity->pads);
-+              free(entity->links);
-+              if (entity->fd != -1)
-+                      close(entity->fd);
-+      }
-+
-+      free(media->entities);
-+      free(media->devnode);
-+      free(media);
-+}
-+
-+int media_device_add_entity(struct media_device *media,
-+                          const struct media_entity_desc *desc,
-+                          const char *devnode)
-+{
-+      struct media_entity **defent = NULL;
-+      struct media_entity *entity;
-+      unsigned int size;
-+
-+      size = (media->entities_count + 1) * sizeof(*media->entities);
-+      entity = realloc(media->entities, size);
-+      if (entity == NULL)
-+              return -ENOMEM;
-+
-+      media->entities = entity;
-+      media->entities_count++;
-+
-+      entity = &media->entities[media->entities_count - 1];
-+      memset(entity, 0, sizeof *entity);
-+
-+      entity->fd = -1;
-+      entity->media = media;
-+      strncpy(entity->devname, devnode, sizeof entity->devname);
-+      entity->devname[sizeof entity->devname - 1] = '\0';
-+
-+      entity->info.id = 0;
-+      entity->info.type = desc->type;
-+      entity->info.flags = 0;
-+      memcpy(entity->info.name, desc->name, sizeof entity->info.name);
-+
-+      switch (entity->info.type) {
-+      case MEDIA_ENT_T_DEVNODE_V4L:
-+              defent = &media->def.v4l;
-+              entity->info.v4l = desc->v4l;
-+              break;
-+      case MEDIA_ENT_T_DEVNODE_FB:
-+              defent = &media->def.fb;
-+              entity->info.fb = desc->fb;
-+              break;
-+      case MEDIA_ENT_T_DEVNODE_ALSA:
-+              defent = &media->def.alsa;
-+              entity->info.alsa = desc->alsa;
-+              break;
-+      case MEDIA_ENT_T_DEVNODE_DVB:
-+              defent = &media->def.dvb;
-+              entity->info.dvb = desc->dvb;
-+              break;
-+      }
-+
-+      if (desc->flags & MEDIA_ENT_FL_DEFAULT) {
-+              entity->info.flags |= MEDIA_ENT_FL_DEFAULT;
-+              if (defent)
-+                      *defent = entity;
-+      }
-+
-+      return 0;
-+}
-+
-+struct media_pad *media_parse_pad(struct media_device *media,
-+                                const char *p, char **endp)
-+{
-+      unsigned int entity_id, pad;
-+      struct media_entity *entity;
-+      char *end;
-+
-+      /* endp can be NULL. To avoid spreading NULL checks across the function,
-+       * set endp to &end in that case.
-+       */
-+      if (endp == NULL)
-+              endp = &end;
-+
-+      for (; isspace(*p); ++p);
-+
-+      if (*p == '"' || *p == '\'') {
-+              for (end = (char *)p + 1; *end && *end != '"' && *end != '\''; ++end);
-+              if (*end != '"' && *end != '\'') {
-+                      media_dbg(media, "missing matching '\"'\n");
-+                      *endp = end;
-+                      return NULL;
-+              }
-+
-+              entity = media_get_entity_by_name(media, p + 1, end - p - 1);
-+              if (entity == NULL) {
-+                      media_dbg(media, "no such entity \"%.*s\"\n", end - p - 1, p + 1);
-+                      *endp = (char *)p + 1;
-+                      return NULL;
-+              }
-+
-+              ++end;
-+      } else {
-+              entity_id = strtoul(p, &end, 10);
-+              entity = media_get_entity_by_id(media, entity_id);
-+              if (entity == NULL) {
-+                      media_dbg(media, "no such entity %d\n", entity_id);
-+                      *endp = (char *)p;
-+                      return NULL;
-+              }
-+      }
-+      for (; isspace(*end); ++end);
-+
-+      if (*end != ':') {
-+              media_dbg(media, "Expected ':'\n", *end);
-+              *endp = end;
-+              return NULL;
-+      }
-+
-+      for (p = end + 1; isspace(*p); ++p);
-+
-+      pad = strtoul(p, &end, 10);
-+
-+      if (pad >= entity->info.pads) {
-+              media_dbg(media, "No pad '%d' on entity \"%s\". Maximum pad number is %d\n",
-+                              pad, entity->info.name, entity->info.pads - 1);
-+              *endp = (char *)p;
-+              return NULL;
-+      }
-+
-+      for (p = end; isspace(*p); ++p);
-+      *endp = (char *)p;
-+
-+      return &entity->pads[pad];
-+}
-+
-+struct media_link *media_parse_link(struct media_device *media,
-+                                  const char *p, char **endp)
-+{
-+      struct media_link *link;
-+      struct media_pad *source;
-+      struct media_pad *sink;
-+      unsigned int i;
-+      char *end;
-+
-+      source = media_parse_pad(media, p, &end);
-+      if (source == NULL) {
-+              *endp = end;
-+              return NULL;
-+      }
-+
-+      if (end[0] != '-' || end[1] != '>') {
-+              *endp = end;
-+              media_dbg(media, "Expected '->'\n");
-+              return NULL;
-+      }
-+
-+      p = end + 2;
-+
-+      sink = media_parse_pad(media, p, &end);
-+      if (sink == NULL) {
-+              *endp = end;
-+              return NULL;
-+      }
-+
-+      *endp = end;
-+
-+      for (i = 0; i < source->entity->num_links; i++) {
-+              link = &source->entity->links[i];
-+
-+              if (link->source == source && link->sink == sink)
-+                      return link;
-+      }
-+
-+      media_dbg(media, "No link between \"%s\":%d and \"%s\":%d\n",
-+                      source->entity->info.name, source->index,
-+                      sink->entity->info.name, sink->index);
-+      return NULL;
-+}
-+
-+int media_parse_setup_link(struct media_device *media,
-+                         const char *p, char **endp)
-+{
-+      struct media_link *link;
-+      __u32 flags;
-+      char *end;
-+
-+      link = media_parse_link(media, p, &end);
-+      if (link == NULL) {
-+              media_dbg(media,
-+                        "%s: Unable to parse link\n", __func__);
-+              *endp = end;
-+              return -EINVAL;
-+      }
-+
-+      p = end;
-+      if (*p++ != '[') {
-+              media_dbg(media, "Unable to parse link flags: expected '['.\n");
-+              *endp = (char *)p - 1;
-+              return -EINVAL;
-+      }
-+
-+      flags = strtoul(p, &end, 10);
-+      for (p = end; isspace(*p); p++);
-+      if (*p++ != ']') {
-+              media_dbg(media, "Unable to parse link flags: expected ']'.\n");
-+              *endp = (char *)p - 1;
-+              return -EINVAL;
-+      }
-+
-+      for (; isspace(*p); p++);
-+      *endp = (char *)p;
-+
-+      media_dbg(media,
-+                "Setting up link %u:%u -> %u:%u [%u]\n",
-+                link->source->entity->info.id, link->source->index,
-+                link->sink->entity->info.id, link->sink->index,
-+                flags);
-+
-+      return media_setup_link(media, link->source, link->sink, flags);
-+}
-+
-+void media_print_streampos(struct media_device *media, const char *p,
-+                         const char *end)
-+{
-+      int pos;
-+
-+      pos = end - p + 1;
-+
-+      if (pos < 0)
-+              pos = 0;
-+      if (pos > strlen(p))
-+              pos = strlen(p);
-+
-+      media_dbg(media, "\n");
-+      media_dbg(media, " %s\n", p);
-+      media_dbg(media, " %*s\n", pos, "^");
-+}
-+
-+int media_parse_setup_links(struct media_device *media, const char *p)
-+{
-+      char *end;
-+      int ret;
-+
-+      do {
-+              ret = media_parse_setup_link(media, p, &end);
-+              if (ret < 0) {
-+                      media_print_streampos(media, p, end);
-+                      return ret;
-+              }
-+
-+              p = end + 1;
-+      } while (*end == ',');
-+
-+      return *end ? -EINVAL : 0;
-+}
-diff --git a/libweston/media-ctl/libv4l2subdev.c b/libweston/media-ctl/libv4l2subdev.c
-new file mode 100644
-index 0000000..4ede4fa
---- /dev/null
-+++ b/libweston/media-ctl/libv4l2subdev.c
-@@ -0,0 +1,759 @@
-+/*
-+ * V4L2 subdev interface library
-+ *
-+ * Copyright (C) 2010-2014 Ideas on board SPRL
-+ *
-+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU Lesser General Public License as published
-+ * by the Free Software Foundation; either version 2.1 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program 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 Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <sys/ioctl.h>
-+#include <sys/stat.h>
-+#include <sys/types.h>
-+
-+#include <ctype.h>
-+#include <errno.h>
-+#include <fcntl.h>
-+#include <stdbool.h>
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <unistd.h>
-+
-+#include <linux/v4l2-subdev.h>
-+
-+#include "mediactl.h"
-+#include "mediactl-priv.h"
-+#include "tools.h"
-+#include "v4l2subdev.h"
-+
-+int v4l2_subdev_open(struct media_entity *entity)
-+{
-+      if (entity->fd != -1)
-+              return 0;
-+
-+      entity->fd = open(entity->devname, O_RDWR);
-+      if (entity->fd == -1) {
-+              int ret = -errno;
-+              media_dbg(entity->media,
-+                        "%s: Failed to open subdev device node %s\n", __func__,
-+                        entity->devname);
-+              return ret;
-+      }
-+
-+      return 0;
-+}
-+
-+void v4l2_subdev_close(struct media_entity *entity)
-+{
-+      close(entity->fd);
-+      entity->fd = -1;
-+}
-+
-+int v4l2_subdev_get_format(struct media_entity *entity,
-+      struct v4l2_mbus_framefmt *format, unsigned int pad,
-+      enum v4l2_subdev_format_whence which)
-+{
-+      struct v4l2_subdev_format fmt;
-+      int ret;
-+
-+      ret = v4l2_subdev_open(entity);
-+      if (ret < 0)
-+              return ret;
-+
-+      memset(&fmt, 0, sizeof(fmt));
-+      fmt.pad = pad;
-+      fmt.which = which;
-+
-+      ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FMT, &fmt);
-+      if (ret < 0)
-+              return -errno;
-+
-+      *format = fmt.format;
-+      return 0;
-+}
-+
-+int v4l2_subdev_set_format(struct media_entity *entity,
-+      struct v4l2_mbus_framefmt *format, unsigned int pad,
-+      enum v4l2_subdev_format_whence which)
-+{
-+      struct v4l2_subdev_format fmt;
-+      int ret;
-+
-+      ret = v4l2_subdev_open(entity);
-+      if (ret < 0)
-+              return ret;
-+
-+      memset(&fmt, 0, sizeof(fmt));
-+      fmt.pad = pad;
-+      fmt.which = which;
-+      fmt.format = *format;
-+
-+      ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FMT, &fmt);
-+      if (ret < 0)
-+              return -errno;
-+
-+      *format = fmt.format;
-+      return 0;
-+}
-+
-+int v4l2_subdev_get_selection(struct media_entity *entity,
-+      struct v4l2_rect *rect, unsigned int pad, unsigned int target,
-+      enum v4l2_subdev_format_whence which)
-+{
-+      union {
-+              struct v4l2_subdev_selection sel;
-+              struct v4l2_subdev_crop crop;
-+      } u;
-+      int ret;
-+
-+      ret = v4l2_subdev_open(entity);
-+      if (ret < 0)
-+              return ret;
-+
-+      memset(&u.sel, 0, sizeof(u.sel));
-+      u.sel.pad = pad;
-+      u.sel.target = target;
-+      u.sel.which = which;
-+
-+      ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_SELECTION, &u.sel);
-+      if (ret >= 0) {
-+              *rect = u.sel.r;
-+              return 0;
-+      }
-+      if (errno != ENOTTY || target != V4L2_SEL_TGT_CROP)
-+              return -errno;
-+
-+      memset(&u.crop, 0, sizeof(u.crop));
-+      u.crop.pad = pad;
-+      u.crop.which = which;
-+
-+      ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_CROP, &u.crop);
-+      if (ret < 0)
-+              return -errno;
-+
-+      *rect = u.crop.rect;
-+      return 0;
-+}
-+
-+int v4l2_subdev_set_selection(struct media_entity *entity,
-+      struct v4l2_rect *rect, unsigned int pad, unsigned int target,
-+      enum v4l2_subdev_format_whence which)
-+{
-+      union {
-+              struct v4l2_subdev_selection sel;
-+              struct v4l2_subdev_crop crop;
-+      } u;
-+      int ret;
-+
-+      ret = v4l2_subdev_open(entity);
-+      if (ret < 0)
-+              return ret;
-+
-+      memset(&u.sel, 0, sizeof(u.sel));
-+      u.sel.pad = pad;
-+      u.sel.target = target;
-+      u.sel.which = which;
-+      u.sel.r = *rect;
-+
-+      ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_SELECTION, &u.sel);
-+      if (ret >= 0) {
-+              *rect = u.sel.r;
-+              return 0;
-+      }
-+      if (errno != ENOTTY || target != V4L2_SEL_TGT_CROP)
-+              return -errno;
-+
-+      memset(&u.crop, 0, sizeof(u.crop));
-+      u.crop.pad = pad;
-+      u.crop.which = which;
-+      u.crop.rect = *rect;
-+
-+      ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_CROP, &u.crop);
-+      if (ret < 0)
-+              return -errno;
-+
-+      *rect = u.crop.rect;
-+      return 0;
-+}
-+
-+#if 0
-+int v4l2_subdev_get_dv_timings_caps(struct media_entity *entity,
-+      struct v4l2_dv_timings_cap *caps)
-+{
-+      unsigned int pad = caps->pad;
-+      int ret;
-+
-+      ret = v4l2_subdev_open(entity);
-+      if (ret < 0)
-+              return ret;
-+
-+      memset(caps, 0, sizeof(*caps));
-+      caps->pad = pad;
-+
-+      ret = ioctl(entity->fd, VIDIOC_SUBDEV_DV_TIMINGS_CAP, caps);
-+      if (ret < 0)
-+              return -errno;
-+
-+      return 0;
-+}
-+
-+int v4l2_subdev_query_dv_timings(struct media_entity *entity,
-+      struct v4l2_dv_timings *timings)
-+{
-+      int ret;
-+
-+      ret = v4l2_subdev_open(entity);
-+      if (ret < 0)
-+              return ret;
-+
-+      memset(timings, 0, sizeof(*timings));
-+
-+      ret = ioctl(entity->fd, VIDIOC_SUBDEV_QUERY_DV_TIMINGS, timings);
-+      if (ret < 0)
-+              return -errno;
-+
-+      return 0;
-+}
-+
-+int v4l2_subdev_get_dv_timings(struct media_entity *entity,
-+      struct v4l2_dv_timings *timings)
-+{
-+      int ret;
-+
-+      ret = v4l2_subdev_open(entity);
-+      if (ret < 0)
-+              return ret;
-+
-+      memset(timings, 0, sizeof(*timings));
-+
-+      ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_DV_TIMINGS, timings);
-+      if (ret < 0)
-+              return -errno;
-+
-+      return 0;
-+}
-+
-+int v4l2_subdev_set_dv_timings(struct media_entity *entity,
-+      struct v4l2_dv_timings *timings)
-+{
-+      int ret;
-+
-+      ret = v4l2_subdev_open(entity);
-+      if (ret < 0)
-+              return ret;
-+
-+      ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_DV_TIMINGS, timings);
-+      if (ret < 0)
-+              return -errno;
-+
-+      return 0;
-+}
-+#endif
-+
-+int v4l2_subdev_get_frame_interval(struct media_entity *entity,
-+                                 struct v4l2_fract *interval)
-+{
-+      struct v4l2_subdev_frame_interval ival;
-+      int ret;
-+
-+      ret = v4l2_subdev_open(entity);
-+      if (ret < 0)
-+              return ret;
-+
-+      memset(&ival, 0, sizeof(ival));
-+
-+      ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &ival);
-+      if (ret < 0)
-+              return -errno;
-+
-+      *interval = ival.interval;
-+      return 0;
-+}
-+
-+int v4l2_subdev_set_frame_interval(struct media_entity *entity,
-+                                 struct v4l2_fract *interval)
-+{
-+      struct v4l2_subdev_frame_interval ival;
-+      int ret;
-+
-+      ret = v4l2_subdev_open(entity);
-+      if (ret < 0)
-+              return ret;
-+
-+      memset(&ival, 0, sizeof(ival));
-+      ival.interval = *interval;
-+
-+      ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &ival);
-+      if (ret < 0)
-+              return -errno;
-+
-+      *interval = ival.interval;
-+      return 0;
-+}
-+
-+static int v4l2_subdev_parse_format(struct media_device *media,
-+                                  struct v4l2_mbus_framefmt *format,
-+                                  const char *p, char **endp)
-+{
-+      enum v4l2_mbus_pixelcode code;
-+      unsigned int width, height;
-+      char *end;
-+
-+      /*
-+       * Compatibility with the old syntax: consider space as valid
-+       * separator between the media bus pixel code and the size.
-+       */
-+      for (; isspace(*p); ++p);
-+      for (end = (char *)p;
-+           *end != '/' && *end != ' ' && *end != '\0'; ++end);
-+
-+      code = v4l2_subdev_string_to_pixelcode(p, end - p);
-+      if (code == (enum v4l2_mbus_pixelcode)-1) {
-+              media_dbg(media, "Invalid pixel code '%.*s'\n", end - p, p);
-+              return -EINVAL;
-+      }
-+
-+      p = end + 1;
-+      width = strtoul(p, &end, 10);
-+      if (*end != 'x') {
-+              media_dbg(media, "Expected 'x'\n");
-+              return -EINVAL;
-+      }
-+
-+      p = end + 1;
-+      height = strtoul(p, &end, 10);
-+      *endp = end;
-+
-+      memset(format, 0, sizeof(*format));
-+      format->width = width;
-+      format->height = height;
-+      format->code = code;
-+
-+      return 0;
-+}
-+
-+static int v4l2_subdev_parse_rectangle(struct media_device *media,
-+                                     struct v4l2_rect *r, const char *p,
-+                                     char **endp)
-+{
-+      char *end;
-+
-+      if (*p++ != '(') {
-+              media_dbg(media, "Expected '('\n");
-+              *endp = (char *)p - 1;
-+              return -EINVAL;
-+      }
-+
-+      r->left = strtoul(p, &end, 10);
-+      if (*end != ',') {
-+              media_dbg(media, "Expected ','\n");
-+              *endp = end;
-+              return -EINVAL;
-+      }
-+
-+      p = end + 1;
-+      r->top = strtoul(p, &end, 10);
-+      if (*end++ != ')') {
-+              media_dbg(media, "Expected ')'\n");
-+              *endp = end - 1;
-+              return -EINVAL;
-+      }
-+      if (*end != '/') {
-+              media_dbg(media, "Expected '/'\n");
-+              *endp = end;
-+              return -EINVAL;
-+      }
-+
-+      p = end + 1;
-+      r->width = strtoul(p, &end, 10);
-+      if (*end != 'x') {
-+              media_dbg(media, "Expected 'x'\n");
-+              *endp = end;
-+              return -EINVAL;
-+      }
-+
-+      p = end + 1;
-+      r->height = strtoul(p, &end, 10);
-+      *endp = end;
-+
-+      return 0;
-+}
-+
-+static int v4l2_subdev_parse_frame_interval(struct media_device *media,
-+                                          struct v4l2_fract *interval,
-+                                          const char *p, char **endp)
-+{
-+      char *end;
-+
-+      for (; isspace(*p); ++p);
-+
-+      interval->numerator = strtoul(p, &end, 10);
-+
-+      for (p = end; isspace(*p); ++p);
-+      if (*p++ != '/') {
-+              media_dbg(media, "Expected '/'\n");
-+              *endp = (char *)p - 1;
-+              return -EINVAL;
-+      }
-+
-+      for (; isspace(*p); ++p);
-+      interval->denominator = strtoul(p, &end, 10);
-+
-+      *endp = end;
-+      return 0;
-+}
-+
-+/*
-+ * The debate over whether this function should be named icanhasstr() instead
-+ * has been strong and heated. If you feel like this would be an important
-+ * change, patches are welcome (or not).
-+ */
-+static bool strhazit(const char *str, const char **p)
-+{
-+      int len = strlen(str);
-+
-+      if (strncmp(str, *p, len))
-+              return false;
-+
-+      for (*p += len; isspace(**p); ++*p);
-+      return true;
-+}
-+
-+static struct media_pad *v4l2_subdev_parse_pad_format(
-+      struct media_device *media, struct v4l2_mbus_framefmt *format,
-+      struct v4l2_rect *crop, struct v4l2_rect *compose,
-+      struct v4l2_fract *interval, const char *p, char **endp)
-+{
-+      struct media_pad *pad;
-+      bool first;
-+      char *end;
-+      int ret;
-+
-+      for (; isspace(*p); ++p);
-+
-+      pad = media_parse_pad(media, p, &end);
-+      if (pad == NULL) {
-+              *endp = end;
-+              return NULL;
-+      }
-+
-+      for (p = end; isspace(*p); ++p);
-+      if (*p++ != '[') {
-+              media_dbg(media, "Expected '['\n");
-+              *endp = (char *)p - 1;
-+              return NULL;
-+      }
-+
-+      for (first = true; ; first = false) {
-+              for (; isspace(*p); p++);
-+
-+              /*
-+               * Backward compatibility: if the first property starts with an
-+               * uppercase later, process it as a format description.
-+               */
-+              if (strhazit("fmt:", &p) || (first && isupper(*p))) {
-+                      ret = v4l2_subdev_parse_format(media, format, p, &end);
-+                      if (ret < 0) {
-+                              *endp = end;
-+                              return NULL;
-+                      }
-+
-+                      p = end;
-+                      continue;
-+              }
-+
-+              /*
-+               * Backward compatibility: crop rectangles can be specified
-+               * implicitly without the 'crop:' property name.
-+               */
-+              if (strhazit("crop:", &p) || *p == '(') {
-+                      ret = v4l2_subdev_parse_rectangle(media, crop, p, &end);
-+                      if (ret < 0) {
-+                              *endp = end;
-+                              return NULL;
-+                      }
-+
-+                      p = end;
-+                      continue;
-+              }
-+
-+              if (strhazit("compose:", &p)) {
-+                      ret = v4l2_subdev_parse_rectangle(media, compose, p, &end);
-+                      if (ret < 0) {
-+                              *endp = end;
-+                              return NULL;
-+                      }
-+
-+                      for (p = end; isspace(*p); p++);
-+                      continue;
-+              }
-+
-+              if (*p == '@') {
-+                      ret = v4l2_subdev_parse_frame_interval(media, interval, ++p, &end);
-+                      if (ret < 0) {
-+                              *endp = end;
-+                              return NULL;
-+                      }
-+
-+                      p = end;
-+                      continue;
-+              }
-+
-+              break;
-+      }
-+
-+      if (*p != ']') {
-+              media_dbg(media, "Expected ']'\n");
-+              *endp = (char *)p;
-+              return NULL;
-+      }
-+
-+      *endp = (char *)p + 1;
-+      return pad;
-+}
-+
-+static int set_format(struct media_pad *pad,
-+                    struct v4l2_mbus_framefmt *format)
-+{
-+      int ret;
-+
-+      if (format->width == 0 || format->height == 0)
-+              return 0;
-+
-+      media_dbg(pad->entity->media,
-+                "Setting up format %s %ux%u on pad %s/%u\n",
-+                v4l2_subdev_pixelcode_to_string(format->code),
-+                format->width, format->height,
-+                pad->entity->info.name, pad->index);
-+
-+      ret = v4l2_subdev_set_format(pad->entity, format, pad->index,
-+                                   V4L2_SUBDEV_FORMAT_ACTIVE);
-+      if (ret < 0) {
-+              media_dbg(pad->entity->media,
-+                        "Unable to set format: %s (%d)\n",
-+                        strerror(-ret), ret);
-+              return ret;
-+      }
-+
-+      media_dbg(pad->entity->media,
-+                "Format set: %s %ux%u\n",
-+                v4l2_subdev_pixelcode_to_string(format->code),
-+                format->width, format->height);
-+
-+      return 0;
-+}
-+
-+static int set_selection(struct media_pad *pad, unsigned int target,
-+                       struct v4l2_rect *rect)
-+{
-+      int ret;
-+
-+      if (rect->left == -1 || rect->top == -1)
-+              return 0;
-+
-+      media_dbg(pad->entity->media,
-+                "Setting up selection target %u rectangle (%u,%u)/%ux%u on pad %s/%u\n",
-+                target, rect->left, rect->top, rect->width, rect->height,
-+                pad->entity->info.name, pad->index);
-+
-+      ret = v4l2_subdev_set_selection(pad->entity, rect, pad->index,
-+                                      target, V4L2_SUBDEV_FORMAT_ACTIVE);
-+      if (ret < 0) {
-+              media_dbg(pad->entity->media,
-+                        "Unable to set selection rectangle: %s (%d)\n",
-+                        strerror(-ret), ret);
-+              return ret;
-+      }
-+
-+      media_dbg(pad->entity->media,
-+                "Selection rectangle set: (%u,%u)/%ux%u\n",
-+                rect->left, rect->top, rect->width, rect->height);
-+
-+      return 0;
-+}
-+
-+static int set_frame_interval(struct media_entity *entity,
-+                            struct v4l2_fract *interval)
-+{
-+      int ret;
-+
-+      if (interval->numerator == 0)
-+              return 0;
-+
-+      media_dbg(entity->media,
-+                "Setting up frame interval %u/%u on entity %s\n",
-+                interval->numerator, interval->denominator,
-+                entity->info.name);
-+
-+      ret = v4l2_subdev_set_frame_interval(entity, interval);
-+      if (ret < 0) {
-+              media_dbg(entity->media,
-+                        "Unable to set frame interval: %s (%d)",
-+                        strerror(-ret), ret);
-+              return ret;
-+      }
-+
-+      media_dbg(entity->media, "Frame interval set: %u/%u\n",
-+                interval->numerator, interval->denominator);
-+
-+      return 0;
-+}
-+
-+
-+static int v4l2_subdev_parse_setup_format(struct media_device *media,
-+                                        const char *p, char **endp)
-+{
-+      struct v4l2_mbus_framefmt format = { 0, 0, 0 };
-+      struct media_pad *pad;
-+      struct v4l2_rect crop = { -1, -1, -1, -1 };
-+      struct v4l2_rect compose = crop;
-+      struct v4l2_fract interval = { 0, 0 };
-+      unsigned int i;
-+      char *end;
-+      int ret;
-+
-+      pad = v4l2_subdev_parse_pad_format(media, &format, &crop, &compose,
-+                                         &interval, p, &end);
-+      if (pad == NULL) {
-+              media_print_streampos(media, p, end);
-+              media_dbg(media, "Unable to parse format\n");
-+              return -EINVAL;
-+      }
-+
-+      if (pad->flags & MEDIA_PAD_FL_SINK) {
-+              ret = set_format(pad, &format);
-+              if (ret < 0)
-+                      return ret;
-+      }
-+
-+      ret = set_selection(pad, V4L2_SEL_TGT_CROP, &crop);
-+      if (ret < 0)
-+              return ret;
-+
-+      ret = set_selection(pad, V4L2_SEL_TGT_COMPOSE, &compose);
-+      if (ret < 0)
-+              return ret;
-+
-+      if (pad->flags & MEDIA_PAD_FL_SOURCE) {
-+              ret = set_format(pad, &format);
-+              if (ret < 0)
-+                      return ret;
-+      }
-+
-+      ret = set_frame_interval(pad->entity, &interval);
-+      if (ret < 0)
-+              return ret;
-+
-+
-+      /* If the pad is an output pad, automatically set the same format on
-+       * the remote subdev input pads, if any.
-+       */
-+      if (pad->flags & MEDIA_PAD_FL_SOURCE) {
-+              for (i = 0; i < pad->entity->num_links; ++i) {
-+                      struct media_link *link = &pad->entity->links[i];
-+                      struct v4l2_mbus_framefmt remote_format;
-+
-+                      if (!(link->flags & MEDIA_LNK_FL_ENABLED))
-+                              continue;
-+
-+                      if (link->source == pad &&
-+                          link->sink->entity->info.type == MEDIA_ENT_T_V4L2_SUBDEV) {
-+                              remote_format = format;
-+                              set_format(link->sink, &remote_format);
-+                      }
-+              }
-+      }
-+
-+      *endp = end;
-+      return 0;
-+}
-+
-+int v4l2_subdev_parse_setup_formats(struct media_device *media, const char *p)
-+{
-+      char *end;
-+      int ret;
-+
-+      do {
-+              ret = v4l2_subdev_parse_setup_format(media, p, &end);
-+              if (ret < 0)
-+                      return ret;
-+
-+              p = end + 1;
-+      } while (*end == ',');
-+
-+      return *end ? -EINVAL : 0;
-+}
-+
-+static struct {
-+      const char *name;
-+      enum v4l2_mbus_pixelcode code;
-+} mbus_formats[] = {
-+      { "Y8", V4L2_MBUS_FMT_Y8_1X8},
-+      { "Y10", V4L2_MBUS_FMT_Y10_1X10 },
-+      { "Y12", V4L2_MBUS_FMT_Y12_1X12 },
-+      { "YUYV", V4L2_MBUS_FMT_YUYV8_1X16 },
-+      { "YUYV1_5X8", V4L2_MBUS_FMT_YUYV8_1_5X8 },
-+      { "YUYV2X8", V4L2_MBUS_FMT_YUYV8_2X8 },
-+      { "UYVY", V4L2_MBUS_FMT_UYVY8_1X16 },
-+      { "UYVY1_5X8", V4L2_MBUS_FMT_UYVY8_1_5X8 },
-+      { "UYVY2X8", V4L2_MBUS_FMT_UYVY8_2X8 },
-+      { "SBGGR8", V4L2_MBUS_FMT_SBGGR8_1X8 },
-+      { "SGBRG8", V4L2_MBUS_FMT_SGBRG8_1X8 },
-+      { "SGRBG8", V4L2_MBUS_FMT_SGRBG8_1X8 },
-+      { "SRGGB8", V4L2_MBUS_FMT_SRGGB8_1X8 },
-+      { "SBGGR10", V4L2_MBUS_FMT_SBGGR10_1X10 },
-+      { "SGBRG10", V4L2_MBUS_FMT_SGBRG10_1X10 },
-+      { "SGRBG10", V4L2_MBUS_FMT_SGRBG10_1X10 },
-+      { "SRGGB10", V4L2_MBUS_FMT_SRGGB10_1X10 },
-+      { "SBGGR10_DPCM8", V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8 },
-+      { "SGBRG10_DPCM8", V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8 },
-+      { "SGRBG10_DPCM8", V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 },
-+      { "SRGGB10_DPCM8", V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8 },
-+      { "SBGGR12", V4L2_MBUS_FMT_SBGGR12_1X12 },
-+      { "SGBRG12", V4L2_MBUS_FMT_SGBRG12_1X12 },
-+      { "SGRBG12", V4L2_MBUS_FMT_SGRBG12_1X12 },
-+      { "SRGGB12", V4L2_MBUS_FMT_SRGGB12_1X12 },
-+      { "AYUV32", V4L2_MBUS_FMT_AYUV8_1X32 },
-+      { "ARGB32", V4L2_MBUS_FMT_ARGB8888_1X32 },
-+};
-+
-+const char *v4l2_subdev_pixelcode_to_string(enum v4l2_mbus_pixelcode code)
-+{
-+      unsigned int i;
-+
-+      for (i = 0; i < ARRAY_SIZE(mbus_formats); ++i) {
-+              if (mbus_formats[i].code == code)
-+                      return mbus_formats[i].name;
-+      }
-+
-+      return "unknown";
-+}
-+
-+enum v4l2_mbus_pixelcode v4l2_subdev_string_to_pixelcode(const char *string,
-+                                                       unsigned int length)
-+{
-+      unsigned int i;
-+
-+      for (i = 0; i < ARRAY_SIZE(mbus_formats); ++i) {
-+              if (strncmp(mbus_formats[i].name, string, length) == 0)
-+                      break;
-+      }
-+
-+      if (i == ARRAY_SIZE(mbus_formats))
-+              return (enum v4l2_mbus_pixelcode)-1;
-+
-+      return mbus_formats[i].code;
-+}
-diff --git a/libweston/media-ctl/mediactl-priv.h b/libweston/media-ctl/mediactl-priv.h
-new file mode 100644
-index 0000000..a0d3a55
---- /dev/null
-+++ b/libweston/media-ctl/mediactl-priv.h
-@@ -0,0 +1,64 @@
-+/*
-+ * Media controller interface library
-+ *
-+ * Copyright (C) 2010-2014 Ideas on board SPRL
-+ *
-+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU Lesser General Public License as published
-+ * by the Free Software Foundation; either version 2.1 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program 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 Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#ifndef __MEDIA_PRIV_H__
-+#define __MEDIA_PRIV_H__
-+
-+#include <linux/media.h>
-+
-+#include "mediactl.h"
-+
-+struct media_entity {
-+      struct media_device *media;
-+      struct media_entity_desc info;
-+      struct media_pad *pads;
-+      struct media_link *links;
-+      unsigned int max_links;
-+      unsigned int num_links;
-+
-+      char devname[32];
-+      int fd;
-+};
-+
-+struct media_device {
-+      int fd;
-+      int refcount;
-+      char *devnode;
-+
-+      struct media_device_info info;
-+      struct media_entity *entities;
-+      unsigned int entities_count;
-+
-+      void (*debug_handler)(void *, ...);
-+      void *debug_priv;
-+
-+      struct {
-+              struct media_entity *v4l;
-+              struct media_entity *fb;
-+              struct media_entity *alsa;
-+              struct media_entity *dvb;
-+      } def;
-+};
-+
-+#define media_dbg(media, ...) \
-+      (media)->debug_handler((media)->debug_priv, __VA_ARGS__)
-+
-+#endif /* __MEDIA_PRIV_H__ */
-diff --git a/libweston/media-ctl/mediactl.h b/libweston/media-ctl/mediactl.h
-new file mode 100644
-index 0000000..77ac182
---- /dev/null
-+++ b/libweston/media-ctl/mediactl.h
-@@ -0,0 +1,423 @@
-+/*
-+ * Media controller interface library
-+ *
-+ * Copyright (C) 2010-2014 Ideas on board SPRL
-+ *
-+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU Lesser General Public License as published
-+ * by the Free Software Foundation; either version 2.1 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program 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 Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#ifndef __MEDIA_H__
-+#define __MEDIA_H__
-+
-+#include <linux/media.h>
-+
-+struct media_link {
-+      struct media_pad *source;
-+      struct media_pad *sink;
-+      struct media_link *twin;
-+      __u32 flags;
-+      __u32 padding[3];
-+};
-+
-+struct media_pad {
-+      struct media_entity *entity;
-+      __u32 index;
-+      __u32 flags;
-+      __u32 padding[3];
-+};
-+
-+struct media_device;
-+struct media_entity;
-+
-+/**
-+ * @brief Create a new media device.
-+ * @param devnode - device node path.
-+ *
-+ * Create a media device instance for the given device node and return it. The
-+ * device node is not accessed by this function, device node access errors will
-+ * not be caught and reported here. The media device needs to be enumerated
-+ * before it can be accessed, see media_device_enumerate().
-+ *
-+ * Media devices are reference-counted, see media_device_ref() and
-+ * media_device_unref() for more information.
-+ *
-+ * @return A pointer to the new media device or NULL if memory cannot be
-+ * allocated.
-+ */
-+struct media_device *media_device_new(const char *devnode);
-+
-+/**
-+ * @brief Create a new emulated media device.
-+ * @param info - device information.
-+ *
-+ * Emulated media devices are userspace-only objects not backed by a kernel
-+ * media device. They are created for ALSA and V4L2 devices that are not
-+ * associated with a media controller device.
-+ *
-+ * Only device query functions are available for media devices. Enumerating or
-+ * setting up links is invalid.
-+ *
-+ * @return A pointer to the new media device or NULL if memory cannot be
-+ * allocated.
-+ */
-+struct media_device *media_device_new_emulated(struct media_device_info *info);
-+
-+/**
-+ * @brief Take a reference to the device.
-+ * @param media - device instance.
-+ *
-+ * Media devices are reference-counted. Taking a reference to a device prevents
-+ * it from being freed until all references are released. The reference count is
-+ * initialized to 1 when the device is created.
-+ *
-+ * @return A pointer to @a media.
-+ */
-+struct media_device *media_device_ref(struct media_device *media);
-+
-+/**
-+ * @brief Release a reference to the device.
-+ * @param media - device instance.
-+ *
-+ * Release a reference to the media device. When the reference count reaches 0
-+ * this function frees the device.
-+ */
-+void media_device_unref(struct media_device *media);
-+
-+/**
-+ * @brief Add an entity to an existing media device
-+ * @param media - device instance.
-+ * @param desc - description of the entity to be added
-+ * @param devnode - device node corresponding to the entity
-+ *
-+ * Entities are usually created and added to media devices automatically when
-+ * the media device is enumerated through the media controller API. However,
-+ * when an emulated media device (thus not backed with a kernel-side media
-+ * controller device) is created, entities need to be manually added.
-+ *
-+ * Entities can also be manually added to a successfully enumerated media device
-+ * to group several functions provided by separate kernel devices. The most
-+ * common use case is to group the audio and video functions of a USB webcam in
-+ * a single media device. Those functions are exposed through separate USB
-+ * interfaces and handled through unrelated kernel drivers, they must thus be
-+ * manually added to the same media device.
-+ *
-+ * This function adds a new entity to the given media device and initializes it
-+ * from the given entity description and device node name. Only the following
-+ * fields of the description are copied over to the new entity:
-+ *
-+ * - type
-+ * - flags (MEDIA_ENT_FL_DEFAULT only)
-+ * - name
-+ * - v4l, fb, alsa or dvb (depending on the device type)
-+ *
-+ * All other fields of the newly created entity id are initialized to 0,
-+ * including the entity ID.
-+ *
-+ * @return Zero on success or -ENOMEM if memory cannot be allocated.
-+ */
-+int media_device_add_entity(struct media_device *media,
-+                          const struct media_entity_desc *desc,
-+                          const char *devnode);
-+
-+/**
-+ * @brief Set a handler for debug messages.
-+ * @param media - device instance.
-+ * @param debug_handler - debug message handler
-+ * @param debug_priv - first argument to debug message handler
-+ *
-+ * Set a handler for debug messages that will be called whenever
-+ * debugging information is to be printed. The handler expects an
-+ * fprintf-like function.
-+ */
-+void media_debug_set_handler(
-+      struct media_device *media, void (*debug_handler)(void *, ...),
-+      void *debug_priv);
-+
-+/**
-+ * @brief Enumerate the device topology
-+ * @param media - device instance.
-+ *
-+ * Enumerate the media device entities, pads and links. Calling this function is
-+ * mandatory before accessing the media device contents.
-+ *
-+ * @return Zero on success or a negative error code on failure.
-+ */
-+int media_device_enumerate(struct media_device *media);
-+
-+/**
-+ * @brief Locate the pad at the other end of a link.
-+ * @param pad - sink pad at one end of the link.
-+ *
-+ * Locate the source pad connected to @a pad through an enabled link. As only one
-+ * link connected to a sink pad can be enabled at a time, the connected source
-+ * pad is guaranteed to be unique.
-+ *
-+ * @return A pointer to the connected source pad, or NULL if all links connected
-+ * to @a pad are disabled. Return NULL also if @a pad is not a sink pad.
-+ */
-+struct media_pad *media_entity_remote_source(struct media_pad *pad);
-+
-+/**
-+ * @brief Get information about a media entity
-+ * @param entity - media entity.
-+ *
-+ * The information structure is owned by the media entity object and will be
-+ * freed when the object is destroyed.
-+ *
-+ * @return A pointer to the media entity information
-+ */
-+const struct media_entity_desc *media_entity_get_info(struct media_entity *entity);
-+
-+/**
-+ * @brief Get an entity pad
-+ * @param entity - media entity.
-+ * @param index - pad index.
-+ *
-+ * This function returns a pointer to the pad object identified by its index
-+ * for the given entity. If the pad index is out of bounds it will return NULL.
-+ *
-+ * @return A pointer to the pad
-+ */
-+const struct media_pad *media_entity_get_pad(struct media_entity *entity,
-+                                           unsigned int index);
-+
-+/**
-+ * @brief Get the number of links
-+ * @param entity - media entity.
-+ *
-+ * This function returns the total number of links that originate from or arrive
-+ * at the the media entity.
-+ *
-+ * @return The number of links for the entity
-+ */
-+unsigned int media_entity_get_links_count(struct media_entity *entity);
-+
-+/**
-+ * @brief Get an entity link
-+ * @param entity - media entity.
-+ * @param index - link index.
-+ *
-+ * This function returns a pointer to the link object identified by its index
-+ * for the given entity. If the link index is out of bounds it will return NULL.
-+ *
-+ * @return A pointer to the link
-+ */
-+const struct media_link *media_entity_get_link(struct media_entity *entity,
-+                                             unsigned int index);
-+
-+/**
-+ * @brief Get the device node name for an entity
-+ * @param entity - media entity.
-+ *
-+ * This function returns the full path and name to the device node corresponding
-+ * to the given entity.
-+ *
-+ * @return A pointer to the device node name or NULL if the entity has no
-+ * associated device node
-+ */
-+const char *media_entity_get_devname(struct media_entity *entity);
-+
-+/**
-+ * @brief Get the type of an entity.
-+ * @param entity - the entity.
-+ *
-+ * @return The type of @a entity.
-+ */
-+static inline unsigned int media_entity_type(struct media_entity *entity)
-+{
-+      return media_entity_get_info(entity)->type & MEDIA_ENT_TYPE_MASK;
-+}
-+
-+/**
-+ * @brief Find an entity by its name.
-+ * @param media - media device.
-+ * @param name - entity name.
-+ * @param length - size of @a name.
-+ *
-+ * Search for an entity with a name equal to @a name.
-+ *
-+ * @return A pointer to the entity if found, or NULL otherwise.
-+ */
-+struct media_entity *media_get_entity_by_name(struct media_device *media,
-+      const char *name, size_t length);
-+
-+/**
-+ * @brief Find an entity by its ID.
-+ * @param media - media device.
-+ * @param id - entity ID.
-+ *
-+ * This function searches for an entity based on its ID using an exact match or
-+ * next ID method based on the given @a id. If @a id is ORed with
-+ * MEDIA_ENT_ID_FLAG_NEXT, the function will return the entity with the smallest
-+ * ID larger than @a id. Otherwise it will return the entity with an ID equal to
-+ * @a id.
-+ *
-+ * @return A pointer to the entity if found, or NULL otherwise.
-+ */
-+struct media_entity *media_get_entity_by_id(struct media_device *media,
-+      __u32 id);
-+
-+/**
-+ * @brief Get the number of entities
-+ * @param media - media device.
-+ *
-+ * This function returns the total number of entities in the media device. If
-+ * entities haven't been enumerated yet it will return 0.
-+ *
-+ * @return The number of entities in the media device
-+ */
-+unsigned int media_get_entities_count(struct media_device *media);
-+
-+/**
-+ * @brief Get the entities
-+ * @param media - media device.
-+ *
-+ * This function returns a pointer to the array of entities for the media
-+ * device. If entities haven't been enumerated yet it will return NULL.
-+ *
-+ * The array of entities is owned by the media device object and will be freed
-+ * when the media object is destroyed.
-+ *
-+ * @return A pointer to an array of entities
-+ */
-+struct media_entity *media_get_entity(struct media_device *media, unsigned int index);
-+
-+/**
-+ * @brief Get the default entity for a given type
-+ * @param media - media device.
-+ * @param type - entity type.
-+ *
-+ * This function returns the default entity of the requested type. @a type must
-+ * be one of
-+ *
-+ *    MEDIA_ENT_T_DEVNODE_V4L
-+ *    MEDIA_ENT_T_DEVNODE_FB
-+ *    MEDIA_ENT_T_DEVNODE_ALSA
-+ *    MEDIA_ENT_T_DEVNODE_DVB
-+ *
-+ * @return A pointer to the default entity for the type if it exists, or NULL
-+ * otherwise.
-+ */
-+struct media_entity *media_get_default_entity(struct media_device *media,
-+                                            unsigned int type);
-+
-+/**
-+ * @brief Get the media device information
-+ * @param media - media device.
-+ *
-+ * The information structure is owned by the media device object and will be freed
-+ * when the media object is destroyed.
-+ *
-+ * @return A pointer to the media device information
-+ */
-+const struct media_device_info *media_get_info(struct media_device *media);
-+
-+/**
-+ * @brief Get the media device node name
-+ * @param media - media device.
-+ *
-+ * The device node name string is owned by the media device object and will be
-+ * freed when the media object is destroyed.
-+ *
-+ * @return A pointer to the media device node name
-+ */
-+const char *media_get_devnode(struct media_device *media);
-+
-+/**
-+ * @brief Configure a link.
-+ * @param media - media device.
-+ * @param source - source pad at the link origin.
-+ * @param sink - sink pad at the link target.
-+ * @param flags - configuration flags.
-+ *
-+ * Locate the link between @a source and @a sink, and configure it by applying
-+ * the new @a flags.
-+ *
-+ * Only the MEDIA_LINK_FLAG_ENABLED flag is writable.
-+ *
-+ * @return 0 on success, -1 on failure:
-+ *       -ENOENT: link not found
-+ *       - other error codes returned by MEDIA_IOC_SETUP_LINK
-+ */
-+int media_setup_link(struct media_device *media,
-+      struct media_pad *source, struct media_pad *sink,
-+      __u32 flags);
-+
-+/**
-+ * @brief Reset all links to the disabled state.
-+ * @param media - media device.
-+ *
-+ * Disable all links in the media device. This function is usually used after
-+ * opening a media device to reset all links to a known state.
-+ *
-+ * @return 0 on success, or a negative error code on failure.
-+ */
-+int media_reset_links(struct media_device *media);
-+
-+/**
-+ * @brief Parse string to a pad on the media device.
-+ * @param media - media device.
-+ * @param p - input string
-+ * @param endp - pointer to string where parsing ended
-+ *
-+ * Parse NULL terminated string describing a pad and return its struct
-+ * media_pad instance.
-+ *
-+ * @return Pointer to struct media_pad on success, NULL on failure.
-+ */
-+struct media_pad *media_parse_pad(struct media_device *media,
-+                                const char *p, char **endp);
-+
-+/**
-+ * @brief Parse string to a link on the media device.
-+ * @param media - media device.
-+ * @param p - input string
-+ * @param endp - pointer to p where parsing ended
-+ *
-+ * Parse NULL terminated string p describing a link and return its struct
-+ * media_link instance.
-+ *
-+ * @return Pointer to struct media_link on success, NULL on failure.
-+ */
-+struct media_link *media_parse_link(struct media_device *media,
-+                                  const char *p, char **endp);
-+
-+/**
-+ * @brief Parse string to a link on the media device and set it up.
-+ * @param media - media device.
-+ * @param p - input string
-+ *
-+ * Parse NULL terminated string p describing a link and its configuration
-+ * and configure the link.
-+ *
-+ * @return 0 on success, or a negative error code on failure.
-+ */
-+int media_parse_setup_link(struct media_device *media,
-+                         const char *p, char **endp);
-+
-+/**
-+ * @brief Parse string to link(s) on the media device and set it up.
-+ * @param media - media device.
-+ * @param p - input string
-+ *
-+ * Parse NULL terminated string p describing link(s) separated by
-+ * commas (,) and configure the link(s).
-+ *
-+ * @return 0 on success, or a negative error code on failure.
-+ */
-+int media_parse_setup_links(struct media_device *media, const char *p);
-+
-+#endif
-diff --git a/libweston/media-ctl/tools.h b/libweston/media-ctl/tools.h
-new file mode 100644
-index 0000000..815534c
---- /dev/null
-+++ b/libweston/media-ctl/tools.h
-@@ -0,0 +1,32 @@
-+/*
-+ * Media controller test application
-+ *
-+ * Copyright (C) 2010-2014 Ideas on board SPRL
-+ *
-+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU Lesser General Public License as published
-+ * by the Free Software Foundation; either version 2.1 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program 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 Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#ifndef __TOOLS_H__
-+#define __TOOLS_H__
-+
-+#define ARRAY_SIZE(array)     (sizeof(array) / sizeof((array)[0]))
-+#define FIELD_SIZEOF(t, f)    (sizeof(((t*)0)->f))
-+
-+void media_print_streampos(struct media_device *media, const char *p,
-+                         const char *end);
-+
-+#endif /* __TOOLS_H__ */
-+
-diff --git a/libweston/media-ctl/v4l2subdev.h b/libweston/media-ctl/v4l2subdev.h
-new file mode 100644
-index 0000000..1cb53ff
---- /dev/null
-+++ b/libweston/media-ctl/v4l2subdev.h
-@@ -0,0 +1,258 @@
-+/*
-+ * V4L2 subdev interface library
-+ *
-+ * Copyright (C) 2010-2014 Ideas on board SPRL
-+ *
-+ * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU Lesser General Public License as published
-+ * by the Free Software Foundation; either version 2.1 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program 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 Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public License
-+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#ifndef __SUBDEV_H__
-+#define __SUBDEV_H__
-+
-+#include <linux/v4l2-subdev.h>
-+
-+struct media_entity;
-+
-+/**
-+ * @brief Open a sub-device.
-+ * @param entity - sub-device media entity.
-+ *
-+ * Open the V4L2 subdev device node associated with @a entity. The file
-+ * descriptor is stored in the media_entity structure.
-+ *
-+ * @return 0 on success, or a negative error code on failure.
-+ */
-+int v4l2_subdev_open(struct media_entity *entity);
-+
-+/**
-+ * @brief Close a sub-device.
-+ * @param entity - sub-device media entity.
-+ *
-+ * Close the V4L2 subdev device node associated with the @a entity and opened by
-+ * a previous call to v4l2_subdev_open() (either explicit or implicit).
-+ */
-+void v4l2_subdev_close(struct media_entity *entity);
-+
-+/**
-+ * @brief Retrieve the format on a pad.
-+ * @param entity - subdev-device media entity.
-+ * @param format - format to be filled.
-+ * @param pad - pad number.
-+ * @param which - identifier of the format to get.
-+ *
-+ * Retrieve the current format on the @a entity @a pad and store it in the
-+ * @a format structure.
-+ *
-+ * @a which is set to V4L2_SUBDEV_FORMAT_TRY to retrieve the try format stored
-+ * in the file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to retrieve the current
-+ * active format.
-+ *
-+ * @return 0 on success, or a negative error code on failure.
-+ */
-+int v4l2_subdev_get_format(struct media_entity *entity,
-+      struct v4l2_mbus_framefmt *format, unsigned int pad,
-+      enum v4l2_subdev_format_whence which);
-+
-+/**
-+ * @brief Set the format on a pad.
-+ * @param entity - subdev-device media entity.
-+ * @param format - format.
-+ * @param pad - pad number.
-+ * @param which - identifier of the format to set.
-+ *
-+ * Set the format on the @a entity @a pad to @a format. The driver is allowed to
-+ * modify the requested format, in which case @a format is updated with the
-+ * modifications.
-+ *
-+ * @a which is set to V4L2_SUBDEV_FORMAT_TRY to set the try format stored in the
-+ * file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to configure the device with an
-+ * active format.
-+ *
-+ * @return 0 on success, or a negative error code on failure.
-+ */
-+int v4l2_subdev_set_format(struct media_entity *entity,
-+      struct v4l2_mbus_framefmt *format, unsigned int pad,
-+      enum v4l2_subdev_format_whence which);
-+
-+/**
-+ * @brief Retrieve a selection rectangle on a pad.
-+ * @param entity - subdev-device media entity.
-+ * @param r - rectangle to be filled.
-+ * @param pad - pad number.
-+ * @param target - selection target
-+ * @param which - identifier of the format to get.
-+ *
-+ * Retrieve the @a target selection rectangle on the @a entity @a pad
-+ * and store it in the @a rect structure.
-+ *
-+ * @a which is set to V4L2_SUBDEV_FORMAT_TRY to retrieve the try
-+ * selection rectangle stored in the file handle, or
-+ * V4L2_SUBDEV_FORMAT_ACTIVE to retrieve the current active selection
-+ * rectangle.
-+ *
-+ * @return 0 on success, or a negative error code on failure.
-+ */
-+int v4l2_subdev_get_selection(struct media_entity *entity,
-+      struct v4l2_rect *rect, unsigned int pad, unsigned int target,
-+      enum v4l2_subdev_format_whence which);
-+
-+/**
-+ * @brief Set a selection rectangle on a pad.
-+ * @param entity - subdev-device media entity.
-+ * @param rect - crop rectangle.
-+ * @param pad - pad number.
-+ * @param target - selection target
-+ * @param which - identifier of the format to set.
-+ *
-+ * Set the @a target selection rectangle on the @a entity @a pad to @a
-+ * rect. The driver is allowed to modify the requested rectangle, in
-+ * which case @a rect is updated with the modifications.
-+ *
-+ * @a which is set to V4L2_SUBDEV_FORMAT_TRY to set the try crop rectangle
-+ * stored in the file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to configure the
-+ * device with an active crop rectangle.
-+ *
-+ * @return 0 on success, or a negative error code on failure.
-+ */
-+int v4l2_subdev_set_selection(struct media_entity *entity,
-+      struct v4l2_rect *rect, unsigned int pad, unsigned int target,
-+      enum v4l2_subdev_format_whence which);
-+
-+/**
-+ * @brief Query the digital video capabilities of a pad.
-+ * @param entity - subdev-device media entity.
-+ * @param cap - capabilities to be filled.
-+ *
-+ * Retrieve the digital video capabilities of the @a entity pad specified by
-+ * @a cap.pad and store it in the @a cap structure.
-+ *
-+ * @return 0 on success, or a negative error code on failure.
-+ */
-+int v4l2_subdev_get_dv_timings_caps(struct media_entity *entity,
-+      struct v4l2_dv_timings_cap *caps);
-+
-+/**
-+ * @brief Query the digital video timings of a sub-device
-+ * @param entity - subdev-device media entity.
-+ * @param timings timings to be filled.
-+ *
-+ * Retrieve the detected digital video timings for the currently selected input
-+ * of @a entity and store them in the @a timings structure.
-+ *
-+ * @return 0 on success, or a negative error code on failure.
-+ */
-+int v4l2_subdev_query_dv_timings(struct media_entity *entity,
-+      struct v4l2_dv_timings *timings);
-+
-+/**
-+ * @brief Get the current digital video timings of a sub-device
-+ * @param entity - subdev-device media entity.
-+ * @param timings timings to be filled.
-+ *
-+ * Retrieve the current digital video timings for the currently selected input
-+ * of @a entity and store them in the @a timings structure.
-+ *
-+ * @return 0 on success, or a negative error code on failure.
-+ */
-+int v4l2_subdev_get_dv_timings(struct media_entity *entity,
-+      struct v4l2_dv_timings *timings);
-+
-+/**
-+ * @brief Set the digital video timings of a sub-device
-+ * @param entity - subdev-device media entity.
-+ * @param timings timings to be set.
-+ *
-+ * Set the digital video timings of @a entity to @a timings. The driver is
-+ * allowed to modify the requested format, in which case @a timings is updated
-+ * with the modifications.
-+ *
-+ * @return 0 on success, or a negative error code on failure.
-+ */
-+int v4l2_subdev_set_dv_timings(struct media_entity *entity,
-+      struct v4l2_dv_timings *timings);
-+
-+/**
-+ * @brief Retrieve the frame interval on a sub-device.
-+ * @param entity - subdev-device media entity.
-+ * @param interval - frame interval to be filled.
-+ *
-+ * Retrieve the current frame interval on subdev @a entity and store it in the
-+ * @a interval structure.
-+ *
-+ * Frame interval retrieving is usually supported only on devices at the
-+ * beginning of video pipelines, such as sensors.
-+ *
-+ * @return 0 on success, or a negative error code on failure.
-+ */
-+
-+int v4l2_subdev_get_frame_interval(struct media_entity *entity,
-+      struct v4l2_fract *interval);
-+
-+/**
-+ * @brief Set the frame interval on a sub-device.
-+ * @param entity - subdev-device media entity.
-+ * @param interval - frame interval.
-+ *
-+ * Set the frame interval on subdev @a entity to @a interval. The driver is
-+ * allowed to modify the requested frame interval, in which case @a interval is
-+ * updated with the modifications.
-+ *
-+ * Frame interval setting is usually supported only on devices at the beginning
-+ * of video pipelines, such as sensors.
-+ *
-+ * @return 0 on success, or a negative error code on failure.
-+ */
-+int v4l2_subdev_set_frame_interval(struct media_entity *entity,
-+      struct v4l2_fract *interval);
-+
-+/**
-+ * @brief Parse a string and apply format, crop and frame interval settings.
-+ * @param media - media device.
-+ * @param p - input string
-+ * @param endp - pointer to string p where parsing ended (return)
-+ *
-+ * Parse string @a p and apply format, crop and frame interval settings to a
-+ * subdev pad specified in @a p. @a endp will be written a pointer where
-+ * parsing of @a p ended.
-+ *
-+ * Format strings are separeted by commas (,).
-+ *
-+ * @return 0 on success, or a negative error code on failure.
-+ */
-+int v4l2_subdev_parse_setup_formats(struct media_device *media, const char *p);
-+
-+/**
-+ * @brief Convert media bus pixel code to string.
-+ * @param code - input string
-+ *
-+ * Convert media bus pixel code @a code to a human-readable string.
-+ *
-+ * @return A pointer to a string on success, NULL on failure.
-+ */
-+const char *v4l2_subdev_pixelcode_to_string(enum v4l2_mbus_pixelcode code);
-+
-+/**
-+ * @brief Parse string to media bus pixel code.
-+ * @param string - input string
-+ * @param lenght - length of the string
-+ *
-+ * Parse human readable string @a string to an media bus pixel code.
-+ *
-+ * @return media bus pixelcode on success, -1 on failure.
-+ */
-+enum v4l2_mbus_pixelcode v4l2_subdev_string_to_pixelcode(const char *string,
-+                                                       unsigned int length);
-+#endif
--- 
-2.9.2
-
diff --git a/recipes-graphics/wayland/weston/0003-gst-recorder-Use-USERPTR-instead-of-DMABUF-for-VSP-o.patch b/recipes-graphics/wayland/weston/0003-gst-recorder-Use-USERPTR-instead-of-DMABUF-for-VSP-o.patch
deleted file mode 100644 (file)
index 6f8d1dc..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-From f450d78f49ab55149b6b64251dd4c4f1ad04c9aa Mon Sep 17 00:00:00 2001
-From: Damian Hobson-Garcia <dhobsong@igel.co.jp>
-Date: Thu, 11 May 2017 12:05:56 +0900
-Subject: [PATCH 3/4] gst-recorder: Use USERPTR instead of DMABUF for VSP
- output
-
-The RCar-Gen3 encoder requires buffers to be allocated and managed
-externally when using dmabuf buffers.  Since different sized buffers
-are required for each output, the VSP cannot allocate these buffers
-externally.  The encoder provides its own buffers in USERPTR mode, so
-switch to that.
----
- libweston/gst-recorder.c | 100 +++++++++++++++++++++++++++++------------------
- 1 file changed, 63 insertions(+), 37 deletions(-)
-
-diff --git a/libweston/gst-recorder.c b/libweston/gst-recorder.c
-index d46d4f0..d2cf8dc 100644
---- a/libweston/gst-recorder.c
-+++ b/libweston/gst-recorder.c
-@@ -311,7 +311,7 @@ vsp_init(const char *devname)
-               weston_log("failed to open subdev '%s'\n", buf);
-               goto error_media;
-       }
--      else if ((vsp->output.fd = open(media_entity_get_devname(entity), O_RDWR | O_NONBLOCK)) < 0)
-+      else if ((vsp->output.fd = open(media_entity_get_devname(entity), O_RDWR )) < 0)
-       {
-               weston_log("failed to open device '%s'\n", media_entity_get_devname(entity));
-               goto error_media;
-@@ -464,7 +464,8 @@ vsp_request_buffers(vsp_data_t *vsp, vsp_port_n port, unsigned int num)
-       memset(&reqbuf, 0, sizeof(reqbuf));
-       reqbuf.type = (port == VSP_PORT_INPUT) ?
-               V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
--      reqbuf.memory = V4L2_MEMORY_DMABUF;
-+      reqbuf.memory = (port == VSP_PORT_INPUT) ?
-+              V4L2_MEMORY_DMABUF : V4L2_MEMORY_USERPTR;
-       reqbuf.count = num;
-       if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
-               weston_log("VSP: %s REQBUFS failed: %d\n",
-@@ -536,7 +537,8 @@ vsp_input_buffer_dequeue_dmafd(vsp_data_t *vsp)
- /* ...enqueue output buffer */
- static int
--vsp_output_buffer_queue_dmafd(vsp_data_t *vsp, int i, int dmafd[])
-+vsp_output_buffer_queue_userptr(vsp_data_t *vsp, int i, void * omx_mem,
-+              int y_plane_size, int c_plane_size)
- {
-       vsp_media_pad_t    *pad = &vsp->output;
-       struct v4l2_plane   planes[2];
-@@ -546,16 +548,23 @@ vsp_output_buffer_queue_dmafd(vsp_data_t *vsp, int i, int dmafd[])
-       memset(&buf, 0, sizeof(buf));
-       memset(planes, 0, sizeof(planes));
-       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
--      buf.memory = V4L2_MEMORY_DMABUF;
-+      buf.memory = V4L2_MEMORY_USERPTR;
-       buf.index = i;
-       buf.m.planes = planes;
-       buf.length = VSP_OUTPUT_BUFFERS_PLANE;
--      buf.m.planes[0].m.fd = dmafd[0];
--      buf.m.planes[1].m.fd = dmafd[1];
-+
-+      buf.m.planes[0].m.userptr = (unsigned long) omx_mem;
-+      buf.m.planes[1].m.userptr = (unsigned long) omx_mem + y_plane_size;
-+
-+      buf.m.planes[0].bytesused = y_plane_size;
-+      buf.m.planes[0].length = y_plane_size;
-+
-+      buf.m.planes[1].bytesused = c_plane_size;
-+      buf.m.planes[1].length = c_plane_size;
-       /* ...submit buffer */
-       if (ioctl(pad->fd, VIDIOC_QBUF, &buf) < 0) {
--              weston_log("VSP: output dmafd queue failed: %d\n", errno);
-+              weston_log("VSP: output buffer queue failed: %d\n", errno);
-               return -1;
-       }
-@@ -564,7 +573,7 @@ vsp_output_buffer_queue_dmafd(vsp_data_t *vsp, int i, int dmafd[])
- /* ...dequeue output buffer */
- static int
--vsp_output_buffer_dequeue_dmafd(vsp_data_t *vsp)
-+vsp_output_buffer_dequeue_userptr(vsp_data_t *vsp)
- {
-       vsp_media_pad_t    *pad = &vsp->output;
-       struct v4l2_buffer  buf;
-@@ -574,12 +583,12 @@ vsp_output_buffer_dequeue_dmafd(vsp_data_t *vsp)
-       memset(&buf, 0, sizeof(buf));
-       memset(planes, 0, sizeof(planes));
-       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
--      buf.memory = V4L2_MEMORY_DMABUF;
-+      buf.memory = V4L2_MEMORY_USERPTR;
-       buf.m.planes = planes;
-       buf.length = VSP_OUTPUT_BUFFERS_PLANE;
-       if (ioctl(pad->fd, VIDIOC_DQBUF, &buf) < 0) {
--              weston_log("VSP: output dmafd de-queue failed: %d\n", errno);
-+              weston_log("VSP: output buffer de-queue failed: %d\n", errno);
-               return -1;
-       }
-@@ -876,33 +885,25 @@ err:
- }
- static int
--gst_recorder_omx_buffer_acquire(struct gst_recorder *r, GstBuffer **ret_buf, int fd[])
-+gst_recorder_omx_buffer_acquire(struct gst_recorder *r, GstBuffer **ret_buf, GstMapInfo *info)
- {
--      unsigned int i;
-       GstFlowReturn ret;
-       GstBuffer *buf;
--      guint n_mem;
--      GstMemory *mem;
-       ret = gst_buffer_pool_acquire_buffer(r->omx_pool, &buf, NULL);
-       if (ret != GST_FLOW_OK) {
--              weston_log("OMX buffer acquire failed\n");
--              return -1;
-+              weston_log("GStreamer buffer acquire failed\n");
-+              goto err_release;
-       }
--      n_mem = gst_buffer_n_memory(buf);
--      if (n_mem < 1) {
--              weston_log("Buffer with no mem!\n");
-+      if (!gst_buffer_is_writable(buf)) {
-+              weston_log("GStreamer buffer not writable\n");
-               goto err_release;
-       }
--      for (i = 0; i < n_mem; i++) {
--              mem = gst_buffer_peek_memory (buf, i);
--              if (!gst_is_dmabuf_memory (mem)) {
--                      weston_log("Mem not dmabuf\n");
--                      goto err_release;
--              }
--              fd[i] = gst_dmabuf_memory_get_fd (mem);
-+      if (!gst_buffer_map(buf, info, GST_MAP_WRITE)) {
-+              weston_log("Cannot map GStreamer buffer\n");
-+              goto err_release;
-       }
-       *ret_buf = buf;
-@@ -956,7 +957,7 @@ gst_recorder_create(struct gst_recorder_settings *settings)
-       /* omx */
-       ptr += sprintf(ptr,
--              "omxh264enc target-bitrate=%d control-rate=2 name=my_encoder ! "
-+              "omxh264enc target-bitrate=%d control-rate=2 no-copy=true name=my_encoder ! "
-               "video/x-h264,width=%d,height=%d ! ",
-               r->set->bitrate, r->set->crop.width, r->set->crop.height);
-@@ -1009,6 +1010,12 @@ gst_recorder_create(struct gst_recorder_settings *settings)
-                                       "framerate", GST_TYPE_FRACTION, 0, DEFAULT_FPS,
-                                       NULL), NULL);
-+      g_object_set(G_OBJECT(r->appsrc),
-+                      "stream-type", 0,
-+                      "format", GST_FORMAT_TIME,
-+                      "is-live", TRUE,
-+                      NULL);
-+
-       r->appsrc_pad = gst_element_get_static_pad(GST_ELEMENT_CAST(r->appsrc), "src");
-       if (!r->appsrc_pad)
-               weston_log("Failed to get src0 pad of appsrc\n");
-@@ -1088,14 +1095,23 @@ gst_recorder_process_dmafd(struct gst_recorder *r, int fd, int stride)
- {
-       int ret;
-       GstBuffer *buf;
--      int omx_fd[2];
-+      GstMapInfo info;
-+      int ysize;
-+      int csize;
-         /* get GST buffer */
--      if (gst_recorder_omx_buffer_acquire(r, &buf, omx_fd) < 0) {
-+      if (gst_recorder_omx_buffer_acquire(r, &buf, &info) < 0) {
-               weston_log("VSP: can not acquire GST buffer, dropping frame\n");
-               return 0;
-       }
-+      ysize = r->set->crop.width * r->set->crop.height;
-+#ifdef VSP_OUTPUT_NV16
-+      csize = ysize;
-+#else
-+      csize = ysize / 2;
-+#endif
-+
-       pthread_mutex_lock(&r->vsp->mutex);
-       /* setup vsp */
-       if (vsp_set_formats(r->vsp, r->set->width, r->set->height, &r->set->crop) < 0) {
-@@ -1116,7 +1132,7 @@ gst_recorder_process_dmafd(struct gst_recorder *r, int fd, int stride)
-       }
-       /* queue output biffer */
--      if (vsp_output_buffer_queue_dmafd(r->vsp, 0, omx_fd) < 0) {
-+      if (vsp_output_buffer_queue_userptr(r->vsp, 0, info.data, ysize, csize) < 0) {
-               weston_log("can not queue OMX buffer %d to VSP\n", 0);
-               gst_recorder_omx_buffer_release(r, buf);
-               goto err_vsp;
-@@ -1147,11 +1163,15 @@ gst_recorder_process_dmafd(struct gst_recorder *r, int fd, int stride)
-       }
-       /* dequeue output */
--      if (vsp_output_buffer_dequeue_dmafd(r->vsp) < 0) {
--              weston_log("VSP: failed to dequeu output buffer\n");
-+      if (vsp_output_buffer_dequeue_userptr(r->vsp) < 0) {
-+              weston_log("VSP: failed to dequeue output buffer\n");
-+              gst_buffer_unmap(buf, &info);
-               gst_recorder_omx_buffer_release(r, buf);
--              /* fall through */
-       } else {
-+
-+              gst_buffer_unmap(buf, &info);
-+              gst_buffer_set_size(buf, ysize + csize);
-+
-               /* set timestamp */
-               gst_recorder_set_timestamp(r, buf);
-@@ -1174,6 +1194,7 @@ gst_recorder_process_dmafd(struct gst_recorder *r, int fd, int stride)
-       vsp_request_buffers(r->vsp, VSP_PORT_OUTPUT, 0);
-       pthread_mutex_unlock(&r->vsp->mutex);
-+      close(fd);
-       return 0;
- err_vsp:
-@@ -1181,6 +1202,7 @@ err_vsp:
-       /* finish vsp here */
- err:
-       pthread_mutex_unlock(&r->vsp->mutex);
-+      close(fd);
-       return -1;
- }
-@@ -1197,9 +1219,13 @@ gst_recorder_frame_dmafd(struct gst_recorder *r, int fd, int stride)
-               goto unlock;
-       }
-               
--      /* The mutex is never released while encoding, so this point should
--       * never be reached if input.valid is true. */
--      assert(!r->input.valid);
-+      /* It is possible that the frame callback can be called mutiple
-+       * times before the worker thread wakes up.  In this case
-+       * drop all buf the first frame */
-+      if(r->input.valid) {
-+              close(fd);
-+              goto unlock;
-+      }
-       r->input.prime_fd = fd;
-       r->input.stride = stride;
-@@ -1209,5 +1235,5 @@ gst_recorder_frame_dmafd(struct gst_recorder *r, int fd, int stride)
- unlock:
-       pthread_mutex_unlock(&r->mutex);
--      return 0;
-+      return ret;
- }
--- 
-2.9.2
-
diff --git a/recipes-graphics/wayland/weston/0004-gst-record-Specify-bytesused-and-length-of-VSP-input.patch b/recipes-graphics/wayland/weston/0004-gst-record-Specify-bytesused-and-length-of-VSP-input.patch
deleted file mode 100644 (file)
index 8b0d44a..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-From 90a51301038e492875ac02ed48fa86e699849e06 Mon Sep 17 00:00:00 2001
-From: Damian Hobson-Garcia <dhobsong@igel.co.jp>
-Date: Tue, 9 May 2017 18:07:52 +0900
-Subject: [PATCH 4/4] gst-record: Specify bytesused and length of VSP input
- buffer
-
-The bytesused=0 setting has been deprecated in newer kernels.
----
- libweston/gst-recorder.c | 8 ++++++--
- 1 file changed, 6 insertions(+), 2 deletions(-)
-
-diff --git a/libweston/gst-recorder.c b/libweston/gst-recorder.c
-index d2cf8dc..7dafd95 100644
---- a/libweston/gst-recorder.c
-+++ b/libweston/gst-recorder.c
-@@ -484,7 +484,7 @@ vsp_request_buffers(vsp_data_t *vsp, vsp_port_n port, unsigned int num)
- /* ...enqueue dmafd buffer */
- static int
--vsp_input_buffer_queue_dmafd(vsp_data_t *vsp, int i, int dmafd)
-+vsp_input_buffer_queue_dmafd(vsp_data_t *vsp, int i, int dmafd, int bytesused)
- {
-       vsp_media_pad_t    *pad = &vsp->input;
-       struct v4l2_buffer  buf;
-@@ -499,6 +499,8 @@ vsp_input_buffer_queue_dmafd(vsp_data_t *vsp, int i, int dmafd)
-       buf.m.planes = planes;
-       buf.length = 1;
-       buf.m.planes[0].m.fd = dmafd;
-+      buf.m.planes[0].bytesused = bytesused;
-+      buf.m.planes[0].length = bytesused;
-       /* ...submit buffer */
-       if (ioctl(pad->fd, VIDIOC_QBUF, &buf) < 0) {
-@@ -1098,6 +1100,7 @@ gst_recorder_process_dmafd(struct gst_recorder *r, int fd, int stride)
-       GstMapInfo info;
-       int ysize;
-       int csize;
-+      int rgbsize;
-         /* get GST buffer */
-       if (gst_recorder_omx_buffer_acquire(r, &buf, &info) < 0) {
-@@ -1111,6 +1114,7 @@ gst_recorder_process_dmafd(struct gst_recorder *r, int fd, int stride)
- #else
-       csize = ysize / 2;
- #endif
-+      rgbsize = stride * r->set->height;
-       pthread_mutex_lock(&r->vsp->mutex);
-       /* setup vsp */
-@@ -1139,7 +1143,7 @@ gst_recorder_process_dmafd(struct gst_recorder *r, int fd, int stride)
-       }
-       /* queue input vsp buffer */
--      if (vsp_input_buffer_queue_dmafd(r->vsp, 0, fd) < 0) {
-+      if (vsp_input_buffer_queue_dmafd(r->vsp, 0, fd, rgbsize) < 0) {
-               weston_log("VSP: failed to queue input buffer\n");
-               goto err_vsp;
-       }
--- 
-2.9.2
-
diff --git a/recipes-graphics/wayland/weston_2.0.0.bbappend b/recipes-graphics/wayland/weston_2.0.0.bbappend
deleted file mode 100644 (file)
index ba1a79d..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
-
-SRC_URI_append_ulcb = " \
-    file://0001-Add-virtual-output-support.patch \
-    file://0002-Add-gst-recorder-for-h264-output-streaming.patch \
-    file://0003-gst-recorder-Use-USERPTR-instead-of-DMABUF-for-VSP-o.patch \
-    file://0004-gst-record-Specify-bytesused-and-length-of-VSP-input.patch \
-"
-