71a45fff653e2f0ee209082d0dd84b97cff2dd4f
[AGL/meta-agl-demo.git] / recipes-graphics / wayland / weston / 0002-Add-gst-recorder-for-h264-output-streaming.patch
1 From c953d91f8d7e4bca5dd68246c763fd4c4e354287 Mon Sep 17 00:00:00 2001
2 From: Harunobu Kurokawa <harunobu.kurokawa.dn@renesas.com>
3 Date: Thu, 10 Aug 2017 15:49:14 +0900
4 Subject: [PATCH 2/4] Add gst-recorder for h264 output streaming
5
6 This patch is ported to weston 2.0.0.
7 --------
8 Author: Damian Hobson-Garcia <dhobsong@igel.co.jp>
9 Date:   Thu Apr 27 16:47:00 2017 +0900
10
11   Following patch ported to Weston 1.11 with minor updates
12   --------
13   To use gst-recorder run weston with arg --gst-record. Add
14   recorder=true property to output section of one of the outputs
15   (real or virtual). Use properties ip, port to set host of RTP
16   stream. Use property bitrate to set desirable maximum h264 bitrate.
17   --------
18 ---
19  Makefile.am                         |   17 +
20  compositor/main.c                   |    4 +-
21  configure.ac                        |   13 +
22  libweston/compositor-drm.c          |  203 +++++-
23  libweston/compositor-drm.h          |    3 +
24  libweston/gst-recorder.c            | 1213 +++++++++++++++++++++++++++++++++++
25  libweston/gst-recorder.h            |   58 ++
26  libweston/media-ctl/libmediactl.c   |  955 +++++++++++++++++++++++++++
27  libweston/media-ctl/libv4l2subdev.c |  759 ++++++++++++++++++++++
28  libweston/media-ctl/mediactl-priv.h |   64 ++
29  libweston/media-ctl/mediactl.h      |  423 ++++++++++++
30  libweston/media-ctl/tools.h         |   32 +
31  libweston/media-ctl/v4l2subdev.h    |  258 ++++++++
32  13 files changed, 4000 insertions(+), 2 deletions(-)
33  create mode 100644 libweston/gst-recorder.c
34  create mode 100644 libweston/gst-recorder.h
35  create mode 100644 libweston/media-ctl/libmediactl.c
36  create mode 100644 libweston/media-ctl/libv4l2subdev.c
37  create mode 100644 libweston/media-ctl/mediactl-priv.h
38  create mode 100644 libweston/media-ctl/mediactl.h
39  create mode 100644 libweston/media-ctl/tools.h
40  create mode 100644 libweston/media-ctl/v4l2subdev.h
41
42 diff --git a/Makefile.am b/Makefile.am
43 index cdf82ab..9fb9ba0 100644
44 --- a/Makefile.am
45 +++ b/Makefile.am
46 @@ -386,6 +386,23 @@ drm_backend_la_LIBADD += $(LIBVA_LIBS)
47  drm_backend_la_LDFLAGS += -pthread
48  drm_backend_la_CFLAGS += $(LIBVA_CFLAGS)
49  endif
50 +
51 +if ENABLE_GST_RECORDER
52 +drm_backend_la_SOURCES +=                      \
53 +       libweston/gst-recorder.c                        \
54 +       libweston/gst-recorder.h                        \
55 +       libweston/v4l2-device.h                 \
56 +       libweston/media-ctl/libmediactl.c               \
57 +       libweston/media-ctl/libv4l2subdev.c             \
58 +       libweston/media-ctl/mediactl-priv.h             \
59 +       libweston/media-ctl/mediactl.h          \
60 +       libweston/media-ctl/tools.h                     \
61 +       libweston/media-ctl/v4l2subdev.h
62 +drm_backend_la_LIBADD += $(LIBVA_LIBS)                 \
63 +       -lgstallocators-1.0                     \
64 +       -lgstvideo-1.0
65 +drm_backend_la_CFLAGS += $(LIBVA_CFLAGS)
66 +endif
67  endif
68  
69  if ENABLE_WAYLAND_COMPOSITOR
70 diff --git a/compositor/main.c b/compositor/main.c
71 index 72c3cd1..6a8ca7f 100644
72 --- a/compositor/main.c
73 +++ b/compositor/main.c
74 @@ -566,7 +566,8 @@ usage(int error_code)
75                 "  --seat=SEAT\t\tThe seat that weston should run on\n"
76                 "  --tty=TTY\t\tThe tty to use\n"
77                 "  --use-pixman\t\tUse the pixman (CPU) renderer\n"
78 -               "  --current-mode\tPrefer current KMS mode over EDID preferred mode\n\n");
79 +               "  --current-mode\tPrefer current KMS mode over EDID preferred mode\n"
80 +               "  --gst-record\t\tEnable GStreamer recording\n\n");
81  #endif
82  
83  #if defined(BUILD_FBDEV_COMPOSITOR)
84 @@ -1227,6 +1228,7 @@ load_drm_backend(struct weston_compositor *c,
85                 { WESTON_OPTION_INTEGER, "tty", 0, &config.tty },
86                 { WESTON_OPTION_BOOLEAN, "current-mode", 0, &wet->drm_use_current_mode },
87                 { WESTON_OPTION_BOOLEAN, "use-pixman", 0, &config.use_pixman },
88 +               { WESTON_OPTION_BOOLEAN, "gst-record", 0, &config.enable_recorder },
89         };
90  
91         parse_options(options, ARRAY_LENGTH(options), argc, argv);
92 diff --git a/configure.ac b/configure.ac
93 index a36a516..3cc7501 100644
94 --- a/configure.ac
95 +++ b/configure.ac
96 @@ -242,6 +242,18 @@ if test x$enable_headless_compositor = xyes; then
97  fi
98  
99  
100 +AC_ARG_ENABLE(gst-recorder, [  --enable-gst-recorder],,
101 +             enable_gst_recorder=yes)
102 +if test x$enable_gst_recorder != xno; then
103 +  AC_DEFINE([BUILD_GST_RECORDER], [1], [Build the gst recorder])
104 +  PKG_CHECK_MODULES(GSTREAMER, [gstreamer-1.0 >= 1.0])
105 +
106 +  CPPFLAGS="$CPPFLAGS $GSTREAMER_CFLAGS"
107 +  LIBS="$LIBS $GSTREAMER_LIBS -lgstapp-1.0"
108 +fi
109 +AM_CONDITIONAL(ENABLE_GST_RECORDER, test "x$enable_gst_recorder" != xno)
110 +
111 +
112  AC_ARG_ENABLE([fbdev-compositor], [  --enable-fbdev-compositor],,
113                enable_fbdev_compositor=yes)
114  AM_CONDITIONAL([ENABLE_FBDEV_COMPOSITOR],
115 @@ -724,4 +736,5 @@ AC_MSG_RESULT([
116         libwebp Support                 ${have_webp}
117         libunwind Support               ${have_libunwind}
118         VA H.264 encoding Support       ${have_libva}
119 +       GStreamer H.264 enc. Support    ${enable_gst_recorder}
120  ])
121 diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
122 index d0f07e9..0b9643f 100644
123 --- a/libweston/compositor-drm.c
124 +++ b/libweston/compositor-drm.c
125 @@ -58,9 +58,11 @@
126  #include "libinput-seat.h"
127  #include "launcher-util.h"
128  #include "vaapi-recorder.h"
129 +#include "gst-recorder.h"
130  #include "presentation-time-server-protocol.h"
131  #include "linux-dmabuf.h"
132  #include "linux-dmabuf-unstable-v1-server-protocol.h"
133 +#include "compositor/weston.h"
134  
135  #ifndef DRM_CAP_TIMESTAMP_MONOTONIC
136  #define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
137 @@ -113,6 +115,8 @@ struct drm_backend {
138  
139         int use_pixman;
140  
141 +       int enable_recorder;
142 +
143         struct udev_input input;
144  
145         int32_t cursor_width;
146 @@ -180,7 +184,12 @@ struct drm_output {
147         int current_image;
148         pixman_region32_t previous_damage;
149  
150 +#ifdef BUILD_VAAPI_RECORDER
151         struct vaapi_recorder *recorder;
152 +#endif
153 +#ifdef BUILD_GST_RECORDER
154 +       struct gst_recorder *recorder;
155 +#endif
156         struct wl_listener recorder_frame_listener;
157  
158         /* not real output device */
159 @@ -239,6 +248,9 @@ drm_output_set_cursor(struct drm_output *output);
160  static void
161  drm_output_update_msc(struct drm_output *output, unsigned int seq);
162  
163 +static void
164 +recorders_enable(struct drm_backend *b);
165 +
166  static int
167  drm_sprite_crtc_supported(struct drm_output *output, struct drm_sprite *sprite)
168  {
169 @@ -2197,6 +2209,23 @@ parse_modeline(const char *s, drmModeModeInfo *mode)
170         return 0;
171  }
172  
173 +static int parse_crop_rect(const char *s, struct v4l2_rect* crop)
174 +{
175 +       crop->left = 0;
176 +       crop->top = 0;
177 +       crop->width = 0;
178 +       crop->height = 0;
179 +
180 +       if (sscanf(s, "%dx%d@%dx%d",
181 +                  &crop->width,
182 +                  &crop->height,
183 +                  &crop->top,
184 +                  &crop->left) != 4)
185 +               return -1;
186 +
187 +       return 0;
188 +}
189 +
190  static void
191  setup_output_seat_constraint(struct drm_backend *b,
192                              struct weston_output *output,
193 @@ -3457,7 +3486,173 @@ recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
194                 recorder_destroy(output);
195         }
196  }
197 -#else
198 +#endif
199 +
200 +#ifdef BUILD_GST_RECORDER
201 +static void
202 +recorder_destroy(struct drm_output *output)
203 +{
204 +       wl_list_remove(&output->recorder_frame_listener.link);
205 +
206 +       gst_recorder_destroy(output->recorder);
207 +       output->recorder = NULL;
208 +
209 +       output->base.disable_planes--;
210 +
211 +       weston_log("[gst recorder] done\n");
212 +}
213 +
214 +static void
215 +recorder_frame_notify(struct wl_listener *listener, void *data)
216 +{
217 +       int ret = 0;
218 +       struct drm_output *output;
219 +       struct drm_backend *b;
220 +       int fd;
221 +
222 +       output = container_of(listener, struct drm_output,
223 +                             recorder_frame_listener);
224 +       b = to_drm_backend(output->base.compositor);
225 +
226 +       if (!output->recorder) {
227 +               weston_log("%s: output have no recorder enabled\n",
228 +                       output->base.name);
229 +               return;
230 +       }
231 +
232 +       if (!output->current) {
233 +               weston_log("%s: frame notify while current frame == NULL\n",
234 +                          output->base.name);
235 +               return;
236 +       }
237 +
238 +       ret = drmPrimeHandleToFD(b->drm.fd, output->current->handle,
239 +                                DRM_CLOEXEC, &fd);
240 +       if (!ret) {
241 +               ret = gst_recorder_frame_dmafd(output->recorder, fd,
242 +                                              output->current->stride);
243 +       }
244 +
245 +       if (ret < 0) {
246 +               weston_log("[gst recorder] aborted: %m\n");
247 +               recorder_destroy(output);
248 +       }
249 +}
250 +
251 +static int
252 +recorder_enable(struct drm_backend *b, struct drm_output *output)
253 +{
254 +       int enable_recorder = 0;
255 +       struct gst_recorder_settings *settings;
256 +       struct weston_config_section *section;
257 +       struct weston_config *config = wet_get_config(b->compositor);
258 +       char* s;
259 +       struct v4l2_rect crop = { .width = output->base.current_mode->width,
260 +                                 .height = output->base.current_mode->height,
261 +                                 .top = 0,
262 +                                 .left = 0 };
263 +
264 +       if (output->recorder)
265 +               return -1;
266 +
267 +       section = weston_config_get_section(config, "output", "name",
268 +                                           output->base.name);
269 +
270 +       weston_config_section_get_bool(section, "recorder", &enable_recorder, 0);
271 +
272 +       if (!enable_recorder)
273 +               return 0;
274 +
275 +       /* TODO: add support for NV16 or NV12 */
276 +       if (output->gbm_format != GBM_FORMAT_XRGB8888) {
277 +               weston_log("[gst recorder] %s: "
278 +                          "output format not supported\n", output->base.name);
279 +               return -1;
280 +       }
281 +
282 +       settings = malloc(sizeof(* settings));
283 +       weston_config_section_get_string(section, "ip", &settings->ip, NULL);
284 +       if (!settings->ip)
285 +               goto err;
286 +       weston_config_section_get_int(section, "port", &settings->port, -1);
287 +       /* default gives about 16 Mbit/s at 1280x720@60FPS */
288 +       weston_config_section_get_int(section, "bitrate", &settings->bitrate, 300000);
289 +
290 +       settings->width = output->base.current_mode->width;
291 +       settings->height = output->base.current_mode->height;
292 +
293 +       settings->crop = crop;
294 +
295 +       weston_config_section_get_string(section, "crop", &s, NULL);
296 +       if (s) {
297 +               if (parse_crop_rect(s, &settings->crop)) {
298 +                       weston_log("[gst recorder] %s:"
299 +                                  " failed to parse crop parameter\n",
300 +                                  output->base.name);
301 +                       goto err;
302 +               }
303 +       }
304 +
305 +
306 +       output->recorder =
307 +               gst_recorder_create(settings);
308 +       if (!output->recorder) {
309 +               weston_log("[gst recorder] %s:"
310 +                       " failed to create gst recorder\n",
311 +                       output->base.name);
312 +               goto err;
313 +       }
314 +
315 +       output->base.disable_planes++;
316 +
317 +       output->recorder_frame_listener.notify = recorder_frame_notify;
318 +       wl_signal_add(&output->base.frame_signal,
319 +                     &output->recorder_frame_listener);
320 +
321 +       weston_output_schedule_repaint(&output->base);
322 +
323 +       weston_log("[gst recorder] %s:"
324 +               " recorder initialized\n",
325 +               output->base.name);
326 +
327 +       return 0;
328 +err:
329 +       weston_log("[gst recorder] %s:"
330 +               " invalid settings\n",
331 +               output->base.name);
332 +       free(settings);
333 +       return -1;
334 +}
335 +
336 +static void
337 +recorders_enable(struct drm_backend *b)
338 +{
339 +       struct drm_output *output;
340 +
341 +       wl_list_for_each(output, &b->compositor->output_list, base.link) {
342 +               recorder_enable(b, output);
343 +       }
344 +}
345 +
346 +static void
347 +recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
348 +                void *data)
349 +{
350 +       struct drm_backend *b = data;
351 +       struct drm_output *output;
352 +
353 +       /* fix this */
354 +       wl_list_for_each(output, &b->compositor->output_list, base.link) {
355 +               if (!output->recorder)
356 +                       recorder_enable(b, output);
357 +               else
358 +                       recorder_destroy(output);
359 +       }
360 +}
361 +#endif
362 +
363 +#if !defined(BUILD_VAAPI_RECORDER) && !defined(BUILD_GST_RECORDER)
364 +
365  static void
366  recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
367                  void *data)
368 @@ -3562,6 +3757,7 @@ drm_backend_create(struct weston_compositor *compositor,
369         b->sprites_are_broken = 1;
370         b->compositor = compositor;
371         b->use_pixman = config->use_pixman;
372 +       b->enable_recorder = config->enable_recorder;
373  
374         if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
375                 goto err_compositor;
376 @@ -3611,6 +3807,11 @@ drm_backend_create(struct weston_compositor *compositor,
377                 }
378         }
379  
380 +#ifdef BUILD_GST_RECORDER
381 +       if (b->enable_recorder)
382 +               gst_recorder_init();
383 +#endif
384 +
385         b->base.destroy = drm_destroy;
386         b->base.restore = drm_restore;
387  
388 diff --git a/libweston/compositor-drm.h b/libweston/compositor-drm.h
389 index 00171c8..4eb6097 100644
390 --- a/libweston/compositor-drm.h
391 +++ b/libweston/compositor-drm.h
392 @@ -111,6 +111,9 @@ struct weston_drm_backend_config {
393         /** Whether to use the pixman renderer instead of the OpenGL ES renderer. */
394         bool use_pixman;
395  
396 +       /** Whether to use the v4l2 renderer insted of the OpenGL ES renderer. */
397 +       bool enable_recorder;
398 +
399         /** The seat to be used for input and output.
400          *
401          * If NULL the default "seat0" will be used.  The backend will
402 diff --git a/libweston/gst-recorder.c b/libweston/gst-recorder.c
403 new file mode 100644
404 index 0000000..d46d4f0
405 --- /dev/null
406 +++ b/libweston/gst-recorder.c
407 @@ -0,0 +1,1213 @@
408 +/*
409 + * Copyright Â© 2016 Cogent Embedded Inc
410 + *
411 + * Permission to use, copy, modify, distribute, and sell this software and
412 + * its documentation for any purpose is hereby granted without fee, provided
413 + * that the above copyright notice appear in all copies and that both that
414 + * copyright notice and this permission notice appear in supporting
415 + * documentation, and that the name of the copyright holders not be used in
416 + * advertising or publicity pertaining to distribution of the software
417 + * without specific, written prior permission.  The copyright holders make
418 + * no representations about the suitability of this software for any
419 + * purpose.  It is provided "as is" without express or implied warranty.
420 + *
421 + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
422 + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
423 + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
424 + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
425 + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
426 + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
427 + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
428 + */
429 +
430 +/*
431 + * TODO:
432 + * 1) Add format parameter to virtual display to render in another format
433 + * with v4l2-renderer
434 + * 2) Add capability to use already NV12 rendered frame
435 + */
436 +#include "config.h"
437 +
438 +#include <stdlib.h>
439 +#include <stdint.h>
440 +#include <string.h>
441 +#include <unistd.h>
442 +#include <assert.h>
443 +#include <errno.h>
444 +
445 +#include <sys/types.h>
446 +#include <sys/stat.h>
447 +#include <sys/mman.h>
448 +#include <sys/ioctl.h>
449 +#include <fcntl.h>
450 +
451 +#include <pthread.h>
452 +
453 +#include "compositor.h"
454 +#include "gst-recorder.h"
455 +
456 +/* Gstreamer includes */
457 +#include <gst/gst.h>
458 +#include <gst/app/gstappsrc.h>
459 +#include <gst/rtp/gstrtpbuffer.h>
460 +
461 +#include <gst/video/video.h>
462 +#include <gst/video/gstvideometa.h>
463 +#include <gst/video/gstvideopool.h>
464 +#include <gst/allocators/gstdmabuf.h>
465 +
466 +struct vsp_data;
467 +
468 +#define DEFAULT_FPS            60
469 +
470 +typedef enum _vsp_port_n {
471 +       VSP_PORT_INPUT  = 0,
472 +       VSP_PORT_INPUT0 = VSP_PORT_INPUT,
473 +       VSP_PORT_INPUT1,
474 +       VSP_PORT_INPUT2,
475 +       VSP_PORT_INPUT3,
476 +       VSP_PORT_OUTPUT
477 +} vsp_port_n;
478 +
479 +struct gst_recorder {
480 +       struct gst_recorder_settings *set;
481 +       int frame_count;
482 +       int input_count;
483 +
484 +       int error;
485 +       int destroying;
486 +       pthread_t worker_thread;
487 +       pthread_mutex_t mutex;
488 +       pthread_cond_t input_cond;
489 +
490 +       struct {
491 +               int valid;
492 +               int prime_fd, stride;
493 +       } input;
494 +
495 +       /* GLib */
496 +       GMainContext *gcontext;
497 +       /* Gstreamer stuff */
498 +       GstElement *pipeline;
499 +       /* AppSrc */
500 +       GstAppSrc *appsrc;
501 +       /* ...and source pad */
502 +       GstPad *appsrc_pad;
503 +       /* OMX encoder buffer pool */
504 +       GstBufferPool *omx_pool;
505 +       /* bus */
506 +       GstBus *bus;
507 +       /* timestamp */
508 +       GstClock   *clock;
509 +       GstClockTime timestamp;
510 +       GstClockTime ts_last_frame;
511 +       /* to be removed */
512 +       guint callback_tag;
513 +
514 +       struct vsp_data *vsp;
515 +};
516 +
517 +/*******************************************************************************
518 + * VSP related code
519 + ******************************************************************************/
520 +
521 +#define VSP_OUTPUT_BUFFERS_PLANE       2
522 +
523 +/* #define VSP_OUTPUT_NV16                     1 */
524 +
525 +/* ...number of input/output pads (WPF1-3 are not implemented) */
526 +#define VSP_PADS_NUM                    1
527 +
528 +/*******************************************************************************
529 + * Local types definition
530 + ******************************************************************************/
531 +
532 +struct vsp_media_pad
533 +{
534 +       struct media_pad           *infmt_pad;
535 +       struct media_pad           *outfmt_pad;
536 +       struct media_entity        *entity;
537 +       int                     fd;
538 +};
539 +
540 +typedef struct vsp_media_pad vsp_media_pad_t;
541 +
542 +struct vsp_data
543 +{
544 +       /* ...media device */
545 +       struct media_device *media;
546 +
547 +       /* ...VSP input/output pads */
548 +       vsp_media_pad_t input, output;
549 +
550 +       /* mutex */
551 +       pthread_mutex_t mutex;
552 +
553 +       /* user count */
554 +       int users;
555 +};
556 +
557 +struct vsp_data *vsp_g = NULL;
558 +
559 +/* ...type declarations */
560 +typedef struct vsp_data vsp_data_t;
561 +
562 +static int
563 +gst_recorder_process_dmafd(struct gst_recorder *r, int fd, int stride);
564 +
565 +/* ...module initialization (a bit of salami) */
566 +static vsp_data_t *
567 +vsp_init(const char *devname)
568 +{
569 +       vsp_data_t                     *vsp;
570 +       struct media_device            *media;
571 +       const struct media_device_info *info;
572 +       const char                     *dev;
573 +       char                            buf[256];
574 +       char                           *endp, *p;
575 +       struct media_entity            *entity;
576 +
577 +       /* ...create data structure */
578 +       if ((vsp = malloc(sizeof(*vsp))) == NULL)
579 +       {
580 +               weston_log("failed to allocate memory\n");
581 +               errno = ENOMEM;
582 +               return NULL;
583 +       }
584 +       memset(vsp, 0, sizeof(*vsp));
585 +
586 +       pthread_mutex_init(&vsp->mutex, NULL);
587 +
588 +       /* ...create media device */
589 +       if ((vsp->media = media = media_device_new(devname)) == NULL)
590 +       {
591 +               weston_log("failed to open device '%s'\n", devname);
592 +               goto error;
593 +       }
594 +       else if ((errno = -media_device_enumerate(media)) != 0)
595 +       {
596 +               weston_log("failed to enumerate device '%s'\n", devname);
597 +               goto error_media;
598 +       }
599 +       else if ((info = media_get_info(media)) == NULL)
600 +       {
601 +               weston_log("failed to get media info data\n");
602 +               goto error_media;
603 +       }
604 +       else
605 +       {
606 +               dev = ((p = strchr(info->bus_info, ':')) ? p + 1 : info->bus_info);
607 +               weston_log("open media device: %s (%s)\n", info->bus_info, dev);
608 +       }
609 +
610 +       /* ...reset links */
611 +       if (media_reset_links(media) != 0)
612 +       {
613 +               weston_log("failed to reset media device\n");
614 +               goto error_media;
615 +       }
616 +
617 +       /* ...setup RPF.0:1 -> WPF.0:0 link */
618 +       snprintf(buf, sizeof(buf), "'%s rpf.0':1 -> '%s wpf.0':0 [1]", dev, dev);
619 +       if (media_parse_setup_link(media, buf, &endp) != 0)
620 +       {
621 +               weston_log("failed to setup link '%s'\n", buf);
622 +               errno = EINVAL;
623 +               goto error_media;
624 +       }
625 +
626 +       /* ...setup WPF.0:1 -> WPF.0 output link */
627 +       snprintf(buf, sizeof(buf), "'%s wpf.0':1 -> '%s wpf.0 output':0 [1]", dev, dev);
628 +       if (media_parse_setup_link(media, buf, &endp) != 0)
629 +       {
630 +               weston_log("failed to setup link '%s'\n", buf);
631 +               errno = EINVAL;
632 +               goto error_media;
633 +       }
634 +
635 +       /* ...specify input/output-format of RPF pad */
636 +       snprintf(buf, sizeof(buf), "'%s rpf.0':0", dev);
637 +       if ((vsp->input.infmt_pad = media_parse_pad(media, buf, NULL)) == NULL)
638 +       {
639 +               weston_log("failed to parse pad '%s'\n", buf);
640 +               errno = EINVAL;
641 +               goto error_media;
642 +       }
643 +
644 +       snprintf(buf, sizeof(buf), "'%s rpf.0':1", dev);
645 +       if ((vsp->input.outfmt_pad = media_parse_pad(media, buf, NULL)) == NULL)
646 +       {
647 +               weston_log("failed to parse pad '%s'\n", buf);
648 +               errno = EINVAL;
649 +               goto error_media;
650 +       }
651 +
652 +       snprintf(buf, sizeof(buf), "%s rpf.0", dev);
653 +       if ((vsp->input.entity = media_get_entity_by_name(media, buf, strlen(buf))) == NULL)
654 +       {
655 +               weston_log("failed to parse entity '%s'\n", buf);
656 +               errno = EINVAL;
657 +               goto error_media;
658 +       }
659 +
660 +       /* ...get input file-descriptor */
661 +       snprintf(buf, sizeof(buf), "%s rpf.0 input", dev);
662 +       if ((entity = media_get_entity_by_name(media, buf, strlen(buf))) == NULL)
663 +       {
664 +               weston_log("entity '%s' not found\n", buf);
665 +               errno = EINVAL;
666 +               goto error_media;
667 +       }
668 +       else if (v4l2_subdev_open(entity) != 0)
669 +       {
670 +               weston_log("failed to open subdev '%s'\n", buf);
671 +               goto error_media;
672 +       }
673 +       else if ((vsp->input.fd = open(media_entity_get_devname(entity), O_RDWR/* | O_NONBLOCK*/)) < 0)
674 +       {
675 +               weston_log("failed to open device '%s'\n", media_entity_get_devname(entity));
676 +               goto error_media;
677 +       }
678 +       else
679 +       {
680 +               weston_log("input pad setup ('%s':'%s')\n", buf, media_entity_get_devname(entity));
681 +       }
682 +
683 +       /* ...specify input/output formats of WPF pad */
684 +       snprintf(buf, sizeof(buf), "'%s wpf.0':0", dev);
685 +       if ((vsp->output.infmt_pad = media_parse_pad(media, buf, NULL)) == NULL)
686 +       {
687 +               weston_log("failed to parse pad '%s'\n", buf);
688 +               errno = EINVAL;
689 +               goto error_media;
690 +       }
691 +
692 +       snprintf(buf, sizeof(buf), "'%s wpf.0':1", dev);
693 +       if ((vsp->output.outfmt_pad = media_parse_pad(media, buf, NULL)) == NULL)
694 +       {
695 +               weston_log("failed to parse pad '%s'\n", buf);
696 +               errno = EINVAL;
697 +               goto error_media;
698 +       }
699 +
700 +       snprintf(buf, sizeof(buf), "%s wpf.0", dev);
701 +       if ((vsp->output.entity = media_get_entity_by_name(media, buf, strlen(buf))) == NULL)
702 +       {
703 +               weston_log("failed to parse entity '%s'\n", buf);
704 +               errno = EINVAL;
705 +               goto error_media;
706 +       }
707 +
708 +       /* ...get a file descriptor for the output */
709 +       snprintf(buf, sizeof(buf), "%s wpf.0 output", dev);
710 +       if ((entity = media_get_entity_by_name(media, buf, strlen(buf))) == NULL)
711 +       {
712 +               weston_log("failed to get entity '%s'\n", buf);
713 +               errno = EINVAL;
714 +               goto error_media;
715 +       }
716 +       else if (v4l2_subdev_open(entity) != 0)
717 +       {
718 +               weston_log("failed to open subdev '%s'\n", buf);
719 +               goto error_media;
720 +       }
721 +       else if ((vsp->output.fd = open(media_entity_get_devname(entity), O_RDWR | O_NONBLOCK)) < 0)
722 +       {
723 +               weston_log("failed to open device '%s'\n", media_entity_get_devname(entity));
724 +               goto error_media;
725 +       }
726 +       else
727 +       {
728 +               weston_log("output pad setup (%s:%s)\n", buf, media_entity_get_devname(entity));
729 +       }
730 +
731 +       weston_log("vsp-device '%s' created\n", devname);
732 +
733 +       return vsp;
734 +
735 +error_media:
736 +       /* ...destroy media device and all associated structures */
737 +       media_device_unref(vsp->media);
738 +
739 +error:
740 +       /* ...destroy data structure */
741 +       free(vsp);
742 +       return NULL;
743 +}
744 +
745 +static void
746 +vsp_deinit(vsp_data_t *vsp)
747 +{
748 +       /* ...destroy media device and all associated structures */
749 +       media_device_unref(vsp->media);
750 +
751 +       /* ...destroy data structure */
752 +       free(vsp);
753 +}
754 +
755 +/* ...set V4L2 device format */
756 +static int
757 +vsp_set_format(int fd, struct v4l2_format *fmt)
758 +{
759 +       /* ...set format */
760 +       if (ioctl(fd, VIDIOC_S_FMT, fmt) < 0) {
761 +               weston_log("format set (fd=%d) failed: %d\n",
762 +                       fd, errno);
763 +       }
764 +
765 +       return 0;
766 +}
767 +
768 +/* ...start streaming on specific V4L2 device */
769 +static int
770 +vsp_streaming_enable(vsp_data_t *vsp, vsp_port_n port, int enable)
771 +{
772 +       vsp_media_pad_t *pad = (port == VSP_PORT_INPUT) ? &vsp->input : &vsp->output;
773 +       int fd = pad->fd;
774 +       int type = (port == VSP_PORT_INPUT) ?
775 +               V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
776 +
777 +       return ioctl(fd, (enable ? VIDIOC_STREAMON : VIDIOC_STREAMOFF), &type);
778 +}
779 +
780 +/* ...prepare VSP filter for operation */
781 +static int
782 +vsp_set_formats(vsp_data_t *vsp, int width, int height, struct v4l2_rect* crop)
783 +{
784 +       vsp_media_pad_t *input = &vsp->input, *output = &vsp->output;
785 +       struct v4l2_mbus_framefmt mfmt = { .width = width, .height = height };
786 +       struct v4l2_format format;
787 +
788 +       /* ...configure RPF input pads; specify pixel format and size (one of YUV variants) */
789 +       mfmt.width = width;
790 +       mfmt.height = height;
791 +       mfmt.code = V4L2_MBUS_FMT_ARGB8888_1X32;
792 +       if (v4l2_subdev_set_format(input->infmt_pad->entity,
793 +               &mfmt, input->infmt_pad->index, V4L2_SUBDEV_FORMAT_ACTIVE) < 0) {
794 +               weston_log("VSP: input pad in format set failed: %d\n", errno);
795 +               return -1;
796 +       }
797 +
798 +        /* set a crop paramters */
799 +       if (v4l2_subdev_set_selection(input->infmt_pad->entity, crop, input->infmt_pad->index,
800 +                                     V4L2_SEL_TGT_CROP, V4L2_SUBDEV_FORMAT_ACTIVE)) {
801 +               weston_log("set crop parameter failed: %dx%d@(%d,%d).\n",
802 +                          crop->width, crop->height, crop->left, crop->top);
803 +               return -1;
804 +       }
805 +
806 +       /* ...output is NV12 or NV16 or I420*/
807 +       mfmt.width = crop->width;
808 +       mfmt.height = crop->height;
809 +       mfmt.code = V4L2_MBUS_FMT_AYUV8_1X32;
810 +       if (v4l2_subdev_set_format(input->outfmt_pad->entity,
811 +               &mfmt, input->outfmt_pad->index, V4L2_SUBDEV_FORMAT_ACTIVE) < 0) {
812 +               weston_log("VSP: input pad out format set failed: %d\n", errno);
813 +               return -1;
814 +       }
815 +
816 +       /* ...specify input format */
817 +       memset(&format, 0, sizeof(format));
818 +       format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
819 +       format.fmt.pix_mp.width = /* crop-> */width;
820 +       format.fmt.pix_mp.height = /* crop-> */height;
821 +       format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_ABGR32;
822 +       format.fmt.pix_mp.num_planes = 1;
823 +       /* ...set input port format */
824 +       if (vsp_set_format(input->fd, &format) < 0) {
825 +               weston_log("VSP: input set format failed: %d\n", errno);
826 +               return -1;
827 +       }
828 +
829 +       /* ...both input and output are ARGB8888 always (now effective) */
830 +       if (v4l2_subdev_set_format(output->infmt_pad->entity,
831 +               &mfmt, output->infmt_pad->index, V4L2_SUBDEV_FORMAT_ACTIVE) < 0) {
832 +               weston_log("VSP: output pad in format set failed: %d\n", errno);
833 +               return -1;
834 +       }
835 +
836 +       /* ...specify cropping area, probably? - tbd */
837 +       if (v4l2_subdev_set_format(output->outfmt_pad->entity,
838 +               &mfmt, output->outfmt_pad->index, V4L2_SUBDEV_FORMAT_ACTIVE) < 0) {
839 +               weston_log("VSP: output pad in format set failed: %d\n", errno);
840 +               return -1;
841 +       }
842 +
843 +       /* ...setup output pads */
844 +       memset(&format, 0, sizeof(format));
845 +       format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
846 +       format.fmt.pix_mp.width = crop->width;
847 +       format.fmt.pix_mp.height = crop->height;
848 +#ifdef VSP_OUTPUT_NV16
849 +       format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV16M;
850 +#else
851 +       format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M;
852 +#endif
853 +       format.fmt.pix_mp.num_planes = VSP_OUTPUT_BUFFERS_PLANE;
854 +       /* ...set output buffer format */
855 +       if (vsp_set_format(output->fd, &format) < 0) {
856 +               weston_log("VSP: output set format failed: %d\n", errno);
857 +               return -1;
858 +       }
859 +
860 +       return 0;
861 +}
862 +
863 +static int
864 +vsp_request_buffers(vsp_data_t *vsp, vsp_port_n port, unsigned int num)
865 +{
866 +       vsp_media_pad_t *pad = (port == VSP_PORT_INPUT) ? &vsp->input : &vsp->output;
867 +       struct v4l2_requestbuffers reqbuf;
868 +       int fd = pad->fd;
869 +
870 +       /* ...input buffers are DMA-fd, output buffers allocated by kernel */
871 +       memset(&reqbuf, 0, sizeof(reqbuf));
872 +       reqbuf.type = (port == VSP_PORT_INPUT) ?
873 +               V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
874 +       reqbuf.memory = V4L2_MEMORY_DMABUF;
875 +       reqbuf.count = num;
876 +       if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
877 +               weston_log("VSP: %s REQBUFS failed: %d\n",
878 +                       (port == VSP_PORT_INPUT) ? "input" : "output", errno);
879 +               return -1;
880 +       }
881 +
882 +       if (reqbuf.count != num) {
883 +               weston_log("VSP: %s failed to request %d (!= %d) bufs\n",
884 +                       (port == VSP_PORT_INPUT) ? "input" : "output", num, reqbuf.count);
885 +               return -1;
886 +       }
887 +       return 0;
888 +}
889 +
890 +
891 +/* ...enqueue dmafd buffer */
892 +static int
893 +vsp_input_buffer_queue_dmafd(vsp_data_t *vsp, int i, int dmafd)
894 +{
895 +       vsp_media_pad_t    *pad = &vsp->input;
896 +       struct v4l2_buffer  buf;
897 +       struct v4l2_plane   planes[1];
898 +
899 +       /* ...set buffer parameters */
900 +       memset(&buf, 0, sizeof(buf));
901 +       memset(planes, 0, sizeof(planes));
902 +       buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
903 +       buf.memory = V4L2_MEMORY_DMABUF;
904 +       buf.index = i;
905 +       buf.m.planes = planes;
906 +       buf.length = 1;
907 +       buf.m.planes[0].m.fd = dmafd;
908 +
909 +       /* ...submit buffer */
910 +       if (ioctl(pad->fd, VIDIOC_QBUF, &buf) < 0) {
911 +               weston_log("VSP: input dmafd (%d) buffer (%i) queue failed: %d\n",
912 +                       dmafd, i, errno);
913 +               return -1;
914 +       }
915 +
916 +       return 0;
917 +}
918 +
919 +/* ...dequeue dmafd buffer */
920 +static int
921 +vsp_input_buffer_dequeue_dmafd(vsp_data_t *vsp)
922 +{
923 +       vsp_media_pad_t    *pad = &vsp->input;
924 +       struct v4l2_buffer  buf;
925 +       struct v4l2_plane   planes[1];
926 +
927 +       /* ...set buffer parameters */
928 +       memset(&buf, 0, sizeof(buf));
929 +       memset(planes, 0, sizeof(planes));
930 +       buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
931 +       buf.memory = V4L2_MEMORY_DMABUF;
932 +       buf.m.planes = planes;
933 +       buf.length = 1;
934 +
935 +       if (ioctl(pad->fd, VIDIOC_DQBUF, &buf) < 0) {
936 +               weston_log("VSP: input dmafd buffer de-queue failed: %d\n", errno);
937 +               return -1;
938 +       }
939 +
940 +       /* ...return buffer index */
941 +       return buf.index;
942 +}
943 +
944 +/* ...enqueue output buffer */
945 +static int
946 +vsp_output_buffer_queue_dmafd(vsp_data_t *vsp, int i, int dmafd[])
947 +{
948 +       vsp_media_pad_t    *pad = &vsp->output;
949 +       struct v4l2_plane   planes[2];
950 +       struct v4l2_buffer  buf;
951 +
952 +       /* ...set buffer parameters (single-plane ARGB always) */
953 +       memset(&buf, 0, sizeof(buf));
954 +       memset(planes, 0, sizeof(planes));
955 +       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
956 +       buf.memory = V4L2_MEMORY_DMABUF;
957 +       buf.index = i;
958 +       buf.m.planes = planes;
959 +       buf.length = VSP_OUTPUT_BUFFERS_PLANE;
960 +       buf.m.planes[0].m.fd = dmafd[0];
961 +       buf.m.planes[1].m.fd = dmafd[1];
962 +
963 +       /* ...submit buffer */
964 +       if (ioctl(pad->fd, VIDIOC_QBUF, &buf) < 0) {
965 +               weston_log("VSP: output dmafd queue failed: %d\n", errno);
966 +               return -1;
967 +       }
968 +
969 +       return 0;
970 +}
971 +
972 +/* ...dequeue output buffer */
973 +static int
974 +vsp_output_buffer_dequeue_dmafd(vsp_data_t *vsp)
975 +{
976 +       vsp_media_pad_t    *pad = &vsp->output;
977 +       struct v4l2_buffer  buf;
978 +       struct v4l2_plane   planes[2];
979 +
980 +       /* ...set buffer parameters */
981 +       memset(&buf, 0, sizeof(buf));
982 +       memset(planes, 0, sizeof(planes));
983 +       buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
984 +       buf.memory = V4L2_MEMORY_DMABUF;
985 +       buf.m.planes = planes;
986 +       buf.length = VSP_OUTPUT_BUFFERS_PLANE;
987 +
988 +       if (ioctl(pad->fd, VIDIOC_DQBUF, &buf) < 0) {
989 +               weston_log("VSP: output dmafd de-queue failed: %d\n", errno);
990 +               return -1;
991 +       }
992 +
993 +       /* ...return dequeue buffer index */
994 +       return buf.index;
995 +}
996 +
997 +/* ...get capturing interface file descriptor */
998 +static int
999 +vsp_capture_fd(vsp_data_t *vsp)
1000 +{
1001 +       return vsp->output.fd;
1002 +}
1003 +
1004 +/*******************************************************************************
1005 + * Gstreamer stuff
1006 + ******************************************************************************/
1007 +
1008 +static void
1009 +print_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
1010 +{
1011 +       int i, num;
1012 +
1013 +       num = gst_tag_list_get_tag_size (list, tag);
1014 +       for (i = 0; i < num; ++i) {
1015 +               const GValue *val;
1016 +
1017 +               /* Note: when looking for specific tags, use the gst_tag_list_get_xyz() API,
1018 +                * we only use the GValue approach here because it is more generic */
1019 +               val = gst_tag_list_get_value_index (list, tag, i);
1020 +               if (G_VALUE_HOLDS_STRING (val)) {
1021 +                       weston_log("\t%20s : %s\n", tag, g_value_get_string (val));
1022 +               } else if (G_VALUE_HOLDS_UINT (val)) {
1023 +                       weston_log("\t%20s : %u\n", tag, g_value_get_uint (val));
1024 +               } else if (G_VALUE_HOLDS_DOUBLE (val)) {
1025 +                       weston_log("\t%20s : %g\n", tag, g_value_get_double (val));
1026 +               } else if (G_VALUE_HOLDS_BOOLEAN (val)) {
1027 +                       weston_log("\t%20s : %s\n", tag,
1028 +                                       (g_value_get_boolean (val)) ? "true" : "false");
1029 +               } else if (GST_VALUE_HOLDS_BUFFER (val)) {
1030 +                       GstBuffer *buf = gst_value_get_buffer (val);
1031 +                       guint buffer_size = gst_buffer_get_size (buf);
1032 +
1033 +                       weston_log("\t%20s : buffer of size %u\n", tag, buffer_size);
1034 +               } else if (GST_VALUE_HOLDS_DATE_TIME (val)) {
1035 +                       GstDateTime *dt = g_value_get_boxed (val);
1036 +                       gchar *dt_str = gst_date_time_to_iso8601_string (dt);
1037 +
1038 +                       weston_log("\t%20s : %s\n", tag, dt_str);
1039 +                       g_free (dt_str);
1040 +               } else {
1041 +                       weston_log("\t%20s : tag of type '%s'\n", tag, G_VALUE_TYPE_NAME (val));
1042 +               }
1043 +       }
1044 +}
1045 +
1046 +static gboolean
1047 +gst_bus_callback(GstBus *bus, GstMessage *message, gpointer user_data)
1048 +{
1049 +       GTimeVal time;
1050 +       struct gst_recorder *r = user_data;
1051 +
1052 +       if (!r->pipeline) {
1053 +               weston_log("gst_pipeline: unexpected gst bus callback event, while pipeline==null\n");
1054 +               return TRUE;
1055 +       }
1056 +
1057 +       g_get_current_time(&time);
1058 +
1059 +       switch (GST_MESSAGE_TYPE(message))
1060 +       {
1061 +               case GST_MESSAGE_QOS:
1062 +                       {
1063 +                               GstFormat format;
1064 +                               guint64 processed;
1065 +                               guint64 dropped;
1066 +
1067 +                               gst_message_parse_qos_stats (message, &format, &processed, &dropped);
1068 +                               weston_log("gst_pipeline: qos from: %s processed %lud, dropped %lud\n",
1069 +                                       GST_OBJECT_NAME (message->src),
1070 +                                       processed, dropped);
1071 +                       }
1072 +               break;
1073 +               case GST_MESSAGE_STREAM_STATUS:
1074 +                       {
1075 +                               const GValue *val;
1076 +
1077 +                               val = gst_message_get_stream_status_object (message);
1078 +                               weston_log("gst_pipeline: stream status type %s, value %p\n",
1079 +                                       G_VALUE_TYPE_NAME(val),
1080 +                                       g_value_get_object(val));
1081 +                       }
1082 +               break;
1083 +               case GST_MESSAGE_TAG:
1084 +                       {
1085 +                               GstTagList *tags = NULL;
1086 +
1087 +                               gst_message_parse_tag (message, &tags);
1088 +                               weston_log("gst_pipeline: tag from element %s:\n",
1089 +                                       GST_OBJECT_NAME (message->src));
1090 +                               gst_tag_list_foreach (tags, print_one_tag, NULL);
1091 +                               weston_log("\n");
1092 +                       }
1093 +               break;
1094 +               case GST_MESSAGE_STATE_CHANGED:
1095 +                       {
1096 +                               GstState oldstate, newstate;
1097 +
1098 +                               gst_message_parse_state_changed(message, &oldstate, &newstate, NULL);
1099 +                               weston_log("gst_pipeline: element %s changed state from %s to %s.\n",
1100 +                                       GST_OBJECT_NAME (message->src),
1101 +                                       gst_element_state_get_name (oldstate),
1102 +                                       gst_element_state_get_name (newstate));
1103 +
1104 +                               /* if gstreamer become ready */
1105 +                               if ((GST_MESSAGE_SRC(message) == GST_OBJECT(r->appsrc)) &&
1106 +                                       (newstate == GST_STATE_PAUSED)) {
1107 +                                       weston_log("gst_pipeline: pipeline ready\n");
1108 +                               }
1109 +                       }
1110 +               break;
1111 +               case GST_MESSAGE_ERROR:
1112 +                       {
1113 +                               GError *err;
1114 +                               gchar *debug_info;
1115 +                               gst_message_parse_error(message, &err, &debug_info);
1116 +                               weston_log("gst_pipeline: error received from element %s: %s\n",
1117 +                                       GST_OBJECT_NAME(message->src), err->message);
1118 +                               weston_log("gst_pipeline: debugging information: %s\n",
1119 +                                       debug_info ? debug_info : "none");
1120 +                               g_clear_error (&err);
1121 +                               g_free (debug_info);
1122 +                       }
1123 +               break;
1124 +               case GST_MESSAGE_WARNING:
1125 +                       {
1126 +                               GError *err;
1127 +                               gchar *debug_info;
1128 +                               gst_message_parse_warning(message, &err, &debug_info);
1129 +                               weston_log("gst_pipeline: warning received from element %s: %s\n",
1130 +                                       GST_OBJECT_NAME(message->src), err->message);
1131 +                               weston_log("gst_pipeline: debugging information: %s\n",
1132 +                                       debug_info ? debug_info : "none");
1133 +                               g_clear_error (&err);
1134 +                               g_free (debug_info);
1135 +                       }
1136 +               break;
1137 +               default:
1138 +                       weston_log("gst_pipeline: %s from %s\n",
1139 +                               GST_MESSAGE_TYPE_NAME(message), GST_OBJECT_NAME (message->src));
1140 +               break;
1141 +       }
1142 +       return TRUE;
1143 +}
1144 +
1145 +static void *
1146 +worker_thread_function(void *data)
1147 +{
1148 +       GstMessage *msg;
1149 +       struct gst_recorder *r = data;
1150 +
1151 +       pthread_mutex_lock(&r->mutex);
1152 +
1153 +       while (!r->destroying) {
1154 +               if (!r->input.valid)
1155 +                       pthread_cond_wait(&r->input_cond, &r->mutex);
1156 +
1157 +               /* If the thread is awaken by destroy_worker_thread(),
1158 +                * there might not be valid input */
1159 +               if (!r->input.valid)
1160 +                       continue;
1161 +
1162 +               /* TODO: move it to separate thread? */
1163 +               g_main_context_iteration(r->gcontext, FALSE);
1164 +
1165 +               do {
1166 +                       msg = gst_bus_pop_filtered(r->bus,
1167 +                                                  GST_MESSAGE_ANY);
1168 +                       if (msg) {
1169 +                               gst_bus_callback(r->bus, msg, r);
1170 +                       }
1171 +               } while (msg);
1172 +
1173 +               /* check input */
1174 +               gst_recorder_process_dmafd(r, r->input.prime_fd, r->input.stride);
1175 +
1176 +               r->input.valid = 0;
1177 +       }
1178 +
1179 +       pthread_mutex_unlock(&r->mutex);
1180 +
1181 +       return NULL;
1182 +}
1183 +
1184 +static int
1185 +setup_worker_thread(struct gst_recorder *r)
1186 +{
1187 +       r->gcontext = g_main_context_new();
1188 +       pthread_mutex_init(&r->mutex, NULL);
1189 +       pthread_cond_init(&r->input_cond, NULL);
1190 +       pthread_create(&r->worker_thread, NULL, worker_thread_function, r);
1191 +
1192 +       return 1;
1193 +}
1194 +
1195 +static void
1196 +destroy_worker_thread(struct gst_recorder *r)
1197 +{
1198 +       /* Make sure the worker thread finishes */
1199 +       r->destroying = 1;
1200 +
1201 +       pthread_cond_signal(&r->input_cond);
1202 +
1203 +       pthread_join(r->worker_thread, NULL);
1204 +
1205 +       pthread_mutex_destroy(&r->mutex);
1206 +       pthread_cond_destroy(&r->input_cond);
1207 +}
1208 +
1209 +void weston_debug_function(GstDebugCategory* category, GstDebugLevel level,
1210 +                          const gchar* file, const char* function,
1211 +                          gint line, GObject* object, GstDebugMessage* message,
1212 +                          gpointer data)
1213 +{
1214 +       weston_log("[GST]:%s %s:%d %s\n", file, function, line, gst_debug_message_get(message));
1215 +}
1216 +
1217 +void
1218 +gst_recorder_init(void)
1219 +{
1220 +       gst_init(NULL, 0);
1221 +
1222 +       /* VSP init */
1223 +       vsp_g = vsp_init("/dev/media0");
1224 +       if (!vsp_g)
1225 +               weston_log("[gst recorder] VSP init failed\n");
1226 +}
1227 +
1228 +static int
1229 +gst_recorder_find_omx_pool(struct gst_recorder *r)
1230 +{
1231 +       int ret = 0;
1232 +       GstCaps *caps;
1233 +       GstQuery *query;
1234 +       GstBufferPool *pool;
1235 +       GstStructure *config;
1236 +       guint size, min, max;
1237 +
1238 +       caps = gst_caps_new_simple (    "video/x-raw",
1239 +#ifdef VSP_OUTPUT_NV16
1240 +                                       "format", G_TYPE_STRING, "NV16",
1241 +#else
1242 +                                       "format", G_TYPE_STRING, "NV12",
1243 +#endif
1244 +                                       "width", G_TYPE_INT, r->set->crop.width,
1245 +                                       "height", G_TYPE_INT, r->set->crop.height,
1246 +                                       "framerate", GST_TYPE_FRACTION, 0, DEFAULT_FPS,
1247 +                                       NULL);
1248 +
1249 +       /* find a pool for the negotiated caps now */
1250 +       query = gst_query_new_allocation (caps, TRUE);
1251 +
1252 +       if (!gst_pad_peer_query (r->appsrc_pad, query)) {
1253 +               /* query failed, not a problem, we use the query defaults */
1254 +               weston_log("allocation query failed\n");
1255 +               ret = -1;
1256 +               goto err;
1257 +       }
1258 +
1259 +       weston_log("goot %d pools\n", gst_query_get_n_allocation_pools (query));
1260 +       if (gst_query_get_n_allocation_pools (query) > 0) {
1261 +               /* we got configuration from our peer, parse them */
1262 +               gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1263 +               weston_log(" pool settings size %d, min %d, max %d\n", size, min, max);
1264 +       } else {
1265 +               weston_log("no pool queried\n");
1266 +               ret = -1;
1267 +               goto err;
1268 +       }
1269 +
1270 +       config = gst_buffer_pool_get_config (pool);
1271 +       gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1272 +       gst_buffer_pool_config_set_params (config, caps, size, min, max);
1273 +       gst_buffer_pool_set_config (pool, config);
1274 +
1275 +       /* and activate */
1276 +       gst_buffer_pool_set_active (pool, TRUE);
1277 +
1278 +       r->omx_pool = pool;
1279 +
1280 +err:
1281 +       gst_query_unref (query);
1282 +       return ret;
1283 +}
1284 +
1285 +static int
1286 +gst_recorder_omx_buffer_acquire(struct gst_recorder *r, GstBuffer **ret_buf, int fd[])
1287 +{
1288 +       unsigned int i;
1289 +       GstFlowReturn ret;
1290 +       GstBuffer *buf;
1291 +       guint n_mem;
1292 +       GstMemory *mem;
1293 +
1294 +       ret = gst_buffer_pool_acquire_buffer(r->omx_pool, &buf, NULL);
1295 +       if (ret != GST_FLOW_OK) {
1296 +               weston_log("OMX buffer acquire failed\n");
1297 +               return -1;
1298 +       }
1299 +
1300 +       n_mem = gst_buffer_n_memory(buf);
1301 +       if (n_mem < 1) {
1302 +               weston_log("Buffer with no mem!\n");
1303 +               goto err_release;
1304 +       }
1305 +
1306 +       for (i = 0; i < n_mem; i++) {
1307 +               mem = gst_buffer_peek_memory (buf, i);
1308 +               if (!gst_is_dmabuf_memory (mem)) {
1309 +                       weston_log("Mem not dmabuf\n");
1310 +                       goto err_release;
1311 +               }
1312 +               fd[i] = gst_dmabuf_memory_get_fd (mem);
1313 +       }
1314 +
1315 +       *ret_buf = buf;
1316 +
1317 +       return 0;
1318 +err_release:
1319 +       gst_buffer_pool_release_buffer(r->omx_pool, buf);
1320 +       return -1;
1321 +}
1322 +
1323 +static int
1324 +gst_recorder_omx_buffer_release(struct gst_recorder *r, GstBuffer *buf)
1325 +{
1326 +       gst_buffer_pool_release_buffer(r->omx_pool, buf);
1327 +
1328 +       return 0;
1329 +}
1330 +
1331 +struct gst_recorder *
1332 +gst_recorder_create(struct gst_recorder_settings *settings)
1333 +{
1334 +       struct gst_recorder *r;
1335 +       char gst_pipe[1024];
1336 +       char *ptr = gst_pipe;
1337 +       GError *perror = NULL;
1338 +
1339 +       weston_log("gst_recorder_create (%dx%d) crop %dx%d at %d,%d\n",
1340 +                  settings->width, settings->height, settings->crop.width,
1341 +                  settings->crop.height, settings->crop.top, settings->crop.left);
1342 +
1343 +       if (!vsp_g) {
1344 +               weston_log("gst_recorder_create: no VSP\n");
1345 +               return NULL;
1346 +       }
1347 +
1348 +       r = calloc(1, sizeof *r);
1349 +       if (!r)
1350 +               return NULL;
1351 +       memset(r, 0, sizeof *r);
1352 +
1353 +       r->set = settings;
1354 +       r->timestamp = 0;
1355 +
1356 +       r->vsp = vsp_g;
1357 +       vsp_g->users++;
1358 +
1359 +       /* GST init */
1360 +       /* source (GST_FORMAT_BYTES) */
1361 +       ptr += sprintf(ptr,
1362 +               "appsrc name=src ! ");
1363 +
1364 +       /* omx */
1365 +       ptr += sprintf(ptr,
1366 +               "omxh264enc target-bitrate=%d control-rate=2 name=my_encoder ! "
1367 +               "video/x-h264,width=%d,height=%d ! ",
1368 +               r->set->bitrate, r->set->crop.width, r->set->crop.height);
1369 +
1370 +       /* rtp payloader */
1371 +       ptr += sprintf(ptr,
1372 +               "rtph264pay config-interval=1 name=my_h264pay ! queue  ! ");
1373 +
1374 +       /* usp sink */
1375 +       ptr += sprintf(ptr,
1376 +               "udpsink host=%s ", r->set->ip);
1377 +       if (r->set->port > 0)
1378 +               ptr += sprintf(ptr,
1379 +                       " port=%d name=my_udpsink", r->set->port);
1380 +
1381 +       weston_log("gst_pipeline: starting: %s\n", gst_pipe);
1382 +
1383 +       /* launch */
1384 +       r->pipeline = gst_parse_launch (gst_pipe, &perror);
1385 +       if (!r->pipeline) {
1386 +               weston_log("gst_pipeline: can not start pipeline: %s\n", perror->message);
1387 +               goto err_gst;
1388 +       }
1389 +
1390 +       /* get appsrc */
1391 +       r->appsrc = gst_bin_get_by_name(GST_BIN (r->pipeline), "src");
1392 +       if (!r->appsrc) {
1393 +               weston_log("gst_pipeline: can not get appsrc\n");
1394 +               goto err_gst;
1395 +       }
1396 +
1397 +       /* get bus */
1398 +       r->bus = gst_pipeline_get_bus (GST_PIPELINE(r->pipeline));
1399 +       if (!r->bus) {
1400 +               weston_log("gst_pipeline: can not get bus\n");
1401 +               goto err_gst;
1402 +       }
1403 +
1404 +       setup_worker_thread(r);
1405 +
1406 +       /* setup caps */
1407 +       g_object_set(G_OBJECT(r->appsrc), "caps",
1408 +               gst_caps_new_simple (   "video/x-raw",
1409 +#ifdef VSP_OUTPUT_NV16
1410 +                                       "format", G_TYPE_STRING, "NV16",
1411 +#else
1412 +                                       "format", G_TYPE_STRING, "NV12",
1413 +#endif
1414 +                                       "width", G_TYPE_INT, r->set->crop.width,
1415 +                                       "height", G_TYPE_INT, r->set->crop.height,
1416 +                                       "framerate", GST_TYPE_FRACTION, 0, DEFAULT_FPS,
1417 +                                       NULL), NULL);
1418 +
1419 +       r->appsrc_pad = gst_element_get_static_pad(GST_ELEMENT_CAST(r->appsrc), "src");
1420 +       if (!r->appsrc_pad)
1421 +               weston_log("Failed to get src0 pad of appsrc\n");
1422 +
1423 +       /* set playing */
1424 +       if (gst_element_set_state (r->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
1425 +               weston_log("gst_pipeline: can not change state to PLAYING\n");
1426 +               goto err_gst;
1427 +       }
1428 +
1429 +       if (gst_recorder_find_omx_pool(r) != 0) {
1430 +               weston_log("failed to find OMX buffer pool\n");
1431 +               goto err_gst_stop;
1432 +       }
1433 +
1434 +       /* set clock time */
1435 +       r->clock = gst_element_get_clock (GST_ELEMENT_CAST (r->appsrc));
1436 +
1437 +       weston_log("gst_recorder_create done\n");
1438 +
1439 +       return r;
1440 +
1441 +err_gst_stop:
1442 +       gst_element_set_state (r->pipeline, GST_STATE_NULL);
1443 +       destroy_worker_thread(r);
1444 +err_gst:
1445 +       free(r->pipeline);
1446 +       free(r);
1447 +
1448 +       return NULL;
1449 +}
1450 +
1451 +void
1452 +gst_recorder_destroy(struct gst_recorder *r)
1453 +{
1454 +       r->vsp->users--;
1455 +
1456 +       if (r->pipeline) {
1457 +               gst_element_set_state (r->pipeline, GST_STATE_NULL);
1458 +               gst_object_unref(r->omx_pool);
1459 +
1460 +               destroy_worker_thread(r);
1461 +
1462 +               gst_object_unref(GST_OBJECT(r->bus));
1463 +               gst_object_unref (r->pipeline);
1464 +               r->pipeline = NULL;
1465 +       }
1466 +       free(r);
1467 +}
1468 +
1469 +static int
1470 +gst_recorder_set_timestamp(struct gst_recorder *r, GstBuffer *buffer)
1471 +{
1472 +       GstClockTime cur_time = gst_clock_get_time(r->clock);
1473 +
1474 +       if (r->timestamp == 0) {
1475 +               /* first frame assume around DEFAULT_FPS FPS */
1476 +               GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale_int(1, GST_SECOND, DEFAULT_FPS);
1477 +       } else {
1478 +               GstClockTime delta = cur_time - r->ts_last_frame;
1479 +               /* delta in nS */
1480 +               GST_BUFFER_DURATION(buffer) = delta;
1481 +       }
1482 +
1483 +       r->timestamp += GST_BUFFER_DURATION(buffer);
1484 +       GST_BUFFER_PTS(buffer) = r->timestamp;
1485 +       GST_BUFFER_DTS(buffer) = r->timestamp;
1486 +
1487 +       r->ts_last_frame = cur_time;
1488 +
1489 +       return 0;
1490 +}
1491 +
1492 +
1493 +static int
1494 +gst_recorder_process_dmafd(struct gst_recorder *r, int fd, int stride)
1495 +{
1496 +       int ret;
1497 +       GstBuffer *buf;
1498 +       int omx_fd[2];
1499 +
1500 +        /* get GST buffer */
1501 +       if (gst_recorder_omx_buffer_acquire(r, &buf, omx_fd) < 0) {
1502 +               weston_log("VSP: can not acquire GST buffer, dropping frame\n");
1503 +               return 0;
1504 +       }
1505 +
1506 +       pthread_mutex_lock(&r->vsp->mutex);
1507 +       /* setup vsp */
1508 +       if (vsp_set_formats(r->vsp, r->set->width, r->set->height, &r->set->crop) < 0) {
1509 +               weston_log("VSP: format set failed\n");
1510 +               goto err;
1511 +       }
1512 +
1513 +       /* input */
1514 +       if (vsp_request_buffers(r->vsp, VSP_PORT_INPUT, 1) < 0) {
1515 +               weston_log("VSP: input buffer allocation failed\n");
1516 +               goto err_vsp;
1517 +       }
1518 +
1519 +       /* output */
1520 +       if (vsp_request_buffers(r->vsp, VSP_PORT_OUTPUT, 1) < 0) {
1521 +               weston_log("VSP: output buffer allocation failed\n");
1522 +               goto err_vsp;
1523 +       }
1524 +
1525 +       /* queue output biffer */
1526 +       if (vsp_output_buffer_queue_dmafd(r->vsp, 0, omx_fd) < 0) {
1527 +               weston_log("can not queue OMX buffer %d to VSP\n", 0);
1528 +               gst_recorder_omx_buffer_release(r, buf);
1529 +               goto err_vsp;
1530 +       }
1531 +
1532 +       /* queue input vsp buffer */
1533 +       if (vsp_input_buffer_queue_dmafd(r->vsp, 0, fd) < 0) {
1534 +               weston_log("VSP: failed to queue input buffer\n");
1535 +               goto err_vsp;
1536 +       }
1537 +
1538 +       /* start input */
1539 +       if (vsp_streaming_enable(r->vsp, VSP_PORT_INPUT, 1) < 0) {
1540 +               weston_log("VSP: failed to start input\n");
1541 +               goto err_vsp;
1542 +       }
1543 +
1544 +       /* start output */
1545 +       if (vsp_streaming_enable(r->vsp, VSP_PORT_OUTPUT, 1) < 0) {
1546 +               weston_log("VSP: failed to start output\n");
1547 +               goto err_vsp;
1548 +       }
1549 +
1550 +       /* dequeue input (do we need this?) */
1551 +       if (vsp_input_buffer_dequeue_dmafd(r->vsp) < 0) {
1552 +               weston_log("VSP: failed to dequeue input buffer\n");
1553 +               /* don't care */
1554 +       }
1555 +
1556 +       /* dequeue output */
1557 +       if (vsp_output_buffer_dequeue_dmafd(r->vsp) < 0) {
1558 +               weston_log("VSP: failed to dequeu output buffer\n");
1559 +               gst_recorder_omx_buffer_release(r, buf);
1560 +               /* fall through */
1561 +       } else {
1562 +               /* set timestamp */
1563 +               gst_recorder_set_timestamp(r, buf);
1564 +
1565 +               ret = gst_app_src_push_buffer(r->appsrc, buf);
1566 +               r->frame_count++;
1567 +
1568 +               if (ret != GST_FLOW_OK) {
1569 +                       /* some error, stop sending data */
1570 +                       weston_log("gst_pipeline: some error %d\n", ret);
1571 +               }
1572 +
1573 +       }
1574 +       /* stop input */
1575 +       vsp_streaming_enable(r->vsp, VSP_PORT_INPUT, 0);
1576 +       /* stop output */
1577 +       vsp_streaming_enable(r->vsp, VSP_PORT_OUTPUT, 0);
1578 +
1579 +       /* deinit */
1580 +       vsp_request_buffers(r->vsp, VSP_PORT_INPUT, 0);
1581 +       vsp_request_buffers(r->vsp, VSP_PORT_OUTPUT, 0);
1582 +
1583 +       pthread_mutex_unlock(&r->vsp->mutex);
1584 +       return 0;
1585 +
1586 +err_vsp:
1587 +       /* drop gst buffer */
1588 +       /* finish vsp here */
1589 +err:
1590 +       pthread_mutex_unlock(&r->vsp->mutex);
1591 +       return -1;
1592 +}
1593 +
1594 +int
1595 +gst_recorder_frame_dmafd(struct gst_recorder *r, int fd, int stride)
1596 +{
1597 +       int ret = 0;
1598 +       
1599 +       pthread_mutex_lock(&r->mutex);
1600 +
1601 +       if (r->error) {
1602 +               errno = r->error;
1603 +               ret = -1;
1604 +               goto unlock;
1605 +       }
1606 +               
1607 +       /* The mutex is never released while encoding, so this point should
1608 +        * never be reached if input.valid is true. */
1609 +       assert(!r->input.valid);
1610 +
1611 +       r->input.prime_fd = fd;
1612 +       r->input.stride = stride;
1613 +       r->input.valid = 1;
1614 +       pthread_cond_signal(&r->input_cond);
1615 +
1616 +unlock:
1617 +       pthread_mutex_unlock(&r->mutex);
1618 +
1619 +       return 0;
1620 +}
1621 diff --git a/libweston/gst-recorder.h b/libweston/gst-recorder.h
1622 new file mode 100644
1623 index 0000000..78290c1
1624 --- /dev/null
1625 +++ b/libweston/gst-recorder.h
1626 @@ -0,0 +1,58 @@
1627 +/*
1628 + * Copyright Â© 2016 Cogent Embedded Inc
1629 + *
1630 + * Permission to use, copy, modify, distribute, and sell this software and
1631 + * its documentation for any purpose is hereby granted without fee, provided
1632 + * that the above copyright notice appear in all copies and that both that
1633 + * copyright notice and this permission notice appear in supporting
1634 + * documentation, and that the name of the copyright holders not be used in
1635 + * advertising or publicity pertaining to distribution of the software
1636 + * without specific, written prior permission.  The copyright holders make
1637 + * no representations about the suitability of this software for any
1638 + * purpose.  It is provided "as is" without express or implied warranty.
1639 + *
1640 + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
1641 + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
1642 + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
1643 + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
1644 + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
1645 + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
1646 + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1647 + */
1648 +
1649 +#ifndef _GST_RECORDER_H_
1650 +#define _GST_RECORDER_H_
1651 +
1652 +/* VSP includes */
1653 +#include <media-ctl/mediactl.h>
1654 +#include <media-ctl/v4l2subdev.h>
1655 +
1656 +struct gst_recorder;
1657 +
1658 +struct gst_recorder_settings {
1659 +       int width;
1660 +       int height;
1661 +       int bitrate;
1662 +       char *ip;
1663 +       int port;
1664 +       int latency_test;
1665 +       int refresh_ratio;
1666 +
1667 +       /* Cropping */
1668 +       struct v4l2_rect crop;
1669 +};
1670 +
1671 +void
1672 +gst_recorder_init(void);
1673 +struct gst_recorder *
1674 +gst_recorder_create(struct gst_recorder_settings *settings);
1675 +void
1676 +gst_recorder_destroy(struct gst_recorder *r);
1677 +int
1678 +gst_recorder_frame(struct gst_recorder *r, int fd, int stride);
1679 +int
1680 +gst_recorder_frame_mmap(struct gst_recorder *r, void *data, int stride);
1681 +int
1682 +gst_recorder_frame_dmafd(struct gst_recorder *r, int fd, int stride);
1683 +
1684 +#endif /* _GST_RECORDER_H_ */
1685 diff --git a/libweston/media-ctl/libmediactl.c b/libweston/media-ctl/libmediactl.c
1686 new file mode 100644
1687 index 0000000..f15b1a3
1688 --- /dev/null
1689 +++ b/libweston/media-ctl/libmediactl.c
1690 @@ -0,0 +1,955 @@
1691 +/*
1692 + * Media controller interface library
1693 + *
1694 + * Copyright (C) 2010-2014 Ideas on board SPRL
1695 + *
1696 + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
1697 + *
1698 + * This program is free software; you can redistribute it and/or modify
1699 + * it under the terms of the GNU Lesser General Public License as published
1700 + * by the Free Software Foundation; either version 2.1 of the License, or
1701 + * (at your option) any later version.
1702 + *
1703 + * This program is distributed in the hope that it will be useful,
1704 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1705 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1706 + * GNU Lesser General Public License for more details.
1707 + *
1708 + * You should have received a copy of the GNU Lesser General Public License
1709 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
1710 + */
1711 +
1712 +#include "config.h"
1713 +
1714 +#include <sys/ioctl.h>
1715 +#include <sys/stat.h>
1716 +#include <sys/types.h>
1717 +
1718 +#include <ctype.h>
1719 +#include <errno.h>
1720 +#include <fcntl.h>
1721 +#include <stdbool.h>
1722 +#include <stdio.h>
1723 +#include <stdlib.h>
1724 +#include <string.h>
1725 +#include <unistd.h>
1726 +
1727 +#include <linux/media.h>
1728 +#include <linux/videodev2.h>
1729 +
1730 +#include "mediactl.h"
1731 +#include "mediactl-priv.h"
1732 +#include "tools.h"
1733 +
1734 +/* -----------------------------------------------------------------------------
1735 + * Graph access
1736 + */
1737 +
1738 +struct media_pad *media_entity_remote_source(struct media_pad *pad)
1739 +{
1740 +       unsigned int i;
1741 +
1742 +       if (!(pad->flags & MEDIA_PAD_FL_SINK))
1743 +               return NULL;
1744 +
1745 +       for (i = 0; i < pad->entity->num_links; ++i) {
1746 +               struct media_link *link = &pad->entity->links[i];
1747 +
1748 +               if (!(link->flags & MEDIA_LNK_FL_ENABLED))
1749 +                       continue;
1750 +
1751 +               if (link->sink == pad)
1752 +                       return link->source;
1753 +       }
1754 +
1755 +       return NULL;
1756 +}
1757 +
1758 +struct media_entity *media_get_entity_by_name(struct media_device *media,
1759 +                                             const char *name, size_t length)
1760 +{
1761 +       unsigned int i;
1762 +
1763 +       /* A match is impossible if the entity name is longer than the maximum
1764 +        * size we can get from the kernel.
1765 +        */
1766 +       if (length >= FIELD_SIZEOF(struct media_entity_desc, name))
1767 +               return NULL;
1768 +
1769 +       for (i = 0; i < media->entities_count; ++i) {
1770 +               struct media_entity *entity = &media->entities[i];
1771 +
1772 +               if (strncmp(entity->info.name, name, length) == 0 &&
1773 +                   entity->info.name[length] == '\0')
1774 +                       return entity;
1775 +       }
1776 +
1777 +       return NULL;
1778 +}
1779 +
1780 +struct media_entity *media_get_entity_by_id(struct media_device *media,
1781 +                                           __u32 id)
1782 +{
1783 +       bool next = id & MEDIA_ENT_ID_FLAG_NEXT;
1784 +       unsigned int i;
1785 +
1786 +       id &= ~MEDIA_ENT_ID_FLAG_NEXT;
1787 +
1788 +       for (i = 0; i < media->entities_count; ++i) {
1789 +               struct media_entity *entity = &media->entities[i];
1790 +
1791 +               if ((entity->info.id == id && !next) ||
1792 +                   (entity->info.id > id && next))
1793 +                       return entity;
1794 +       }
1795 +
1796 +       return NULL;
1797 +}
1798 +
1799 +unsigned int media_get_entities_count(struct media_device *media)
1800 +{
1801 +       return media->entities_count;
1802 +}
1803 +
1804 +struct media_entity *media_get_entity(struct media_device *media, unsigned int index)
1805 +{
1806 +       if (index >= media->entities_count)
1807 +               return NULL;
1808 +
1809 +       return &media->entities[index];
1810 +}
1811 +
1812 +const struct media_pad *media_entity_get_pad(struct media_entity *entity, unsigned int index)
1813 +{
1814 +       if (index >= entity->info.pads)
1815 +               return NULL;
1816 +
1817 +       return &entity->pads[index];
1818 +}
1819 +
1820 +unsigned int media_entity_get_links_count(struct media_entity *entity)
1821 +{
1822 +       return entity->num_links;
1823 +}
1824 +
1825 +const struct media_link *media_entity_get_link(struct media_entity *entity, unsigned int index)
1826 +{
1827 +       if (index >= entity->num_links)
1828 +               return NULL;
1829 +
1830 +       return &entity->links[index];
1831 +}
1832 +
1833 +const char *media_entity_get_devname(struct media_entity *entity)
1834 +{
1835 +       return entity->devname[0] ? entity->devname : NULL;
1836 +}
1837 +
1838 +struct media_entity *media_get_default_entity(struct media_device *media,
1839 +                                             unsigned int type)
1840 +{
1841 +       switch (type) {
1842 +       case MEDIA_ENT_T_DEVNODE_V4L:
1843 +               return media->def.v4l;
1844 +       case MEDIA_ENT_T_DEVNODE_FB:
1845 +               return media->def.fb;
1846 +       case MEDIA_ENT_T_DEVNODE_ALSA:
1847 +               return media->def.alsa;
1848 +       case MEDIA_ENT_T_DEVNODE_DVB:
1849 +               return media->def.dvb;
1850 +       }
1851 +
1852 +       return NULL;
1853 +}
1854 +
1855 +const struct media_device_info *media_get_info(struct media_device *media)
1856 +{
1857 +       return &media->info;
1858 +}
1859 +
1860 +const char *media_get_devnode(struct media_device *media)
1861 +{
1862 +       return media->devnode;
1863 +}
1864 +
1865 +const struct media_entity_desc *media_entity_get_info(struct media_entity *entity)
1866 +{
1867 +       return &entity->info;
1868 +}
1869 +
1870 +/* -----------------------------------------------------------------------------
1871 + * Open/close
1872 + */
1873 +
1874 +static int media_device_open(struct media_device *media)
1875 +{
1876 +       int ret;
1877 +
1878 +       if (media->fd != -1)
1879 +               return 0;
1880 +
1881 +       media_dbg(media, "Opening media device %s\n", media->devnode);
1882 +
1883 +       media->fd = open(media->devnode, O_RDWR);
1884 +       if (media->fd < 0) {
1885 +               ret = -errno;
1886 +               media_dbg(media, "%s: Can't open media device %s\n",
1887 +                         __func__, media->devnode);
1888 +               return ret;
1889 +       }
1890 +
1891 +       return 0;
1892 +}
1893 +
1894 +static void media_device_close(struct media_device *media)
1895 +{
1896 +       if (media->fd != -1) {
1897 +               close(media->fd);
1898 +               media->fd = -1;
1899 +       }
1900 +}
1901 +
1902 +/* -----------------------------------------------------------------------------
1903 + * Link setup
1904 + */
1905 +
1906 +int media_setup_link(struct media_device *media,
1907 +                    struct media_pad *source,
1908 +                    struct media_pad *sink,
1909 +                    __u32 flags)
1910 +{
1911 +       struct media_link *link;
1912 +       struct media_link_desc ulink;
1913 +       unsigned int i;
1914 +       int ret;
1915 +
1916 +       ret = media_device_open(media);
1917 +       if (ret < 0)
1918 +               goto done;
1919 +
1920 +       for (i = 0; i < source->entity->num_links; i++) {
1921 +               link = &source->entity->links[i];
1922 +
1923 +               if (link->source->entity == source->entity &&
1924 +                   link->source->index == source->index &&
1925 +                   link->sink->entity == sink->entity &&
1926 +                   link->sink->index == sink->index)
1927 +                       break;
1928 +       }
1929 +
1930 +       if (i == source->entity->num_links) {
1931 +               media_dbg(media, "%s: Link not found\n", __func__);
1932 +               ret = -ENOENT;
1933 +               goto done;
1934 +       }
1935 +
1936 +       /* source pad */
1937 +       ulink.source.entity = source->entity->info.id;
1938 +       ulink.source.index = source->index;
1939 +       ulink.source.flags = MEDIA_PAD_FL_SOURCE;
1940 +
1941 +       /* sink pad */
1942 +       ulink.sink.entity = sink->entity->info.id;
1943 +       ulink.sink.index = sink->index;
1944 +       ulink.sink.flags = MEDIA_PAD_FL_SINK;
1945 +
1946 +       ulink.flags = flags | (link->flags & MEDIA_LNK_FL_IMMUTABLE);
1947 +
1948 +       ret = ioctl(media->fd, MEDIA_IOC_SETUP_LINK, &ulink);
1949 +       if (ret == -1) {
1950 +               ret = -errno;
1951 +               media_dbg(media, "%s: Unable to setup link (%s)\n",
1952 +                         __func__, strerror(errno));
1953 +               goto done;
1954 +       }
1955 +
1956 +       link->flags = ulink.flags;
1957 +       link->twin->flags = ulink.flags;
1958 +
1959 +       ret = 0;
1960 +
1961 +done:
1962 +       return ret;
1963 +}
1964 +
1965 +int media_reset_links(struct media_device *media)
1966 +{
1967 +       unsigned int i, j;
1968 +       int ret;
1969 +
1970 +       for (i = 0; i < media->entities_count; ++i) {
1971 +               struct media_entity *entity = &media->entities[i];
1972 +
1973 +               for (j = 0; j < entity->num_links; j++) {
1974 +                       struct media_link *link = &entity->links[j];
1975 +
1976 +                       if (link->flags & MEDIA_LNK_FL_IMMUTABLE ||
1977 +                           link->source->entity != entity)
1978 +                               continue;
1979 +
1980 +                       ret = media_setup_link(media, link->source, link->sink,
1981 +                                              link->flags & ~MEDIA_LNK_FL_ENABLED);
1982 +                       if (ret < 0)
1983 +                               return ret;
1984 +               }
1985 +       }
1986 +
1987 +       return 0;
1988 +}
1989 +
1990 +/* -----------------------------------------------------------------------------
1991 + * Entities, pads and links enumeration
1992 + */
1993 +
1994 +static struct media_link *media_entity_add_link(struct media_entity *entity)
1995 +{
1996 +       if (entity->num_links >= entity->max_links) {
1997 +               struct media_link *links = entity->links;
1998 +               unsigned int max_links = entity->max_links * 2;
1999 +               unsigned int i;
2000 +
2001 +               links = realloc(links, max_links * sizeof *links);
2002 +               if (links == NULL)
2003 +                       return NULL;
2004 +
2005 +               for (i = 0; i < entity->num_links; ++i)
2006 +                       links[i].twin->twin = &links[i];
2007 +
2008 +               entity->max_links = max_links;
2009 +               entity->links = links;
2010 +       }
2011 +
2012 +       return &entity->links[entity->num_links++];
2013 +}
2014 +
2015 +static int media_enum_links(struct media_device *media)
2016 +{
2017 +       __u32 id;
2018 +       int ret = 0;
2019 +
2020 +       for (id = 1; id <= media->entities_count; id++) {
2021 +               struct media_entity *entity = &media->entities[id - 1];
2022 +               struct media_links_enum links;
2023 +               unsigned int i;
2024 +
2025 +               links.entity = entity->info.id;
2026 +               links.pads = calloc(entity->info.pads, sizeof(struct media_pad_desc));
2027 +               links.links = calloc(entity->info.links, sizeof(struct media_link_desc));
2028 +
2029 +               if (ioctl(media->fd, MEDIA_IOC_ENUM_LINKS, &links) < 0) {
2030 +                       ret = -errno;
2031 +                       media_dbg(media,
2032 +                                 "%s: Unable to enumerate pads and links (%s).\n",
2033 +                                 __func__, strerror(errno));
2034 +                       free(links.pads);
2035 +                       free(links.links);
2036 +                       return ret;
2037 +               }
2038 +
2039 +               for (i = 0; i < entity->info.pads; ++i) {
2040 +                       entity->pads[i].entity = entity;
2041 +                       entity->pads[i].index = links.pads[i].index;
2042 +                       entity->pads[i].flags = links.pads[i].flags;
2043 +               }
2044 +
2045 +               for (i = 0; i < entity->info.links; ++i) {
2046 +                       struct media_link_desc *link = &links.links[i];
2047 +                       struct media_link *fwdlink;
2048 +                       struct media_link *backlink;
2049 +                       struct media_entity *source;
2050 +                       struct media_entity *sink;
2051 +
2052 +                       source = media_get_entity_by_id(media, link->source.entity);
2053 +                       sink = media_get_entity_by_id(media, link->sink.entity);
2054 +
2055 +                       if (source == NULL || sink == NULL) {
2056 +                               media_dbg(media,
2057 +                                         "WARNING entity %u link %u from %u/%u to %u/%u is invalid!\n",
2058 +                                         id, i, link->source.entity,
2059 +                                         link->source.index,
2060 +                                         link->sink.entity,
2061 +                                         link->sink.index);
2062 +                               ret = -EINVAL;
2063 +                       } else {
2064 +                               fwdlink = media_entity_add_link(source);
2065 +                               fwdlink->source = &source->pads[link->source.index];
2066 +                               fwdlink->sink = &sink->pads[link->sink.index];
2067 +                               fwdlink->flags = link->flags;
2068 +
2069 +                               backlink = media_entity_add_link(sink);
2070 +                               backlink->source = &source->pads[link->source.index];
2071 +                               backlink->sink = &sink->pads[link->sink.index];
2072 +                               backlink->flags = link->flags;
2073 +
2074 +                               fwdlink->twin = backlink;
2075 +                               backlink->twin = fwdlink;
2076 +                       }
2077 +               }
2078 +
2079 +               free(links.pads);
2080 +               free(links.links);
2081 +       }
2082 +
2083 +       return ret;
2084 +}
2085 +
2086 +#ifdef HAVE_LIBUDEV
2087 +
2088 +#include <libudev.h>
2089 +
2090 +static inline int media_udev_open(struct udev **udev)
2091 +{
2092 +       *udev = udev_new();
2093 +       if (*udev == NULL)
2094 +               return -ENOMEM;
2095 +       return 0;
2096 +}
2097 +
2098 +static inline void media_udev_close(struct udev *udev)
2099 +{
2100 +       if (udev != NULL)
2101 +               udev_unref(udev);
2102 +}
2103 +
2104 +static int media_get_devname_udev(struct udev *udev,
2105 +               struct media_entity *entity)
2106 +{
2107 +       struct udev_device *device;
2108 +       dev_t devnum;
2109 +       const char *p;
2110 +       int ret = -ENODEV;
2111 +
2112 +       if (udev == NULL)
2113 +               return -EINVAL;
2114 +
2115 +       devnum = makedev(entity->info.v4l.major, entity->info.v4l.minor);
2116 +       media_dbg(entity->media, "looking up device: %u:%u\n",
2117 +                 major(devnum), minor(devnum));
2118 +       device = udev_device_new_from_devnum(udev, 'c', devnum);
2119 +       if (device) {
2120 +               p = udev_device_get_devnode(device);
2121 +               if (p) {
2122 +                       strncpy(entity->devname, p, sizeof(entity->devname));
2123 +                       entity->devname[sizeof(entity->devname) - 1] = '\0';
2124 +               }
2125 +               ret = 0;
2126 +       }
2127 +
2128 +       udev_device_unref(device);
2129 +
2130 +       return ret;
2131 +}
2132 +
2133 +#else  /* HAVE_LIBUDEV */
2134 +
2135 +struct udev;
2136 +
2137 +static inline int media_udev_open(struct udev **udev) { return 0; }
2138 +
2139 +static inline void media_udev_close(struct udev *udev) { }
2140 +
2141 +static inline int media_get_devname_udev(struct udev *udev,
2142 +               struct media_entity *entity)
2143 +{
2144 +       return -ENOTSUP;
2145 +}
2146 +
2147 +#endif /* HAVE_LIBUDEV */
2148 +
2149 +static int media_get_devname_sysfs(struct media_entity *entity)
2150 +{
2151 +       struct stat devstat;
2152 +       char devname[32];
2153 +       char sysname[32];
2154 +       char target[1024];
2155 +       char *p;
2156 +       int ret;
2157 +
2158 +       sprintf(sysname, "/sys/dev/char/%u:%u", entity->info.v4l.major,
2159 +               entity->info.v4l.minor);
2160 +       ret = readlink(sysname, target, sizeof(target) - 1);
2161 +       if (ret < 0)
2162 +               return -errno;
2163 +
2164 +       target[ret] = '\0';
2165 +       p = strrchr(target, '/');
2166 +       if (p == NULL)
2167 +               return -EINVAL;
2168 +
2169 +       sprintf(devname, "/dev/%s", p + 1);
2170 +       ret = stat(devname, &devstat);
2171 +       if (ret < 0)
2172 +               return -errno;
2173 +
2174 +       /* Sanity check: udev might have reordered the device nodes.
2175 +        * Make sure the major/minor match. We should really use
2176 +        * libudev.
2177 +        */
2178 +       if (major(devstat.st_rdev) == entity->info.v4l.major &&
2179 +           minor(devstat.st_rdev) == entity->info.v4l.minor)
2180 +               strcpy(entity->devname, devname);
2181 +
2182 +       return 0;
2183 +}
2184 +
2185 +static int media_enum_entities(struct media_device *media)
2186 +{
2187 +       struct media_entity *entity;
2188 +       struct udev *udev;
2189 +       unsigned int size;
2190 +       __u32 id;
2191 +       int ret;
2192 +
2193 +       ret = media_udev_open(&udev);
2194 +       if (ret < 0)
2195 +               media_dbg(media, "Can't get udev context\n");
2196 +
2197 +       for (id = 0, ret = 0; ; id = entity->info.id) {
2198 +               size = (media->entities_count + 1) * sizeof(*media->entities);
2199 +               media->entities = realloc(media->entities, size);
2200 +
2201 +               entity = &media->entities[media->entities_count];
2202 +               memset(entity, 0, sizeof(*entity));
2203 +               entity->fd = -1;
2204 +               entity->info.id = id | MEDIA_ENT_ID_FLAG_NEXT;
2205 +               entity->media = media;
2206 +
2207 +               ret = ioctl(media->fd, MEDIA_IOC_ENUM_ENTITIES, &entity->info);
2208 +               if (ret < 0) {
2209 +                       ret = errno != EINVAL ? -errno : 0;
2210 +                       break;
2211 +               }
2212 +
2213 +               /* Number of links (for outbound links) plus number of pads (for
2214 +                * inbound links) is a good safe initial estimate of the total
2215 +                * number of links.
2216 +                */
2217 +               entity->max_links = entity->info.pads + entity->info.links;
2218 +
2219 +               entity->pads = malloc(entity->info.pads * sizeof(*entity->pads));
2220 +               entity->links = malloc(entity->max_links * sizeof(*entity->links));
2221 +               if (entity->pads == NULL || entity->links == NULL) {
2222 +                       ret = -ENOMEM;
2223 +                       break;
2224 +               }
2225 +
2226 +               media->entities_count++;
2227 +
2228 +               if (entity->info.flags & MEDIA_ENT_FL_DEFAULT) {
2229 +                       switch (entity->info.type) {
2230 +                       case MEDIA_ENT_T_DEVNODE_V4L:
2231 +                               media->def.v4l = entity;
2232 +                               break;
2233 +                       case MEDIA_ENT_T_DEVNODE_FB:
2234 +                               media->def.fb = entity;
2235 +                               break;
2236 +                       case MEDIA_ENT_T_DEVNODE_ALSA:
2237 +                               media->def.alsa = entity;
2238 +                               break;
2239 +                       case MEDIA_ENT_T_DEVNODE_DVB:
2240 +                               media->def.dvb = entity;
2241 +                               break;
2242 +                       }
2243 +               }
2244 +
2245 +               /* Find the corresponding device name. */
2246 +               if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE &&
2247 +                   media_entity_type(entity) != MEDIA_ENT_T_V4L2_SUBDEV)
2248 +                       continue;
2249 +
2250 +               /* Try to get the device name via udev */
2251 +               if (!media_get_devname_udev(udev, entity))
2252 +                       continue;
2253 +
2254 +               /* Fall back to get the device name via sysfs */
2255 +               media_get_devname_sysfs(entity);
2256 +       }
2257 +
2258 +       media_udev_close(udev);
2259 +       return ret;
2260 +}
2261 +
2262 +int media_device_enumerate(struct media_device *media)
2263 +{
2264 +       int ret;
2265 +
2266 +       if (media->entities)
2267 +               return 0;
2268 +
2269 +       ret = media_device_open(media);
2270 +       if (ret < 0)
2271 +               return ret;
2272 +
2273 +       ret = ioctl(media->fd, MEDIA_IOC_DEVICE_INFO, &media->info);
2274 +       if (ret < 0) {
2275 +               ret = -errno;
2276 +               media_dbg(media, "%s: Unable to retrieve media device "
2277 +                         "information for device %s (%s)\n", __func__,
2278 +                         media->devnode, strerror(errno));
2279 +               goto done;
2280 +       }
2281 +
2282 +       media_dbg(media, "Enumerating entities\n");
2283 +
2284 +       ret = media_enum_entities(media);
2285 +       if (ret < 0) {
2286 +               media_dbg(media,
2287 +                         "%s: Unable to enumerate entities for device %s (%s)\n",
2288 +                         __func__, media->devnode, strerror(-ret));
2289 +               goto done;
2290 +       }
2291 +
2292 +       media_dbg(media, "Found %u entities\n", media->entities_count);
2293 +       media_dbg(media, "Enumerating pads and links\n");
2294 +
2295 +       ret = media_enum_links(media);
2296 +       if (ret < 0) {
2297 +               media_dbg(media,
2298 +                         "%s: Unable to enumerate pads and linksfor device %s\n",
2299 +                         __func__, media->devnode);
2300 +               goto done;
2301 +       }
2302 +
2303 +       ret = 0;
2304 +
2305 +done:
2306 +       return ret;
2307 +}
2308 +
2309 +/* -----------------------------------------------------------------------------
2310 + * Create/destroy
2311 + */
2312 +
2313 +static void media_debug_default(void *ptr, ...)
2314 +{
2315 +}
2316 +
2317 +void media_debug_set_handler(struct media_device *media,
2318 +                            void (*debug_handler)(void *, ...),
2319 +                            void *debug_priv)
2320 +{
2321 +       if (debug_handler) {
2322 +               media->debug_handler = debug_handler;
2323 +               media->debug_priv = debug_priv;
2324 +       } else {
2325 +               media->debug_handler = media_debug_default;
2326 +               media->debug_priv = NULL;
2327 +       }
2328 +}
2329 +
2330 +static struct media_device *__media_device_new(void)
2331 +{
2332 +       struct media_device *media;
2333 +
2334 +       media = calloc(1, sizeof(*media));
2335 +       if (media == NULL)
2336 +               return NULL;
2337 +
2338 +       media->fd = -1;
2339 +       media->refcount = 1;
2340 +
2341 +       media_debug_set_handler(media, NULL, NULL);
2342 +
2343 +       return media;
2344 +}
2345 +
2346 +struct media_device *media_device_new(const char *devnode)
2347 +{
2348 +       struct media_device *media;
2349 +
2350 +       media = __media_device_new();
2351 +       if (media == NULL)
2352 +               return NULL;
2353 +
2354 +       media->devnode = strdup(devnode);
2355 +       if (media->devnode == NULL) {
2356 +               media_device_unref(media);
2357 +               return NULL;
2358 +       }
2359 +
2360 +       return media;
2361 +}
2362 +
2363 +struct media_device *media_device_new_emulated(struct media_device_info *info)
2364 +{
2365 +       struct media_device *media;
2366 +
2367 +       media = __media_device_new();
2368 +       if (media == NULL)
2369 +               return NULL;
2370 +
2371 +       media->info = *info;
2372 +
2373 +       return media;
2374 +}
2375 +
2376 +struct media_device *media_device_ref(struct media_device *media)
2377 +{
2378 +       media->refcount++;
2379 +       return media;
2380 +}
2381 +
2382 +void media_device_unref(struct media_device *media)
2383 +{
2384 +       unsigned int i;
2385 +
2386 +       media->refcount--;
2387 +       if (media->refcount > 0)
2388 +               return;
2389 +
2390 +       for (i = 0; i < media->entities_count; ++i) {
2391 +               struct media_entity *entity = &media->entities[i];
2392 +
2393 +               free(entity->pads);
2394 +               free(entity->links);
2395 +               if (entity->fd != -1)
2396 +                       close(entity->fd);
2397 +       }
2398 +
2399 +       free(media->entities);
2400 +       free(media->devnode);
2401 +       free(media);
2402 +}
2403 +
2404 +int media_device_add_entity(struct media_device *media,
2405 +                           const struct media_entity_desc *desc,
2406 +                           const char *devnode)
2407 +{
2408 +       struct media_entity **defent = NULL;
2409 +       struct media_entity *entity;
2410 +       unsigned int size;
2411 +
2412 +       size = (media->entities_count + 1) * sizeof(*media->entities);
2413 +       entity = realloc(media->entities, size);
2414 +       if (entity == NULL)
2415 +               return -ENOMEM;
2416 +
2417 +       media->entities = entity;
2418 +       media->entities_count++;
2419 +
2420 +       entity = &media->entities[media->entities_count - 1];
2421 +       memset(entity, 0, sizeof *entity);
2422 +
2423 +       entity->fd = -1;
2424 +       entity->media = media;
2425 +       strncpy(entity->devname, devnode, sizeof entity->devname);
2426 +       entity->devname[sizeof entity->devname - 1] = '\0';
2427 +
2428 +       entity->info.id = 0;
2429 +       entity->info.type = desc->type;
2430 +       entity->info.flags = 0;
2431 +       memcpy(entity->info.name, desc->name, sizeof entity->info.name);
2432 +
2433 +       switch (entity->info.type) {
2434 +       case MEDIA_ENT_T_DEVNODE_V4L:
2435 +               defent = &media->def.v4l;
2436 +               entity->info.v4l = desc->v4l;
2437 +               break;
2438 +       case MEDIA_ENT_T_DEVNODE_FB:
2439 +               defent = &media->def.fb;
2440 +               entity->info.fb = desc->fb;
2441 +               break;
2442 +       case MEDIA_ENT_T_DEVNODE_ALSA:
2443 +               defent = &media->def.alsa;
2444 +               entity->info.alsa = desc->alsa;
2445 +               break;
2446 +       case MEDIA_ENT_T_DEVNODE_DVB:
2447 +               defent = &media->def.dvb;
2448 +               entity->info.dvb = desc->dvb;
2449 +               break;
2450 +       }
2451 +
2452 +       if (desc->flags & MEDIA_ENT_FL_DEFAULT) {
2453 +               entity->info.flags |= MEDIA_ENT_FL_DEFAULT;
2454 +               if (defent)
2455 +                       *defent = entity;
2456 +       }
2457 +
2458 +       return 0;
2459 +}
2460 +
2461 +struct media_pad *media_parse_pad(struct media_device *media,
2462 +                                 const char *p, char **endp)
2463 +{
2464 +       unsigned int entity_id, pad;
2465 +       struct media_entity *entity;
2466 +       char *end;
2467 +
2468 +       /* endp can be NULL. To avoid spreading NULL checks across the function,
2469 +        * set endp to &end in that case.
2470 +        */
2471 +       if (endp == NULL)
2472 +               endp = &end;
2473 +
2474 +       for (; isspace(*p); ++p);
2475 +
2476 +       if (*p == '"' || *p == '\'') {
2477 +               for (end = (char *)p + 1; *end && *end != '"' && *end != '\''; ++end);
2478 +               if (*end != '"' && *end != '\'') {
2479 +                       media_dbg(media, "missing matching '\"'\n");
2480 +                       *endp = end;
2481 +                       return NULL;
2482 +               }
2483 +
2484 +               entity = media_get_entity_by_name(media, p + 1, end - p - 1);
2485 +               if (entity == NULL) {
2486 +                       media_dbg(media, "no such entity \"%.*s\"\n", end - p - 1, p + 1);
2487 +                       *endp = (char *)p + 1;
2488 +                       return NULL;
2489 +               }
2490 +
2491 +               ++end;
2492 +       } else {
2493 +               entity_id = strtoul(p, &end, 10);
2494 +               entity = media_get_entity_by_id(media, entity_id);
2495 +               if (entity == NULL) {
2496 +                       media_dbg(media, "no such entity %d\n", entity_id);
2497 +                       *endp = (char *)p;
2498 +                       return NULL;
2499 +               }
2500 +       }
2501 +       for (; isspace(*end); ++end);
2502 +
2503 +       if (*end != ':') {
2504 +               media_dbg(media, "Expected ':'\n", *end);
2505 +               *endp = end;
2506 +               return NULL;
2507 +       }
2508 +
2509 +       for (p = end + 1; isspace(*p); ++p);
2510 +
2511 +       pad = strtoul(p, &end, 10);
2512 +
2513 +       if (pad >= entity->info.pads) {
2514 +               media_dbg(media, "No pad '%d' on entity \"%s\". Maximum pad number is %d\n",
2515 +                               pad, entity->info.name, entity->info.pads - 1);
2516 +               *endp = (char *)p;
2517 +               return NULL;
2518 +       }
2519 +
2520 +       for (p = end; isspace(*p); ++p);
2521 +       *endp = (char *)p;
2522 +
2523 +       return &entity->pads[pad];
2524 +}
2525 +
2526 +struct media_link *media_parse_link(struct media_device *media,
2527 +                                   const char *p, char **endp)
2528 +{
2529 +       struct media_link *link;
2530 +       struct media_pad *source;
2531 +       struct media_pad *sink;
2532 +       unsigned int i;
2533 +       char *end;
2534 +
2535 +       source = media_parse_pad(media, p, &end);
2536 +       if (source == NULL) {
2537 +               *endp = end;
2538 +               return NULL;
2539 +       }
2540 +
2541 +       if (end[0] != '-' || end[1] != '>') {
2542 +               *endp = end;
2543 +               media_dbg(media, "Expected '->'\n");
2544 +               return NULL;
2545 +       }
2546 +
2547 +       p = end + 2;
2548 +
2549 +       sink = media_parse_pad(media, p, &end);
2550 +       if (sink == NULL) {
2551 +               *endp = end;
2552 +               return NULL;
2553 +       }
2554 +
2555 +       *endp = end;
2556 +
2557 +       for (i = 0; i < source->entity->num_links; i++) {
2558 +               link = &source->entity->links[i];
2559 +
2560 +               if (link->source == source && link->sink == sink)
2561 +                       return link;
2562 +       }
2563 +
2564 +       media_dbg(media, "No link between \"%s\":%d and \"%s\":%d\n",
2565 +                       source->entity->info.name, source->index,
2566 +                       sink->entity->info.name, sink->index);
2567 +       return NULL;
2568 +}
2569 +
2570 +int media_parse_setup_link(struct media_device *media,
2571 +                          const char *p, char **endp)
2572 +{
2573 +       struct media_link *link;
2574 +       __u32 flags;
2575 +       char *end;
2576 +
2577 +       link = media_parse_link(media, p, &end);
2578 +       if (link == NULL) {
2579 +               media_dbg(media,
2580 +                         "%s: Unable to parse link\n", __func__);
2581 +               *endp = end;
2582 +               return -EINVAL;
2583 +       }
2584 +
2585 +       p = end;
2586 +       if (*p++ != '[') {
2587 +               media_dbg(media, "Unable to parse link flags: expected '['.\n");
2588 +               *endp = (char *)p - 1;
2589 +               return -EINVAL;
2590 +       }
2591 +
2592 +       flags = strtoul(p, &end, 10);
2593 +       for (p = end; isspace(*p); p++);
2594 +       if (*p++ != ']') {
2595 +               media_dbg(media, "Unable to parse link flags: expected ']'.\n");
2596 +               *endp = (char *)p - 1;
2597 +               return -EINVAL;
2598 +       }
2599 +
2600 +       for (; isspace(*p); p++);
2601 +       *endp = (char *)p;
2602 +
2603 +       media_dbg(media,
2604 +                 "Setting up link %u:%u -> %u:%u [%u]\n",
2605 +                 link->source->entity->info.id, link->source->index,
2606 +                 link->sink->entity->info.id, link->sink->index,
2607 +                 flags);
2608 +
2609 +       return media_setup_link(media, link->source, link->sink, flags);
2610 +}
2611 +
2612 +void media_print_streampos(struct media_device *media, const char *p,
2613 +                          const char *end)
2614 +{
2615 +       int pos;
2616 +
2617 +       pos = end - p + 1;
2618 +
2619 +       if (pos < 0)
2620 +               pos = 0;
2621 +       if (pos > strlen(p))
2622 +               pos = strlen(p);
2623 +
2624 +       media_dbg(media, "\n");
2625 +       media_dbg(media, " %s\n", p);
2626 +       media_dbg(media, " %*s\n", pos, "^");
2627 +}
2628 +
2629 +int media_parse_setup_links(struct media_device *media, const char *p)
2630 +{
2631 +       char *end;
2632 +       int ret;
2633 +
2634 +       do {
2635 +               ret = media_parse_setup_link(media, p, &end);
2636 +               if (ret < 0) {
2637 +                       media_print_streampos(media, p, end);
2638 +                       return ret;
2639 +               }
2640 +
2641 +               p = end + 1;
2642 +       } while (*end == ',');
2643 +
2644 +       return *end ? -EINVAL : 0;
2645 +}
2646 diff --git a/libweston/media-ctl/libv4l2subdev.c b/libweston/media-ctl/libv4l2subdev.c
2647 new file mode 100644
2648 index 0000000..4ede4fa
2649 --- /dev/null
2650 +++ b/libweston/media-ctl/libv4l2subdev.c
2651 @@ -0,0 +1,759 @@
2652 +/*
2653 + * V4L2 subdev interface library
2654 + *
2655 + * Copyright (C) 2010-2014 Ideas on board SPRL
2656 + *
2657 + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
2658 + *
2659 + * This program is free software; you can redistribute it and/or modify
2660 + * it under the terms of the GNU Lesser General Public License as published
2661 + * by the Free Software Foundation; either version 2.1 of the License, or
2662 + * (at your option) any later version.
2663 + *
2664 + * This program is distributed in the hope that it will be useful,
2665 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2666 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2667 + * GNU Lesser General Public License for more details.
2668 + *
2669 + * You should have received a copy of the GNU Lesser General Public License
2670 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
2671 + */
2672 +
2673 +#include <sys/ioctl.h>
2674 +#include <sys/stat.h>
2675 +#include <sys/types.h>
2676 +
2677 +#include <ctype.h>
2678 +#include <errno.h>
2679 +#include <fcntl.h>
2680 +#include <stdbool.h>
2681 +#include <stdio.h>
2682 +#include <stdlib.h>
2683 +#include <string.h>
2684 +#include <unistd.h>
2685 +
2686 +#include <linux/v4l2-subdev.h>
2687 +
2688 +#include "mediactl.h"
2689 +#include "mediactl-priv.h"
2690 +#include "tools.h"
2691 +#include "v4l2subdev.h"
2692 +
2693 +int v4l2_subdev_open(struct media_entity *entity)
2694 +{
2695 +       if (entity->fd != -1)
2696 +               return 0;
2697 +
2698 +       entity->fd = open(entity->devname, O_RDWR);
2699 +       if (entity->fd == -1) {
2700 +               int ret = -errno;
2701 +               media_dbg(entity->media,
2702 +                         "%s: Failed to open subdev device node %s\n", __func__,
2703 +                         entity->devname);
2704 +               return ret;
2705 +       }
2706 +
2707 +       return 0;
2708 +}
2709 +
2710 +void v4l2_subdev_close(struct media_entity *entity)
2711 +{
2712 +       close(entity->fd);
2713 +       entity->fd = -1;
2714 +}
2715 +
2716 +int v4l2_subdev_get_format(struct media_entity *entity,
2717 +       struct v4l2_mbus_framefmt *format, unsigned int pad,
2718 +       enum v4l2_subdev_format_whence which)
2719 +{
2720 +       struct v4l2_subdev_format fmt;
2721 +       int ret;
2722 +
2723 +       ret = v4l2_subdev_open(entity);
2724 +       if (ret < 0)
2725 +               return ret;
2726 +
2727 +       memset(&fmt, 0, sizeof(fmt));
2728 +       fmt.pad = pad;
2729 +       fmt.which = which;
2730 +
2731 +       ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FMT, &fmt);
2732 +       if (ret < 0)
2733 +               return -errno;
2734 +
2735 +       *format = fmt.format;
2736 +       return 0;
2737 +}
2738 +
2739 +int v4l2_subdev_set_format(struct media_entity *entity,
2740 +       struct v4l2_mbus_framefmt *format, unsigned int pad,
2741 +       enum v4l2_subdev_format_whence which)
2742 +{
2743 +       struct v4l2_subdev_format fmt;
2744 +       int ret;
2745 +
2746 +       ret = v4l2_subdev_open(entity);
2747 +       if (ret < 0)
2748 +               return ret;
2749 +
2750 +       memset(&fmt, 0, sizeof(fmt));
2751 +       fmt.pad = pad;
2752 +       fmt.which = which;
2753 +       fmt.format = *format;
2754 +
2755 +       ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FMT, &fmt);
2756 +       if (ret < 0)
2757 +               return -errno;
2758 +
2759 +       *format = fmt.format;
2760 +       return 0;
2761 +}
2762 +
2763 +int v4l2_subdev_get_selection(struct media_entity *entity,
2764 +       struct v4l2_rect *rect, unsigned int pad, unsigned int target,
2765 +       enum v4l2_subdev_format_whence which)
2766 +{
2767 +       union {
2768 +               struct v4l2_subdev_selection sel;
2769 +               struct v4l2_subdev_crop crop;
2770 +       } u;
2771 +       int ret;
2772 +
2773 +       ret = v4l2_subdev_open(entity);
2774 +       if (ret < 0)
2775 +               return ret;
2776 +
2777 +       memset(&u.sel, 0, sizeof(u.sel));
2778 +       u.sel.pad = pad;
2779 +       u.sel.target = target;
2780 +       u.sel.which = which;
2781 +
2782 +       ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_SELECTION, &u.sel);
2783 +       if (ret >= 0) {
2784 +               *rect = u.sel.r;
2785 +               return 0;
2786 +       }
2787 +       if (errno != ENOTTY || target != V4L2_SEL_TGT_CROP)
2788 +               return -errno;
2789 +
2790 +       memset(&u.crop, 0, sizeof(u.crop));
2791 +       u.crop.pad = pad;
2792 +       u.crop.which = which;
2793 +
2794 +       ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_CROP, &u.crop);
2795 +       if (ret < 0)
2796 +               return -errno;
2797 +
2798 +       *rect = u.crop.rect;
2799 +       return 0;
2800 +}
2801 +
2802 +int v4l2_subdev_set_selection(struct media_entity *entity,
2803 +       struct v4l2_rect *rect, unsigned int pad, unsigned int target,
2804 +       enum v4l2_subdev_format_whence which)
2805 +{
2806 +       union {
2807 +               struct v4l2_subdev_selection sel;
2808 +               struct v4l2_subdev_crop crop;
2809 +       } u;
2810 +       int ret;
2811 +
2812 +       ret = v4l2_subdev_open(entity);
2813 +       if (ret < 0)
2814 +               return ret;
2815 +
2816 +       memset(&u.sel, 0, sizeof(u.sel));
2817 +       u.sel.pad = pad;
2818 +       u.sel.target = target;
2819 +       u.sel.which = which;
2820 +       u.sel.r = *rect;
2821 +
2822 +       ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_SELECTION, &u.sel);
2823 +       if (ret >= 0) {
2824 +               *rect = u.sel.r;
2825 +               return 0;
2826 +       }
2827 +       if (errno != ENOTTY || target != V4L2_SEL_TGT_CROP)
2828 +               return -errno;
2829 +
2830 +       memset(&u.crop, 0, sizeof(u.crop));
2831 +       u.crop.pad = pad;
2832 +       u.crop.which = which;
2833 +       u.crop.rect = *rect;
2834 +
2835 +       ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_CROP, &u.crop);
2836 +       if (ret < 0)
2837 +               return -errno;
2838 +
2839 +       *rect = u.crop.rect;
2840 +       return 0;
2841 +}
2842 +
2843 +#if 0
2844 +int v4l2_subdev_get_dv_timings_caps(struct media_entity *entity,
2845 +       struct v4l2_dv_timings_cap *caps)
2846 +{
2847 +       unsigned int pad = caps->pad;
2848 +       int ret;
2849 +
2850 +       ret = v4l2_subdev_open(entity);
2851 +       if (ret < 0)
2852 +               return ret;
2853 +
2854 +       memset(caps, 0, sizeof(*caps));
2855 +       caps->pad = pad;
2856 +
2857 +       ret = ioctl(entity->fd, VIDIOC_SUBDEV_DV_TIMINGS_CAP, caps);
2858 +       if (ret < 0)
2859 +               return -errno;
2860 +
2861 +       return 0;
2862 +}
2863 +
2864 +int v4l2_subdev_query_dv_timings(struct media_entity *entity,
2865 +       struct v4l2_dv_timings *timings)
2866 +{
2867 +       int ret;
2868 +
2869 +       ret = v4l2_subdev_open(entity);
2870 +       if (ret < 0)
2871 +               return ret;
2872 +
2873 +       memset(timings, 0, sizeof(*timings));
2874 +
2875 +       ret = ioctl(entity->fd, VIDIOC_SUBDEV_QUERY_DV_TIMINGS, timings);
2876 +       if (ret < 0)
2877 +               return -errno;
2878 +
2879 +       return 0;
2880 +}
2881 +
2882 +int v4l2_subdev_get_dv_timings(struct media_entity *entity,
2883 +       struct v4l2_dv_timings *timings)
2884 +{
2885 +       int ret;
2886 +
2887 +       ret = v4l2_subdev_open(entity);
2888 +       if (ret < 0)
2889 +               return ret;
2890 +
2891 +       memset(timings, 0, sizeof(*timings));
2892 +
2893 +       ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_DV_TIMINGS, timings);
2894 +       if (ret < 0)
2895 +               return -errno;
2896 +
2897 +       return 0;
2898 +}
2899 +
2900 +int v4l2_subdev_set_dv_timings(struct media_entity *entity,
2901 +       struct v4l2_dv_timings *timings)
2902 +{
2903 +       int ret;
2904 +
2905 +       ret = v4l2_subdev_open(entity);
2906 +       if (ret < 0)
2907 +               return ret;
2908 +
2909 +       ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_DV_TIMINGS, timings);
2910 +       if (ret < 0)
2911 +               return -errno;
2912 +
2913 +       return 0;
2914 +}
2915 +#endif
2916 +
2917 +int v4l2_subdev_get_frame_interval(struct media_entity *entity,
2918 +                                  struct v4l2_fract *interval)
2919 +{
2920 +       struct v4l2_subdev_frame_interval ival;
2921 +       int ret;
2922 +
2923 +       ret = v4l2_subdev_open(entity);
2924 +       if (ret < 0)
2925 +               return ret;
2926 +
2927 +       memset(&ival, 0, sizeof(ival));
2928 +
2929 +       ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &ival);
2930 +       if (ret < 0)
2931 +               return -errno;
2932 +
2933 +       *interval = ival.interval;
2934 +       return 0;
2935 +}
2936 +
2937 +int v4l2_subdev_set_frame_interval(struct media_entity *entity,
2938 +                                  struct v4l2_fract *interval)
2939 +{
2940 +       struct v4l2_subdev_frame_interval ival;
2941 +       int ret;
2942 +
2943 +       ret = v4l2_subdev_open(entity);
2944 +       if (ret < 0)
2945 +               return ret;
2946 +
2947 +       memset(&ival, 0, sizeof(ival));
2948 +       ival.interval = *interval;
2949 +
2950 +       ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &ival);
2951 +       if (ret < 0)
2952 +               return -errno;
2953 +
2954 +       *interval = ival.interval;
2955 +       return 0;
2956 +}
2957 +
2958 +static int v4l2_subdev_parse_format(struct media_device *media,
2959 +                                   struct v4l2_mbus_framefmt *format,
2960 +                                   const char *p, char **endp)
2961 +{
2962 +       enum v4l2_mbus_pixelcode code;
2963 +       unsigned int width, height;
2964 +       char *end;
2965 +
2966 +       /*
2967 +        * Compatibility with the old syntax: consider space as valid
2968 +        * separator between the media bus pixel code and the size.
2969 +        */
2970 +       for (; isspace(*p); ++p);
2971 +       for (end = (char *)p;
2972 +            *end != '/' && *end != ' ' && *end != '\0'; ++end);
2973 +
2974 +       code = v4l2_subdev_string_to_pixelcode(p, end - p);
2975 +       if (code == (enum v4l2_mbus_pixelcode)-1) {
2976 +               media_dbg(media, "Invalid pixel code '%.*s'\n", end - p, p);
2977 +               return -EINVAL;
2978 +       }
2979 +
2980 +       p = end + 1;
2981 +       width = strtoul(p, &end, 10);
2982 +       if (*end != 'x') {
2983 +               media_dbg(media, "Expected 'x'\n");
2984 +               return -EINVAL;
2985 +       }
2986 +
2987 +       p = end + 1;
2988 +       height = strtoul(p, &end, 10);
2989 +       *endp = end;
2990 +
2991 +       memset(format, 0, sizeof(*format));
2992 +       format->width = width;
2993 +       format->height = height;
2994 +       format->code = code;
2995 +
2996 +       return 0;
2997 +}
2998 +
2999 +static int v4l2_subdev_parse_rectangle(struct media_device *media,
3000 +                                      struct v4l2_rect *r, const char *p,
3001 +                                      char **endp)
3002 +{
3003 +       char *end;
3004 +
3005 +       if (*p++ != '(') {
3006 +               media_dbg(media, "Expected '('\n");
3007 +               *endp = (char *)p - 1;
3008 +               return -EINVAL;
3009 +       }
3010 +
3011 +       r->left = strtoul(p, &end, 10);
3012 +       if (*end != ',') {
3013 +               media_dbg(media, "Expected ','\n");
3014 +               *endp = end;
3015 +               return -EINVAL;
3016 +       }
3017 +
3018 +       p = end + 1;
3019 +       r->top = strtoul(p, &end, 10);
3020 +       if (*end++ != ')') {
3021 +               media_dbg(media, "Expected ')'\n");
3022 +               *endp = end - 1;
3023 +               return -EINVAL;
3024 +       }
3025 +       if (*end != '/') {
3026 +               media_dbg(media, "Expected '/'\n");
3027 +               *endp = end;
3028 +               return -EINVAL;
3029 +       }
3030 +
3031 +       p = end + 1;
3032 +       r->width = strtoul(p, &end, 10);
3033 +       if (*end != 'x') {
3034 +               media_dbg(media, "Expected 'x'\n");
3035 +               *endp = end;
3036 +               return -EINVAL;
3037 +       }
3038 +
3039 +       p = end + 1;
3040 +       r->height = strtoul(p, &end, 10);
3041 +       *endp = end;
3042 +
3043 +       return 0;
3044 +}
3045 +
3046 +static int v4l2_subdev_parse_frame_interval(struct media_device *media,
3047 +                                           struct v4l2_fract *interval,
3048 +                                           const char *p, char **endp)
3049 +{
3050 +       char *end;
3051 +
3052 +       for (; isspace(*p); ++p);
3053 +
3054 +       interval->numerator = strtoul(p, &end, 10);
3055 +
3056 +       for (p = end; isspace(*p); ++p);
3057 +       if (*p++ != '/') {
3058 +               media_dbg(media, "Expected '/'\n");
3059 +               *endp = (char *)p - 1;
3060 +               return -EINVAL;
3061 +       }
3062 +
3063 +       for (; isspace(*p); ++p);
3064 +       interval->denominator = strtoul(p, &end, 10);
3065 +
3066 +       *endp = end;
3067 +       return 0;
3068 +}
3069 +
3070 +/*
3071 + * The debate over whether this function should be named icanhasstr() instead
3072 + * has been strong and heated. If you feel like this would be an important
3073 + * change, patches are welcome (or not).
3074 + */
3075 +static bool strhazit(const char *str, const char **p)
3076 +{
3077 +       int len = strlen(str);
3078 +
3079 +       if (strncmp(str, *p, len))
3080 +               return false;
3081 +
3082 +       for (*p += len; isspace(**p); ++*p);
3083 +       return true;
3084 +}
3085 +
3086 +static struct media_pad *v4l2_subdev_parse_pad_format(
3087 +       struct media_device *media, struct v4l2_mbus_framefmt *format,
3088 +       struct v4l2_rect *crop, struct v4l2_rect *compose,
3089 +       struct v4l2_fract *interval, const char *p, char **endp)
3090 +{
3091 +       struct media_pad *pad;
3092 +       bool first;
3093 +       char *end;
3094 +       int ret;
3095 +
3096 +       for (; isspace(*p); ++p);
3097 +
3098 +       pad = media_parse_pad(media, p, &end);
3099 +       if (pad == NULL) {
3100 +               *endp = end;
3101 +               return NULL;
3102 +       }
3103 +
3104 +       for (p = end; isspace(*p); ++p);
3105 +       if (*p++ != '[') {
3106 +               media_dbg(media, "Expected '['\n");
3107 +               *endp = (char *)p - 1;
3108 +               return NULL;
3109 +       }
3110 +
3111 +       for (first = true; ; first = false) {
3112 +               for (; isspace(*p); p++);
3113 +
3114 +               /*
3115 +                * Backward compatibility: if the first property starts with an
3116 +                * uppercase later, process it as a format description.
3117 +                */
3118 +               if (strhazit("fmt:", &p) || (first && isupper(*p))) {
3119 +                       ret = v4l2_subdev_parse_format(media, format, p, &end);
3120 +                       if (ret < 0) {
3121 +                               *endp = end;
3122 +                               return NULL;
3123 +                       }
3124 +
3125 +                       p = end;
3126 +                       continue;
3127 +               }
3128 +
3129 +               /*
3130 +                * Backward compatibility: crop rectangles can be specified
3131 +                * implicitly without the 'crop:' property name.
3132 +                */
3133 +               if (strhazit("crop:", &p) || *p == '(') {
3134 +                       ret = v4l2_subdev_parse_rectangle(media, crop, p, &end);
3135 +                       if (ret < 0) {
3136 +                               *endp = end;
3137 +                               return NULL;
3138 +                       }
3139 +
3140 +                       p = end;
3141 +                       continue;
3142 +               }
3143 +
3144 +               if (strhazit("compose:", &p)) {
3145 +                       ret = v4l2_subdev_parse_rectangle(media, compose, p, &end);
3146 +                       if (ret < 0) {
3147 +                               *endp = end;
3148 +                               return NULL;
3149 +                       }
3150 +
3151 +                       for (p = end; isspace(*p); p++);
3152 +                       continue;
3153 +               }
3154 +
3155 +               if (*p == '@') {
3156 +                       ret = v4l2_subdev_parse_frame_interval(media, interval, ++p, &end);
3157 +                       if (ret < 0) {
3158 +                               *endp = end;
3159 +                               return NULL;
3160 +                       }
3161 +
3162 +                       p = end;
3163 +                       continue;
3164 +               }
3165 +
3166 +               break;
3167 +       }
3168 +
3169 +       if (*p != ']') {
3170 +               media_dbg(media, "Expected ']'\n");
3171 +               *endp = (char *)p;
3172 +               return NULL;
3173 +       }
3174 +
3175 +       *endp = (char *)p + 1;
3176 +       return pad;
3177 +}
3178 +
3179 +static int set_format(struct media_pad *pad,
3180 +                     struct v4l2_mbus_framefmt *format)
3181 +{
3182 +       int ret;
3183 +
3184 +       if (format->width == 0 || format->height == 0)
3185 +               return 0;
3186 +
3187 +       media_dbg(pad->entity->media,
3188 +                 "Setting up format %s %ux%u on pad %s/%u\n",
3189 +                 v4l2_subdev_pixelcode_to_string(format->code),
3190 +                 format->width, format->height,
3191 +                 pad->entity->info.name, pad->index);
3192 +
3193 +       ret = v4l2_subdev_set_format(pad->entity, format, pad->index,
3194 +                                    V4L2_SUBDEV_FORMAT_ACTIVE);
3195 +       if (ret < 0) {
3196 +               media_dbg(pad->entity->media,
3197 +                         "Unable to set format: %s (%d)\n",
3198 +                         strerror(-ret), ret);
3199 +               return ret;
3200 +       }
3201 +
3202 +       media_dbg(pad->entity->media,
3203 +                 "Format set: %s %ux%u\n",
3204 +                 v4l2_subdev_pixelcode_to_string(format->code),
3205 +                 format->width, format->height);
3206 +
3207 +       return 0;
3208 +}
3209 +
3210 +static int set_selection(struct media_pad *pad, unsigned int target,
3211 +                        struct v4l2_rect *rect)
3212 +{
3213 +       int ret;
3214 +
3215 +       if (rect->left == -1 || rect->top == -1)
3216 +               return 0;
3217 +
3218 +       media_dbg(pad->entity->media,
3219 +                 "Setting up selection target %u rectangle (%u,%u)/%ux%u on pad %s/%u\n",
3220 +                 target, rect->left, rect->top, rect->width, rect->height,
3221 +                 pad->entity->info.name, pad->index);
3222 +
3223 +       ret = v4l2_subdev_set_selection(pad->entity, rect, pad->index,
3224 +                                       target, V4L2_SUBDEV_FORMAT_ACTIVE);
3225 +       if (ret < 0) {
3226 +               media_dbg(pad->entity->media,
3227 +                         "Unable to set selection rectangle: %s (%d)\n",
3228 +                         strerror(-ret), ret);
3229 +               return ret;
3230 +       }
3231 +
3232 +       media_dbg(pad->entity->media,
3233 +                 "Selection rectangle set: (%u,%u)/%ux%u\n",
3234 +                 rect->left, rect->top, rect->width, rect->height);
3235 +
3236 +       return 0;
3237 +}
3238 +
3239 +static int set_frame_interval(struct media_entity *entity,
3240 +                             struct v4l2_fract *interval)
3241 +{
3242 +       int ret;
3243 +
3244 +       if (interval->numerator == 0)
3245 +               return 0;
3246 +
3247 +       media_dbg(entity->media,
3248 +                 "Setting up frame interval %u/%u on entity %s\n",
3249 +                 interval->numerator, interval->denominator,
3250 +                 entity->info.name);
3251 +
3252 +       ret = v4l2_subdev_set_frame_interval(entity, interval);
3253 +       if (ret < 0) {
3254 +               media_dbg(entity->media,
3255 +                         "Unable to set frame interval: %s (%d)",
3256 +                         strerror(-ret), ret);
3257 +               return ret;
3258 +       }
3259 +
3260 +       media_dbg(entity->media, "Frame interval set: %u/%u\n",
3261 +                 interval->numerator, interval->denominator);
3262 +
3263 +       return 0;
3264 +}
3265 +
3266 +
3267 +static int v4l2_subdev_parse_setup_format(struct media_device *media,
3268 +                                         const char *p, char **endp)
3269 +{
3270 +       struct v4l2_mbus_framefmt format = { 0, 0, 0 };
3271 +       struct media_pad *pad;
3272 +       struct v4l2_rect crop = { -1, -1, -1, -1 };
3273 +       struct v4l2_rect compose = crop;
3274 +       struct v4l2_fract interval = { 0, 0 };
3275 +       unsigned int i;
3276 +       char *end;
3277 +       int ret;
3278 +
3279 +       pad = v4l2_subdev_parse_pad_format(media, &format, &crop, &compose,
3280 +                                          &interval, p, &end);
3281 +       if (pad == NULL) {
3282 +               media_print_streampos(media, p, end);
3283 +               media_dbg(media, "Unable to parse format\n");
3284 +               return -EINVAL;
3285 +       }
3286 +
3287 +       if (pad->flags & MEDIA_PAD_FL_SINK) {
3288 +               ret = set_format(pad, &format);
3289 +               if (ret < 0)
3290 +                       return ret;
3291 +       }
3292 +
3293 +       ret = set_selection(pad, V4L2_SEL_TGT_CROP, &crop);
3294 +       if (ret < 0)
3295 +               return ret;
3296 +
3297 +       ret = set_selection(pad, V4L2_SEL_TGT_COMPOSE, &compose);
3298 +       if (ret < 0)
3299 +               return ret;
3300 +
3301 +       if (pad->flags & MEDIA_PAD_FL_SOURCE) {
3302 +               ret = set_format(pad, &format);
3303 +               if (ret < 0)
3304 +                       return ret;
3305 +       }
3306 +
3307 +       ret = set_frame_interval(pad->entity, &interval);
3308 +       if (ret < 0)
3309 +               return ret;
3310 +
3311 +
3312 +       /* If the pad is an output pad, automatically set the same format on
3313 +        * the remote subdev input pads, if any.
3314 +        */
3315 +       if (pad->flags & MEDIA_PAD_FL_SOURCE) {
3316 +               for (i = 0; i < pad->entity->num_links; ++i) {
3317 +                       struct media_link *link = &pad->entity->links[i];
3318 +                       struct v4l2_mbus_framefmt remote_format;
3319 +
3320 +                       if (!(link->flags & MEDIA_LNK_FL_ENABLED))
3321 +                               continue;
3322 +
3323 +                       if (link->source == pad &&
3324 +                           link->sink->entity->info.type == MEDIA_ENT_T_V4L2_SUBDEV) {
3325 +                               remote_format = format;
3326 +                               set_format(link->sink, &remote_format);
3327 +                       }
3328 +               }
3329 +       }
3330 +
3331 +       *endp = end;
3332 +       return 0;
3333 +}
3334 +
3335 +int v4l2_subdev_parse_setup_formats(struct media_device *media, const char *p)
3336 +{
3337 +       char *end;
3338 +       int ret;
3339 +
3340 +       do {
3341 +               ret = v4l2_subdev_parse_setup_format(media, p, &end);
3342 +               if (ret < 0)
3343 +                       return ret;
3344 +
3345 +               p = end + 1;
3346 +       } while (*end == ',');
3347 +
3348 +       return *end ? -EINVAL : 0;
3349 +}
3350 +
3351 +static struct {
3352 +       const char *name;
3353 +       enum v4l2_mbus_pixelcode code;
3354 +} mbus_formats[] = {
3355 +       { "Y8", V4L2_MBUS_FMT_Y8_1X8},
3356 +       { "Y10", V4L2_MBUS_FMT_Y10_1X10 },
3357 +       { "Y12", V4L2_MBUS_FMT_Y12_1X12 },
3358 +       { "YUYV", V4L2_MBUS_FMT_YUYV8_1X16 },
3359 +       { "YUYV1_5X8", V4L2_MBUS_FMT_YUYV8_1_5X8 },
3360 +       { "YUYV2X8", V4L2_MBUS_FMT_YUYV8_2X8 },
3361 +       { "UYVY", V4L2_MBUS_FMT_UYVY8_1X16 },
3362 +       { "UYVY1_5X8", V4L2_MBUS_FMT_UYVY8_1_5X8 },
3363 +       { "UYVY2X8", V4L2_MBUS_FMT_UYVY8_2X8 },
3364 +       { "SBGGR8", V4L2_MBUS_FMT_SBGGR8_1X8 },
3365 +       { "SGBRG8", V4L2_MBUS_FMT_SGBRG8_1X8 },
3366 +       { "SGRBG8", V4L2_MBUS_FMT_SGRBG8_1X8 },
3367 +       { "SRGGB8", V4L2_MBUS_FMT_SRGGB8_1X8 },
3368 +       { "SBGGR10", V4L2_MBUS_FMT_SBGGR10_1X10 },
3369 +       { "SGBRG10", V4L2_MBUS_FMT_SGBRG10_1X10 },
3370 +       { "SGRBG10", V4L2_MBUS_FMT_SGRBG10_1X10 },
3371 +       { "SRGGB10", V4L2_MBUS_FMT_SRGGB10_1X10 },
3372 +       { "SBGGR10_DPCM8", V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8 },
3373 +       { "SGBRG10_DPCM8", V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8 },
3374 +       { "SGRBG10_DPCM8", V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 },
3375 +       { "SRGGB10_DPCM8", V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8 },
3376 +       { "SBGGR12", V4L2_MBUS_FMT_SBGGR12_1X12 },
3377 +       { "SGBRG12", V4L2_MBUS_FMT_SGBRG12_1X12 },
3378 +       { "SGRBG12", V4L2_MBUS_FMT_SGRBG12_1X12 },
3379 +       { "SRGGB12", V4L2_MBUS_FMT_SRGGB12_1X12 },
3380 +       { "AYUV32", V4L2_MBUS_FMT_AYUV8_1X32 },
3381 +       { "ARGB32", V4L2_MBUS_FMT_ARGB8888_1X32 },
3382 +};
3383 +
3384 +const char *v4l2_subdev_pixelcode_to_string(enum v4l2_mbus_pixelcode code)
3385 +{
3386 +       unsigned int i;
3387 +
3388 +       for (i = 0; i < ARRAY_SIZE(mbus_formats); ++i) {
3389 +               if (mbus_formats[i].code == code)
3390 +                       return mbus_formats[i].name;
3391 +       }
3392 +
3393 +       return "unknown";
3394 +}
3395 +
3396 +enum v4l2_mbus_pixelcode v4l2_subdev_string_to_pixelcode(const char *string,
3397 +                                                        unsigned int length)
3398 +{
3399 +       unsigned int i;
3400 +
3401 +       for (i = 0; i < ARRAY_SIZE(mbus_formats); ++i) {
3402 +               if (strncmp(mbus_formats[i].name, string, length) == 0)
3403 +                       break;
3404 +       }
3405 +
3406 +       if (i == ARRAY_SIZE(mbus_formats))
3407 +               return (enum v4l2_mbus_pixelcode)-1;
3408 +
3409 +       return mbus_formats[i].code;
3410 +}
3411 diff --git a/libweston/media-ctl/mediactl-priv.h b/libweston/media-ctl/mediactl-priv.h
3412 new file mode 100644
3413 index 0000000..a0d3a55
3414 --- /dev/null
3415 +++ b/libweston/media-ctl/mediactl-priv.h
3416 @@ -0,0 +1,64 @@
3417 +/*
3418 + * Media controller interface library
3419 + *
3420 + * Copyright (C) 2010-2014 Ideas on board SPRL
3421 + *
3422 + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
3423 + *
3424 + * This program is free software; you can redistribute it and/or modify
3425 + * it under the terms of the GNU Lesser General Public License as published
3426 + * by the Free Software Foundation; either version 2.1 of the License, or
3427 + * (at your option) any later version.
3428 + *
3429 + * This program is distributed in the hope that it will be useful,
3430 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3431 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3432 + * GNU Lesser General Public License for more details.
3433 + *
3434 + * You should have received a copy of the GNU Lesser General Public License
3435 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
3436 + */
3437 +
3438 +#ifndef __MEDIA_PRIV_H__
3439 +#define __MEDIA_PRIV_H__
3440 +
3441 +#include <linux/media.h>
3442 +
3443 +#include "mediactl.h"
3444 +
3445 +struct media_entity {
3446 +       struct media_device *media;
3447 +       struct media_entity_desc info;
3448 +       struct media_pad *pads;
3449 +       struct media_link *links;
3450 +       unsigned int max_links;
3451 +       unsigned int num_links;
3452 +
3453 +       char devname[32];
3454 +       int fd;
3455 +};
3456 +
3457 +struct media_device {
3458 +       int fd;
3459 +       int refcount;
3460 +       char *devnode;
3461 +
3462 +       struct media_device_info info;
3463 +       struct media_entity *entities;
3464 +       unsigned int entities_count;
3465 +
3466 +       void (*debug_handler)(void *, ...);
3467 +       void *debug_priv;
3468 +
3469 +       struct {
3470 +               struct media_entity *v4l;
3471 +               struct media_entity *fb;
3472 +               struct media_entity *alsa;
3473 +               struct media_entity *dvb;
3474 +       } def;
3475 +};
3476 +
3477 +#define media_dbg(media, ...) \
3478 +       (media)->debug_handler((media)->debug_priv, __VA_ARGS__)
3479 +
3480 +#endif /* __MEDIA_PRIV_H__ */
3481 diff --git a/libweston/media-ctl/mediactl.h b/libweston/media-ctl/mediactl.h
3482 new file mode 100644
3483 index 0000000..77ac182
3484 --- /dev/null
3485 +++ b/libweston/media-ctl/mediactl.h
3486 @@ -0,0 +1,423 @@
3487 +/*
3488 + * Media controller interface library
3489 + *
3490 + * Copyright (C) 2010-2014 Ideas on board SPRL
3491 + *
3492 + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
3493 + *
3494 + * This program is free software; you can redistribute it and/or modify
3495 + * it under the terms of the GNU Lesser General Public License as published
3496 + * by the Free Software Foundation; either version 2.1 of the License, or
3497 + * (at your option) any later version.
3498 + *
3499 + * This program is distributed in the hope that it will be useful,
3500 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3501 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3502 + * GNU Lesser General Public License for more details.
3503 + *
3504 + * You should have received a copy of the GNU Lesser General Public License
3505 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
3506 + */
3507 +
3508 +#ifndef __MEDIA_H__
3509 +#define __MEDIA_H__
3510 +
3511 +#include <linux/media.h>
3512 +
3513 +struct media_link {
3514 +       struct media_pad *source;
3515 +       struct media_pad *sink;
3516 +       struct media_link *twin;
3517 +       __u32 flags;
3518 +       __u32 padding[3];
3519 +};
3520 +
3521 +struct media_pad {
3522 +       struct media_entity *entity;
3523 +       __u32 index;
3524 +       __u32 flags;
3525 +       __u32 padding[3];
3526 +};
3527 +
3528 +struct media_device;
3529 +struct media_entity;
3530 +
3531 +/**
3532 + * @brief Create a new media device.
3533 + * @param devnode - device node path.
3534 + *
3535 + * Create a media device instance for the given device node and return it. The
3536 + * device node is not accessed by this function, device node access errors will
3537 + * not be caught and reported here. The media device needs to be enumerated
3538 + * before it can be accessed, see media_device_enumerate().
3539 + *
3540 + * Media devices are reference-counted, see media_device_ref() and
3541 + * media_device_unref() for more information.
3542 + *
3543 + * @return A pointer to the new media device or NULL if memory cannot be
3544 + * allocated.
3545 + */
3546 +struct media_device *media_device_new(const char *devnode);
3547 +
3548 +/**
3549 + * @brief Create a new emulated media device.
3550 + * @param info - device information.
3551 + *
3552 + * Emulated media devices are userspace-only objects not backed by a kernel
3553 + * media device. They are created for ALSA and V4L2 devices that are not
3554 + * associated with a media controller device.
3555 + *
3556 + * Only device query functions are available for media devices. Enumerating or
3557 + * setting up links is invalid.
3558 + *
3559 + * @return A pointer to the new media device or NULL if memory cannot be
3560 + * allocated.
3561 + */
3562 +struct media_device *media_device_new_emulated(struct media_device_info *info);
3563 +
3564 +/**
3565 + * @brief Take a reference to the device.
3566 + * @param media - device instance.
3567 + *
3568 + * Media devices are reference-counted. Taking a reference to a device prevents
3569 + * it from being freed until all references are released. The reference count is
3570 + * initialized to 1 when the device is created.
3571 + *
3572 + * @return A pointer to @a media.
3573 + */
3574 +struct media_device *media_device_ref(struct media_device *media);
3575 +
3576 +/**
3577 + * @brief Release a reference to the device.
3578 + * @param media - device instance.
3579 + *
3580 + * Release a reference to the media device. When the reference count reaches 0
3581 + * this function frees the device.
3582 + */
3583 +void media_device_unref(struct media_device *media);
3584 +
3585 +/**
3586 + * @brief Add an entity to an existing media device
3587 + * @param media - device instance.
3588 + * @param desc - description of the entity to be added
3589 + * @param devnode - device node corresponding to the entity
3590 + *
3591 + * Entities are usually created and added to media devices automatically when
3592 + * the media device is enumerated through the media controller API. However,
3593 + * when an emulated media device (thus not backed with a kernel-side media
3594 + * controller device) is created, entities need to be manually added.
3595 + *
3596 + * Entities can also be manually added to a successfully enumerated media device
3597 + * to group several functions provided by separate kernel devices. The most
3598 + * common use case is to group the audio and video functions of a USB webcam in
3599 + * a single media device. Those functions are exposed through separate USB
3600 + * interfaces and handled through unrelated kernel drivers, they must thus be
3601 + * manually added to the same media device.
3602 + *
3603 + * This function adds a new entity to the given media device and initializes it
3604 + * from the given entity description and device node name. Only the following
3605 + * fields of the description are copied over to the new entity:
3606 + *
3607 + * - type
3608 + * - flags (MEDIA_ENT_FL_DEFAULT only)
3609 + * - name
3610 + * - v4l, fb, alsa or dvb (depending on the device type)
3611 + *
3612 + * All other fields of the newly created entity id are initialized to 0,
3613 + * including the entity ID.
3614 + *
3615 + * @return Zero on success or -ENOMEM if memory cannot be allocated.
3616 + */
3617 +int media_device_add_entity(struct media_device *media,
3618 +                           const struct media_entity_desc *desc,
3619 +                           const char *devnode);
3620 +
3621 +/**
3622 + * @brief Set a handler for debug messages.
3623 + * @param media - device instance.
3624 + * @param debug_handler - debug message handler
3625 + * @param debug_priv - first argument to debug message handler
3626 + *
3627 + * Set a handler for debug messages that will be called whenever
3628 + * debugging information is to be printed. The handler expects an
3629 + * fprintf-like function.
3630 + */
3631 +void media_debug_set_handler(
3632 +       struct media_device *media, void (*debug_handler)(void *, ...),
3633 +       void *debug_priv);
3634 +
3635 +/**
3636 + * @brief Enumerate the device topology
3637 + * @param media - device instance.
3638 + *
3639 + * Enumerate the media device entities, pads and links. Calling this function is
3640 + * mandatory before accessing the media device contents.
3641 + *
3642 + * @return Zero on success or a negative error code on failure.
3643 + */
3644 +int media_device_enumerate(struct media_device *media);
3645 +
3646 +/**
3647 + * @brief Locate the pad at the other end of a link.
3648 + * @param pad - sink pad at one end of the link.
3649 + *
3650 + * Locate the source pad connected to @a pad through an enabled link. As only one
3651 + * link connected to a sink pad can be enabled at a time, the connected source
3652 + * pad is guaranteed to be unique.
3653 + *
3654 + * @return A pointer to the connected source pad, or NULL if all links connected
3655 + * to @a pad are disabled. Return NULL also if @a pad is not a sink pad.
3656 + */
3657 +struct media_pad *media_entity_remote_source(struct media_pad *pad);
3658 +
3659 +/**
3660 + * @brief Get information about a media entity
3661 + * @param entity - media entity.
3662 + *
3663 + * The information structure is owned by the media entity object and will be
3664 + * freed when the object is destroyed.
3665 + *
3666 + * @return A pointer to the media entity information
3667 + */
3668 +const struct media_entity_desc *media_entity_get_info(struct media_entity *entity);
3669 +
3670 +/**
3671 + * @brief Get an entity pad
3672 + * @param entity - media entity.
3673 + * @param index - pad index.
3674 + *
3675 + * This function returns a pointer to the pad object identified by its index
3676 + * for the given entity. If the pad index is out of bounds it will return NULL.
3677 + *
3678 + * @return A pointer to the pad
3679 + */
3680 +const struct media_pad *media_entity_get_pad(struct media_entity *entity,
3681 +                                            unsigned int index);
3682 +
3683 +/**
3684 + * @brief Get the number of links
3685 + * @param entity - media entity.
3686 + *
3687 + * This function returns the total number of links that originate from or arrive
3688 + * at the the media entity.
3689 + *
3690 + * @return The number of links for the entity
3691 + */
3692 +unsigned int media_entity_get_links_count(struct media_entity *entity);
3693 +
3694 +/**
3695 + * @brief Get an entity link
3696 + * @param entity - media entity.
3697 + * @param index - link index.
3698 + *
3699 + * This function returns a pointer to the link object identified by its index
3700 + * for the given entity. If the link index is out of bounds it will return NULL.
3701 + *
3702 + * @return A pointer to the link
3703 + */
3704 +const struct media_link *media_entity_get_link(struct media_entity *entity,
3705 +                                              unsigned int index);
3706 +
3707 +/**
3708 + * @brief Get the device node name for an entity
3709 + * @param entity - media entity.
3710 + *
3711 + * This function returns the full path and name to the device node corresponding
3712 + * to the given entity.
3713 + *
3714 + * @return A pointer to the device node name or NULL if the entity has no
3715 + * associated device node
3716 + */
3717 +const char *media_entity_get_devname(struct media_entity *entity);
3718 +
3719 +/**
3720 + * @brief Get the type of an entity.
3721 + * @param entity - the entity.
3722 + *
3723 + * @return The type of @a entity.
3724 + */
3725 +static inline unsigned int media_entity_type(struct media_entity *entity)
3726 +{
3727 +       return media_entity_get_info(entity)->type & MEDIA_ENT_TYPE_MASK;
3728 +}
3729 +
3730 +/**
3731 + * @brief Find an entity by its name.
3732 + * @param media - media device.
3733 + * @param name - entity name.
3734 + * @param length - size of @a name.
3735 + *
3736 + * Search for an entity with a name equal to @a name.
3737 + *
3738 + * @return A pointer to the entity if found, or NULL otherwise.
3739 + */
3740 +struct media_entity *media_get_entity_by_name(struct media_device *media,
3741 +       const char *name, size_t length);
3742 +
3743 +/**
3744 + * @brief Find an entity by its ID.
3745 + * @param media - media device.
3746 + * @param id - entity ID.
3747 + *
3748 + * This function searches for an entity based on its ID using an exact match or
3749 + * next ID method based on the given @a id. If @a id is ORed with
3750 + * MEDIA_ENT_ID_FLAG_NEXT, the function will return the entity with the smallest
3751 + * ID larger than @a id. Otherwise it will return the entity with an ID equal to
3752 + * @a id.
3753 + *
3754 + * @return A pointer to the entity if found, or NULL otherwise.
3755 + */
3756 +struct media_entity *media_get_entity_by_id(struct media_device *media,
3757 +       __u32 id);
3758 +
3759 +/**
3760 + * @brief Get the number of entities
3761 + * @param media - media device.
3762 + *
3763 + * This function returns the total number of entities in the media device. If
3764 + * entities haven't been enumerated yet it will return 0.
3765 + *
3766 + * @return The number of entities in the media device
3767 + */
3768 +unsigned int media_get_entities_count(struct media_device *media);
3769 +
3770 +/**
3771 + * @brief Get the entities
3772 + * @param media - media device.
3773 + *
3774 + * This function returns a pointer to the array of entities for the media
3775 + * device. If entities haven't been enumerated yet it will return NULL.
3776 + *
3777 + * The array of entities is owned by the media device object and will be freed
3778 + * when the media object is destroyed.
3779 + *
3780 + * @return A pointer to an array of entities
3781 + */
3782 +struct media_entity *media_get_entity(struct media_device *media, unsigned int index);
3783 +
3784 +/**
3785 + * @brief Get the default entity for a given type
3786 + * @param media - media device.
3787 + * @param type - entity type.
3788 + *
3789 + * This function returns the default entity of the requested type. @a type must
3790 + * be one of
3791 + *
3792 + *     MEDIA_ENT_T_DEVNODE_V4L
3793 + *     MEDIA_ENT_T_DEVNODE_FB
3794 + *     MEDIA_ENT_T_DEVNODE_ALSA
3795 + *     MEDIA_ENT_T_DEVNODE_DVB
3796 + *
3797 + * @return A pointer to the default entity for the type if it exists, or NULL
3798 + * otherwise.
3799 + */
3800 +struct media_entity *media_get_default_entity(struct media_device *media,
3801 +                                             unsigned int type);
3802 +
3803 +/**
3804 + * @brief Get the media device information
3805 + * @param media - media device.
3806 + *
3807 + * The information structure is owned by the media device object and will be freed
3808 + * when the media object is destroyed.
3809 + *
3810 + * @return A pointer to the media device information
3811 + */
3812 +const struct media_device_info *media_get_info(struct media_device *media);
3813 +
3814 +/**
3815 + * @brief Get the media device node name
3816 + * @param media - media device.
3817 + *
3818 + * The device node name string is owned by the media device object and will be
3819 + * freed when the media object is destroyed.
3820 + *
3821 + * @return A pointer to the media device node name
3822 + */
3823 +const char *media_get_devnode(struct media_device *media);
3824 +
3825 +/**
3826 + * @brief Configure a link.
3827 + * @param media - media device.
3828 + * @param source - source pad at the link origin.
3829 + * @param sink - sink pad at the link target.
3830 + * @param flags - configuration flags.
3831 + *
3832 + * Locate the link between @a source and @a sink, and configure it by applying
3833 + * the new @a flags.
3834 + *
3835 + * Only the MEDIA_LINK_FLAG_ENABLED flag is writable.
3836 + *
3837 + * @return 0 on success, -1 on failure:
3838 + *        -ENOENT: link not found
3839 + *        - other error codes returned by MEDIA_IOC_SETUP_LINK
3840 + */
3841 +int media_setup_link(struct media_device *media,
3842 +       struct media_pad *source, struct media_pad *sink,
3843 +       __u32 flags);
3844 +
3845 +/**
3846 + * @brief Reset all links to the disabled state.
3847 + * @param media - media device.
3848 + *
3849 + * Disable all links in the media device. This function is usually used after
3850 + * opening a media device to reset all links to a known state.
3851 + *
3852 + * @return 0 on success, or a negative error code on failure.
3853 + */
3854 +int media_reset_links(struct media_device *media);
3855 +
3856 +/**
3857 + * @brief Parse string to a pad on the media device.
3858 + * @param media - media device.
3859 + * @param p - input string
3860 + * @param endp - pointer to string where parsing ended
3861 + *
3862 + * Parse NULL terminated string describing a pad and return its struct
3863 + * media_pad instance.
3864 + *
3865 + * @return Pointer to struct media_pad on success, NULL on failure.
3866 + */
3867 +struct media_pad *media_parse_pad(struct media_device *media,
3868 +                                 const char *p, char **endp);
3869 +
3870 +/**
3871 + * @brief Parse string to a link on the media device.
3872 + * @param media - media device.
3873 + * @param p - input string
3874 + * @param endp - pointer to p where parsing ended
3875 + *
3876 + * Parse NULL terminated string p describing a link and return its struct
3877 + * media_link instance.
3878 + *
3879 + * @return Pointer to struct media_link on success, NULL on failure.
3880 + */
3881 +struct media_link *media_parse_link(struct media_device *media,
3882 +                                   const char *p, char **endp);
3883 +
3884 +/**
3885 + * @brief Parse string to a link on the media device and set it up.
3886 + * @param media - media device.
3887 + * @param p - input string
3888 + *
3889 + * Parse NULL terminated string p describing a link and its configuration
3890 + * and configure the link.
3891 + *
3892 + * @return 0 on success, or a negative error code on failure.
3893 + */
3894 +int media_parse_setup_link(struct media_device *media,
3895 +                          const char *p, char **endp);
3896 +
3897 +/**
3898 + * @brief Parse string to link(s) on the media device and set it up.
3899 + * @param media - media device.
3900 + * @param p - input string
3901 + *
3902 + * Parse NULL terminated string p describing link(s) separated by
3903 + * commas (,) and configure the link(s).
3904 + *
3905 + * @return 0 on success, or a negative error code on failure.
3906 + */
3907 +int media_parse_setup_links(struct media_device *media, const char *p);
3908 +
3909 +#endif
3910 diff --git a/libweston/media-ctl/tools.h b/libweston/media-ctl/tools.h
3911 new file mode 100644
3912 index 0000000..815534c
3913 --- /dev/null
3914 +++ b/libweston/media-ctl/tools.h
3915 @@ -0,0 +1,32 @@
3916 +/*
3917 + * Media controller test application
3918 + *
3919 + * Copyright (C) 2010-2014 Ideas on board SPRL
3920 + *
3921 + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
3922 + *
3923 + * This program is free software; you can redistribute it and/or modify
3924 + * it under the terms of the GNU Lesser General Public License as published
3925 + * by the Free Software Foundation; either version 2.1 of the License, or
3926 + * (at your option) any later version.
3927 + *
3928 + * This program is distributed in the hope that it will be useful,
3929 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3930 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3931 + * GNU Lesser General Public License for more details.
3932 + *
3933 + * You should have received a copy of the GNU Lesser General Public License
3934 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
3935 + */
3936 +
3937 +#ifndef __TOOLS_H__
3938 +#define __TOOLS_H__
3939 +
3940 +#define ARRAY_SIZE(array)      (sizeof(array) / sizeof((array)[0]))
3941 +#define FIELD_SIZEOF(t, f)     (sizeof(((t*)0)->f))
3942 +
3943 +void media_print_streampos(struct media_device *media, const char *p,
3944 +                          const char *end);
3945 +
3946 +#endif /* __TOOLS_H__ */
3947 +
3948 diff --git a/libweston/media-ctl/v4l2subdev.h b/libweston/media-ctl/v4l2subdev.h
3949 new file mode 100644
3950 index 0000000..1cb53ff
3951 --- /dev/null
3952 +++ b/libweston/media-ctl/v4l2subdev.h
3953 @@ -0,0 +1,258 @@
3954 +/*
3955 + * V4L2 subdev interface library
3956 + *
3957 + * Copyright (C) 2010-2014 Ideas on board SPRL
3958 + *
3959 + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
3960 + *
3961 + * This program is free software; you can redistribute it and/or modify
3962 + * it under the terms of the GNU Lesser General Public License as published
3963 + * by the Free Software Foundation; either version 2.1 of the License, or
3964 + * (at your option) any later version.
3965 + *
3966 + * This program is distributed in the hope that it will be useful,
3967 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3968 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
3969 + * GNU Lesser General Public License for more details.
3970 + *
3971 + * You should have received a copy of the GNU Lesser General Public License
3972 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
3973 + */
3974 +
3975 +#ifndef __SUBDEV_H__
3976 +#define __SUBDEV_H__
3977 +
3978 +#include <linux/v4l2-subdev.h>
3979 +
3980 +struct media_entity;
3981 +
3982 +/**
3983 + * @brief Open a sub-device.
3984 + * @param entity - sub-device media entity.
3985 + *
3986 + * Open the V4L2 subdev device node associated with @a entity. The file
3987 + * descriptor is stored in the media_entity structure.
3988 + *
3989 + * @return 0 on success, or a negative error code on failure.
3990 + */
3991 +int v4l2_subdev_open(struct media_entity *entity);
3992 +
3993 +/**
3994 + * @brief Close a sub-device.
3995 + * @param entity - sub-device media entity.
3996 + *
3997 + * Close the V4L2 subdev device node associated with the @a entity and opened by
3998 + * a previous call to v4l2_subdev_open() (either explicit or implicit).
3999 + */
4000 +void v4l2_subdev_close(struct media_entity *entity);
4001 +
4002 +/**
4003 + * @brief Retrieve the format on a pad.
4004 + * @param entity - subdev-device media entity.
4005 + * @param format - format to be filled.
4006 + * @param pad - pad number.
4007 + * @param which - identifier of the format to get.
4008 + *
4009 + * Retrieve the current format on the @a entity @a pad and store it in the
4010 + * @a format structure.
4011 + *
4012 + * @a which is set to V4L2_SUBDEV_FORMAT_TRY to retrieve the try format stored
4013 + * in the file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to retrieve the current
4014 + * active format.
4015 + *
4016 + * @return 0 on success, or a negative error code on failure.
4017 + */
4018 +int v4l2_subdev_get_format(struct media_entity *entity,
4019 +       struct v4l2_mbus_framefmt *format, unsigned int pad,
4020 +       enum v4l2_subdev_format_whence which);
4021 +
4022 +/**
4023 + * @brief Set the format on a pad.
4024 + * @param entity - subdev-device media entity.
4025 + * @param format - format.
4026 + * @param pad - pad number.
4027 + * @param which - identifier of the format to set.
4028 + *
4029 + * Set the format on the @a entity @a pad to @a format. The driver is allowed to
4030 + * modify the requested format, in which case @a format is updated with the
4031 + * modifications.
4032 + *
4033 + * @a which is set to V4L2_SUBDEV_FORMAT_TRY to set the try format stored in the
4034 + * file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to configure the device with an
4035 + * active format.
4036 + *
4037 + * @return 0 on success, or a negative error code on failure.
4038 + */
4039 +int v4l2_subdev_set_format(struct media_entity *entity,
4040 +       struct v4l2_mbus_framefmt *format, unsigned int pad,
4041 +       enum v4l2_subdev_format_whence which);
4042 +
4043 +/**
4044 + * @brief Retrieve a selection rectangle on a pad.
4045 + * @param entity - subdev-device media entity.
4046 + * @param r - rectangle to be filled.
4047 + * @param pad - pad number.
4048 + * @param target - selection target
4049 + * @param which - identifier of the format to get.
4050 + *
4051 + * Retrieve the @a target selection rectangle on the @a entity @a pad
4052 + * and store it in the @a rect structure.
4053 + *
4054 + * @a which is set to V4L2_SUBDEV_FORMAT_TRY to retrieve the try
4055 + * selection rectangle stored in the file handle, or
4056 + * V4L2_SUBDEV_FORMAT_ACTIVE to retrieve the current active selection
4057 + * rectangle.
4058 + *
4059 + * @return 0 on success, or a negative error code on failure.
4060 + */
4061 +int v4l2_subdev_get_selection(struct media_entity *entity,
4062 +       struct v4l2_rect *rect, unsigned int pad, unsigned int target,
4063 +       enum v4l2_subdev_format_whence which);
4064 +
4065 +/**
4066 + * @brief Set a selection rectangle on a pad.
4067 + * @param entity - subdev-device media entity.
4068 + * @param rect - crop rectangle.
4069 + * @param pad - pad number.
4070 + * @param target - selection target
4071 + * @param which - identifier of the format to set.
4072 + *
4073 + * Set the @a target selection rectangle on the @a entity @a pad to @a
4074 + * rect. The driver is allowed to modify the requested rectangle, in
4075 + * which case @a rect is updated with the modifications.
4076 + *
4077 + * @a which is set to V4L2_SUBDEV_FORMAT_TRY to set the try crop rectangle
4078 + * stored in the file handle, of V4L2_SUBDEV_FORMAT_ACTIVE to configure the
4079 + * device with an active crop rectangle.
4080 + *
4081 + * @return 0 on success, or a negative error code on failure.
4082 + */
4083 +int v4l2_subdev_set_selection(struct media_entity *entity,
4084 +       struct v4l2_rect *rect, unsigned int pad, unsigned int target,
4085 +       enum v4l2_subdev_format_whence which);
4086 +
4087 +/**
4088 + * @brief Query the digital video capabilities of a pad.
4089 + * @param entity - subdev-device media entity.
4090 + * @param cap - capabilities to be filled.
4091 + *
4092 + * Retrieve the digital video capabilities of the @a entity pad specified by
4093 + * @a cap.pad and store it in the @a cap structure.
4094 + *
4095 + * @return 0 on success, or a negative error code on failure.
4096 + */
4097 +int v4l2_subdev_get_dv_timings_caps(struct media_entity *entity,
4098 +       struct v4l2_dv_timings_cap *caps);
4099 +
4100 +/**
4101 + * @brief Query the digital video timings of a sub-device
4102 + * @param entity - subdev-device media entity.
4103 + * @param timings timings to be filled.
4104 + *
4105 + * Retrieve the detected digital video timings for the currently selected input
4106 + * of @a entity and store them in the @a timings structure.
4107 + *
4108 + * @return 0 on success, or a negative error code on failure.
4109 + */
4110 +int v4l2_subdev_query_dv_timings(struct media_entity *entity,
4111 +       struct v4l2_dv_timings *timings);
4112 +
4113 +/**
4114 + * @brief Get the current digital video timings of a sub-device
4115 + * @param entity - subdev-device media entity.
4116 + * @param timings timings to be filled.
4117 + *
4118 + * Retrieve the current digital video timings for the currently selected input
4119 + * of @a entity and store them in the @a timings structure.
4120 + *
4121 + * @return 0 on success, or a negative error code on failure.
4122 + */
4123 +int v4l2_subdev_get_dv_timings(struct media_entity *entity,
4124 +       struct v4l2_dv_timings *timings);
4125 +
4126 +/**
4127 + * @brief Set the digital video timings of a sub-device
4128 + * @param entity - subdev-device media entity.
4129 + * @param timings timings to be set.
4130 + *
4131 + * Set the digital video timings of @a entity to @a timings. The driver is
4132 + * allowed to modify the requested format, in which case @a timings is updated
4133 + * with the modifications.
4134 + *
4135 + * @return 0 on success, or a negative error code on failure.
4136 + */
4137 +int v4l2_subdev_set_dv_timings(struct media_entity *entity,
4138 +       struct v4l2_dv_timings *timings);
4139 +
4140 +/**
4141 + * @brief Retrieve the frame interval on a sub-device.
4142 + * @param entity - subdev-device media entity.
4143 + * @param interval - frame interval to be filled.
4144 + *
4145 + * Retrieve the current frame interval on subdev @a entity and store it in the
4146 + * @a interval structure.
4147 + *
4148 + * Frame interval retrieving is usually supported only on devices at the
4149 + * beginning of video pipelines, such as sensors.
4150 + *
4151 + * @return 0 on success, or a negative error code on failure.
4152 + */
4153 +
4154 +int v4l2_subdev_get_frame_interval(struct media_entity *entity,
4155 +       struct v4l2_fract *interval);
4156 +
4157 +/**
4158 + * @brief Set the frame interval on a sub-device.
4159 + * @param entity - subdev-device media entity.
4160 + * @param interval - frame interval.
4161 + *
4162 + * Set the frame interval on subdev @a entity to @a interval. The driver is
4163 + * allowed to modify the requested frame interval, in which case @a interval is
4164 + * updated with the modifications.
4165 + *
4166 + * Frame interval setting is usually supported only on devices at the beginning
4167 + * of video pipelines, such as sensors.
4168 + *
4169 + * @return 0 on success, or a negative error code on failure.
4170 + */
4171 +int v4l2_subdev_set_frame_interval(struct media_entity *entity,
4172 +       struct v4l2_fract *interval);
4173 +
4174 +/**
4175 + * @brief Parse a string and apply format, crop and frame interval settings.
4176 + * @param media - media device.
4177 + * @param p - input string
4178 + * @param endp - pointer to string p where parsing ended (return)
4179 + *
4180 + * Parse string @a p and apply format, crop and frame interval settings to a
4181 + * subdev pad specified in @a p. @a endp will be written a pointer where
4182 + * parsing of @a p ended.
4183 + *
4184 + * Format strings are separeted by commas (,).
4185 + *
4186 + * @return 0 on success, or a negative error code on failure.
4187 + */
4188 +int v4l2_subdev_parse_setup_formats(struct media_device *media, const char *p);
4189 +
4190 +/**
4191 + * @brief Convert media bus pixel code to string.
4192 + * @param code - input string
4193 + *
4194 + * Convert media bus pixel code @a code to a human-readable string.
4195 + *
4196 + * @return A pointer to a string on success, NULL on failure.
4197 + */
4198 +const char *v4l2_subdev_pixelcode_to_string(enum v4l2_mbus_pixelcode code);
4199 +
4200 +/**
4201 + * @brief Parse string to media bus pixel code.
4202 + * @param string - input string
4203 + * @param lenght - length of the string
4204 + *
4205 + * Parse human readable string @a string to an media bus pixel code.
4206 + *
4207 + * @return media bus pixelcode on success, -1 on failure.
4208 + */
4209 +enum v4l2_mbus_pixelcode v4l2_subdev_string_to_pixelcode(const char *string,
4210 +                                                        unsigned int length);
4211 +#endif
4212 -- 
4213 2.9.2
4214