summaryrefslogtreecommitdiff
path: root/packages/mplayer/files
diff options
context:
space:
mode:
authorGregoire Gentil <gregoire@gentil.com>2008-11-23 22:59:23 +0100
committerKoen Kooi <koen@openembedded.org>2008-11-23 22:59:23 +0100
commit59f5a9c741bba79e6ebf8e6527142aeeb8ea9236 (patch)
treef587ca00c136e4873a7d71c426f0848fa9443fe4 /packages/mplayer/files
parenta989a5ab47bc885c1f3b7436c0ad1b41f42ec8cb (diff)
mplayer svn: add vo_omapfb for the overlay found in omap2/omap3 chips
Diffstat (limited to 'packages/mplayer/files')
-rw-r--r--packages/mplayer/files/omapfb.patch29
-rw-r--r--packages/mplayer/files/vo_omapfb.c586
-rw-r--r--packages/mplayer/files/yuv.S119
3 files changed, 734 insertions, 0 deletions
diff --git a/packages/mplayer/files/omapfb.patch b/packages/mplayer/files/omapfb.patch
new file mode 100644
index 0000000000..5c9bca7a6f
--- /dev/null
+++ b/packages/mplayer/files/omapfb.patch
@@ -0,0 +1,29 @@
+--- a/libvo/video_out.c 2008-11-07 11:59:48.000000000 -0800
++++ b/libvo/video_out.c 2008-11-07 12:01:52.000000000 -0800
+@@ -86,6 +86,7 @@
+ extern vo_functions_t video_out_bl;
+ extern vo_functions_t video_out_fbdev;
+ extern vo_functions_t video_out_fbdev2;
++extern vo_functions_t video_out_omapfb;
+ extern vo_functions_t video_out_svga;
+ extern vo_functions_t video_out_png;
+ extern vo_functions_t video_out_ggi;
+@@ -172,6 +173,7 @@
+ #ifdef CONFIG_FBDEV
+ &video_out_fbdev,
+ &video_out_fbdev2,
++ &video_out_omapfb,
+ #endif
+ #ifdef CONFIG_SVGALIB
+ &video_out_svga,
+--- a/configure 2008-11-07 12:00:32.000000000 -0800
++++ b/configure 2008-11-07 12:13:31.000000000 -0800
+@@ -4558,7 +4558,7 @@
+ fi
+ if test "$_fbdev" = yes ; then
+ _def_fbdev='#define CONFIG_FBDEV 1'
+- _vosrc="$_vosrc vo_fbdev.c vo_fbdev2.c"
++ _vosrc="$_vosrc vo_fbdev.c vo_fbdev2.c vo_omapfb.c yuv.S"
+ _vomodules="fbdev $_vomodules"
+ else
+ _def_fbdev='#undef CONFIG_FBDEV'
diff --git a/packages/mplayer/files/vo_omapfb.c b/packages/mplayer/files/vo_omapfb.c
new file mode 100644
index 0000000000..5a43404300
--- /dev/null
+++ b/packages/mplayer/files/vo_omapfb.c
@@ -0,0 +1,586 @@
+/*
+
+Copyright (C) 2008 Gregoire Gentil <gregoire@gentil.com>
+This file adds an optimized vo output to mplayer for the OMAP platform. This is a first pass and an attempt to help to improve
+media playing on the OMAP platform. The usual disclaimer comes here: this code is provided without any warranty.
+Many bugs and issues still exist. Feed-back is welcome.
+
+This output uses the yuv420_to_yuv422 conversion from Mans Rullgard, and is heavily inspired from the work of Siarhei Siamashka.
+I would like to thank those two persons here, without them this code would certainly not exist.
+
+Two options of the output are available:
+fb_overlay_only (disabled by default): only the overlay is drawn. X11 stuff is ignored.
+dbl_buffer (disabled by default): add double buffering. Some tearsync flags are probably missing in the code.
+
+Syntax is the following:
+mplayer -ao alsa -vo omapfb /test.avi
+mplayer -nosound -vo omapfb:fb_overlay_only:dbl_buffer /test.avi
+
+You need to have two planes on your system. On beagleboard, it means something like: video=omapfb:vram:2M,vram:4M
+
+Known issues:
+1) A green line or some vertical lines (if mplayer decides to draw bands instead of frame) may appear.
+It's an interpolation bug in the color conversion that needs to be fixed
+
+2) The color conversion accepts only 16-pixel multiple for width and height.
+
+3) The scaling down is disabled as the scaling down kernel patch for the OMAP3 platform doesn't seem to work yet.
+
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <linux/fb.h>
+
+#include "config.h"
+#include "video_out.h"
+#include "video_out_internal.h"
+#include "fastmemcpy.h"
+#include "sub.h"
+#include "mp_msg.h"
+
+#include "omapfb.h"
+
+#include "libswscale/swscale.h"
+#include "libmpcodecs/vf_scale.h"
+#include "libavcodec/avcodec.h"
+
+#include "aspect.h"
+
+#include "subopt-helper.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include "wskeys.h"
+
+static vo_info_t info = {
+ "omapfb video driver",
+ "omapfb",
+ "",
+ ""
+};
+
+LIBVO_EXTERN(omapfb)
+
+static int fb_overlay_only = 0; // if set, we need only framebuffer overlay, but do not need any x11 code
+static int dbl_buffer = 0;
+static int fullscreen_flag = 0;
+static int plane_ready = 0;
+
+extern void yuv420_to_yuv422(uint8_t *yuv, uint8_t *y, uint8_t *u, uint8_t *v, int w, int h, int yw, int cw, int dw);
+static struct fb_var_screeninfo sinfo_p0;
+static struct fb_var_screeninfo sinfo;
+static struct omapfb_mem_info minfo;
+static struct omapfb_plane_info pinfo;
+static struct {
+ unsigned x;
+ unsigned y;
+ uint8_t *buf;
+} fb_pages[2];
+static int dev_fd = -1;
+static int fb_page_flip = 0;
+static int page = 0;
+static void omapfb_update(int x, int y, int out_w, int out_h, int show);
+
+extern void mplayer_put_key( int code );
+#include "osdep/keycodes.h"
+
+#define TRANSPARENT_COLOR_KEY 0xff0
+
+static Display *display = NULL; // pointer to X Display structure.
+static int screen_num; // number of screen to place the window on.
+static Window win = 0;
+static Window parent = 0; // pointer to the newly created window.
+
+/* This is used to intercept window closing requests. */
+static Atom wm_delete_window;
+
+/**
+ * Function to get the offset to be used when in windowed mode
+ * or when using -wid option
+ */
+static void x11_get_window_abs_position(Display *display, Window window,
+ int *wx, int *wy, int *ww, int *wh)
+{
+ Window root, parent;
+ Window *child;
+ unsigned int n_children;
+ XWindowAttributes attribs;
+
+ /* Get window attributes */
+ XGetWindowAttributes(display, window, &attribs);
+
+ /* Get relative position of given window */
+ *wx = attribs.x;
+ *wy = attribs.y;
+ if (ww)
+ *ww = attribs.width;
+ if (wh)
+ *wh = attribs.height;
+
+ /* Query window tree information */
+ XQueryTree(display, window, &root, &parent, &child, &n_children);
+ if (parent)
+ {
+ int x, y;
+ /* If we have a parent we must go there and discover his position*/
+ x11_get_window_abs_position(display, parent, &x, &y, NULL, NULL);
+ *wx += x;
+ *wy += y;
+ }
+
+ /* If we had children, free it */
+ if(n_children)
+ XFree(child);
+}
+
+
+/**
+ * Function that controls fullscreen state for x11 window
+ * action = 1 (set fullscreen)
+ * action = 0 (set windowed mode)
+ */
+static void x11_set_fullscreen_state(Display *display, Window window, int action)
+{
+ XEvent xev;
+
+ /* init X event structure for _NET_WM_FULLSCREEN client msg */
+ xev.xclient.type = ClientMessage;
+ xev.xclient.serial = 0;
+ xev.xclient.send_event = True;
+ xev.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", False);
+ xev.xclient.window = window;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = action;
+ xev.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", False);
+ xev.xclient.data.l[2] = 0;
+ xev.xclient.data.l[3] = 0;
+ xev.xclient.data.l[4] = 0;
+
+ /* finally send that damn thing */
+ if (!XSendEvent(display, DefaultRootWindow(display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev)) {
+ mp_msg(MSGT_VO, MSGL_ERR, "[omapfb] failure in x11_set_fullscreen_state\n");
+ exit(1);
+ }
+ XSync(display, False);
+}
+
+
+XClassHint classhint = {"mediaplayer-ui", "mediaplayer-ui"};
+
+
+/**
+ * Initialize x11 window (it is used to allocate some screen area for framebuffer overlay)
+ */
+static void x11_init()
+{
+ display = XOpenDisplay(getenv("DISPLAY"));
+ if (display == NULL) {
+ mp_msg(MSGT_VO, MSGL_ERR, "[omapfb] failure in x11_init, can't open display\n");
+ exit(1);
+ }
+
+ screen_num = DefaultScreen(display);
+
+ if (WinID > 0)
+ {
+ Window root;
+ Window *child;
+ unsigned int n_children;
+
+ win = WinID;
+
+ /* Query window tree information */
+ XQueryTree(display, win, &root, &parent, &child, &n_children);
+ if (n_children)
+ XFree(child);
+
+ XUnmapWindow(display, win);
+ if (parent)
+ XSelectInput(display, parent, StructureNotifyMask);
+ XMapWindow(display, win);
+
+ wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(display, win, &wm_delete_window, 1);
+ } else {
+ win = XCreateSimpleWindow(display, RootWindow(display, screen_num),
+ sinfo_p0.xres / 2 - sinfo.xres / 2, sinfo_p0.yres / 2 - sinfo.yres / 2, sinfo.xres, sinfo.yres, 0,
+ WhitePixel(display, screen_num),
+ TRANSPARENT_COLOR_KEY);
+
+ XSetClassHint(display, win, &classhint);
+
+ XStoreName(display, win, "MPlayer");
+ XMapWindow(display, win);
+
+ /* Set WM_DELETE_WINDOW atom in WM_PROTOCOLS property (to get window_delete requests). */
+ wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(display, win, &wm_delete_window, 1);
+ XSelectInput(display, win, StructureNotifyMask | KeyPressMask);
+ }
+}
+
+
+void print_properties(Window win2)
+{
+ Atom *p;
+ int num, j;
+ char *aname;
+ Atom type;
+ int format;
+ unsigned long nitems, bytes_after;
+ unsigned char *ret = NULL;
+
+ p = XListProperties(display, win2, &num);
+ printf("found %d properties for window %d\n", num, (int)win2);
+ for (j = 0; j < num; j++) {
+ aname = XGetAtomName(display, p[j]);
+ if (aname) {
+ if(Success == XGetWindowProperty(display, win2, XInternAtom(display, aname, False),
+ 0L, ~0L, False, XA_STRING,
+ &type, &format, &nitems,
+ &bytes_after, &ret))
+ {
+/* printf("format = %d, nitems = %d, bytes_after = %d\n", format, nitems, bytes_after);*/
+ printf("%s = %s\n", aname, ret);
+ XFree(ret);
+ }
+ XFree(aname);
+ } else printf("NULL\n");
+ }
+ XFree(p);
+}
+
+
+static int x11_check_events()
+{
+ if (!display) {
+ mp_msg(MSGT_VO, MSGL_ERR, "[omapfb] 'x11_check_events' called out of sequence\n");
+ exit(1);
+ }
+
+ int ret = 0;
+ XEvent Event;
+ while (XPending(display)) {
+ XNextEvent(display, &Event);
+ if (Event.type == UnmapNotify)
+ omapfb_update(0, 0, 0, 0, 0);
+ else if ((Event.type == MapNotify) || (Event.type == ConfigureNotify))
+ omapfb_update(0, 0, 0, 0, 1);
+ else if (Event.type == KeyPress) {
+ int key;
+ KeySym keySym = XKeycodeToKeysym(display, Event.xkey.keycode, 0);
+ key = ((keySym & 0xff00) != 0 ? ((keySym & 0x00ff) + 256) : (keySym));
+ ret |= VO_EVENT_KEYPRESS;
+ vo_x11_putkey(key);
+ } else if (Event.type == ClientMessage) {
+ if ((Atom)Event.xclient.data.l[0] == wm_delete_window) {
+ mplayer_put_key(KEY_ESC);
+ }
+ }
+ }
+ return ret;
+}
+
+
+static void x11_uninit()
+{
+ if (display) {
+ XCloseDisplay(display);
+ display = NULL;
+ }
+}
+
+
+/**
+ * Initialize framebuffer
+ */
+static int preinit(const char *arg)
+{
+
+ opt_t subopts[] = {
+ {"fb_overlay_only", OPT_ARG_BOOL, &fb_overlay_only, NULL},
+ {"dbl_buffer", OPT_ARG_BOOL, &dbl_buffer, NULL},
+ {NULL}
+ };
+
+ if (subopt_parse(arg, subopts) != 0) {
+ mp_msg(MSGT_VO, MSGL_FATAL, "[omapfb] unknown suboptions: %s\n", arg);
+ return -1;
+ }
+
+ dev_fd = open("/dev/fb0", O_RDWR);
+
+ if (dev_fd == -1) {
+ mp_msg(MSGT_VO, MSGL_FATAL, "[omapfb] Error /dev/fb0\n");
+ return -1;
+ }
+
+ ioctl(dev_fd, FBIOGET_VSCREENINFO, &sinfo_p0);
+ close(dev_fd);
+
+ dev_fd = open("/dev/fb1", O_RDWR);
+
+ if (dev_fd == -1) {
+ mp_msg(MSGT_VO, MSGL_FATAL, "[omapfb] Error /dev/fb1\n");
+ return -1;
+ }
+
+ ioctl(dev_fd, FBIOGET_VSCREENINFO, &sinfo);
+ ioctl(dev_fd, OMAPFB_QUERY_PLANE, &pinfo);
+ ioctl(dev_fd, OMAPFB_QUERY_MEM, &minfo);
+
+ if (!fb_overlay_only)
+ x11_init();
+
+ return 0;
+}
+
+
+static void omapfb_update(int x, int y, int out_w, int out_h, int show)
+{
+ if (!fb_overlay_only)
+ x11_get_window_abs_position(display, win, &x, &y, &out_w, &out_h);
+
+ if ((x < 0) || (y < 0)
+
+// If you develop the right scaling-down patch in kernel, uncomment the line below and comment the next one
+// || (out_w < sinfo.xres / 4) || (out_h < sinfo.yres / 4)
+ || (out_w < sinfo.xres) || (out_h < sinfo.yres)
+
+// If you don't have the right scaling-up patch in kernel, comment the line below and uncomment the next one
+/* Kernel patch to enable scaling up on the omap3
+======================================================
+--- a/drivers/video/omap/dispc.c 2008-11-01 20:08:04.000000000 -0700
++++ b/drivers/video/omap/dispc.c 2008-11-01 20:09:02.000000000 -0700
+@@ -523,9 +523,6 @@
+ if ((unsigned)plane > OMAPFB_PLANE_NUM)
+ return -ENODEV;
+
+- if (out_width != orig_width || out_height != orig_height)
+- return -EINVAL;
+-
+ enable_lcd_clocks(1);
+ if (orig_width < out_width) {
+ /*
+======================================================
+*/
+ || (out_w > sinfo.xres * 8) || (out_h > sinfo.yres * 8)
+// || (out_w > sinfo.xres) || (out_h > sinfo.yres)
+
+ || (x + out_w > sinfo_p0.xres) || (y + out_h > sinfo_p0.yres)) {
+ pinfo.enabled = 0;
+ pinfo.pos_x = 0;
+ pinfo.pos_y = 0;
+ ioctl(dev_fd, OMAPFB_SETUP_PLANE, &pinfo);
+ return;
+ }
+
+ pinfo.enabled = show;
+ pinfo.pos_x = x;
+ pinfo.pos_y = y;
+ pinfo.out_width = out_w;
+ pinfo.out_height = out_h;
+ ioctl(dev_fd, OMAPFB_SETUP_PLANE, &pinfo);
+}
+
+
+static int config(uint32_t width, uint32_t height, uint32_t d_width,
+ uint32_t d_height, uint32_t flags, char *title,
+ uint32_t format)
+{
+ uint8_t *fbmem;
+ int i;
+ struct omapfb_color_key color_key;
+
+ fullscreen_flag = flags & VOFLAG_FULLSCREEN;
+
+ fbmem = mmap(NULL, minfo.size, PROT_READ|PROT_WRITE, MAP_SHARED, dev_fd, 0);
+ if (fbmem == MAP_FAILED) {
+ mp_msg(MSGT_VO, MSGL_FATAL, "[omapfb] Error mmap\n");
+ return -1;
+ }
+
+ for (i = 0; i < minfo.size / 4; i++)
+ ((uint32_t*)fbmem)[i] = 0x80008000;
+
+ sinfo.xres = FFMIN(sinfo_p0.xres, width) & ~15;
+ sinfo.yres = FFMIN(sinfo_p0.yres, height) & ~15;
+ sinfo.xoffset = 0;
+ sinfo.yoffset = 0;
+ sinfo.nonstd = OMAPFB_COLOR_YUY422;
+
+ fb_pages[0].x = 0;
+ fb_pages[0].y = 0;
+ fb_pages[0].buf = fbmem;
+
+ if (dbl_buffer && minfo.size >= sinfo.xres * sinfo.yres * 2) {
+ sinfo.xres_virtual = sinfo.xres;
+ sinfo.yres_virtual = sinfo.yres * 2;
+ fb_pages[1].x = 0;
+ fb_pages[1].y = sinfo.yres;
+ fb_pages[1].buf = fbmem + sinfo.xres * sinfo.yres * 2;
+ fb_page_flip = 1;
+ } else {
+ sinfo.xres_virtual = sinfo.xres;
+ sinfo.yres_virtual = sinfo.yres;
+ fb_page_flip = 0;
+ }
+
+ ioctl(dev_fd, FBIOPUT_VSCREENINFO, &sinfo);
+
+ if (WinID <= 0) {
+ if (fullscreen_flag) {
+ if (!fb_overlay_only)
+ x11_set_fullscreen_state(display, win, 1);
+ omapfb_update(0, 0, sinfo_p0.xres, sinfo_p0.yres, 1);
+ } else {
+ if (!fb_overlay_only)
+ x11_set_fullscreen_state(display, win, 0);
+ omapfb_update(sinfo_p0.xres / 2 - sinfo.xres / 2, sinfo_p0.yres / 2 - sinfo.yres / 2, sinfo.xres, sinfo.yres, 1);
+ }
+ }
+
+ color_key.channel_out = OMAPFB_CHANNEL_OUT_LCD;
+ color_key.background = 0x0;
+ color_key.trans_key = TRANSPARENT_COLOR_KEY;
+ if (fb_overlay_only)
+ color_key.key_type = OMAPFB_COLOR_KEY_DISABLED;
+ else
+ color_key.key_type = OMAPFB_COLOR_KEY_GFX_DST;
+ ioctl(dev_fd, OMAPFB_SET_COLOR_KEY, &color_key);
+
+ plane_ready = 1;
+ return 0;
+}
+
+
+static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride)
+{
+ vo_draw_alpha_yuy2(w, h, src, srca, stride, fb_pages[page].buf + sinfo.xres * y0 * 2 + x0 * 2, sinfo.xres);
+}
+
+
+static void draw_osd(void)
+{
+ vo_draw_text(sinfo.xres, sinfo.yres, draw_alpha);
+}
+
+
+static int draw_frame(uint8_t *src[])
+{
+ return 1;
+}
+
+
+static int draw_slice(uint8_t *src[], int stride[], int w, int h, int x, int y)
+{
+ if (x!=0)
+ return 0;
+
+ if (!plane_ready)
+ return 0;
+
+ ioctl(dev_fd, OMAPFB_SYNC_GFX);
+
+ yuv420_to_yuv422(fb_pages[page].buf + 2 * sinfo.xres * y, src[0], src[1], src[2], w & ~15, h, stride[0], stride[1], 2 * sinfo.xres_virtual);
+
+ return 0;
+}
+
+
+static void flip_page(void)
+{
+ if (fb_page_flip) {
+ sinfo.xoffset = fb_pages[page].x;
+ sinfo.yoffset = fb_pages[page].y;
+ ioctl(dev_fd, FBIOPAN_DISPLAY, &sinfo);
+ page ^= fb_page_flip;
+ }
+}
+
+
+static int query_format(uint32_t format)
+{
+ // For simplicity pretend that we can only do YV12, support for
+ // other formats can be added quite easily if/when needed
+ if (format != IMGFMT_YV12)
+ return 0;
+
+ return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD | VFCAP_SWSCALE | VFCAP_ACCEPT_STRIDE;
+}
+
+
+/**
+ * Uninitialize framebuffer
+ */
+static void uninit()
+{
+ pinfo.enabled = 0;
+ ioctl(dev_fd, OMAPFB_SETUP_PLANE, &pinfo);
+
+ if (!fb_overlay_only) {
+ struct omapfb_color_key color_key;
+ color_key.channel_out = OMAPFB_CHANNEL_OUT_LCD;
+ color_key.key_type = OMAPFB_COLOR_KEY_DISABLED;
+ ioctl(dev_fd, OMAPFB_SET_COLOR_KEY, &color_key);
+ }
+
+ close(dev_fd);
+
+ if (!fb_overlay_only)
+ x11_uninit();
+}
+
+
+static int control(uint32_t request, void *data, ...)
+{
+ switch (request) {
+ case VOCTRL_QUERY_FORMAT:
+ return query_format(*((uint32_t*)data));
+ case VOCTRL_FULLSCREEN: {
+ if (WinID > 0) return VO_FALSE;
+ if (fullscreen_flag) {
+ if (!fb_overlay_only)
+ x11_set_fullscreen_state(display, win, 0);
+ fullscreen_flag = 0;
+ omapfb_update(sinfo_p0.xres / 2 - sinfo.xres / 2, sinfo_p0.yres / 2 - sinfo.yres / 2, sinfo.xres, sinfo.yres, 1);
+ } else {
+ if (!fb_overlay_only)
+ x11_set_fullscreen_state(display, win, 1);
+ fullscreen_flag = 1;
+ omapfb_update(0, 0, sinfo_p0.xres, sinfo_p0.yres, 1);
+ }
+ return VO_TRUE;
+ }
+ }
+ return VO_NOTIMPL;
+}
+
+
+static void check_events(void)
+{
+ if (!fb_overlay_only)
+ x11_check_events();
+}
diff --git a/packages/mplayer/files/yuv.S b/packages/mplayer/files/yuv.S
new file mode 100644
index 0000000000..3eaf284a61
--- /dev/null
+++ b/packages/mplayer/files/yuv.S
@@ -0,0 +1,119 @@
+/*
+ Copyright (C) 2008 Mans Rullgard
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use, copy,
+ modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ */
+
+ .fpu neon
+ .text
+
+@ yuv420_to_yuv422(uint8_t *yuv, uint8_t *y, uint8_t *u, uint8_t *v,
+@ int w, int h, int yw, int cw, int dw)
+
+#define yuv r0
+#define y r1
+#define u r2
+#define v r3
+#define w r4
+#define h r5
+#define yw r6
+#define cw r7
+#define dw r8
+
+#define tyuv r9
+#define ty r10
+#define tu r11
+#define tv r12
+#define i lr
+
+ .global yuv420_to_yuv422
+ .func yuv420_to_yuv422
+yuv420_to_yuv422:
+ push {r4-r11,lr}
+ add r4, sp, #36
+ ldm r4, {r4-r8}
+ dmb
+1:
+ mov tu, u
+ mov tv, v
+ vld1.64 {d2}, [u,:64], cw @ u0
+ vld1.64 {d3}, [v,:64], cw @ v0
+ mov tyuv, yuv
+ mov ty, y
+ vzip.8 d2, d3 @ u0v0
+ mov i, #16
+2:
+ pld [y, #64]
+ vld1.64 {d0, d1}, [y,:128], yw @ y0
+ pld [u, #64]
+ subs i, i, #4
+ vld1.64 {d6}, [u,:64], cw @ u2
+ pld [y, #64]
+ vld1.64 {d4, d5}, [y,:128], yw @ y1
+ pld [v, #64]
+ vld1.64 {d7}, [v,:64], cw @ v2
+ pld [y, #64]
+ vld1.64 {d16,d17}, [y,:128], yw @ y2
+ vzip.8 d6, d7 @ u2v2
+ pld [u, #64]
+ vld1.64 {d22}, [u,:64], cw @ u4
+ pld [v, #64]
+ vld1.64 {d23}, [v,:64], cw @ v4
+ pld [y, #64]
+ vld1.64 {d20,d21}, [y,:128], yw @ y3
+ vmov q9, q3 @ u2v2
+ vzip.8 d22, d23 @ u4v4
+ vrhadd.u8 q3, q1, q3 @ u1v1
+ vzip.8 q0, q1 @ y0u0y0v0
+ vmov q12, q11 @ u4v4
+ vzip.8 q2, q3 @ y1u1y1v1
+ vrhadd.u8 q11, q9, q11 @ u3v3
+ vst1.64 {d0-d3}, [yuv,:128], dw @ y0u0y0v0
+ vzip.8 q8, q9 @ y2u2y2v2
+ vst1.64 {d4-d7}, [yuv,:128], dw @ y1u1y1v1
+ vzip.8 q10, q11 @ y3u3y3v3
+ vst1.64 {d16-d19}, [yuv,:128], dw @ y2u2y2v2
+ vmov q1, q12
+ vst1.64 {d20-d23}, [yuv,:128], dw @ y3u3y3v3
+ bgt 2b
+
+ subs w, w, #16
+ add yuv, tyuv, #32
+ add y, ty, #16
+ add u, tu, #8
+ add v, tv, #8
+ bgt 1b
+
+ ldr w, [sp, #36]
+ subs h, h, #16
+ add yuv, yuv, dw, lsl #4
+ sub yuv, yuv, w, lsl #1
+ add y, y, yw, lsl #4
+ sub y, y, w
+ add u, u, cw, lsl #3
+ sub u, u, w, asr #1
+ add v, v, cw, lsl #3
+ sub v, v, w, asr #1
+ bgt 1b
+
+ pop {r4-r11,pc}
+ .endfunc
+