Initial commit of work-in-progress MPEG video player plugin based on libmpeg2.  Works on all targets with colour LCDs, but most optimised for the ipod Color/Photo and Nano.  It currently only plays raw MPEG-1 or MPEG-2 video streams (no audio).  Also adds a new lcd_yuv_blit() function to the plugin API - currently only implemented for the ipod Color/Photo and Nano.


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@10479 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/plugin.c b/apps/plugin.c
index f9f7e42..96d55ab 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -462,6 +462,11 @@
     lcd_remote_bitmap_part,
     lcd_remote_bitmap,
 #endif
+
+#if (CONFIG_LCD == LCD_IPODCOLOR || CONFIG_LCD == LCD_IPODNANO) && \
+    !defined(SIMULATOR)
+    lcd_yuv_blit,
+#endif
 };
 
 int plugin_load(const char* plugin, void* parameter)
diff --git a/apps/plugin.h b/apps/plugin.h
index 0187de8..69fbea9 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -104,7 +104,7 @@
 #define PLUGIN_MAGIC 0x526F634B /* RocK */
 
 /* increase this every time the api struct changes */
-#define PLUGIN_API_VERSION 25
+#define PLUGIN_API_VERSION 26
 
 /* update this to latest version if a change to the api struct breaks
    backwards compatibility (and please take the opportunity to sort in any
@@ -539,6 +539,13 @@
     void (*lcd_remote_bitmap)(const fb_remote_data *src, int x, int y, int width,
                               int height);
 #endif
+#if (CONFIG_LCD == LCD_IPODCOLOR || CONFIG_LCD == LCD_IPODNANO) && \
+    !defined(SIMULATOR)
+    void (*lcd_yuv_blit)(unsigned char * const src[3],
+                         int src_x, int src_y, int stride,
+                         int x, int y, int width, int height);
+#endif
+
 };
 
 /* plugin header */
diff --git a/apps/plugins/SUBDIRS b/apps/plugins/SUBDIRS
index 2d0d6d3..d45283c 100644
--- a/apps/plugins/SUBDIRS
+++ b/apps/plugins/SUBDIRS
@@ -32,5 +32,10 @@
 doom
 #endif
 
+/* For all the colour targets */
+#if defined(HAVE_LCD_COLOR)
+mpegplayer
+#endif
+
 
 #endif /* IRIVER_IFP7XX_SERIES */
diff --git a/apps/plugins/mpegplayer/AUTHORS b/apps/plugins/mpegplayer/AUTHORS
new file mode 100644
index 0000000..901810b
--- /dev/null
+++ b/apps/plugins/mpegplayer/AUTHORS
@@ -0,0 +1,33 @@
+Aaron Holtzman <aholtzma@ess.engr.uvic.ca> started the project and
+made the initial working implementation.
+
+Michel Lespinasse <walken@zoy.org> did major changes for speed and
+mpeg conformance and is the current maintainer. Most of the current
+code was (re)written by him.
+
+Other contributors include:
+	Bruno Barreyra <barreyra@ufl.edu> - build fixes
+	Gildas Bazin <gbazin@netcourrier.com> - mingw32 port
+	Alexander W. Chin <alexc@newt.phys.unsw.edu.au> - progressive_seq fix
+	Stephen Crowley <stephenc@dns2.digitalpassage.com> - build fixes
+	Didier Gautheron <dgautheron@magic.fr> - bug fixes
+	Ryan C. Gordon <icculus@lokigames.com> - SDL support
+	Peter Gubanov <peter@elecard.net.ru> - MMX IDCT scheduling
+	Håkan Hjort <d95hjort@dtek.chalmers.se> - Solaris fixes, mlib code
+	Nicolas Joly <njoly@pasteur.fr> - assorted bug fixes
+	Gerd Knorr <kraxel@goldbach.in-berlin.de> - Xv support
+	David I. Lehn <dlehn@vt.edu> - motion_comp mmx code
+	Olie Lho <ollie@sis.com.tw> - MMX yuv2rgb routine
+	David S. Miller <davem@redhat.com> - sparc VIS optimizations
+	Rick Niles <niles@scyld.com> - build fixes
+	Real Ouellet <realo@sympatico.ca> - g200 fixes
+	Bajusz Peter <hyp-x@inf.bme.hu> - motion comp fixes
+	Franck Sicard <Franck.Sicard@miniruth.solsoft.fr> - x11 fixes
+	Brion Vibber <brion@gizmo.usc.edu> - x11 fixes
+	Martin Vogt <mvogt@rhrk.uni-kl.de> - reentrancy fixes
+	Fredrik Vraalsen <vraalsen@cs.uiuc.edu> - general hackage and stuff
+
+(let me know if I forgot anyone)
+
+Thanks to David Schleef for creating me an account on his ppc g4
+machine and making it possible for me to work on the altivec code.
diff --git a/apps/plugins/mpegplayer/Makefile b/apps/plugins/mpegplayer/Makefile
new file mode 100644
index 0000000..46ea766
--- /dev/null
+++ b/apps/plugins/mpegplayer/Makefile
@@ -0,0 +1,116 @@
+#             __________               __   ___.
+#   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
+#   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
+#   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
+#   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
+#                     \/            \/     \/    \/            \/
+# $Id$
+#
+
+INCLUDES = -I$(APPSDIR) -I.. -I. $(TARGET_INC) -I$(FIRMDIR)/include -I$(FIRMDIR)/export \
+ -I$(FIRMDIR)/common -I$(FIRMDIR)/drivers -I$(OUTDIR) -I$(BUILDDIR)
+CFLAGS = $(INCLUDES) $(GCCOPTS) -O2 $(TARGET) $(EXTRA_DEFINES) \
+ -DTARGET_ID=$(TARGET_ID) -DMEM=${MEMORYSIZE} -DPLUGIN
+
+
+ifdef APPEXTRA
+   INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA)))
+endif
+
+LINKFILE := $(OBJDIR)/link.lds
+DEPFILE = $(OBJDIR)/dep-mpegplayer
+
+# This sets up 'SRC' based on the files mentioned in SOURCES
+include $(TOOLSDIR)/makesrc.inc
+
+SOURCES = $(SRC)
+OBJS2 := $(SRC:%.c=$(OBJDIR)/%.o)
+OBJS = $(patsubst %.S, $(OBJDIR)/%.o, $(OBJS2))
+DIRS = .
+
+LDS := ../plugin.lds
+OUTPUT = $(OUTDIR)/mpegplayer.rock
+
+all: $(OUTPUT)
+
+ifndef SIMVER
+$(OBJDIR)/mpegplayer.elf: $(OBJS) $(LINKFILE)
+	@echo "LD "`basename $@`
+	@$(CC) $(GCCOPTS) -O -nostdlib -o $@ $(OBJS) -L$(BUILDDIR) -lplugin -lgcc \
+           -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/mpegplayer.map
+
+$(OUTPUT): $(OBJDIR)/mpegplayer.elf
+	@echo "OBJCOPY "`basename $@`
+	@$(OC) -O binary $< $@
+else
+
+ifeq ($(SIMVER), x11)
+###################################################
+# This is the X11 simulator version
+
+$(OUTPUT): $(OBJS)
+	@echo "LD $<"
+	@$(CC) $(CFLAGS) -shared $(OBJS) -L$(BUILDDIR) -lplugin -o $@
+ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
+# 'x' must be kept or you'll have "Win32 error 5"
+#     $ fgrep 5 /usr/include/w32api/winerror.h | head -1
+#         #define ERROR_ACCESS_DENIED 5L
+else
+	@chmod -x $@
+endif
+
+else # end of x11-simulator
+ifeq ($(SIMVER), sdl)
+###################################################
+# This is the SDL simulator version
+
+$(OUTPUT): $(OBJS)
+	@echo "LD $<"
+	@$(CC) $(CFLAGS) -shared $(OBJS) -L$(BUILDDIR) -lplugin -o $@
+ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
+# 'x' must be kept or you'll have "Win32 error 5"
+#     $ fgrep 5 /usr/include/w32api/winerror.h | head -1
+#         #define ERROR_ACCESS_DENIED 5L
+else
+	@chmod -x $@
+endif
+
+else # end of sdl-simulator
+###################################################
+# This is the win32 simulator version
+DLLTOOLFLAGS = --export-all
+DLLWRAPFLAGS = -s --entry _DllMain@12 --target=i386-mingw32 -mno-cygwin
+
+$(OUTPUT): $(OBJS)
+	@echo "DLL "`basename $@`
+	@$(DLLTOOL) $(DLLTOOLFLAGS) -z $(OBJDIR)/$*.def $(OBJS)
+	@$(DLLWRAP) $(DLLWRAPFLAGS) --def $(OBJDIR)/$*.def $(OBJS) \
+                $(BUILDDIR)/libplugin.a -o $@
+ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN)
+# 'x' must be kept or you'll have "Win32 error 5"
+#     $ fgrep 5 /usr/include/w32api/winerror.h | head -1
+#         #define ERROR_ACCESS_DENIED 5L
+else
+	@chmod -x $@
+endif
+endif # end of win32-simulator
+endif
+endif # end of simulator section
+
+
+include $(TOOLSDIR)/make.inc
+
+# MEMORYSIZE should be passed on to this makefile with the chosen memory size
+# given in number of MB
+$(LINKFILE): $(LDS)
+	@echo "build "`basename $@`
+	@cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) \
+	$(DEFINES) -E -P - >$@
+
+clean:
+	@echo "cleaning mpegplayer"
+	@rm -rf $(OBJDIR)/mpegplayer
+	@rm -f $(OBJDIR)/mpegplayer.* $(DEPFILE)
+
+-include $(DEPFILE)
+
diff --git a/apps/plugins/mpegplayer/README b/apps/plugins/mpegplayer/README
new file mode 100644
index 0000000..2a58846
--- /dev/null
+++ b/apps/plugins/mpegplayer/README
@@ -0,0 +1,204 @@
+
+
+ABOUT LIBMPEG2
+
+libmpeg2 is a free library for decoding mpeg-2 and mpeg-1 video
+streams. It is released under the terms of the GPL license.
+
+The main goals in libmpeg2 development are:
+
+      *	Conformance - libmpeg2 is able to decode all mpeg streams that
+	conform to certain restrictions: "constrained parameters" for
+	mpeg-1, and "main profile" for mpeg-2. In practice, this is
+	what most people are using. For streams that follow these
+	restrictions, we believe libmpeg2 is 100% conformant to the
+	mpeg standards - and we have a pretty extensive test suite to
+	check this.
+
+      *	Speed - there has been huge efforts there, and we believe
+	libmpeg2 is the fastest library around for what it
+	does. Please tell us if you find a faster one ! With typical
+	video streams as found on DVD's, and doing only decoding with
+	no display, you should be able to get about 110 fps on a
+	PIII/666, or 150 fps on an Athlon/950. This is less than 20
+	cycles per output pixel. In a real player program, the display
+	routines will probably take as much time as the actual
+	decoding !
+
+      *	Portability - most of the code is written in C, and when we
+	use platform-specific optimizations (typically assembly
+	routines, currently used for the motion compensation and the
+	inverse cosine transform stages) we always have a generic C
+	routine to fall back on.  This should be portable to all
+	architectures - at least we have heard reports from people
+	running this code on x86, ppc, sparc, arm and
+	sh4. Assembly-optimized implementations are available on x86
+	(MMX) and ppc (altivec) architectures. Ultrasparc (VIS) is
+	probably the next on the list - we'll see.
+
+      *	Reuseability - we do not want libmpeg2 to include any
+	project-specific code, but it should still include enough
+	features to be used by very diverse projects. We are only
+	starting to get there - the best way to help here is to give
+	us some feedback !
+
+The project homepage is at http://libmpeg2.sourceforge.net/
+
+
+MPEG2DEC
+
+mpeg2dec is a test program for libmpeg2. It decodes mpeg-1 and mpeg-2
+video streams, and also includes a demultiplexer for mpeg-1 and mpeg-2
+program streams. It is purposely kept simple : it does not include
+features like reading files from a DVD, CSS, fullscreen output,
+navigation, etc... The main purpose of mpeg2dec is to have a simple
+test bed for libmpeg2.
+
+The libmpeg2 source code is always distributed in the mpeg2dec
+package, to make it easier for people to test it.
+
+The basic usage is to just type "mpeg2dec file" where file is a
+demultiplexed mpeg video file.
+
+The "-s" option must be used for multiplexed (audio and video) mpeg
+files using the "program stream" format. These files are usualy found
+on the internet or on unencrypted DVDs.
+
+The "-t" option must be used for multiplexed (audio and video) mpeg
+files using the "transport stream" format. These files are usualy
+found in digital TV applications.
+
+The "-o" option is used to select a given output module - for example
+to redirect the output to a file. This is also used for performance
+testing and conformance testing.
+
+The "-c" option is used to disable all optimizations.
+
+
+OTHER PROJECTS USING LIBMPEG2
+
+libmpeg2 is being used by various other projects, including:
+
+      *	xine (http://xine.sourceforge.net/) - started as a simple
+	mpeg-2 audio and video decoder, but it since became a
+	full-featured DVD and video media player.
+
+      *	VideoLAN (http://www.videolan.org/) - video streaming over an
+	ethernet network, can also be used as a standalone player.
+
+      *	MPlayer (http://www.MPlayerHQ.hu) - another good player, it is
+	also very robust against damaged streams.
+
+      *	movietime (http://movietime.sourceforge.net/) - still quite
+	young, but it looks very promising !
+
+      *	mpeg2decX (http://homepage1.nifty.com/~toku/software_en.html) -
+	a graphical interface for mpeg2dec for macintosh osX.
+
+      *	TCVP (http://tcvp.sf.net) - video and music player for unix.
+
+      *	drip (http://drip.sourceforge.net/) - a DVD to DIVX transcoder.
+
+      *	PoMP
+	(http://www.dmclab.hanyang.ac.kr/research/project/PoDS/PoDS_sw.htm) -
+	a research player optimized to minimize disk power consumption.
+
+      *	OMS (http://www.linuxvideo.org/oms/)
+
+      *	XMPS (http://xmps.sourceforge.net/)
+
+      *	GStreamer (http://www.gstreamer.net/) - a framework for
+	streaming media; it has an mpeg2 decoding plugin based on
+	libmpeg2.
+
+      *	mpeglib (http://mpeglib.sourceforge.net/) - a video decoding
+	library that usess libmpeg2 when decoding mpeg streams.
+
+      *	daphne (http://daphne.rulecity.com/) - a laserdisc arcade game
+	simulator.
+
+      *	GOPchop (http://outflux.net/unix/software/GOPchop/) - a
+	GOP-accurate editor for MPEG2 streams.
+
+If you use libmpeg2 in another project, let us know !
+
+
+TASKS
+
+There are several places where we could easily use some help:
+
+      *	Documentation: libmpeg2 still has no documentation. Every
+	project using it has had to figure things out by looking at
+	the header files, at the mpeg2dec sample application, and by
+	asking questions. Writing down a nice documentation would make
+	the code more easily reuseable.
+
+      *	Testing: If you find any stream that does not decode right
+	with libmpeg2, let us know ! The best thing would be to mail
+	to the libmpeg2-devel mailing list. Also, it would be nice to
+	build a stress test so we can make sure libmpeg2 never crashes
+	on bad streams.
+
+      *	Coding: There is a small TODO list in the mpeg2dec package,
+	you can have a look there ! Most items are pretty terse
+	though.
+
+      *	Porting: If you're porting to a new architecture, you might
+	want to experiment with the compile flags defined in
+	configure.in . When you figure out whats fastest on your
+	platform, send us a patch !
+
+      *	Assembly optimizations: We only have x86 and altivec
+	optimizations yet, it would be worthwhile writing routines for
+	other architectures, especially those that have SIMD
+	instruction set extensions ! Also the yuv2rgb x86 routines
+	could probably be optimized a lot.
+
+
+CVS SNAPSHOTS
+
+A daily snapshot is created using "make distcheck" every night and
+uploaded to http://libmpeg2.sourceforge.net/files/mpeg2dec-snapshot.tar.gz .
+It is easier to use than the CVS repository, because you do not need
+to have the right versions of automake, autoconf and libtool
+installed. It might be convenient when working on a libmpeg2 port for
+example.
+
+
+CVS REPOSITORY
+
+The latest libmpeg2 and mpeg2dec source code can always be found by
+anonymous CVS:
+
+# export CVSROOT=:pserver:anonymous@cvs.libmpeg2.sourceforge.net:/cvsroot/libmpeg2
+# cvs login (Just press Return when prompted for a password)
+# cvs checkout mpeg2dec
+
+You can also browse the latest changes online at
+http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/libmpeg2/mpeg2dec/
+
+The other CVS modules are mpeg2dec-streams for the test suite, and
+mpeg2dec-livid for the CVS history of the project while it was still
+hosted on the linuxvideo.org servers.
+
+
+MAILING LISTS
+
+See the subscription information at http://libmpeg2.sourceforge.net/lists.html
+
+libmpeg2-devel
+
+This is the main mailing list for technical discussion about
+libmpeg2. Anyone wanting to work on libmpeg2, or maybe just stay
+informed about the development process, should probably subscribe to
+this list.
+
+libmpeg2-checkins
+
+All libmpeg2 checkins are announced there. This is a good way to keep
+track of what goes into CVS.
+
+libmpeg2-announce
+
+This is a very low traffic mailing list, only for announcements of new
+versions of libmpeg2. Only project administrators can post there.
diff --git a/apps/plugins/mpegplayer/README.rockbox b/apps/plugins/mpegplayer/README.rockbox
new file mode 100644
index 0000000..95f5a3d
--- /dev/null
+++ b/apps/plugins/mpegplayer/README.rockbox
@@ -0,0 +1,44 @@
+Library: libmpeg2 from mpeg2dec-0.4.0b (Released 2004-01-21)
+Imported: 2006-08-06 by Dave Chapman
+
+
+This directory contains a local version of libmpeg2 imported into
+Rockbox for MPEG video decoding.
+
+
+LICENSING INFORMATION
+
+mpeg2dec and libmpeg2 are licensed under Version 2 of the GNU General
+Public License.
+
+
+IMPORT DETAILS
+
+The following files were imported from the mpeg2dec-0.4.0b
+distribution.  Minor changes were made to enable compilation in
+Rockbox and TABs were replaced by spaces to comply with the Rockbox
+coding guidelines.
+
+AUTHORS
+README
+SOURCES
+attributes.h
+cpu_accel.c
+cpu_state.c
+decode.c
+header.c
+idct.c
+motion_comp.c
+mpeg2.h
+mpeg2_internal.h
+slice.c
+video_out.h
+vlc.h
+
+The following files are new, but based on code in mpeg2dec.
+
+Makefile
+mpegplayer.c
+video_out_rockbox.c
+mpeg2dec_config.h
+alloc.c
diff --git a/apps/plugins/mpegplayer/SOURCES b/apps/plugins/mpegplayer/SOURCES
new file mode 100644
index 0000000..2ea6f30
--- /dev/null
+++ b/apps/plugins/mpegplayer/SOURCES
@@ -0,0 +1,10 @@
+alloc.c
+cpu_accel.c
+cpu_state.c
+decode.c
+header.c
+idct.c
+motion_comp.c
+slice.c
+video_out_rockbox.c
+mpegplayer.c
diff --git a/apps/plugins/mpegplayer/alloc.c b/apps/plugins/mpegplayer/alloc.c
new file mode 100644
index 0000000..0a3568a
--- /dev/null
+++ b/apps/plugins/mpegplayer/alloc.c
@@ -0,0 +1,76 @@
+/*
+ * alloc.c
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec 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.
+ *
+ * mpeg2dec 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "plugin.h"
+
+#include "mpeg2.h"
+
+extern struct plugin_api* rb;
+
+long mem_ptr;
+long bufsize;
+unsigned char* mallocbuf;
+
+void mpeg2_alloc_init(unsigned char* buf, int mallocsize)
+{
+    mem_ptr = 0;
+    bufsize = mallocsize;
+    mallocbuf = buf;
+  
+    return;
+}
+
+void * mpeg2_malloc (unsigned size, mpeg2_alloc_t reason)
+{
+    void* x;
+
+    (void)reason;
+
+    if (mem_ptr + (long)size > bufsize) {
+        DEBUGF("OUT OF MEMORY\n");
+        return NULL;
+    }
+    
+    x=&mallocbuf[mem_ptr];
+    mem_ptr+=(size+3)&~3; /* Keep memory 32-bit aligned */
+
+    return(x);
+}
+
+void mpeg2_free(void* ptr) {
+    (void)ptr;
+}
+
+/* gcc may want to use memcpy before rb is initialised, so here's a trivial 
+   implementation */
+
+void *memcpy(void *dest, const void *src, size_t n) {
+    size_t i;
+    char* d=(char*)dest;
+    char* s=(char*)src;
+
+    for (i=0;i<n;i++)
+        d[i]=s[i];
+
+    return dest;
+}
diff --git a/apps/plugins/mpegplayer/attributes.h b/apps/plugins/mpegplayer/attributes.h
new file mode 100644
index 0000000..eefbc0d
--- /dev/null
+++ b/apps/plugins/mpegplayer/attributes.h
@@ -0,0 +1,37 @@
+/*
+ * attributes.h
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec 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.
+ *
+ * mpeg2dec 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* use gcc attribs to align critical data structures */
+#ifdef ATTRIBUTE_ALIGNED_MAX
+#define ATTR_ALIGN(align) __attribute__ ((__aligned__ ((ATTRIBUTE_ALIGNED_MAX < align) ? ATTRIBUTE_ALIGNED_MAX : align)))
+#else
+#define ATTR_ALIGN(align)
+#endif
+
+#ifdef HAVE_BUILTIN_EXPECT
+#define likely(x) __builtin_expect ((x) != 0, 1)
+#define unlikely(x) __builtin_expect ((x) != 0, 0)
+#else
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif
diff --git a/apps/plugins/mpegplayer/cpu_accel.c b/apps/plugins/mpegplayer/cpu_accel.c
new file mode 100644
index 0000000..2616e04
--- /dev/null
+++ b/apps/plugins/mpegplayer/cpu_accel.c
@@ -0,0 +1,220 @@
+/*
+ * cpu_accel.c
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec 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.
+ *
+ * mpeg2dec 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "plugin.h"
+
+#include "mpeg2dec_config.h"
+
+#include "mpeg2.h"
+#include "attributes.h"
+#include "mpeg2_internal.h"
+
+#ifdef ACCEL_DETECT
+#ifdef ARCH_X86
+static inline uint32_t arch_accel (void)
+{
+    uint32_t eax, ebx, ecx, edx;
+    int AMD;
+    uint32_t caps;
+
+#if !defined(PIC) && !defined(__PIC__)
+#define cpuid(op,eax,ebx,ecx,edx)        \
+    __asm__ ("cpuid"                        \
+             : "=a" (eax),                \
+               "=b" (ebx),                \
+               "=c" (ecx),                \
+               "=d" (edx)                \
+             : "a" (op)                        \
+             : "cc")
+#else        /* PIC version : save ebx */
+#define cpuid(op,eax,ebx,ecx,edx)        \
+    __asm__ ("push %%ebx\n\t"                \
+             "cpuid\n\t"                \
+             "movl %%ebx,%1\n\t"        \
+             "pop %%ebx"                \
+             : "=a" (eax),                \
+               "=r" (ebx),                \
+               "=c" (ecx),                \
+               "=d" (edx)                \
+             : "a" (op)                        \
+             : "cc")
+#endif
+
+    __asm__ ("pushf\n\t"
+             "pushf\n\t"
+             "pop %0\n\t"
+             "movl %0,%1\n\t"
+             "xorl $0x200000,%0\n\t"
+             "push %0\n\t"
+             "popf\n\t"
+             "pushf\n\t"
+             "pop %0\n\t"
+             "popf"
+             : "=r" (eax),
+               "=r" (ebx)
+             :
+             : "cc");
+
+    if (eax == ebx)                /* no cpuid */
+        return 0;
+
+    cpuid (0x00000000, eax, ebx, ecx, edx);
+    if (!eax)                        /* vendor string only */
+        return 0;
+
+    AMD = (ebx == 0x68747541) && (ecx == 0x444d4163) && (edx == 0x69746e65);
+
+    cpuid (0x00000001, eax, ebx, ecx, edx);
+    if (! (edx & 0x00800000))        /* no MMX */
+        return 0;
+
+    caps = MPEG2_ACCEL_X86_MMX;
+    if (edx & 0x02000000)        /* SSE - identical to AMD MMX extensions */
+        caps = MPEG2_ACCEL_X86_MMX | MPEG2_ACCEL_X86_MMXEXT;
+
+    cpuid (0x80000000, eax, ebx, ecx, edx);
+    if (eax < 0x80000001)        /* no extended capabilities */
+        return caps;
+
+    cpuid (0x80000001, eax, ebx, ecx, edx);
+
+    if (edx & 0x80000000)
+        caps |= MPEG2_ACCEL_X86_3DNOW;
+
+    if (AMD && (edx & 0x00400000))        /* AMD MMX extensions */
+        caps |= MPEG2_ACCEL_X86_MMXEXT;
+
+    return caps;
+}
+#endif /* ARCH_X86 */
+
+#if defined(ARCH_PPC) || defined(ARCH_SPARC)
+#include <signal.h>
+#include <setjmp.h>
+
+static sigjmp_buf jmpbuf;
+static volatile sig_atomic_t canjump = 0;
+
+static RETSIGTYPE sigill_handler (int sig)
+{
+    if (!canjump) {
+        signal (sig, SIG_DFL);
+        raise (sig);
+    }
+
+    canjump = 0;
+    siglongjmp (jmpbuf, 1);
+}
+
+#ifdef ARCH_PPC
+static inline uint32_t arch_accel (void)
+{
+    static RETSIGTYPE (* oldsig) (int);
+
+    oldsig = signal (SIGILL, sigill_handler);
+    if (sigsetjmp (jmpbuf, 1)) {
+        signal (SIGILL, oldsig);
+        return 0;
+    }
+
+    canjump = 1;
+
+#ifdef HAVE_ALTIVEC_H        /* gnu */
+#define VAND(a,b,c) "vand " #a "," #b "," #c "\n\t"
+#else                        /* apple */
+#define VAND(a,b,c) "vand v" #a ",v" #b ",v" #c "\n\t"
+#endif
+    asm volatile ("mtspr 256, %0\n\t"
+                  VAND (0, 0, 0)
+                  :
+                  : "r" (-1));
+
+    canjump = 0;
+
+    signal (SIGILL, oldsig);
+    return MPEG2_ACCEL_PPC_ALTIVEC;
+}
+#endif /* ARCH_PPC */
+
+#ifdef ARCH_SPARC
+static inline uint32_t arch_accel (void)
+{
+    static RETSIGTYPE (* oldsig) (int);
+
+    oldsig = signal (SIGILL, sigill_handler);
+    if (sigsetjmp (jmpbuf, 1)) {
+        signal (SIGILL, oldsig);
+        return 0;
+    }
+
+    canjump = 1;
+
+    /* pdist %f0, %f0, %f0 */
+    __asm__ __volatile__(".word\t0x81b007c0");
+
+    canjump = 0;
+
+    if (sigsetjmp (jmpbuf, 1)) {
+        signal (SIGILL, oldsig);
+        return MPEG2_ACCEL_SPARC_VIS;
+    }
+
+    canjump = 1;
+
+    /* edge8n %g0, %g0, %g0 */
+    __asm__ __volatile__(".word\t0x81b00020");
+
+    canjump = 0;
+
+    signal (SIGILL, oldsig);
+    return MPEG2_ACCEL_SPARC_VIS | MPEG2_ACCEL_SPARC_VIS2;
+}
+#endif /* ARCH_SPARC */
+#endif /* ARCH_PPC || ARCH_SPARC */
+
+#ifdef ARCH_ALPHA
+static inline uint32_t arch_accel (void)
+{
+    uint64_t no_mvi;
+
+    asm volatile ("amask %1, %0"
+                  : "=r" (no_mvi)
+                  : "rI" (256));        /* AMASK_MVI */
+    return no_mvi ? MPEG2_ACCEL_ALPHA : (MPEG2_ACCEL_ALPHA |
+                                         MPEG2_ACCEL_ALPHA_MVI);
+}
+#endif /* ARCH_ALPHA */
+#endif /* ACCEL_DETECT */
+
+uint32_t mpeg2_detect_accel (void)
+{
+    uint32_t accel;
+
+    accel = 0;
+#ifdef ACCEL_DETECT
+#if defined (ARCH_X86) || defined (ARCH_PPC) || defined (ARCH_ALPHA) || defined (ARCH_SPARC)
+    accel = arch_accel ();
+#endif
+#endif
+    return accel;
+}
diff --git a/apps/plugins/mpegplayer/cpu_state.c b/apps/plugins/mpegplayer/cpu_state.c
new file mode 100644
index 0000000..4406853
--- /dev/null
+++ b/apps/plugins/mpegplayer/cpu_state.c
@@ -0,0 +1,129 @@
+/*
+ * cpu_state.c
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec 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.
+ *
+ * mpeg2dec 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "plugin.h"
+
+#include "mpeg2dec_config.h"
+
+#include "mpeg2.h"
+#include "attributes.h"
+#include "mpeg2_internal.h"
+#ifdef ARCH_X86
+#include "mmx.h"
+#endif
+
+void (* mpeg2_cpu_state_save) (cpu_state_t * state) = NULL;
+void (* mpeg2_cpu_state_restore) (cpu_state_t * state) = NULL;
+
+#ifdef ARCH_X86
+static void state_restore_mmx (cpu_state_t * state)
+{
+    emms ();
+}
+#endif
+
+#ifdef ARCH_PPC
+#ifdef HAVE_ALTIVEC_H        /* gnu */
+#define LI(a,b) "li " #a "," #b "\n\t"
+#define STVX0(a,b,c) "stvx " #a ",0," #c "\n\t"
+#define STVX(a,b,c) "stvx " #a "," #b "," #c "\n\t"
+#define LVX0(a,b,c) "lvx " #a ",0," #c "\n\t"
+#define LVX(a,b,c) "lvx " #a "," #b "," #c "\n\t"
+#else                        /* apple */
+#define LI(a,b) "li r" #a "," #b "\n\t"
+#define STVX0(a,b,c) "stvx v" #a ",0,r" #c "\n\t"
+#define STVX(a,b,c) "stvx v" #a ",r" #b ",r" #c "\n\t"
+#define LVX0(a,b,c) "lvx v" #a ",0,r" #c "\n\t"
+#define LVX(a,b,c) "lvx v" #a ",r" #b ",r" #c "\n\t"
+#endif
+
+static void state_save_altivec (cpu_state_t * state)
+{
+    asm (LI (9, 16)
+         STVX0 (20, 0, 3)
+         LI (11, 32)
+         STVX (21, 9, 3)
+         LI (9, 48)
+         STVX (22, 11, 3)
+         LI (11, 64)
+         STVX (23, 9, 3)
+         LI (9, 80)
+         STVX (24, 11, 3)
+         LI (11, 96)
+         STVX (25, 9, 3)
+         LI (9, 112)
+         STVX (26, 11, 3)
+         LI (11, 128)
+         STVX (27, 9, 3)
+         LI (9, 144)
+         STVX (28, 11, 3)
+         LI (11, 160)
+         STVX (29, 9, 3)
+         LI (9, 176)
+         STVX (30, 11, 3)
+         STVX (31, 9, 3));
+}
+
+static void state_restore_altivec (cpu_state_t * state)
+{
+    asm (LI (9, 16)
+         LVX0 (20, 0, 3)
+         LI (11, 32)
+         LVX (21, 9, 3)
+         LI (9, 48)
+         LVX (22, 11, 3)
+         LI (11, 64)
+         LVX (23, 9, 3)
+         LI (9, 80)
+         LVX (24, 11, 3)
+         LI (11, 96)
+         LVX (25, 9, 3)
+         LI (9, 112)
+         LVX (26, 11, 3)
+         LI (11, 128)
+         LVX (27, 9, 3)
+         LI (9, 144)
+         LVX (28, 11, 3)
+         LI (11, 160)
+         LVX (29, 9, 3)
+         LI (9, 176)
+         LVX (30, 11, 3)
+         LVX (31, 9, 3));
+}
+#endif
+
+void mpeg2_cpu_state_init (uint32_t accel)
+{
+    (void)accel;
+#ifdef ARCH_X86
+    if (accel & MPEG2_ACCEL_X86_MMX) {
+        mpeg2_cpu_state_restore = state_restore_mmx;
+    }
+#endif
+#ifdef ARCH_PPC
+    if (accel & MPEG2_ACCEL_PPC_ALTIVEC) {
+        mpeg2_cpu_state_save = state_save_altivec;
+        mpeg2_cpu_state_restore = state_restore_altivec;
+    }
+#endif
+}
diff --git a/apps/plugins/mpegplayer/decode.c b/apps/plugins/mpegplayer/decode.c
new file mode 100644
index 0000000..6132926
--- /dev/null
+++ b/apps/plugins/mpegplayer/decode.c
@@ -0,0 +1,447 @@
+/*
+ * decode.c
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec 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.
+ *
+ * mpeg2dec 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "plugin.h"
+
+#include "mpeg2dec_config.h"
+
+extern struct plugin_api* rb;
+
+#include "mpeg2.h"
+#include "attributes.h"
+#include "mpeg2_internal.h"
+
+static int mpeg2_accels = 0;
+
+#define BUFFER_SIZE (1194 * 1024)
+
+const mpeg2_info_t * mpeg2_info (mpeg2dec_t * mpeg2dec)
+{
+    return &(mpeg2dec->info);
+}
+
+static inline int skip_chunk (mpeg2dec_t * mpeg2dec, int bytes)
+{
+    uint8_t * current;
+    uint32_t shift;
+    uint8_t * limit;
+    uint8_t byte;
+
+    if (!bytes)
+	return 0;
+
+    current = mpeg2dec->buf_start;
+    shift = mpeg2dec->shift;
+    limit = current + bytes;
+
+    do {
+	byte = *current++;
+	if (shift == 0x00000100) {
+	    int skipped;
+
+	    mpeg2dec->shift = 0xffffff00;
+	    skipped = current - mpeg2dec->buf_start;
+	    mpeg2dec->buf_start = current;
+	    return skipped;
+	}
+	shift = (shift | byte) << 8;
+    } while (current < limit);
+
+    mpeg2dec->shift = shift;
+    mpeg2dec->buf_start = current;
+    return 0;
+}
+
+static inline int copy_chunk (mpeg2dec_t * mpeg2dec, int bytes)
+{
+    uint8_t * current;
+    uint32_t shift;
+    uint8_t * chunk_ptr;
+    uint8_t * limit;
+    uint8_t byte;
+
+    if (!bytes)
+	return 0;
+
+    current = mpeg2dec->buf_start;
+    shift = mpeg2dec->shift;
+    chunk_ptr = mpeg2dec->chunk_ptr;
+    limit = current + bytes;
+
+    do {
+	byte = *current++;
+	if (shift == 0x00000100) {
+	    int copied;
+
+	    mpeg2dec->shift = 0xffffff00;
+	    mpeg2dec->chunk_ptr = chunk_ptr + 1;
+	    copied = current - mpeg2dec->buf_start;
+	    mpeg2dec->buf_start = current;
+	    return copied;
+	}
+	shift = (shift | byte) << 8;
+	*chunk_ptr++ = byte;
+    } while (current < limit);
+
+    mpeg2dec->shift = shift;
+    mpeg2dec->buf_start = current;
+    return 0;
+}
+
+void mpeg2_buffer (mpeg2dec_t * mpeg2dec, uint8_t * start, uint8_t * end)
+{
+    mpeg2dec->buf_start = start;
+    mpeg2dec->buf_end = end;
+}
+
+int mpeg2_getpos (mpeg2dec_t * mpeg2dec)
+{
+    return mpeg2dec->buf_end - mpeg2dec->buf_start;
+}
+
+static inline mpeg2_state_t seek_chunk (mpeg2dec_t * mpeg2dec)
+{
+    int size, skipped;
+
+    size = mpeg2dec->buf_end - mpeg2dec->buf_start;
+    skipped = skip_chunk (mpeg2dec, size);
+    if (!skipped) {
+	mpeg2dec->bytes_since_tag += size;
+	return STATE_BUFFER;
+    }
+    mpeg2dec->bytes_since_tag += skipped;
+    mpeg2dec->code = mpeg2dec->buf_start[-1];
+    return (mpeg2_state_t)-1;
+}
+
+mpeg2_state_t mpeg2_seek_header (mpeg2dec_t * mpeg2dec)
+{
+    while (mpeg2dec->code != 0xb3 &&
+	   ((mpeg2dec->code != 0xb7 && mpeg2dec->code != 0xb8 &&
+	     mpeg2dec->code) || mpeg2dec->sequence.width == (unsigned)-1))
+	if (seek_chunk (mpeg2dec) == STATE_BUFFER)
+	    return STATE_BUFFER;
+    mpeg2dec->chunk_start = mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer;
+    mpeg2dec->user_data_len = 0;
+    return (mpeg2dec->code ? mpeg2_parse_header (mpeg2dec) :
+	    mpeg2_header_picture_start (mpeg2dec));
+}
+
+#define RECEIVED(code,state) (((state) << 8) + (code))
+
+mpeg2_state_t mpeg2_parse (mpeg2dec_t * mpeg2dec)
+{
+    int size_buffer, size_chunk, copied;
+
+    if (mpeg2dec->action) {
+	mpeg2_state_t state;
+
+	state = mpeg2dec->action (mpeg2dec);
+	if ((int)state >= 0)
+	    return state;
+    }
+
+    while (1) {
+	while ((unsigned) (mpeg2dec->code - mpeg2dec->first_decode_slice) <
+	       mpeg2dec->nb_decode_slices) {
+	    size_buffer = mpeg2dec->buf_end - mpeg2dec->buf_start;
+	    size_chunk = (mpeg2dec->chunk_buffer + BUFFER_SIZE -
+			  mpeg2dec->chunk_ptr);
+	    if (size_buffer <= size_chunk) {
+		copied = copy_chunk (mpeg2dec, size_buffer);
+		if (!copied) {
+		    mpeg2dec->bytes_since_tag += size_buffer;
+		    mpeg2dec->chunk_ptr += size_buffer;
+		    return STATE_BUFFER;
+		}
+	    } else {
+		copied = copy_chunk (mpeg2dec, size_chunk);
+		if (!copied) {
+		    /* filled the chunk buffer without finding a start code */
+		    mpeg2dec->bytes_since_tag += size_chunk;
+		    mpeg2dec->action = seek_chunk;
+		    return STATE_INVALID;
+		}
+	    }
+	    mpeg2dec->bytes_since_tag += copied;
+
+	    mpeg2_slice (&(mpeg2dec->decoder), mpeg2dec->code,
+			 mpeg2dec->chunk_start);
+	    mpeg2dec->code = mpeg2dec->buf_start[-1];
+	    mpeg2dec->chunk_ptr = mpeg2dec->chunk_start;
+	}
+	if ((unsigned) (mpeg2dec->code - 1) >= 0xb0 - 1)
+	    break;
+	if (seek_chunk (mpeg2dec) == STATE_BUFFER)
+	    return STATE_BUFFER;
+    }
+
+    switch (mpeg2dec->code) {
+    case 0x00:
+	mpeg2dec->action = mpeg2_header_picture_start;
+	return mpeg2dec->state;
+    case 0xb7:
+	mpeg2dec->action = mpeg2_header_end;
+	break;
+    case 0xb3:
+    case 0xb8:
+	mpeg2dec->action = mpeg2_parse_header;
+	break;
+    default:
+	mpeg2dec->action = seek_chunk;
+	return STATE_INVALID;
+    }
+    return (mpeg2dec->state == STATE_SLICE) ? STATE_SLICE : STATE_INVALID;
+}
+
+mpeg2_state_t mpeg2_parse_header (mpeg2dec_t * mpeg2dec)
+{
+    static int (* process_header[]) (mpeg2dec_t * mpeg2dec) = {
+	mpeg2_header_picture, mpeg2_header_extension, mpeg2_header_user_data,
+	mpeg2_header_sequence, NULL, NULL, NULL, NULL, mpeg2_header_gop
+    };
+    int size_buffer, size_chunk, copied;
+
+    mpeg2dec->action = mpeg2_parse_header;
+    mpeg2dec->info.user_data = NULL;	mpeg2dec->info.user_data_len = 0;
+    while (1) {
+	size_buffer = mpeg2dec->buf_end - mpeg2dec->buf_start;
+	size_chunk = (mpeg2dec->chunk_buffer + BUFFER_SIZE -
+		      mpeg2dec->chunk_ptr);
+	if (size_buffer <= size_chunk) {
+	    copied = copy_chunk (mpeg2dec, size_buffer);
+	    if (!copied) {
+		mpeg2dec->bytes_since_tag += size_buffer;
+		mpeg2dec->chunk_ptr += size_buffer;
+		return STATE_BUFFER;
+	    }
+	} else {
+	    copied = copy_chunk (mpeg2dec, size_chunk);
+	    if (!copied) {
+		/* filled the chunk buffer without finding a start code */
+		mpeg2dec->bytes_since_tag += size_chunk;
+		mpeg2dec->code = 0xb4;
+		mpeg2dec->action = mpeg2_seek_header;
+		return STATE_INVALID;
+	    }
+	}
+	mpeg2dec->bytes_since_tag += copied;
+
+	if (process_header[mpeg2dec->code & 0x0b] (mpeg2dec)) {
+	    mpeg2dec->code = mpeg2dec->buf_start[-1];
+	    mpeg2dec->action = mpeg2_seek_header;
+	    return STATE_INVALID;
+	}
+
+	mpeg2dec->code = mpeg2dec->buf_start[-1];
+	switch (RECEIVED (mpeg2dec->code, mpeg2dec->state)) {
+
+	/* state transition after a sequence header */
+	case RECEIVED (0x00, STATE_SEQUENCE):
+	    mpeg2dec->action = mpeg2_header_picture_start;
+	case RECEIVED (0xb8, STATE_SEQUENCE):
+	    mpeg2_header_sequence_finalize (mpeg2dec);
+	    break;
+
+	/* other legal state transitions */
+	case RECEIVED (0x00, STATE_GOP):
+	    mpeg2_header_gop_finalize (mpeg2dec);
+	    mpeg2dec->action = mpeg2_header_picture_start;
+	    break;
+	case RECEIVED (0x01, STATE_PICTURE):
+	case RECEIVED (0x01, STATE_PICTURE_2ND):
+	    mpeg2_header_picture_finalize (mpeg2dec, mpeg2_accels);
+	    mpeg2dec->action = mpeg2_header_slice_start;
+	    break;
+
+	/* legal headers within a given state */
+	case RECEIVED (0xb2, STATE_SEQUENCE):
+	case RECEIVED (0xb2, STATE_GOP):
+	case RECEIVED (0xb2, STATE_PICTURE):
+	case RECEIVED (0xb2, STATE_PICTURE_2ND):
+	case RECEIVED (0xb5, STATE_SEQUENCE):
+	case RECEIVED (0xb5, STATE_PICTURE):
+	case RECEIVED (0xb5, STATE_PICTURE_2ND):
+	    mpeg2dec->chunk_ptr = mpeg2dec->chunk_start;
+	    continue;
+
+	default:
+	    mpeg2dec->action = mpeg2_seek_header;
+	    return STATE_INVALID;
+	}
+
+	mpeg2dec->chunk_start = mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer;
+	mpeg2dec->user_data_len = 0;
+	return mpeg2dec->state;
+    }
+}
+
+int mpeg2_convert (mpeg2dec_t * mpeg2dec, mpeg2_convert_t convert, void * arg)
+{
+    mpeg2_convert_init_t convert_init;
+    int error;
+
+    error = convert (MPEG2_CONVERT_SET, NULL, &(mpeg2dec->sequence), 0,
+		     mpeg2_accels, arg, &convert_init);
+    if (!error) {
+	mpeg2dec->convert = convert;
+	mpeg2dec->convert_arg = arg;
+	mpeg2dec->convert_id_size = convert_init.id_size;
+	mpeg2dec->convert_stride = 0;
+    }
+    return error;
+}
+
+int mpeg2_stride (mpeg2dec_t * mpeg2dec, int stride)
+{
+    if (!mpeg2dec->convert) {
+	if (stride < (int) mpeg2dec->sequence.width)
+	    stride = mpeg2dec->sequence.width;
+	mpeg2dec->decoder.stride_frame = stride;
+    } else {
+	mpeg2_convert_init_t convert_init;
+
+	stride = mpeg2dec->convert (MPEG2_CONVERT_STRIDE, NULL,
+				    &(mpeg2dec->sequence), stride,
+				    mpeg2_accels, mpeg2dec->convert_arg,
+				    &convert_init);
+	mpeg2dec->convert_id_size = convert_init.id_size;
+	mpeg2dec->convert_stride = stride;
+    }
+    return stride;
+}
+
+void mpeg2_set_buf (mpeg2dec_t * mpeg2dec, uint8_t * buf[3], void * id)
+{
+    mpeg2_fbuf_t * fbuf;
+
+    if (mpeg2dec->custom_fbuf) {
+	if (mpeg2dec->state == STATE_SEQUENCE) {
+	    mpeg2dec->fbuf[2] = mpeg2dec->fbuf[1];
+	    mpeg2dec->fbuf[1] = mpeg2dec->fbuf[0];
+	}
+	mpeg2_set_fbuf (mpeg2dec, (mpeg2dec->decoder.coding_type ==
+				   PIC_FLAG_CODING_TYPE_B));
+	fbuf = mpeg2dec->fbuf[0];
+    } else {
+	fbuf = &(mpeg2dec->fbuf_alloc[mpeg2dec->alloc_index].fbuf);
+	mpeg2dec->alloc_index_user = ++mpeg2dec->alloc_index;
+    }
+    fbuf->buf[0] = buf[0];
+    fbuf->buf[1] = buf[1];
+    fbuf->buf[2] = buf[2];
+    fbuf->id = id;
+}
+
+void mpeg2_custom_fbuf (mpeg2dec_t * mpeg2dec, int custom_fbuf)
+{
+    mpeg2dec->custom_fbuf = custom_fbuf;
+}
+
+void mpeg2_skip (mpeg2dec_t * mpeg2dec, int skip)
+{
+    mpeg2dec->first_decode_slice = 1;
+    mpeg2dec->nb_decode_slices = skip ? 0 : (0xb0 - 1);
+}
+
+void mpeg2_slice_region (mpeg2dec_t * mpeg2dec, int start, int end)
+{
+    start = (start < 1) ? 1 : (start > 0xb0) ? 0xb0 : start;
+    end = (end < start) ? start : (end > 0xb0) ? 0xb0 : end;
+    mpeg2dec->first_decode_slice = start;
+    mpeg2dec->nb_decode_slices = end - start;
+}
+
+void mpeg2_tag_picture (mpeg2dec_t * mpeg2dec, uint32_t tag, uint32_t tag2)
+{
+    mpeg2dec->tag_previous = mpeg2dec->tag_current;
+    mpeg2dec->tag2_previous = mpeg2dec->tag2_current;
+    mpeg2dec->tag_current = tag;
+    mpeg2dec->tag2_current = tag2;
+    mpeg2dec->num_tags++;
+    mpeg2dec->bytes_since_tag = 0;
+}
+
+uint32_t mpeg2_accel (uint32_t accel)
+{
+    if (!mpeg2_accels) {
+	if (accel & MPEG2_ACCEL_DETECT)
+	    accel |= mpeg2_detect_accel ();
+	mpeg2_accels = accel |= MPEG2_ACCEL_DETECT;
+	mpeg2_cpu_state_init (accel);
+	mpeg2_idct_init (accel);
+	mpeg2_mc_init (accel);
+    }
+    return mpeg2_accels & ~MPEG2_ACCEL_DETECT;
+}
+
+void mpeg2_reset (mpeg2dec_t * mpeg2dec, int full_reset)
+{
+    mpeg2dec->buf_start = mpeg2dec->buf_end = NULL;
+    mpeg2dec->num_tags = 0;
+    mpeg2dec->shift = 0xffffff00;
+    mpeg2dec->code = 0xb4;
+    mpeg2dec->action = mpeg2_seek_header;
+    mpeg2dec->state = STATE_INVALID;
+    mpeg2dec->first = 1;
+
+    mpeg2_reset_info(&(mpeg2dec->info));
+    mpeg2dec->info.gop = NULL;
+    mpeg2dec->info.user_data = NULL;
+    mpeg2dec->info.user_data_len = 0;
+    if (full_reset) {
+	mpeg2dec->info.sequence = NULL;
+	mpeg2_header_state_init (mpeg2dec);
+    }
+
+}
+
+mpeg2dec_t * mpeg2_init (void)
+{
+    mpeg2dec_t * mpeg2dec;
+
+    mpeg2_accel (MPEG2_ACCEL_DETECT);
+
+    mpeg2dec = (mpeg2dec_t *) mpeg2_malloc (sizeof (mpeg2dec_t),
+					    MPEG2_ALLOC_MPEG2DEC);
+    if (mpeg2dec == NULL)
+	return NULL;
+
+    rb->memset (mpeg2dec->decoder.DCTblock, 0, 64 * sizeof (int16_t));
+    rb->memset (mpeg2dec->quantizer_matrix, 0, 4 * 64 * sizeof (uint8_t));
+
+    mpeg2dec->chunk_buffer = (uint8_t *) mpeg2_malloc (BUFFER_SIZE + 4,
+						       MPEG2_ALLOC_CHUNK);
+
+    mpeg2dec->sequence.width = (unsigned)-1;
+    mpeg2_reset (mpeg2dec, 1);
+
+    return mpeg2dec;
+}
+
+void mpeg2_close (mpeg2dec_t * mpeg2dec)
+{
+    mpeg2_header_state_init (mpeg2dec);
+    mpeg2_free (mpeg2dec->chunk_buffer);
+    mpeg2_free (mpeg2dec);
+}
diff --git a/apps/plugins/mpegplayer/header.c b/apps/plugins/mpegplayer/header.c
new file mode 100644
index 0000000..a5dc27f
--- /dev/null
+++ b/apps/plugins/mpegplayer/header.c
@@ -0,0 +1,892 @@
+/*
+ * header.c
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 2003      Regis Duchesne <hpreg@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec 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.
+ *
+ * mpeg2dec 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "plugin.h"
+
+#include "mpeg2dec_config.h"
+
+extern struct plugin_api* rb;
+
+#include "mpeg2.h"
+#include "attributes.h"
+#include "mpeg2_internal.h"
+
+#define SEQ_EXT 2
+#define SEQ_DISPLAY_EXT 4
+#define QUANT_MATRIX_EXT 8
+#define COPYRIGHT_EXT 0x10
+#define PIC_DISPLAY_EXT 0x80
+#define PIC_CODING_EXT 0x100
+
+/* default intra quant matrix, in zig-zag order */
+static const uint8_t default_intra_quantizer_matrix[64] IBSS_ATTR = {
+    8,
+    16, 16,
+    19, 16, 19,
+    22, 22, 22, 22,
+    22, 22, 26, 24, 26,
+    27, 27, 27, 26, 26, 26,
+    26, 27, 27, 27, 29, 29, 29,
+    34, 34, 34, 29, 29, 29, 27, 27,
+    29, 29, 32, 32, 34, 34, 37,
+    38, 37, 35, 35, 34, 35,
+    38, 38, 40, 40, 40,
+    48, 48, 46, 46,
+    56, 56, 58,
+    69, 69,
+    83
+};
+
+uint8_t mpeg2_scan_norm[64] ICONST_ATTR = {
+    /* Zig-Zag scan pattern */
+     0,  1,  8, 16,  9,  2,  3, 10, 17, 24, 32, 25, 18, 11,  4,  5,
+    12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13,  6,  7, 14, 21, 28,
+    35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
+    58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
+};
+
+uint8_t mpeg2_scan_alt[64] ICONST_ATTR = {
+    /* Alternate scan pattern */
+     0, 8,  16, 24,  1,  9,  2, 10, 17, 25, 32, 40, 48, 56, 57, 49,
+    41, 33, 26, 18,  3, 11,  4, 12, 19, 27, 34, 42, 50, 58, 35, 43,
+    51, 59, 20, 28,  5, 13,  6, 14, 21, 29, 36, 44, 52, 60, 37, 45,
+    53, 61, 22, 30,  7, 15, 23, 31, 38, 46, 54, 62, 39, 47, 55, 63
+};
+
+void mpeg2_header_state_init (mpeg2dec_t * mpeg2dec)
+{
+    if (mpeg2dec->sequence.width != (unsigned)-1) {
+        int i;
+
+        mpeg2dec->sequence.width = (unsigned)-1;
+        if (!mpeg2dec->custom_fbuf)
+            for (i = mpeg2dec->alloc_index_user;
+                 i < mpeg2dec->alloc_index; i++) {
+                mpeg2_free (mpeg2dec->fbuf_alloc[i].fbuf.buf[0]);
+                mpeg2_free (mpeg2dec->fbuf_alloc[i].fbuf.buf[1]);
+                mpeg2_free (mpeg2dec->fbuf_alloc[i].fbuf.buf[2]);
+            }
+        if (mpeg2dec->convert_start)
+            for (i = 0; i < 3; i++) {
+                mpeg2_free (mpeg2dec->yuv_buf[i][0]);
+                mpeg2_free (mpeg2dec->yuv_buf[i][1]);
+                mpeg2_free (mpeg2dec->yuv_buf[i][2]);
+            }
+        if (mpeg2dec->decoder.convert_id)
+            mpeg2_free (mpeg2dec->decoder.convert_id);
+    }
+    mpeg2dec->decoder.coding_type = I_TYPE;
+    mpeg2dec->decoder.convert = NULL;
+    mpeg2dec->decoder.convert_id = NULL;
+    mpeg2dec->picture = mpeg2dec->pictures;
+    mpeg2dec->fbuf[0] = &mpeg2dec->fbuf_alloc[0].fbuf;
+    mpeg2dec->fbuf[1] = &mpeg2dec->fbuf_alloc[1].fbuf;
+    mpeg2dec->fbuf[2] = &mpeg2dec->fbuf_alloc[2].fbuf;
+    mpeg2dec->first = 1;
+    mpeg2dec->alloc_index = 0;
+    mpeg2dec->alloc_index_user = 0;
+    mpeg2dec->first_decode_slice = 1;
+    mpeg2dec->nb_decode_slices = 0xb0 - 1;
+    mpeg2dec->convert = NULL;
+    mpeg2dec->convert_start = NULL;
+    mpeg2dec->custom_fbuf = 0;
+    mpeg2dec->yuv_index = 0;
+}
+
+void mpeg2_reset_info (mpeg2_info_t * info)
+{
+    info->current_picture = info->current_picture_2nd = NULL;
+    info->display_picture = info->display_picture_2nd = NULL;
+    info->current_fbuf = info->display_fbuf = info->discard_fbuf = NULL;
+}
+
+static void info_user_data (mpeg2dec_t * mpeg2dec)
+{
+    if (mpeg2dec->user_data_len) {
+        mpeg2dec->info.user_data = mpeg2dec->chunk_buffer;
+        mpeg2dec->info.user_data_len = mpeg2dec->user_data_len - 3;
+    }
+}
+
+int mpeg2_header_sequence (mpeg2dec_t * mpeg2dec)
+{
+    uint8_t * buffer = mpeg2dec->chunk_start;
+    mpeg2_sequence_t * sequence = &(mpeg2dec->new_sequence);
+    static unsigned int frame_period[16] = {
+        0, 1126125, 1125000, 1080000, 900900, 900000, 540000, 450450, 450000,
+        /* unofficial: xing 15 fps */
+        1800000,
+        /* unofficial: libmpeg3 "Unofficial economy rates" 5/10/12/15 fps */
+        5400000, 2700000, 2250000, 1800000, 0, 0
+    };
+    int i;
+
+    if ((buffer[6] & 0x20) != 0x20)        /* missing marker_bit */
+        return 1;
+
+    i = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
+    if (! (sequence->display_width = sequence->picture_width = i >> 12))
+        return 1;
+    if (! (sequence->display_height = sequence->picture_height = i & 0xfff))
+        return 1;
+    sequence->width = (sequence->picture_width + 15) & ~15;
+    sequence->height = (sequence->picture_height + 15) & ~15;
+    sequence->chroma_width = sequence->width >> 1;
+    sequence->chroma_height = sequence->height >> 1;
+
+    sequence->flags = (SEQ_FLAG_PROGRESSIVE_SEQUENCE |
+                       SEQ_VIDEO_FORMAT_UNSPECIFIED);
+
+    sequence->pixel_width = buffer[3] >> 4;        /* aspect ratio */
+    sequence->frame_period = frame_period[buffer[3] & 15];
+
+    sequence->byte_rate = (buffer[4]<<10) | (buffer[5]<<2) | (buffer[6]>>6);
+
+    sequence->vbv_buffer_size = ((buffer[6]<<16)|(buffer[7]<<8))&0x1ff800;
+
+    if (buffer[7] & 4)
+        sequence->flags |= SEQ_FLAG_CONSTRAINED_PARAMETERS;
+
+    mpeg2dec->copy_matrix = 3;
+    if (buffer[7] & 2) {
+        for (i = 0; i < 64; i++)
+            mpeg2dec->new_quantizer_matrix[0][mpeg2_scan_norm[i]] =
+                (buffer[i+7] << 7) | (buffer[i+8] >> 1);
+        buffer += 64;
+    } else
+        for (i = 0; i < 64; i++)
+            mpeg2dec->new_quantizer_matrix[0][mpeg2_scan_norm[i]] =
+                default_intra_quantizer_matrix[i];
+
+    if (buffer[7] & 1)
+        for (i = 0; i < 64; i++)
+            mpeg2dec->new_quantizer_matrix[1][mpeg2_scan_norm[i]] =
+                buffer[i+8];
+    else
+        rb->memset (mpeg2dec->new_quantizer_matrix[1], 16, 64);
+
+    sequence->profile_level_id = 0x80;
+    sequence->colour_primaries = 0;
+    sequence->transfer_characteristics = 0;
+    sequence->matrix_coefficients = 0;
+
+    mpeg2dec->ext_state = SEQ_EXT;
+    mpeg2dec->state = STATE_SEQUENCE;
+    mpeg2dec->display_offset_x = mpeg2dec->display_offset_y = 0;
+
+    return 0;
+}
+
+static int sequence_ext (mpeg2dec_t * mpeg2dec)
+{
+    uint8_t * buffer = mpeg2dec->chunk_start;
+    mpeg2_sequence_t * sequence = &(mpeg2dec->new_sequence);
+    uint32_t flags;
+
+    if (!(buffer[3] & 1))
+        return 1;
+
+    sequence->profile_level_id = (buffer[0] << 4) | (buffer[1] >> 4);
+
+    sequence->display_width = sequence->picture_width +=
+        ((buffer[1] << 13) | (buffer[2] << 5)) & 0x3000;
+    sequence->display_height = sequence->picture_height +=
+        (buffer[2] << 7) & 0x3000;
+    sequence->width = (sequence->picture_width + 15) & ~15;
+    sequence->height = (sequence->picture_height + 15) & ~15;
+    flags = sequence->flags | SEQ_FLAG_MPEG2;
+    if (!(buffer[1] & 8)) {
+        flags &= ~SEQ_FLAG_PROGRESSIVE_SEQUENCE;
+        sequence->height = (sequence->height + 31) & ~31;
+    }
+    if (buffer[5] & 0x80)
+        flags |= SEQ_FLAG_LOW_DELAY;
+    sequence->flags = flags;
+    sequence->chroma_width = sequence->width;
+    sequence->chroma_height = sequence->height;
+    switch (buffer[1] & 6) {
+    case 0:        /* invalid */
+        return 1;
+    case 2:        /* 4:2:0 */
+        sequence->chroma_height >>= 1;
+    case 4:        /* 4:2:2 */
+        sequence->chroma_width >>= 1;
+    }
+
+    sequence->byte_rate += ((buffer[2]<<25) | (buffer[3]<<17)) & 0x3ffc0000;
+
+    sequence->vbv_buffer_size |= buffer[4] << 21;
+
+    sequence->frame_period =
+        sequence->frame_period * ((buffer[5]&31)+1) / (((buffer[5]>>2)&3)+1);
+
+    mpeg2dec->ext_state = SEQ_DISPLAY_EXT;
+
+    return 0;
+}
+
+static int sequence_display_ext (mpeg2dec_t * mpeg2dec)
+{
+    uint8_t * buffer = mpeg2dec->chunk_start;
+    mpeg2_sequence_t * sequence = &(mpeg2dec->new_sequence);
+    uint32_t flags;
+
+    flags = ((sequence->flags & ~SEQ_MASK_VIDEO_FORMAT) |
+             ((buffer[0]<<4) & SEQ_MASK_VIDEO_FORMAT));
+    if (buffer[0] & 1) {
+        flags |= SEQ_FLAG_COLOUR_DESCRIPTION;
+        sequence->colour_primaries = buffer[1];
+        sequence->transfer_characteristics = buffer[2];
+        sequence->matrix_coefficients = buffer[3];
+        buffer += 3;
+    }
+
+    if (!(buffer[2] & 2))        /* missing marker_bit */
+        return 1;
+
+    sequence->display_width = (buffer[1] << 6) | (buffer[2] >> 2);
+    sequence->display_height =
+        ((buffer[2]& 1 ) << 13) | (buffer[3] << 5) | (buffer[4] >> 3);
+
+    return 0;
+}
+
+static inline void finalize_sequence (mpeg2_sequence_t * sequence)
+{
+    int width;
+    int height;
+
+    sequence->byte_rate *= 50;
+
+    if (sequence->flags & SEQ_FLAG_MPEG2) {
+        switch (sequence->pixel_width) {
+        case 1:                /* square pixels */
+            sequence->pixel_width = sequence->pixel_height = 1;        return;
+        case 2:                /* 4:3 aspect ratio */
+            width = 4; height = 3;        break;
+        case 3:                /* 16:9 aspect ratio */
+            width = 16; height = 9;        break;
+        case 4:                /* 2.21:1 aspect ratio */
+            width = 221; height = 100;        break;
+        default:        /* illegal */
+            sequence->pixel_width = sequence->pixel_height = 0;        return;
+        }
+        width *= sequence->display_height;
+        height *= sequence->display_width;
+
+    } else {
+        if (sequence->byte_rate == 50 * 0x3ffff) 
+            sequence->byte_rate = 0;        /* mpeg-1 VBR */ 
+
+        switch (sequence->pixel_width) {
+        case 0:        case 15:        /* illegal */
+            sequence->pixel_width = sequence->pixel_height = 0;                return;
+        case 1:        /* square pixels */
+            sequence->pixel_width = sequence->pixel_height = 1;                return;
+        case 3:        /* 720x576 16:9 */
+            sequence->pixel_width = 64;        sequence->pixel_height = 45;        return;
+        case 6:        /* 720x480 16:9 */
+            sequence->pixel_width = 32;        sequence->pixel_height = 27;        return;
+        case 12:        /* 720*480 4:3 */
+            sequence->pixel_width = 8;        sequence->pixel_height = 9;        return;
+        default:
+            height = 88 * sequence->pixel_width + 1171;
+            width = 2000;
+        }
+    }
+
+    sequence->pixel_width = width;
+    sequence->pixel_height = height;
+    while (width) {        /* find greatest common divisor */
+        int tmp = width;
+        width = height % tmp;
+        height = tmp;
+    }
+    sequence->pixel_width /= height;
+    sequence->pixel_height /= height;
+}
+
+static void copy_matrix (mpeg2dec_t * mpeg2dec, int index)
+{
+    if (rb->memcmp (mpeg2dec->quantizer_matrix[index],
+                mpeg2dec->new_quantizer_matrix[index], 64)) {
+        rb->memcpy (mpeg2dec->quantizer_matrix[index],
+                mpeg2dec->new_quantizer_matrix[index], 64);
+        mpeg2dec->scaled[index] = -1;
+    }
+}
+
+static void finalize_matrix (mpeg2dec_t * mpeg2dec)
+{
+    mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);
+    int i;
+
+    for (i = 0; i < 2; i++) {
+        if (mpeg2dec->copy_matrix & (1 << i))
+            copy_matrix (mpeg2dec, i);
+        if ((mpeg2dec->copy_matrix & (4 << i)) &&
+            rb->memcmp (mpeg2dec->quantizer_matrix[i],
+                    mpeg2dec->new_quantizer_matrix[i+2], 64)) {
+            copy_matrix (mpeg2dec, i + 2);
+            decoder->chroma_quantizer[i] = decoder->quantizer_prescale[i+2];
+        } else if (mpeg2dec->copy_matrix & (5 << i))
+            decoder->chroma_quantizer[i] = decoder->quantizer_prescale[i];
+    }
+}
+
+static mpeg2_state_t invalid_end_action (mpeg2dec_t * mpeg2dec)
+{
+    mpeg2_reset_info (&(mpeg2dec->info));
+    mpeg2dec->info.gop = NULL;
+    info_user_data (mpeg2dec);
+    mpeg2_header_state_init (mpeg2dec);
+    mpeg2dec->sequence = mpeg2dec->new_sequence;
+    mpeg2dec->action = mpeg2_seek_header;
+    mpeg2dec->state = STATE_SEQUENCE;
+    return STATE_SEQUENCE;
+}
+
+void mpeg2_header_sequence_finalize (mpeg2dec_t * mpeg2dec)
+{
+    mpeg2_sequence_t * sequence = &(mpeg2dec->new_sequence);
+    mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);
+
+    finalize_sequence (sequence);
+    finalize_matrix (mpeg2dec);
+
+    decoder->mpeg1 = !(sequence->flags & SEQ_FLAG_MPEG2);
+    decoder->width = sequence->width;
+    decoder->height = sequence->height;
+    decoder->vertical_position_extension = (sequence->picture_height > 2800);
+    decoder->chroma_format = ((sequence->chroma_width == sequence->width) +
+                              (sequence->chroma_height == sequence->height));
+
+    if (mpeg2dec->sequence.width != (unsigned)-1) {
+        unsigned int new_byte_rate;
+
+        /*
+         * According to 6.1.1.6, repeat sequence headers should be
+         * identical to the original. However some DVDs dont respect
+         * that and have different bitrates in the repeat sequence
+         * headers. So we'll ignore that in the comparison and still
+         * consider these as repeat sequence headers.
+         *
+         * However, be careful not to alter the current sequence when
+         * returning STATE_INVALID_END.
+         */
+        new_byte_rate = sequence->byte_rate;
+        sequence->byte_rate = mpeg2dec->sequence.byte_rate;
+        if (rb->memcmp (&(mpeg2dec->sequence), sequence,
+                    sizeof (mpeg2_sequence_t))) {
+            decoder->stride_frame = sequence->width;
+            sequence->byte_rate = new_byte_rate;
+            mpeg2_header_end (mpeg2dec);
+            mpeg2dec->action = invalid_end_action;
+            mpeg2dec->state = STATE_INVALID_END;
+            return;
+        }
+        sequence->byte_rate = new_byte_rate;
+        mpeg2dec->state = STATE_SEQUENCE_REPEATED;
+    } else
+        decoder->stride_frame = sequence->width;
+    mpeg2dec->sequence = *sequence;
+    mpeg2_reset_info (&(mpeg2dec->info));
+    mpeg2dec->info.sequence = &(mpeg2dec->sequence);
+    mpeg2dec->info.gop = NULL;
+    info_user_data (mpeg2dec);
+}
+
+int mpeg2_header_gop (mpeg2dec_t * mpeg2dec)
+{
+    uint8_t * buffer = mpeg2dec->chunk_start;
+    mpeg2_gop_t * gop = &(mpeg2dec->new_gop);
+
+    if (! (buffer[1] & 8))
+        return 1;
+    gop->hours = (buffer[0] >> 2) & 31;
+    gop->minutes = ((buffer[0] << 4) | (buffer[1] >> 4)) & 63;
+    gop->seconds = ((buffer[1] << 3) | (buffer[2] >> 5)) & 63;
+    gop->pictures = ((buffer[2] << 1) | (buffer[3] >> 7)) & 63;
+    gop->flags = (buffer[0] >> 7) | ((buffer[3] >> 4) & 6);
+    mpeg2dec->state = STATE_GOP;
+    return 0;
+}
+
+void mpeg2_header_gop_finalize (mpeg2dec_t * mpeg2dec)
+{
+    mpeg2dec->gop = mpeg2dec->new_gop;
+    mpeg2_reset_info (&(mpeg2dec->info));
+    mpeg2dec->info.gop = &(mpeg2dec->gop);
+    info_user_data (mpeg2dec);
+}
+
+void mpeg2_set_fbuf (mpeg2dec_t * mpeg2dec, int b_type)
+{
+    int i;
+
+    for (i = 0; i < 3; i++)
+        if (mpeg2dec->fbuf[1] != &mpeg2dec->fbuf_alloc[i].fbuf &&
+            mpeg2dec->fbuf[2] != &mpeg2dec->fbuf_alloc[i].fbuf) {
+            mpeg2dec->fbuf[0] = &mpeg2dec->fbuf_alloc[i].fbuf;
+            mpeg2dec->info.current_fbuf = mpeg2dec->fbuf[0];
+            if (b_type || (mpeg2dec->sequence.flags & SEQ_FLAG_LOW_DELAY)) {
+                if (b_type || mpeg2dec->convert)
+                    mpeg2dec->info.discard_fbuf = mpeg2dec->fbuf[0];
+                mpeg2dec->info.display_fbuf = mpeg2dec->fbuf[0];
+            }
+            break;
+        }
+}
+
+mpeg2_state_t mpeg2_header_picture_start (mpeg2dec_t * mpeg2dec)
+{
+    mpeg2_picture_t * picture = &(mpeg2dec->new_picture);
+
+    mpeg2dec->state = ((mpeg2dec->state != STATE_SLICE_1ST) ?
+                       STATE_PICTURE : STATE_PICTURE_2ND);
+    picture->flags = 0;
+    picture->tag = picture->tag2 = 0;
+    if (mpeg2dec->num_tags) {
+        if (mpeg2dec->bytes_since_tag >= 4) {
+            mpeg2dec->num_tags = 0;
+            picture->tag = mpeg2dec->tag_current;
+            picture->tag2 = mpeg2dec->tag2_current;
+            picture->flags = PIC_FLAG_TAGS;
+        } else if (mpeg2dec->num_tags > 1) {
+            mpeg2dec->num_tags = 1;
+            picture->tag = mpeg2dec->tag_previous;
+            picture->tag2 = mpeg2dec->tag2_previous;
+            picture->flags = PIC_FLAG_TAGS;
+        }
+    }
+    picture->display_offset[0].x = picture->display_offset[1].x =
+        picture->display_offset[2].x = mpeg2dec->display_offset_x;
+    picture->display_offset[0].y = picture->display_offset[1].y =
+        picture->display_offset[2].y = mpeg2dec->display_offset_y;
+    return mpeg2_parse_header (mpeg2dec);
+}
+
+int mpeg2_header_picture (mpeg2dec_t * mpeg2dec)
+{
+    uint8_t * buffer = mpeg2dec->chunk_start;
+    mpeg2_picture_t * picture = &(mpeg2dec->new_picture);
+    mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);
+    int type;
+
+    type = (buffer [1] >> 3) & 7;
+    mpeg2dec->ext_state = PIC_CODING_EXT;
+
+    picture->temporal_reference = (buffer[0] << 2) | (buffer[1] >> 6);
+
+    picture->flags |= type;
+
+    if (type == PIC_FLAG_CODING_TYPE_P || type == PIC_FLAG_CODING_TYPE_B) {
+        /* forward_f_code and backward_f_code - used in mpeg1 only */
+        decoder->f_motion.f_code[1] = (buffer[3] >> 2) & 1;
+        decoder->f_motion.f_code[0] =
+            (((buffer[3] << 1) | (buffer[4] >> 7)) & 7) - 1;
+        decoder->b_motion.f_code[1] = (buffer[4] >> 6) & 1;
+        decoder->b_motion.f_code[0] = ((buffer[4] >> 3) & 7) - 1;
+    }
+
+    /* XXXXXX decode extra_information_picture as well */
+
+    picture->nb_fields = 2;
+
+    mpeg2dec->q_scale_type = 0;
+    decoder->intra_dc_precision = 7;
+    decoder->frame_pred_frame_dct = 1;
+    decoder->concealment_motion_vectors = 0;
+    decoder->scan = mpeg2_scan_norm;
+    decoder->picture_structure = FRAME_PICTURE;
+    mpeg2dec->copy_matrix = 0;
+
+    return 0;
+}
+
+static int picture_coding_ext (mpeg2dec_t * mpeg2dec)
+{
+    uint8_t * buffer = mpeg2dec->chunk_start;
+    mpeg2_picture_t * picture = &(mpeg2dec->new_picture);
+    mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);
+    uint32_t flags;
+
+    /* pre subtract 1 for use later in compute_motion_vector */
+    decoder->f_motion.f_code[0] = (buffer[0] & 15) - 1;
+    decoder->f_motion.f_code[1] = (buffer[1] >> 4) - 1;
+    decoder->b_motion.f_code[0] = (buffer[1] & 15) - 1;
+    decoder->b_motion.f_code[1] = (buffer[2] >> 4) - 1;
+
+    flags = picture->flags;
+    decoder->intra_dc_precision = 7 - ((buffer[2] >> 2) & 3);
+    decoder->picture_structure = buffer[2] & 3;
+    switch (decoder->picture_structure) {
+    case TOP_FIELD:
+        flags |= PIC_FLAG_TOP_FIELD_FIRST;
+    case BOTTOM_FIELD:
+        picture->nb_fields = 1;
+        break;
+    case FRAME_PICTURE:
+        if (!(mpeg2dec->sequence.flags & SEQ_FLAG_PROGRESSIVE_SEQUENCE)) {
+            picture->nb_fields = (buffer[3] & 2) ? 3 : 2;
+            flags |= (buffer[3] & 128) ? PIC_FLAG_TOP_FIELD_FIRST : 0;
+        } else
+            picture->nb_fields = (buffer[3]&2) ? ((buffer[3]&128) ? 6 : 4) : 2;
+        break;
+    default:
+        return 1;
+    }
+    decoder->top_field_first = buffer[3] >> 7;
+    decoder->frame_pred_frame_dct = (buffer[3] >> 6) & 1;
+    decoder->concealment_motion_vectors = (buffer[3] >> 5) & 1;
+    mpeg2dec->q_scale_type = buffer[3] & 16;
+    decoder->intra_vlc_format = (buffer[3] >> 3) & 1;
+    decoder->scan = (buffer[3] & 4) ? mpeg2_scan_alt : mpeg2_scan_norm;
+    flags |= (buffer[4] & 0x80) ? PIC_FLAG_PROGRESSIVE_FRAME : 0;
+    if (buffer[4] & 0x40)
+        flags |= (((buffer[4]<<26) | (buffer[5]<<18) | (buffer[6]<<10)) &
+                  PIC_MASK_COMPOSITE_DISPLAY) | PIC_FLAG_COMPOSITE_DISPLAY;
+    picture->flags = flags;
+
+    mpeg2dec->ext_state = PIC_DISPLAY_EXT | COPYRIGHT_EXT | QUANT_MATRIX_EXT;
+
+    return 0;
+}
+
+static int picture_display_ext (mpeg2dec_t * mpeg2dec)
+{
+    uint8_t * buffer = mpeg2dec->chunk_start;
+    mpeg2_picture_t * picture = &(mpeg2dec->new_picture);
+    int i, nb_pos;
+
+    nb_pos = picture->nb_fields;
+    if (mpeg2dec->sequence.flags & SEQ_FLAG_PROGRESSIVE_SEQUENCE)
+        nb_pos >>= 1;
+
+    for (i = 0; i < nb_pos; i++) {
+        int x, y;
+
+        x = ((buffer[4*i] << 24) | (buffer[4*i+1] << 16) |
+             (buffer[4*i+2] << 8) | buffer[4*i+3]) >> (11-2*i);
+        y = ((buffer[4*i+2] << 24) | (buffer[4*i+3] << 16) |
+             (buffer[4*i+4] << 8) | buffer[4*i+5]) >> (10-2*i);
+        if (! (x & y & 1))
+            return 1;
+        picture->display_offset[i].x = mpeg2dec->display_offset_x = x >> 1;
+        picture->display_offset[i].y = mpeg2dec->display_offset_y = y >> 1;
+    }
+    for (; i < 3; i++) {
+        picture->display_offset[i].x = mpeg2dec->display_offset_x;
+        picture->display_offset[i].y = mpeg2dec->display_offset_y;
+    }
+    return 0;
+}
+
+void mpeg2_header_picture_finalize (mpeg2dec_t * mpeg2dec, uint32_t accels)
+{
+    mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);
+    int old_type_b = (decoder->coding_type == B_TYPE);
+    int low_delay = mpeg2dec->sequence.flags & SEQ_FLAG_LOW_DELAY;
+
+    finalize_matrix (mpeg2dec);
+    decoder->coding_type = mpeg2dec->new_picture.flags & PIC_MASK_CODING_TYPE;
+
+    if (mpeg2dec->state == STATE_PICTURE) {
+        mpeg2_picture_t * picture;
+        mpeg2_picture_t * other;
+
+        decoder->second_field = 0;
+
+        picture = other = mpeg2dec->pictures;
+        if (old_type_b ^ (mpeg2dec->picture < mpeg2dec->pictures + 2))
+            picture += 2;
+        else
+            other += 2;
+        mpeg2dec->picture = picture;
+        *picture = mpeg2dec->new_picture;
+
+        if (!old_type_b) {
+            mpeg2dec->fbuf[2] = mpeg2dec->fbuf[1];
+            mpeg2dec->fbuf[1] = mpeg2dec->fbuf[0];
+        }
+        mpeg2dec->fbuf[0] = NULL;
+        mpeg2_reset_info (&(mpeg2dec->info));
+        mpeg2dec->info.current_picture = picture;
+        mpeg2dec->info.display_picture = picture;
+        if (decoder->coding_type != B_TYPE) {
+            if (!low_delay) {
+                if (mpeg2dec->first) {
+                    mpeg2dec->info.display_picture = NULL;
+                    mpeg2dec->first = 0;
+                } else {
+                    mpeg2dec->info.display_picture = other;
+                    if (other->nb_fields == 1)
+                        mpeg2dec->info.display_picture_2nd = other + 1;
+                    mpeg2dec->info.display_fbuf = mpeg2dec->fbuf[1];
+                }
+            }
+            if (!low_delay + !mpeg2dec->convert)
+                mpeg2dec->info.discard_fbuf =
+                    mpeg2dec->fbuf[!low_delay + !mpeg2dec->convert];
+        }
+        if (mpeg2dec->convert) {
+            mpeg2_convert_init_t convert_init;
+            if (!mpeg2dec->convert_start) {
+                int y_size, uv_size;
+
+                mpeg2dec->decoder.convert_id =
+                    mpeg2_malloc (mpeg2dec->convert_id_size,
+                                  MPEG2_ALLOC_CONVERT_ID);
+                mpeg2dec->convert (MPEG2_CONVERT_START,
+                                   mpeg2dec->decoder.convert_id,
+                                   &(mpeg2dec->sequence),
+                                   mpeg2dec->convert_stride, accels,
+                                   mpeg2dec->convert_arg, &convert_init);
+                mpeg2dec->convert_start = convert_init.start;
+                mpeg2dec->decoder.convert = convert_init.copy;
+
+                y_size = decoder->stride_frame * mpeg2dec->sequence.height;
+                uv_size = y_size >> (2 - mpeg2dec->decoder.chroma_format);
+                mpeg2dec->yuv_buf[0][0] =
+                    (uint8_t *) mpeg2_malloc (y_size, MPEG2_ALLOC_YUV);
+                mpeg2dec->yuv_buf[0][1] =
+                    (uint8_t *) mpeg2_malloc (uv_size, MPEG2_ALLOC_YUV);
+                mpeg2dec->yuv_buf[0][2] =
+                    (uint8_t *) mpeg2_malloc (uv_size, MPEG2_ALLOC_YUV);
+                mpeg2dec->yuv_buf[1][0] =
+                    (uint8_t *) mpeg2_malloc (y_size, MPEG2_ALLOC_YUV);
+                mpeg2dec->yuv_buf[1][1] =
+                    (uint8_t *) mpeg2_malloc (uv_size, MPEG2_ALLOC_YUV);
+                mpeg2dec->yuv_buf[1][2] =
+                    (uint8_t *) mpeg2_malloc (uv_size, MPEG2_ALLOC_YUV);
+                y_size = decoder->stride_frame * 32;
+                uv_size = y_size >> (2 - mpeg2dec->decoder.chroma_format);
+                mpeg2dec->yuv_buf[2][0] =
+                    (uint8_t *) mpeg2_malloc (y_size, MPEG2_ALLOC_YUV);
+                mpeg2dec->yuv_buf[2][1] =
+                    (uint8_t *) mpeg2_malloc (uv_size, MPEG2_ALLOC_YUV);
+                mpeg2dec->yuv_buf[2][2] =
+                    (uint8_t *) mpeg2_malloc (uv_size, MPEG2_ALLOC_YUV);
+            }
+            if (!mpeg2dec->custom_fbuf) {
+                while (mpeg2dec->alloc_index < 3) {
+                    mpeg2_fbuf_t * fbuf;
+
+                    fbuf = &mpeg2dec->fbuf_alloc[mpeg2dec->alloc_index++].fbuf;
+                    fbuf->id = NULL;
+                    fbuf->buf[0] =
+                        (uint8_t *) mpeg2_malloc (convert_init.buf_size[0],
+                                                  MPEG2_ALLOC_CONVERTED);
+                    fbuf->buf[1] =
+                        (uint8_t *) mpeg2_malloc (convert_init.buf_size[1],
+                                                  MPEG2_ALLOC_CONVERTED);
+                    fbuf->buf[2] =
+                        (uint8_t *) mpeg2_malloc (convert_init.buf_size[2],
+                                                  MPEG2_ALLOC_CONVERTED);
+                }
+                mpeg2_set_fbuf (mpeg2dec, (decoder->coding_type == B_TYPE));
+            }
+        } else if (!mpeg2dec->custom_fbuf) {
+            while (mpeg2dec->alloc_index < 3) {
+                mpeg2_fbuf_t * fbuf;
+                int y_size, uv_size;
+
+                fbuf = &(mpeg2dec->fbuf_alloc[mpeg2dec->alloc_index++].fbuf);
+                fbuf->id = NULL;
+                y_size = decoder->stride_frame * mpeg2dec->sequence.height;
+                uv_size = y_size >> (2 - decoder->chroma_format);
+                fbuf->buf[0] = (uint8_t *) mpeg2_malloc (y_size,
+                                                         MPEG2_ALLOC_YUV);
+                fbuf->buf[1] = (uint8_t *) mpeg2_malloc (uv_size,
+                                                         MPEG2_ALLOC_YUV);
+                fbuf->buf[2] = (uint8_t *) mpeg2_malloc (uv_size,
+                                                         MPEG2_ALLOC_YUV);
+            }
+            mpeg2_set_fbuf (mpeg2dec, (decoder->coding_type == B_TYPE));
+        }
+    } else {
+        decoder->second_field = 1;
+        mpeg2dec->picture++;        /* second field picture */
+        *(mpeg2dec->picture) = mpeg2dec->new_picture;
+        mpeg2dec->info.current_picture_2nd = mpeg2dec->picture;
+        if (low_delay || decoder->coding_type == B_TYPE)
+            mpeg2dec->info.display_picture_2nd = mpeg2dec->picture;
+    }
+
+    info_user_data (mpeg2dec);
+}
+
+static int copyright_ext (mpeg2dec_t * mpeg2dec)
+{
+    (void)mpeg2dec;
+    return 0;
+}
+
+static int quant_matrix_ext (mpeg2dec_t * mpeg2dec)
+{
+    uint8_t * buffer = mpeg2dec->chunk_start;
+    int i, j;
+
+    for (i = 0; i < 4; i++)
+        if (buffer[0] & (8 >> i)) {
+            for (j = 0; j < 64; j++)
+                mpeg2dec->new_quantizer_matrix[i][mpeg2_scan_norm[j]] =
+                    (buffer[j] << (i+5)) | (buffer[j+1] >> (3-i));
+            mpeg2dec->copy_matrix |= 1 << i;
+            buffer += 64;
+        }
+
+    return 0;
+}
+
+int mpeg2_header_extension (mpeg2dec_t * mpeg2dec)
+{
+    static int (* parser[]) (mpeg2dec_t *) = {
+        0, sequence_ext, sequence_display_ext, quant_matrix_ext,
+        copyright_ext, 0, 0, picture_display_ext, picture_coding_ext
+    };
+    int ext, ext_bit;
+
+    ext = mpeg2dec->chunk_start[0] >> 4;
+    ext_bit = 1 << ext;
+
+    if (!(mpeg2dec->ext_state & ext_bit))
+        return 0;        /* ignore illegal extensions */
+    mpeg2dec->ext_state &= ~ext_bit;
+    return parser[ext] (mpeg2dec);
+}
+
+int mpeg2_header_user_data (mpeg2dec_t * mpeg2dec)
+{
+    mpeg2dec->user_data_len += mpeg2dec->chunk_ptr - 1 - mpeg2dec->chunk_start;
+    mpeg2dec->chunk_start = mpeg2dec->chunk_ptr - 1;
+    
+    return 0;
+}
+
+static void prescale (mpeg2dec_t * mpeg2dec, int index)
+{
+    static int non_linear_scale [] = {
+         0,  1,  2,  3,  4,  5,   6,   7,
+         8, 10, 12, 14, 16, 18,  20,  22,
+        24, 28, 32, 36, 40, 44,  48,  52,
+        56, 64, 72, 80, 88, 96, 104, 112
+    };
+    int i, j, k;
+    mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);
+
+    if (mpeg2dec->scaled[index] != mpeg2dec->q_scale_type) {
+        mpeg2dec->scaled[index] = mpeg2dec->q_scale_type;
+        for (i = 0; i < 32; i++) {
+            k = mpeg2dec->q_scale_type ? non_linear_scale[i] : (i << 1);
+            for (j = 0; j < 64; j++)
+                decoder->quantizer_prescale[index][i][j] =
+                    k * mpeg2dec->quantizer_matrix[index][j];
+        }
+    }
+}
+
+mpeg2_state_t mpeg2_header_slice_start (mpeg2dec_t * mpeg2dec)
+{
+    mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);
+
+    mpeg2dec->info.user_data = NULL;        mpeg2dec->info.user_data_len = 0;
+    mpeg2dec->state = ((mpeg2dec->picture->nb_fields > 1 ||
+                        mpeg2dec->state == STATE_PICTURE_2ND) ?
+                       STATE_SLICE : STATE_SLICE_1ST);
+
+    if (mpeg2dec->decoder.coding_type != D_TYPE) {
+        prescale (mpeg2dec, 0);
+        if (decoder->chroma_quantizer[0] == decoder->quantizer_prescale[2])
+            prescale (mpeg2dec, 2);
+        if (mpeg2dec->decoder.coding_type != I_TYPE) {
+            prescale (mpeg2dec, 1);
+            if (decoder->chroma_quantizer[1] == decoder->quantizer_prescale[3])
+                prescale (mpeg2dec, 3);
+        }
+    }
+
+    if (!(mpeg2dec->nb_decode_slices))
+        mpeg2dec->picture->flags |= PIC_FLAG_SKIP;
+    else if (mpeg2dec->convert_start) {
+        mpeg2dec->convert_start (decoder->convert_id, mpeg2dec->fbuf[0],
+                                 mpeg2dec->picture, mpeg2dec->info.gop);
+
+        if (mpeg2dec->decoder.coding_type == B_TYPE)
+            mpeg2_init_fbuf (&(mpeg2dec->decoder), mpeg2dec->yuv_buf[2],
+                             mpeg2dec->yuv_buf[mpeg2dec->yuv_index ^ 1],
+                             mpeg2dec->yuv_buf[mpeg2dec->yuv_index]);
+        else {
+            mpeg2_init_fbuf (&(mpeg2dec->decoder),
+                             mpeg2dec->yuv_buf[mpeg2dec->yuv_index ^ 1],
+                             mpeg2dec->yuv_buf[mpeg2dec->yuv_index],
+                             mpeg2dec->yuv_buf[mpeg2dec->yuv_index]);
+            if (mpeg2dec->state == STATE_SLICE)
+                mpeg2dec->yuv_index ^= 1;
+        }
+    } else {
+        int b_type;
+
+        b_type = (mpeg2dec->decoder.coding_type == B_TYPE);
+        mpeg2_init_fbuf (&(mpeg2dec->decoder), mpeg2dec->fbuf[0]->buf,
+                         mpeg2dec->fbuf[b_type + 1]->buf,
+                         mpeg2dec->fbuf[b_type]->buf);
+    }
+    mpeg2dec->action = NULL;
+    return (mpeg2_state_t)-1;
+}
+
+static mpeg2_state_t seek_sequence (mpeg2dec_t * mpeg2dec)
+{
+    mpeg2_reset_info (&(mpeg2dec->info));
+    mpeg2dec->info.sequence = NULL;
+    mpeg2dec->info.gop = NULL;
+    mpeg2_header_state_init (mpeg2dec);
+    mpeg2dec->action = mpeg2_seek_header;
+    return mpeg2_seek_header (mpeg2dec);
+}
+
+mpeg2_state_t mpeg2_header_end (mpeg2dec_t * mpeg2dec)
+{
+    mpeg2_picture_t * picture;
+    int b_type;
+
+    b_type = (mpeg2dec->decoder.coding_type == B_TYPE);
+    picture = mpeg2dec->pictures;
+    if ((mpeg2dec->picture >= picture + 2) ^ b_type)
+        picture = mpeg2dec->pictures + 2;
+
+    mpeg2_reset_info (&(mpeg2dec->info));
+    if (!(mpeg2dec->sequence.flags & SEQ_FLAG_LOW_DELAY)) {
+        mpeg2dec->info.display_picture = picture;
+        if (picture->nb_fields == 1)
+            mpeg2dec->info.display_picture_2nd = picture + 1;
+        mpeg2dec->info.display_fbuf = mpeg2dec->fbuf[b_type];
+        if (!mpeg2dec->convert)
+            mpeg2dec->info.discard_fbuf = mpeg2dec->fbuf[b_type + 1];
+    } else if (!mpeg2dec->convert)
+        mpeg2dec->info.discard_fbuf = mpeg2dec->fbuf[b_type];
+    mpeg2dec->action = seek_sequence;
+    return STATE_END;
+}
diff --git a/apps/plugins/mpegplayer/idct.c b/apps/plugins/mpegplayer/idct.c
new file mode 100644
index 0000000..8a0b56e
--- /dev/null
+++ b/apps/plugins/mpegplayer/idct.c
@@ -0,0 +1,287 @@
+/*
+ * idct.c
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec 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.
+ *
+ * mpeg2dec 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "plugin.h"
+
+#include "mpeg2dec_config.h"
+
+#include "mpeg2.h"
+#include "attributes.h"
+#include "mpeg2_internal.h"
+
+#define W1 2841 /* 2048 * sqrt (2) * cos (1 * pi / 16) */
+#define W2 2676 /* 2048 * sqrt (2) * cos (2 * pi / 16) */
+#define W3 2408 /* 2048 * sqrt (2) * cos (3 * pi / 16) */
+#define W5 1609 /* 2048 * sqrt (2) * cos (5 * pi / 16) */
+#define W6 1108 /* 2048 * sqrt (2) * cos (6 * pi / 16) */
+#define W7 565  /* 2048 * sqrt (2) * cos (7 * pi / 16) */
+
+/* idct main entry point  */
+void (* mpeg2_idct_copy) (int16_t * block, uint8_t * dest, int stride);
+void (* mpeg2_idct_add) (int last, int16_t * block,
+                         uint8_t * dest, int stride);
+
+/*
+ * In legal streams, the IDCT output should be between -384 and +384.
+ * In corrupted streams, it is possible to force the IDCT output to go
+ * to +-3826 - this is the worst case for a column IDCT where the
+ * column inputs are 16-bit values.
+ */
+uint8_t mpeg2_clip[3840 * 2 + 256] IBSS_ATTR;
+#define CLIP(i) ((mpeg2_clip + 3840)[i])
+
+#if 0
+#define BUTTERFLY(t0,t1,W0,W1,d0,d1)        \
+do {                                        \
+    t0 = W0 * d0 + W1 * d1;                \
+    t1 = W0 * d1 - W1 * d0;                \
+} while (0)
+#else
+#define BUTTERFLY(t0,t1,W0,W1,d0,d1)        \
+do {                                        \
+    int tmp = W0 * (d0 + d1);                \
+    t0 = tmp + (W1 - W0) * d1;                \
+    t1 = tmp - (W1 + W0) * d0;                \
+} while (0)
+#endif
+
+static inline void idct_row (int16_t * const block)
+{
+    int d0, d1, d2, d3;
+    int a0, a1, a2, a3, b0, b1, b2, b3;
+    int t0, t1, t2, t3;
+
+    /* shortcut */
+    if (likely (!(block[1] | ((int32_t *)block)[1] | ((int32_t *)block)[2] |
+                  ((int32_t *)block)[3]))) {
+        uint32_t tmp = (uint16_t) (block[0] >> 1);
+        tmp |= tmp << 16;
+        ((int32_t *)block)[0] = tmp;
+        ((int32_t *)block)[1] = tmp;
+        ((int32_t *)block)[2] = tmp;
+        ((int32_t *)block)[3] = tmp;
+        return;
+    }
+
+    d0 = (block[0] << 11) + 2048;
+    d1 = block[1];
+    d2 = block[2] << 11;
+    d3 = block[3];
+    t0 = d0 + d2;
+    t1 = d0 - d2;
+    BUTTERFLY (t2, t3, W6, W2, d3, d1);
+    a0 = t0 + t2;
+    a1 = t1 + t3;
+    a2 = t1 - t3;
+    a3 = t0 - t2;
+
+    d0 = block[4];
+    d1 = block[5];
+    d2 = block[6];
+    d3 = block[7];
+    BUTTERFLY (t0, t1, W7, W1, d3, d0);
+    BUTTERFLY (t2, t3, W3, W5, d1, d2);
+    b0 = t0 + t2;
+    b3 = t1 + t3;
+    t0 -= t2;
+    t1 -= t3;
+    b1 = ((t0 + t1) >> 8) * 181;
+    b2 = ((t0 - t1) >> 8) * 181;
+
+    block[0] = (a0 + b0) >> 12;
+    block[1] = (a1 + b1) >> 12;
+    block[2] = (a2 + b2) >> 12;
+    block[3] = (a3 + b3) >> 12;
+    block[4] = (a3 - b3) >> 12;
+    block[5] = (a2 - b2) >> 12;
+    block[6] = (a1 - b1) >> 12;
+    block[7] = (a0 - b0) >> 12;
+}
+
+static inline void idct_col (int16_t * const block)
+{
+    int d0, d1, d2, d3;
+    int a0, a1, a2, a3, b0, b1, b2, b3;
+    int t0, t1, t2, t3;
+
+    d0 = (block[8*0] << 11) + 65536;
+    d1 = block[8*1];
+    d2 = block[8*2] << 11;
+    d3 = block[8*3];
+    t0 = d0 + d2;
+    t1 = d0 - d2;
+    BUTTERFLY (t2, t3, W6, W2, d3, d1);
+    a0 = t0 + t2;
+    a1 = t1 + t3;
+    a2 = t1 - t3;
+    a3 = t0 - t2;
+
+    d0 = block[8*4];
+    d1 = block[8*5];
+    d2 = block[8*6];
+    d3 = block[8*7];
+    BUTTERFLY (t0, t1, W7, W1, d3, d0);
+    BUTTERFLY (t2, t3, W3, W5, d1, d2);
+    b0 = t0 + t2;
+    b3 = t1 + t3;
+    t0 -= t2;
+    t1 -= t3;
+    b1 = ((t0 + t1) >> 8) * 181;
+    b2 = ((t0 - t1) >> 8) * 181;
+
+    block[8*0] = (a0 + b0) >> 17;
+    block[8*1] = (a1 + b1) >> 17;
+    block[8*2] = (a2 + b2) >> 17;
+    block[8*3] = (a3 + b3) >> 17;
+    block[8*4] = (a3 - b3) >> 17;
+    block[8*5] = (a2 - b2) >> 17;
+    block[8*6] = (a1 - b1) >> 17;
+    block[8*7] = (a0 - b0) >> 17;
+}
+
+static void mpeg2_idct_copy_c (int16_t * block, uint8_t * dest,
+                               const int stride)
+{
+    int i;
+
+    for (i = 0; i < 8; i++)
+        idct_row (block + 8 * i);
+    for (i = 0; i < 8; i++)
+        idct_col (block + i);
+    do {
+        dest[0] = CLIP (block[0]);
+        dest[1] = CLIP (block[1]);
+        dest[2] = CLIP (block[2]);
+        dest[3] = CLIP (block[3]);
+        dest[4] = CLIP (block[4]);
+        dest[5] = CLIP (block[5]);
+        dest[6] = CLIP (block[6]);
+        dest[7] = CLIP (block[7]);
+
+        ((int32_t *)block)[0] = 0;        ((int32_t *)block)[1] = 0;
+        ((int32_t *)block)[2] = 0;        ((int32_t *)block)[3] = 0;
+
+        dest += stride;
+        block += 8;
+    } while (--i);
+}
+
+static void mpeg2_idct_add_c (const int last, int16_t * block,
+                              uint8_t * dest, const int stride)
+{
+    int i;
+
+    if (last != 129 || (block[0] & (7 << 4)) == (4 << 4)) {
+        for (i = 0; i < 8; i++)
+            idct_row (block + 8 * i);
+        for (i = 0; i < 8; i++)
+            idct_col (block + i);
+        do {
+            dest[0] = CLIP (block[0] + dest[0]);
+            dest[1] = CLIP (block[1] + dest[1]);
+            dest[2] = CLIP (block[2] + dest[2]);
+            dest[3] = CLIP (block[3] + dest[3]);
+            dest[4] = CLIP (block[4] + dest[4]);
+            dest[5] = CLIP (block[5] + dest[5]);
+            dest[6] = CLIP (block[6] + dest[6]);
+            dest[7] = CLIP (block[7] + dest[7]);
+
+            ((int32_t *)block)[0] = 0;        ((int32_t *)block)[1] = 0;
+            ((int32_t *)block)[2] = 0;        ((int32_t *)block)[3] = 0;
+
+            dest += stride;
+            block += 8;
+        } while (--i);
+    } else {
+        int DC;
+
+        DC = (block[0] + 64) >> 7;
+        block[0] = block[63] = 0;
+        i = 8;
+        do {
+            dest[0] = CLIP (DC + dest[0]);
+            dest[1] = CLIP (DC + dest[1]);
+            dest[2] = CLIP (DC + dest[2]);
+            dest[3] = CLIP (DC + dest[3]);
+            dest[4] = CLIP (DC + dest[4]);
+            dest[5] = CLIP (DC + dest[5]);
+            dest[6] = CLIP (DC + dest[6]);
+            dest[7] = CLIP (DC + dest[7]);
+            dest += stride;
+        } while (--i);
+    }
+}
+
+void mpeg2_idct_init (uint32_t accel)
+{
+    (void)accel;
+#ifdef ARCH_X86
+    if (accel & MPEG2_ACCEL_X86_MMXEXT) {
+        mpeg2_idct_copy = mpeg2_idct_copy_mmxext;
+        mpeg2_idct_add = mpeg2_idct_add_mmxext;
+        mpeg2_idct_mmx_init ();
+    } else if (accel & MPEG2_ACCEL_X86_MMX) {
+        mpeg2_idct_copy = mpeg2_idct_copy_mmx;
+        mpeg2_idct_add = mpeg2_idct_add_mmx;
+        mpeg2_idct_mmx_init ();
+    } else
+#endif
+#ifdef ARCH_PPC
+    if (accel & MPEG2_ACCEL_PPC_ALTIVEC) {
+        mpeg2_idct_copy = mpeg2_idct_copy_altivec;
+        mpeg2_idct_add = mpeg2_idct_add_altivec;
+        mpeg2_idct_altivec_init ();
+    } else
+#endif
+#ifdef ARCH_ALPHA
+    if (accel & MPEG2_ACCEL_ALPHA_MVI) {
+        mpeg2_idct_copy = mpeg2_idct_copy_mvi;
+        mpeg2_idct_add = mpeg2_idct_add_mvi;
+        mpeg2_idct_alpha_init ();
+    } else if (accel & MPEG2_ACCEL_ALPHA) {
+        int i;
+
+        mpeg2_idct_copy = mpeg2_idct_copy_alpha;
+        mpeg2_idct_add = mpeg2_idct_add_alpha;
+        mpeg2_idct_alpha_init ();
+        for (i = -3840; i < 3840 + 256; i++)
+            CLIP(i) = (i < 0) ? 0 : ((i > 255) ? 255 : i);
+    } else
+#endif
+    {
+        extern uint8_t mpeg2_scan_norm[64];
+        extern uint8_t mpeg2_scan_alt[64];
+        int i, j;
+
+        mpeg2_idct_copy = mpeg2_idct_copy_c;
+        mpeg2_idct_add = mpeg2_idct_add_c;
+        for (i = -3840; i < 3840 + 256; i++)
+            CLIP(i) = (i < 0) ? 0 : ((i > 255) ? 255 : i);
+        for (i = 0; i < 64; i++) {
+            j = mpeg2_scan_norm[i];
+            mpeg2_scan_norm[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2);
+            j = mpeg2_scan_alt[i];
+            mpeg2_scan_alt[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2);
+        }
+    }
+}
diff --git a/apps/plugins/mpegplayer/motion_comp.c b/apps/plugins/mpegplayer/motion_comp.c
new file mode 100644
index 0000000..fbf2ee1
--- /dev/null
+++ b/apps/plugins/mpegplayer/motion_comp.c
@@ -0,0 +1,131 @@
+/*
+ * motion_comp.c
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec 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.
+ *
+ * mpeg2dec 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "plugin.h"
+
+#include "mpeg2dec_config.h"
+
+#include "mpeg2.h"
+#include "attributes.h"
+#include "mpeg2_internal.h"
+
+mpeg2_mc_t mpeg2_mc;
+
+void mpeg2_mc_init (uint32_t accel)
+{
+    (void)accel;
+#ifdef ARCH_X86
+    if (accel & MPEG2_ACCEL_X86_MMXEXT)
+        mpeg2_mc = mpeg2_mc_mmxext;
+    else if (accel & MPEG2_ACCEL_X86_3DNOW)
+        mpeg2_mc = mpeg2_mc_3dnow;
+    else if (accel & MPEG2_ACCEL_X86_MMX)
+        mpeg2_mc = mpeg2_mc_mmx;
+    else
+#endif
+#ifdef ARCH_PPC
+    if (accel & MPEG2_ACCEL_PPC_ALTIVEC)
+        mpeg2_mc = mpeg2_mc_altivec;
+    else
+#endif
+#ifdef ARCH_ALPHA
+    if (accel & MPEG2_ACCEL_ALPHA)
+        mpeg2_mc = mpeg2_mc_alpha;
+    else
+#endif
+#ifdef ARCH_SPARC
+    if (accel & MPEG2_ACCEL_SPARC_VIS)
+        mpeg2_mc = mpeg2_mc_vis;
+    else
+#endif
+        mpeg2_mc = mpeg2_mc_c;
+}
+
+#define avg2(a,b) ((a+b+1)>>1)
+#define avg4(a,b,c,d) ((a+b+c+d+2)>>2)
+
+#define predict_o(i) (ref[i])
+#define predict_x(i) (avg2 (ref[i], ref[i+1]))
+#define predict_y(i) (avg2 (ref[i], (ref+stride)[i]))
+#define predict_xy(i) (avg4 (ref[i], ref[i+1], \
+                             (ref+stride)[i], (ref+stride)[i+1]))
+
+#define put(predictor,i) dest[i] = predictor (i)
+#define avg(predictor,i) dest[i] = avg2 (predictor (i), dest[i])
+
+/* mc function template */
+
+#define MC_FUNC(op,xy)                                                        \
+static void MC_##op##_##xy##_16_c (uint8_t * dest, const uint8_t * ref,       \
+                                   const int stride, int height)              \
+{                                                                             \
+    do {                                                                      \
+        op (predict_##xy, 0);                                                 \
+        op (predict_##xy, 1);                                                 \
+        op (predict_##xy, 2);                                                 \
+        op (predict_##xy, 3);                                                 \
+        op (predict_##xy, 4);                                                 \
+        op (predict_##xy, 5);                                                 \
+        op (predict_##xy, 6);                                                 \
+        op (predict_##xy, 7);                                                 \
+        op (predict_##xy, 8);                                                 \
+        op (predict_##xy, 9);                                                 \
+        op (predict_##xy, 10);                                                \
+        op (predict_##xy, 11);                                                \
+        op (predict_##xy, 12);                                                \
+        op (predict_##xy, 13);                                                \
+        op (predict_##xy, 14);                                                \
+        op (predict_##xy, 15);                                                \
+        ref += stride;                                                        \
+        dest += stride;                                                       \
+    } while (--height);                                                       \
+}                                                                             \
+static void MC_##op##_##xy##_8_c (uint8_t * dest, const uint8_t * ref,        \
+                                  const int stride, int height)               \
+{                                                                             \
+    do {                                                                      \
+        op (predict_##xy, 0);                                                 \
+        op (predict_##xy, 1);                                                 \
+        op (predict_##xy, 2);                                                 \
+        op (predict_##xy, 3);                                                 \
+        op (predict_##xy, 4);                                                 \
+        op (predict_##xy, 5);                                                 \
+        op (predict_##xy, 6);                                                 \
+        op (predict_##xy, 7);                                                 \
+        ref += stride;                                                        \
+        dest += stride;                                                       \
+    } while (--height);                                                       \
+}
+
+/* definitions of the actual mc functions */
+
+MC_FUNC (put,o)
+MC_FUNC (avg,o)
+MC_FUNC (put,x)
+MC_FUNC (avg,x)
+MC_FUNC (put,y)
+MC_FUNC (avg,y)
+MC_FUNC (put,xy)
+MC_FUNC (avg,xy)
+
+MPEG2_MC_EXTERN (c)
diff --git a/apps/plugins/mpegplayer/mpeg2.h b/apps/plugins/mpegplayer/mpeg2.h
new file mode 100644
index 0000000..6062f93
--- /dev/null
+++ b/apps/plugins/mpegplayer/mpeg2.h
@@ -0,0 +1,195 @@
+/*
+ * mpeg2.h
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec 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.
+ *
+ * mpeg2dec 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef MPEG2_H
+#define MPEG2_H
+
+#define MPEG2_VERSION(a,b,c) (((a)<<16)|((b)<<8)|(c))
+#define MPEG2_RELEASE MPEG2_VERSION (0, 4, 0)	/* 0.4.0 */
+
+#define SEQ_FLAG_MPEG2 1
+#define SEQ_FLAG_CONSTRAINED_PARAMETERS 2
+#define SEQ_FLAG_PROGRESSIVE_SEQUENCE 4
+#define SEQ_FLAG_LOW_DELAY 8
+#define SEQ_FLAG_COLOUR_DESCRIPTION 16
+
+#define SEQ_MASK_VIDEO_FORMAT 0xe0
+#define SEQ_VIDEO_FORMAT_COMPONENT 0
+#define SEQ_VIDEO_FORMAT_PAL 0x20
+#define SEQ_VIDEO_FORMAT_NTSC 0x40
+#define SEQ_VIDEO_FORMAT_SECAM 0x60
+#define SEQ_VIDEO_FORMAT_MAC 0x80
+#define SEQ_VIDEO_FORMAT_UNSPECIFIED 0xa0
+
+typedef struct mpeg2_sequence_s {
+    unsigned int width, height;
+    unsigned int chroma_width, chroma_height;
+    unsigned int byte_rate;
+    unsigned int vbv_buffer_size;
+    uint32_t flags;
+
+    unsigned int picture_width, picture_height;
+    unsigned int display_width, display_height;
+    unsigned int pixel_width, pixel_height;
+    unsigned int frame_period;
+
+    uint8_t profile_level_id;
+    uint8_t colour_primaries;
+    uint8_t transfer_characteristics;
+    uint8_t matrix_coefficients;
+} mpeg2_sequence_t;
+
+#define GOP_FLAG_DROP_FRAME 1
+#define GOP_FLAG_BROKEN_LINK 2
+#define GOP_FLAG_CLOSED_GOP 4
+
+typedef struct mpeg2_gop_s {
+    uint8_t hours;
+    uint8_t minutes;
+    uint8_t seconds;
+    uint8_t pictures;
+    uint32_t flags;
+} mpeg2_gop_t;
+
+#define PIC_MASK_CODING_TYPE 7
+#define PIC_FLAG_CODING_TYPE_I 1
+#define PIC_FLAG_CODING_TYPE_P 2
+#define PIC_FLAG_CODING_TYPE_B 3
+#define PIC_FLAG_CODING_TYPE_D 4
+
+#define PIC_FLAG_TOP_FIELD_FIRST 8
+#define PIC_FLAG_PROGRESSIVE_FRAME 16
+#define PIC_FLAG_COMPOSITE_DISPLAY 32
+#define PIC_FLAG_SKIP 64
+#define PIC_FLAG_TAGS 128
+#define PIC_MASK_COMPOSITE_DISPLAY 0xfffff000
+
+typedef struct mpeg2_picture_s {
+    unsigned int temporal_reference;
+    unsigned int nb_fields;
+    uint32_t tag, tag2;
+    uint32_t flags;
+    struct {
+	int x, y;
+    } display_offset[3];
+} mpeg2_picture_t;
+
+typedef struct mpeg2_fbuf_s {
+    uint8_t * buf[3];
+    void * id;
+} mpeg2_fbuf_t;
+
+typedef struct mpeg2_info_s {
+    const mpeg2_sequence_t * sequence;
+    const mpeg2_gop_t * gop;
+    const mpeg2_picture_t * current_picture;
+    const mpeg2_picture_t * current_picture_2nd;
+    const mpeg2_fbuf_t * current_fbuf;
+    const mpeg2_picture_t * display_picture;
+    const mpeg2_picture_t * display_picture_2nd;
+    const mpeg2_fbuf_t * display_fbuf;
+    const mpeg2_fbuf_t * discard_fbuf;
+    const uint8_t * user_data;
+    unsigned int user_data_len;
+} mpeg2_info_t;
+
+typedef struct mpeg2dec_s mpeg2dec_t;
+typedef struct mpeg2_decoder_s mpeg2_decoder_t;
+
+typedef enum {
+    STATE_BUFFER = 0,
+    STATE_SEQUENCE = 1,
+    STATE_SEQUENCE_REPEATED = 2,
+    STATE_GOP = 3,
+    STATE_PICTURE = 4,
+    STATE_SLICE_1ST = 5,
+    STATE_PICTURE_2ND = 6,
+    STATE_SLICE = 7,
+    STATE_END = 8,
+    STATE_INVALID = 9,
+    STATE_INVALID_END = 10
+} mpeg2_state_t;
+
+typedef struct mpeg2_convert_init_s {
+    unsigned int id_size;
+    unsigned int buf_size[3];
+    void (* start) (void * id, const mpeg2_fbuf_t * fbuf,
+		    const mpeg2_picture_t * picture, const mpeg2_gop_t * gop);
+    void (* copy) (void * id, uint8_t * const * src, unsigned int v_offset);
+} mpeg2_convert_init_t;
+typedef enum {
+    MPEG2_CONVERT_SET = 0,
+    MPEG2_CONVERT_STRIDE = 1,
+    MPEG2_CONVERT_START = 2
+} mpeg2_convert_stage_t;
+typedef int mpeg2_convert_t (int stage, void * id,
+			     const mpeg2_sequence_t * sequence, int stride,
+			     uint32_t accel, void * arg,
+			     mpeg2_convert_init_t * result);
+int mpeg2_convert (mpeg2dec_t * mpeg2dec, mpeg2_convert_t convert, void * arg);
+int mpeg2_stride (mpeg2dec_t * mpeg2dec, int stride);
+void mpeg2_set_buf (mpeg2dec_t * mpeg2dec, uint8_t * buf[3], void * id);
+void mpeg2_custom_fbuf (mpeg2dec_t * mpeg2dec, int custom_fbuf);
+
+#define MPEG2_ACCEL_X86_MMX 1
+#define MPEG2_ACCEL_X86_3DNOW 2
+#define MPEG2_ACCEL_X86_MMXEXT 4
+#define MPEG2_ACCEL_PPC_ALTIVEC 1
+#define MPEG2_ACCEL_ALPHA 1
+#define MPEG2_ACCEL_ALPHA_MVI 2
+#define MPEG2_ACCEL_SPARC_VIS 1
+#define MPEG2_ACCEL_SPARC_VIS2 2
+#define MPEG2_ACCEL_DETECT 0x80000000
+
+uint32_t mpeg2_accel (uint32_t accel);
+mpeg2dec_t * mpeg2_init (void);
+const mpeg2_info_t * mpeg2_info (mpeg2dec_t * mpeg2dec);
+void mpeg2_close (mpeg2dec_t * mpeg2dec);
+
+void mpeg2_buffer (mpeg2dec_t * mpeg2dec, uint8_t * start, uint8_t * end);
+int mpeg2_getpos (mpeg2dec_t * mpeg2dec);
+mpeg2_state_t mpeg2_parse (mpeg2dec_t * mpeg2dec);
+
+void mpeg2_reset (mpeg2dec_t * mpeg2dec, int full_reset);
+void mpeg2_skip (mpeg2dec_t * mpeg2dec, int skip);
+void mpeg2_slice_region (mpeg2dec_t * mpeg2dec, int start, int end);
+
+void mpeg2_tag_picture (mpeg2dec_t * mpeg2dec, uint32_t tag, uint32_t tag2);
+
+void mpeg2_init_fbuf (mpeg2_decoder_t * decoder, uint8_t * current_fbuf[3],
+		      uint8_t * forward_fbuf[3], uint8_t * backward_fbuf[3]);
+void mpeg2_slice (mpeg2_decoder_t * decoder, int code, const uint8_t * buffer);
+
+typedef enum {
+    MPEG2_ALLOC_MPEG2DEC = 0,
+    MPEG2_ALLOC_CHUNK = 1,
+    MPEG2_ALLOC_YUV = 2,
+    MPEG2_ALLOC_CONVERT_ID = 3,
+    MPEG2_ALLOC_CONVERTED = 4
+} mpeg2_alloc_t;
+
+void * mpeg2_malloc (unsigned size, mpeg2_alloc_t reason);
+void mpeg2_free (void * buf);
+void mpeg2_alloc_init(unsigned char* buf, int mallocsize);
+
+#endif /* MPEG2_H */
diff --git a/apps/plugins/mpegplayer/mpeg2_internal.h b/apps/plugins/mpegplayer/mpeg2_internal.h
new file mode 100644
index 0000000..850456b
--- /dev/null
+++ b/apps/plugins/mpegplayer/mpeg2_internal.h
@@ -0,0 +1,300 @@
+/*
+ * mpeg2_internal.h
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec 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.
+ *
+ * mpeg2dec 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* macroblock modes */
+#define MACROBLOCK_INTRA 1
+#define MACROBLOCK_PATTERN 2
+#define MACROBLOCK_MOTION_BACKWARD 4
+#define MACROBLOCK_MOTION_FORWARD 8
+#define MACROBLOCK_QUANT 16
+#define DCT_TYPE_INTERLACED 32
+/* motion_type */
+#define MOTION_TYPE_SHIFT 6
+#define MC_FIELD 1
+#define MC_FRAME 2
+#define MC_16X8 2
+#define MC_DMV 3
+
+/* picture structure */
+#define TOP_FIELD 1
+#define BOTTOM_FIELD 2
+#define FRAME_PICTURE 3
+
+/* picture coding type */
+#define I_TYPE 1
+#define P_TYPE 2
+#define B_TYPE 3
+#define D_TYPE 4
+
+typedef void mpeg2_mc_fct (uint8_t *, const uint8_t *, int, int);
+
+typedef struct {
+    uint8_t * ref[2][3];
+    uint8_t ** ref2[2];
+    int pmv[2][2];
+    int f_code[2];
+} motion_t;
+
+typedef void motion_parser_t (mpeg2_decoder_t * decoder,
+			      motion_t * motion,
+			      mpeg2_mc_fct * const * table);
+
+struct mpeg2_decoder_s {
+    /* first, state that carries information from one macroblock to the */
+    /* next inside a slice, and is never used outside of mpeg2_slice() */
+
+    /* bit parsing stuff */
+    uint32_t bitstream_buf;		/* current 32 bit working set */
+    int bitstream_bits;			/* used bits in working set */
+    const uint8_t * bitstream_ptr;	/* buffer with stream data */
+
+    uint8_t * dest[3];
+
+    int offset;
+    int stride;
+    int uv_stride;
+    int slice_stride;
+    int slice_uv_stride;
+    int stride_frame;
+    unsigned int limit_x;
+    unsigned int limit_y_16;
+    unsigned int limit_y_8;
+    unsigned int limit_y;
+
+    /* Motion vectors */
+    /* The f_ and b_ correspond to the forward and backward motion */
+    /* predictors */
+    motion_t b_motion;
+    motion_t f_motion;
+    motion_parser_t * motion_parser[5];
+
+    /* predictor for DC coefficients in intra blocks */
+    int16_t dc_dct_pred[3];
+
+    /* DCT coefficients */
+    int16_t DCTblock[64] ATTR_ALIGN(64);
+
+    uint8_t * picture_dest[3];
+    void (* convert) (void * convert_id, uint8_t * const * src,
+		      unsigned int v_offset);
+    void * convert_id;
+
+    int dmv_offset;
+    unsigned int v_offset;
+
+    /* now non-slice-specific information */
+
+    /* sequence header stuff */
+    uint16_t * quantizer_matrix[4];
+    uint16_t (* chroma_quantizer[2])[64];
+    uint16_t quantizer_prescale[4][32][64];
+
+    /* The width and height of the picture snapped to macroblock units */
+    int width;
+    int height;
+    int vertical_position_extension;
+    int chroma_format;
+
+    /* picture header stuff */
+
+    /* what type of picture this is (I, P, B, D) */
+    int coding_type;
+
+    /* picture coding extension stuff */
+
+    /* quantization factor for intra dc coefficients */
+    int intra_dc_precision;
+    /* top/bottom/both fields */
+    int picture_structure;
+    /* bool to indicate all predictions are frame based */
+    int frame_pred_frame_dct;
+    /* bool to indicate whether intra blocks have motion vectors */
+    /* (for concealment) */
+    int concealment_motion_vectors;
+    /* bool to use different vlc tables */
+    int intra_vlc_format;
+    /* used for DMV MC */
+    int top_field_first;
+
+    /* stuff derived from bitstream */
+
+    /* pointer to the zigzag scan we're supposed to be using */
+    const uint8_t * scan;
+
+    int second_field;
+
+    int mpeg1;
+};
+
+typedef struct {
+    mpeg2_fbuf_t fbuf;
+} fbuf_alloc_t;
+
+struct mpeg2dec_s {
+    mpeg2_decoder_t decoder;
+
+    mpeg2_info_t info;
+
+    uint32_t shift;
+    int is_display_initialized;
+    mpeg2_state_t (* action) (struct mpeg2dec_s * mpeg2dec);
+    mpeg2_state_t state;
+    uint32_t ext_state;
+
+    /* allocated in init - gcc has problems allocating such big structures */
+    uint8_t * chunk_buffer;
+    /* pointer to start of the current chunk */
+    uint8_t * chunk_start;
+    /* pointer to current position in chunk_buffer */
+    uint8_t * chunk_ptr;
+    /* last start code ? */
+    uint8_t code;
+
+    /* picture tags */
+    uint32_t tag_current, tag2_current, tag_previous, tag2_previous;
+    int num_tags;
+    int bytes_since_tag;
+
+    int first;
+    int alloc_index_user;
+    int alloc_index;
+    uint8_t first_decode_slice;
+    uint8_t nb_decode_slices;
+
+    unsigned int user_data_len;
+
+    mpeg2_sequence_t new_sequence;
+    mpeg2_sequence_t sequence;
+    mpeg2_gop_t new_gop;
+    mpeg2_gop_t gop;
+    mpeg2_picture_t new_picture;
+    mpeg2_picture_t pictures[4];
+    mpeg2_picture_t * picture;
+    /*const*/ mpeg2_fbuf_t * fbuf[3];	/* 0: current fbuf, 1-2: prediction fbufs */
+
+    fbuf_alloc_t fbuf_alloc[3];
+    int custom_fbuf;
+
+    uint8_t * yuv_buf[3][3];
+    int yuv_index;
+    mpeg2_convert_t * convert;
+    void * convert_arg;
+    unsigned int convert_id_size;
+    int convert_stride;
+    void (* convert_start) (void * id, const mpeg2_fbuf_t * fbuf,
+			    const mpeg2_picture_t * picture,
+			    const mpeg2_gop_t * gop);
+
+    uint8_t * buf_start;
+    uint8_t * buf_end;
+
+    int16_t display_offset_x, display_offset_y;
+
+    int copy_matrix;
+    int8_t q_scale_type, scaled[4];
+    uint8_t quantizer_matrix[4][64];
+    uint8_t new_quantizer_matrix[4][64];
+};
+
+typedef struct {
+#ifdef ARCH_PPC
+    uint8_t regv[12*16];
+#endif
+    int dummy;
+} cpu_state_t;
+
+/* cpu_accel.c */
+uint32_t mpeg2_detect_accel (void);
+
+/* cpu_state.c */
+void mpeg2_cpu_state_init (uint32_t accel);
+
+/* decode.c */
+mpeg2_state_t mpeg2_seek_header (mpeg2dec_t * mpeg2dec);
+mpeg2_state_t mpeg2_parse_header (mpeg2dec_t * mpeg2dec);
+
+/* header.c */
+void mpeg2_header_state_init (mpeg2dec_t * mpeg2dec);
+void mpeg2_reset_info (mpeg2_info_t * info);
+int mpeg2_header_sequence (mpeg2dec_t * mpeg2dec);
+int mpeg2_header_gop (mpeg2dec_t * mpeg2dec);
+mpeg2_state_t mpeg2_header_picture_start (mpeg2dec_t * mpeg2dec);
+int mpeg2_header_picture (mpeg2dec_t * mpeg2dec);
+int mpeg2_header_extension (mpeg2dec_t * mpeg2dec);
+int mpeg2_header_user_data (mpeg2dec_t * mpeg2dec);
+void mpeg2_header_sequence_finalize (mpeg2dec_t * mpeg2dec);
+void mpeg2_header_gop_finalize (mpeg2dec_t * mpeg2dec);
+void mpeg2_header_picture_finalize (mpeg2dec_t * mpeg2dec, uint32_t accels);
+mpeg2_state_t mpeg2_header_slice_start (mpeg2dec_t * mpeg2dec);
+mpeg2_state_t mpeg2_header_end (mpeg2dec_t * mpeg2dec);
+void mpeg2_set_fbuf (mpeg2dec_t * mpeg2dec, int b_type);
+
+/* idct.c */
+void mpeg2_idct_init (uint32_t accel);
+
+/* idct_mmx.c */
+void mpeg2_idct_copy_mmxext (int16_t * block, uint8_t * dest, int stride);
+void mpeg2_idct_add_mmxext (int last, int16_t * block,
+			    uint8_t * dest, int stride);
+void mpeg2_idct_copy_mmx (int16_t * block, uint8_t * dest, int stride);
+void mpeg2_idct_add_mmx (int last, int16_t * block,
+			 uint8_t * dest, int stride);
+void mpeg2_idct_mmx_init (void);
+
+/* idct_altivec.c */
+void mpeg2_idct_copy_altivec (int16_t * block, uint8_t * dest, int stride);
+void mpeg2_idct_add_altivec (int last, int16_t * block,
+			     uint8_t * dest, int stride);
+void mpeg2_idct_altivec_init (void);
+
+/* idct_alpha.c */
+void mpeg2_idct_copy_mvi (int16_t * block, uint8_t * dest, int stride);
+void mpeg2_idct_add_mvi (int last, int16_t * block,
+			 uint8_t * dest, int stride);
+void mpeg2_idct_copy_alpha (int16_t * block, uint8_t * dest, int stride);
+void mpeg2_idct_add_alpha (int last, int16_t * block,
+			   uint8_t * dest, int stride);
+void mpeg2_idct_alpha_init (void);
+
+/* motion_comp.c */
+void mpeg2_mc_init (uint32_t accel);
+
+typedef struct {
+    mpeg2_mc_fct * put [8];
+    mpeg2_mc_fct * avg [8];
+} mpeg2_mc_t;
+
+#define MPEG2_MC_EXTERN(x) mpeg2_mc_t mpeg2_mc_##x = {			  \
+    {MC_put_o_16_##x, MC_put_x_16_##x, MC_put_y_16_##x, MC_put_xy_16_##x, \
+     MC_put_o_8_##x,  MC_put_x_8_##x,  MC_put_y_8_##x,  MC_put_xy_8_##x}, \
+    {MC_avg_o_16_##x, MC_avg_x_16_##x, MC_avg_y_16_##x, MC_avg_xy_16_##x, \
+     MC_avg_o_8_##x,  MC_avg_x_8_##x,  MC_avg_y_8_##x,  MC_avg_xy_8_##x}  \
+};
+
+extern mpeg2_mc_t mpeg2_mc_c;
+extern mpeg2_mc_t mpeg2_mc_mmx;
+extern mpeg2_mc_t mpeg2_mc_mmxext;
+extern mpeg2_mc_t mpeg2_mc_3dnow;
+extern mpeg2_mc_t mpeg2_mc_altivec;
+extern mpeg2_mc_t mpeg2_mc_alpha;
+extern mpeg2_mc_t mpeg2_mc_vis;
diff --git a/apps/plugins/mpegplayer/mpeg2dec_config.h b/apps/plugins/mpegplayer/mpeg2dec_config.h
new file mode 100644
index 0000000..b8ad116
--- /dev/null
+++ b/apps/plugins/mpegplayer/mpeg2dec_config.h
@@ -0,0 +1,2 @@
+#define ATTRIBUTE_ALIGNED_MAX 16
+
diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c
new file mode 100644
index 0000000..ce4199a
--- /dev/null
+++ b/apps/plugins/mpegplayer/mpegplayer.c
@@ -0,0 +1,246 @@
+/*
+ * mpegplayer.c - based on  mpeg2dec.c
+ *
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec 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.
+ *
+ * mpeg2dec 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "mpeg2dec_config.h"
+
+#include "plugin.h"
+
+#include "mpeg2.h"
+#include "video_out.h"
+
+PLUGIN_HEADER
+
+#ifdef USE_IRAM
+extern char iramcopy[];
+extern char iramstart[];
+extern char iramend[];
+extern char iedata[];
+extern char iend[];
+#endif
+
+struct plugin_api* rb;
+
+#define BUFFER_SIZE 25*1024*1024
+
+static mpeg2dec_t * mpeg2dec;
+static vo_open_t * output_open = NULL;
+static vo_instance_t * output;
+static int total_offset = 0;
+
+extern vo_open_t vo_rockbox_open;
+
+static void decode_mpeg2 (uint8_t * current, uint8_t * end)
+{
+    const mpeg2_info_t * info;
+    mpeg2_state_t state;
+    vo_setup_result_t setup_result;
+
+    mpeg2_buffer (mpeg2dec, current, end);
+    total_offset += end - current;
+
+    info = mpeg2_info (mpeg2dec);
+    while (1) {
+        state = mpeg2_parse (mpeg2dec);
+
+        switch (state) {
+        case STATE_BUFFER:
+            return;
+        case STATE_SEQUENCE:
+            /* might set nb fbuf, convert format, stride */
+            /* might set fbufs */
+            if (output->setup (output, info->sequence->width,
+                               info->sequence->height,
+                               info->sequence->chroma_width,
+                               info->sequence->chroma_height, &setup_result)) {
+                //fprintf (stderr, "display setup failed\n");
+                return;
+            }
+            if (setup_result.convert &&
+                mpeg2_convert (mpeg2dec, setup_result.convert, NULL)) {
+                //fprintf (stderr, "color conversion setup failed\n");
+                return;
+            }
+            if (output->set_fbuf) {
+                uint8_t * buf[3];
+                void * id;
+
+                mpeg2_custom_fbuf (mpeg2dec, 1);
+                output->set_fbuf (output, buf, &id);
+                mpeg2_set_buf (mpeg2dec, buf, id);
+                output->set_fbuf (output, buf, &id);
+                mpeg2_set_buf (mpeg2dec, buf, id);
+            } else if (output->setup_fbuf) {
+                uint8_t * buf[3];
+                void * id;
+
+                output->setup_fbuf (output, buf, &id);
+                mpeg2_set_buf (mpeg2dec, buf, id);
+                output->setup_fbuf (output, buf, &id);
+                mpeg2_set_buf (mpeg2dec, buf, id);
+                output->setup_fbuf (output, buf, &id);
+                mpeg2_set_buf (mpeg2dec, buf, id);
+            }
+            mpeg2_skip (mpeg2dec, (output->draw == NULL));
+            break;
+        case STATE_PICTURE:
+            /* might skip */
+            /* might set fbuf */
+            if (output->set_fbuf) {
+                uint8_t * buf[3];
+                void * id;
+
+                output->set_fbuf (output, buf, &id);
+                mpeg2_set_buf (mpeg2dec, buf, id);
+            }
+            if (output->start_fbuf)
+                output->start_fbuf (output, info->current_fbuf->buf,
+                                    info->current_fbuf->id);
+            break;
+        case STATE_SLICE:
+        case STATE_END:
+        case STATE_INVALID_END:
+            /* draw current picture */
+            /* might free frame buffer */
+            if (info->display_fbuf) {
+                if (output->draw)
+                    output->draw (output, info->display_fbuf->buf,
+                                  info->display_fbuf->id);
+                //print_fps (0);
+            }
+            if (output->discard && info->discard_fbuf)
+                output->discard (output, info->discard_fbuf->buf,
+                                 info->discard_fbuf->id);
+            break;
+        default:
+            break;
+        }
+
+        rb->yield();
+    }
+}
+
+static void es_loop (int in_file)
+{
+    static uint8_t* buffer;
+    uint8_t * end;
+
+    buffer=mpeg2_malloc(BUFFER_SIZE,0);
+
+    if (buffer==NULL)
+        return;
+
+    do {
+        rb->splash(0,true,"Buffering...");
+        end = buffer + rb->read (in_file, buffer, BUFFER_SIZE);
+        decode_mpeg2 (buffer, end);
+    } while (end == buffer + BUFFER_SIZE);
+}
+
+enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
+{
+    (void)parameter;
+    void* audiobuf;
+    int audiosize;
+    int in_file;
+
+    rb = api;
+
+    /* This also stops audio playback - so we do it before using IRAM */
+    audiobuf = rb->plugin_get_audio_buffer(&audiosize);
+
+    /* Initialise our malloc buffer */
+    mpeg2_alloc_init(audiobuf,audiosize);
+
+#ifdef USE_IRAM
+    rb->memcpy(iramstart, iramcopy, iramend-iramstart);
+    rb->memset(iedata, 0, iend - iedata);
+#endif
+
+#ifdef HAVE_LCD_COLOR
+    rb->lcd_set_foreground(LCD_WHITE);
+    rb->lcd_set_background(LCD_BLACK);
+#endif
+    rb->lcd_clear_display();
+    rb->lcd_update();
+
+    if (parameter == NULL) {
+        return PLUGIN_ERROR;
+    }
+
+    in_file = rb->open((char*)parameter,O_RDONLY);
+
+    if (in_file < 0) {
+        //fprintf(stderr,"Could not open %s\n",argv[1]);
+        return PLUGIN_ERROR;
+    }
+
+    output_open = vo_rockbox_open;
+
+    if (output_open == NULL) {
+        //fprintf (stderr, "output_open is NULL\n");
+        return PLUGIN_ERROR;
+    }
+
+    output = output_open ();
+
+    if (output == NULL) {
+        //fprintf (stderr, "Can not open output\n");
+        return PLUGIN_ERROR;
+    }
+
+    mpeg2dec = mpeg2_init ();
+
+    if (mpeg2dec == NULL)
+        return PLUGIN_ERROR;
+
+    /* make sure the backlight is always on when viewing video
+       (actually it should also set the timeout when plugged in,
+       but the function backlight_set_timeout_plugged is not
+       available in plugins) */
+#ifdef CONFIG_BACKLIGHT
+    if (rb->global_settings->backlight_timeout > 0)
+        rb->backlight_set_timeout(1);
+#endif
+
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+    rb->cpu_boost(true);
+#endif
+
+    es_loop (in_file);
+
+    mpeg2_close (mpeg2dec);
+
+    rb->close (in_file);
+
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+    rb->cpu_boost(false);
+#endif
+
+#ifdef CONFIG_BACKLIGHT
+    /* reset backlight settings */
+    rb->backlight_set_timeout(rb->global_settings->backlight_timeout);
+#endif
+
+    return PLUGIN_OK;
+}
diff --git a/apps/plugins/mpegplayer/slice.c b/apps/plugins/mpegplayer/slice.c
new file mode 100644
index 0000000..8ee3417
--- /dev/null
+++ b/apps/plugins/mpegplayer/slice.c
@@ -0,0 +1,2060 @@
+/*
+ * slice.c
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 2003      Peter Gubanov <peter@elecard.net.ru>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec 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.
+ *
+ * mpeg2dec 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "plugin.h"
+
+#include "mpeg2dec_config.h"
+
+#include "mpeg2.h"
+#include "attributes.h"
+#include "mpeg2_internal.h"
+
+extern mpeg2_mc_t mpeg2_mc;
+extern void (* mpeg2_idct_copy) (int16_t * block, uint8_t * dest, int stride);
+extern void (* mpeg2_idct_add) (int last, int16_t * block,
+                                uint8_t * dest, int stride);
+extern void (* mpeg2_cpu_state_save) (cpu_state_t * state);
+extern void (* mpeg2_cpu_state_restore) (cpu_state_t * state);
+
+#include "vlc.h"
+
+static inline int get_macroblock_modes (mpeg2_decoder_t * const decoder)
+{
+#define bit_buf (decoder->bitstream_buf)
+#define bits (decoder->bitstream_bits)
+#define bit_ptr (decoder->bitstream_ptr)
+    int macroblock_modes;
+    const MBtab * tab;
+
+    switch (decoder->coding_type) {
+    case I_TYPE:
+
+        tab = MB_I + UBITS (bit_buf, 1);
+        DUMPBITS (bit_buf, bits, tab->len);
+        macroblock_modes = tab->modes;
+
+        if ((! (decoder->frame_pred_frame_dct)) &&
+            (decoder->picture_structure == FRAME_PICTURE)) {
+            macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED;
+            DUMPBITS (bit_buf, bits, 1);
+        }
+
+        return macroblock_modes;
+
+    case P_TYPE:
+
+        tab = MB_P + UBITS (bit_buf, 5);
+        DUMPBITS (bit_buf, bits, tab->len);
+        macroblock_modes = tab->modes;
+
+        if (decoder->picture_structure != FRAME_PICTURE) {
+            if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) {
+                macroblock_modes |= UBITS (bit_buf, 2) << MOTION_TYPE_SHIFT;
+                DUMPBITS (bit_buf, bits, 2);
+            }
+            return macroblock_modes | MACROBLOCK_MOTION_FORWARD;
+        } else if (decoder->frame_pred_frame_dct) {
+            if (macroblock_modes & MACROBLOCK_MOTION_FORWARD)
+                macroblock_modes |= MC_FRAME << MOTION_TYPE_SHIFT;
+            return macroblock_modes | MACROBLOCK_MOTION_FORWARD;
+        } else {
+            if (macroblock_modes & MACROBLOCK_MOTION_FORWARD) {
+                macroblock_modes |= UBITS (bit_buf, 2) << MOTION_TYPE_SHIFT;
+                DUMPBITS (bit_buf, bits, 2);
+            }
+            if (macroblock_modes & (MACROBLOCK_INTRA | MACROBLOCK_PATTERN)) {
+                macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED;
+                DUMPBITS (bit_buf, bits, 1);
+            }
+            return macroblock_modes | MACROBLOCK_MOTION_FORWARD;
+        }
+
+    case B_TYPE:
+
+        tab = MB_B + UBITS (bit_buf, 6);
+        DUMPBITS (bit_buf, bits, tab->len);
+        macroblock_modes = tab->modes;
+
+        if (decoder->picture_structure != FRAME_PICTURE) {
+            if (! (macroblock_modes & MACROBLOCK_INTRA)) {
+                macroblock_modes |= UBITS (bit_buf, 2) << MOTION_TYPE_SHIFT;
+                DUMPBITS (bit_buf, bits, 2);
+            }
+            return macroblock_modes;
+        } else if (decoder->frame_pred_frame_dct) {
+            /* if (! (macroblock_modes & MACROBLOCK_INTRA)) */
+            macroblock_modes |= MC_FRAME << MOTION_TYPE_SHIFT;
+            return macroblock_modes;
+        } else {
+            if (macroblock_modes & MACROBLOCK_INTRA)
+                goto intra;
+            macroblock_modes |= UBITS (bit_buf, 2) << MOTION_TYPE_SHIFT;
+            DUMPBITS (bit_buf, bits, 2);
+            if (macroblock_modes & (MACROBLOCK_INTRA | MACROBLOCK_PATTERN)) {
+            intra:
+                macroblock_modes |= UBITS (bit_buf, 1) * DCT_TYPE_INTERLACED;
+                DUMPBITS (bit_buf, bits, 1);
+            }
+            return macroblock_modes;
+        }
+
+    case D_TYPE:
+
+        DUMPBITS (bit_buf, bits, 1);
+        return MACROBLOCK_INTRA;
+
+    default:
+        return 0;
+    }
+#undef bit_buf
+#undef bits
+#undef bit_ptr
+}
+
+static inline void get_quantizer_scale (mpeg2_decoder_t * const decoder)
+{
+#define bit_buf (decoder->bitstream_buf)
+#define bits (decoder->bitstream_bits)
+#define bit_ptr (decoder->bitstream_ptr)
+
+    int quantizer_scale_code;
+
+    quantizer_scale_code = UBITS (bit_buf, 5);
+    DUMPBITS (bit_buf, bits, 5);
+
+    decoder->quantizer_matrix[0] =
+        decoder->quantizer_prescale[0][quantizer_scale_code];
+    decoder->quantizer_matrix[1] =
+        decoder->quantizer_prescale[1][quantizer_scale_code];
+    decoder->quantizer_matrix[2] =
+        decoder->chroma_quantizer[0][quantizer_scale_code];
+    decoder->quantizer_matrix[3] =
+        decoder->chroma_quantizer[1][quantizer_scale_code];
+#undef bit_buf
+#undef bits
+#undef bit_ptr
+}
+
+static inline int get_motion_delta (mpeg2_decoder_t * const decoder,
+                                    const int f_code)
+{
+#define bit_buf (decoder->bitstream_buf)
+#define bits (decoder->bitstream_bits)
+#define bit_ptr (decoder->bitstream_ptr)
+
+    int delta;
+    int sign;
+    const MVtab * tab;
+
+    if (bit_buf & 0x80000000) {
+        DUMPBITS (bit_buf, bits, 1);
+        return 0;
+    } else if (bit_buf >= 0x0c000000) {
+
+        tab = MV_4 + UBITS (bit_buf, 4);
+        delta = (tab->delta << f_code) + 1;
+        bits += tab->len + f_code + 1;
+        bit_buf <<= tab->len;
+
+        sign = SBITS (bit_buf, 1);
+        bit_buf <<= 1;
+
+        if (f_code)
+            delta += UBITS (bit_buf, f_code);
+        bit_buf <<= f_code;
+
+        return (delta ^ sign) - sign;
+
+    } else {
+
+        tab = MV_10 + UBITS (bit_buf, 10);
+        delta = (tab->delta << f_code) + 1;
+        bits += tab->len + 1;
+        bit_buf <<= tab->len;
+
+        sign = SBITS (bit_buf, 1);
+        bit_buf <<= 1;
+
+        if (f_code) {
+            NEEDBITS (bit_buf, bits, bit_ptr);
+            delta += UBITS (bit_buf, f_code);
+            DUMPBITS (bit_buf, bits, f_code);
+        }
+
+        return (delta ^ sign) - sign;
+
+    }
+#undef bit_buf
+#undef bits
+#undef bit_ptr
+}
+
+static inline int bound_motion_vector (const int vector, const int f_code)
+{
+    return ((int32_t)vector << (27 - f_code)) >> (27 - f_code);
+}
+
+static inline int get_dmv (mpeg2_decoder_t * const decoder)
+{
+#define bit_buf (decoder->bitstream_buf)
+#define bits (decoder->bitstream_bits)
+#define bit_ptr (decoder->bitstream_ptr)
+
+    const DMVtab * tab;
+
+    tab = DMV_2 + UBITS (bit_buf, 2);
+    DUMPBITS (bit_buf, bits, tab->len);
+    return tab->dmv;
+#undef bit_buf
+#undef bits
+#undef bit_ptr
+}
+
+static inline int get_coded_block_pattern (mpeg2_decoder_t * const decoder)
+{
+#define bit_buf (decoder->bitstream_buf)
+#define bits (decoder->bitstream_bits)
+#define bit_ptr (decoder->bitstream_ptr)
+
+    const CBPtab * tab;
+
+    NEEDBITS (bit_buf, bits, bit_ptr);
+
+    if (bit_buf >= 0x20000000) {
+
+        tab = CBP_7 + (UBITS (bit_buf, 7) - 16);
+        DUMPBITS (bit_buf, bits, tab->len);
+        return tab->cbp;
+
+    } else {
+
+        tab = CBP_9 + UBITS (bit_buf, 9);
+        DUMPBITS (bit_buf, bits, tab->len);
+        return tab->cbp;
+    }
+
+#undef bit_buf
+#undef bits
+#undef bit_ptr
+}
+
+static inline int get_luma_dc_dct_diff (mpeg2_decoder_t * const decoder)
+{
+#define bit_buf (decoder->bitstream_buf)
+#define bits (decoder->bitstream_bits)
+#define bit_ptr (decoder->bitstream_ptr)
+    const DCtab * tab;
+    int size;
+    int dc_diff;
+
+    if (bit_buf < 0xf8000000) {
+        tab = DC_lum_5 + UBITS (bit_buf, 5);
+        size = tab->size;
+        if (size) {
+            bits += tab->len + size;
+            bit_buf <<= tab->len;
+            dc_diff =
+                UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size);
+            bit_buf <<= size;
+            return dc_diff << decoder->intra_dc_precision;
+        } else {
+            DUMPBITS (bit_buf, bits, 3);
+            return 0;
+        }
+    } else {
+        tab = DC_long + (UBITS (bit_buf, 9) - 0x1e0);
+        size = tab->size;
+        DUMPBITS (bit_buf, bits, tab->len);
+        NEEDBITS (bit_buf, bits, bit_ptr);
+        dc_diff = UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size);
+        DUMPBITS (bit_buf, bits, size);
+        return dc_diff << decoder->intra_dc_precision;
+    }
+#undef bit_buf
+#undef bits
+#undef bit_ptr
+}
+
+static inline int get_chroma_dc_dct_diff (mpeg2_decoder_t * const decoder)
+{
+#define bit_buf (decoder->bitstream_buf)
+#define bits (decoder->bitstream_bits)
+#define bit_ptr (decoder->bitstream_ptr)
+    const DCtab * tab;
+    int size;
+    int dc_diff;
+
+    if (bit_buf < 0xf8000000) {
+        tab = DC_chrom_5 + UBITS (bit_buf, 5);
+        size = tab->size;
+        if (size) {
+            bits += tab->len + size;
+            bit_buf <<= tab->len;
+            dc_diff =
+                UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size);
+            bit_buf <<= size;
+            return dc_diff << decoder->intra_dc_precision;
+        } else {
+            DUMPBITS (bit_buf, bits, 2);
+            return 0;
+        }
+    } else {
+        tab = DC_long + (UBITS (bit_buf, 10) - 0x3e0);
+        size = tab->size;
+        DUMPBITS (bit_buf, bits, tab->len + 1);
+        NEEDBITS (bit_buf, bits, bit_ptr);
+        dc_diff = UBITS (bit_buf, size) - UBITS (SBITS (~bit_buf, 1), size);
+        DUMPBITS (bit_buf, bits, size);
+        return dc_diff << decoder->intra_dc_precision;
+    }
+#undef bit_buf
+#undef bits
+#undef bit_ptr
+}
+
+#define SATURATE(val)                                \
+do {                                                \
+    val <<= 4;                                        \
+    if (unlikely (val != (int16_t) val))        \
+        val = (SBITS (val, 1) ^ 2047) << 4;        \
+} while (0)
+
+static void get_intra_block_B14 (mpeg2_decoder_t * const decoder,
+                                 const uint16_t * const quant_matrix)
+{
+    int i;
+    int j;
+    int val;
+    const uint8_t * const scan = decoder->scan;
+    int mismatch;
+    const DCTtab * tab;
+    uint32_t bit_buf;
+    int bits;
+    const uint8_t * bit_ptr;
+    int16_t * const dest = decoder->DCTblock;
+
+    i = 0;
+    mismatch = ~dest[0];
+
+    bit_buf = decoder->bitstream_buf;
+    bits = decoder->bitstream_bits;
+    bit_ptr = decoder->bitstream_ptr;
+
+    NEEDBITS (bit_buf, bits, bit_ptr);
+
+    while (1) {
+        if (bit_buf >= 0x28000000) {
+
+            tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5);
+
+            i += tab->run;
+            if (i >= 64)
+                break;        /* end of block */
+
+        normal_code:
+            j = scan[i];
+            bit_buf <<= tab->len;
+            bits += tab->len + 1;
+            val = (tab->level * quant_matrix[j]) >> 4;
+
+            /* if (bitstream_get (1)) val = -val; */
+            val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1);
+
+            SATURATE (val);
+            dest[j] = val;
+            mismatch ^= val;
+
+            bit_buf <<= 1;
+            NEEDBITS (bit_buf, bits, bit_ptr);
+
+            continue;
+
+        } else if (bit_buf >= 0x04000000) {
+
+            tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4);
+
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+
+            /* escape code */
+
+            i += UBITS (bit_buf << 6, 6) - 64;
+            if (i >= 64)
+                break;        /* illegal, check needed to avoid buffer overflow */
+
+            j = scan[i];
+
+            DUMPBITS (bit_buf, bits, 12);
+            NEEDBITS (bit_buf, bits, bit_ptr);
+            val = (SBITS (bit_buf, 12) * quant_matrix[j]) / 16;
+
+            SATURATE (val);
+            dest[j] = val;
+            mismatch ^= val;
+
+            DUMPBITS (bit_buf, bits, 12);
+            NEEDBITS (bit_buf, bits, bit_ptr);
+
+            continue;
+
+        } else if (bit_buf >= 0x02000000) {
+            tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        } else if (bit_buf >= 0x00800000) {
+            tab = DCT_13 + (UBITS (bit_buf, 13) - 16);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        } else if (bit_buf >= 0x00200000) {
+            tab = DCT_15 + (UBITS (bit_buf, 15) - 16);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        } else {
+            tab = DCT_16 + UBITS (bit_buf, 16);
+            bit_buf <<= 16;
+            GETWORD (bit_buf, bits + 16, bit_ptr);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        }
+        break;        /* illegal, check needed to avoid buffer overflow */
+    }
+    dest[63] ^= mismatch & 16;
+    DUMPBITS (bit_buf, bits, 2);        /* dump end of block code */
+    decoder->bitstream_buf = bit_buf;
+    decoder->bitstream_bits = bits;
+    decoder->bitstream_ptr = bit_ptr;
+}
+
+static void get_intra_block_B15 (mpeg2_decoder_t * const decoder,
+                                 const uint16_t * const quant_matrix)
+{
+    int i;
+    int j;
+    int val;
+    const uint8_t * const scan = decoder->scan;
+    int mismatch;
+    const DCTtab * tab;
+    uint32_t bit_buf;
+    int bits;
+    const uint8_t * bit_ptr;
+    int16_t * const dest = decoder->DCTblock;
+
+    i = 0;
+    mismatch = ~dest[0];
+
+    bit_buf = decoder->bitstream_buf;
+    bits = decoder->bitstream_bits;
+    bit_ptr = decoder->bitstream_ptr;
+
+    NEEDBITS (bit_buf, bits, bit_ptr);
+
+    while (1) {
+        if (bit_buf >= 0x04000000) {
+
+            tab = DCT_B15_8 + (UBITS (bit_buf, 8) - 4);
+
+            i += tab->run;
+            if (i < 64) {
+
+            normal_code:
+                j = scan[i];
+                bit_buf <<= tab->len;
+                bits += tab->len + 1;
+                val = (tab->level * quant_matrix[j]) >> 4;
+
+                /* if (bitstream_get (1)) val = -val; */
+                val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1);
+
+                SATURATE (val);
+                dest[j] = val;
+                mismatch ^= val;
+
+                bit_buf <<= 1;
+                NEEDBITS (bit_buf, bits, bit_ptr);
+
+                continue;
+
+            } else {
+
+                /* end of block. I commented out this code because if we */
+                /* dont exit here we will still exit at the later test :) */
+
+                /* if (i >= 128) break;        */        /* end of block */
+
+                /* escape code */
+
+                i += UBITS (bit_buf << 6, 6) - 64;
+                if (i >= 64)
+                    break;        /* illegal, check against buffer overflow */
+
+                j = scan[i];
+
+                DUMPBITS (bit_buf, bits, 12);
+                NEEDBITS (bit_buf, bits, bit_ptr);
+                val = (SBITS (bit_buf, 12) * quant_matrix[j]) / 16;
+
+                SATURATE (val);
+                dest[j] = val;
+                mismatch ^= val;
+
+                DUMPBITS (bit_buf, bits, 12);
+                NEEDBITS (bit_buf, bits, bit_ptr);
+
+                continue;
+
+            }
+        } else if (bit_buf >= 0x02000000) {
+            tab = DCT_B15_10 + (UBITS (bit_buf, 10) - 8);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        } else if (bit_buf >= 0x00800000) {
+            tab = DCT_13 + (UBITS (bit_buf, 13) - 16);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        } else if (bit_buf >= 0x00200000) {
+            tab = DCT_15 + (UBITS (bit_buf, 15) - 16);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        } else {
+            tab = DCT_16 + UBITS (bit_buf, 16);
+            bit_buf <<= 16;
+            GETWORD (bit_buf, bits + 16, bit_ptr);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        }
+        break;        /* illegal, check needed to avoid buffer overflow */
+    }
+    dest[63] ^= mismatch & 16;
+    DUMPBITS (bit_buf, bits, 4);        /* dump end of block code */
+    decoder->bitstream_buf = bit_buf;
+    decoder->bitstream_bits = bits;
+    decoder->bitstream_ptr = bit_ptr;
+}
+
+static int get_non_intra_block (mpeg2_decoder_t * const decoder,
+                                const uint16_t * const quant_matrix)
+{
+    int i;
+    int j;
+    int val;
+    const uint8_t * const scan = decoder->scan;
+    int mismatch;
+    const DCTtab * tab;
+    uint32_t bit_buf;
+    int bits;
+    const uint8_t * bit_ptr;
+    int16_t * const dest = decoder->DCTblock;
+
+    i = -1;
+    mismatch = -1;
+
+    bit_buf = decoder->bitstream_buf;
+    bits = decoder->bitstream_bits;
+    bit_ptr = decoder->bitstream_ptr;
+
+    NEEDBITS (bit_buf, bits, bit_ptr);
+    if (bit_buf >= 0x28000000) {
+        tab = DCT_B14DC_5 + (UBITS (bit_buf, 5) - 5);
+        goto entry_1;
+    } else
+        goto entry_2;
+
+    while (1) {
+        if (bit_buf >= 0x28000000) {
+
+            tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5);
+
+        entry_1:
+            i += tab->run;
+            if (i >= 64)
+                break;        /* end of block */
+
+        normal_code:
+            j = scan[i];
+            bit_buf <<= tab->len;
+            bits += tab->len + 1;
+            val = ((2 * tab->level + 1) * quant_matrix[j]) >> 5;
+
+            /* if (bitstream_get (1)) val = -val; */
+            val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1);
+
+            SATURATE (val);
+            dest[j] = val;
+            mismatch ^= val;
+
+            bit_buf <<= 1;
+            NEEDBITS (bit_buf, bits, bit_ptr);
+
+            continue;
+
+        }
+
+    entry_2:
+        if (bit_buf >= 0x04000000) {
+
+            tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4);
+
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+
+            /* escape code */
+
+            i += UBITS (bit_buf << 6, 6) - 64;
+            if (i >= 64)
+                break;        /* illegal, check needed to avoid buffer overflow */
+
+            j = scan[i];
+
+            DUMPBITS (bit_buf, bits, 12);
+            NEEDBITS (bit_buf, bits, bit_ptr);
+            val = 2 * (SBITS (bit_buf, 12) + SBITS (bit_buf, 1)) + 1;
+            val = (val * quant_matrix[j]) / 32;
+
+            SATURATE (val);
+            dest[j] = val;
+            mismatch ^= val;
+
+            DUMPBITS (bit_buf, bits, 12);
+            NEEDBITS (bit_buf, bits, bit_ptr);
+
+            continue;
+
+        } else if (bit_buf >= 0x02000000) {
+            tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        } else if (bit_buf >= 0x00800000) {
+            tab = DCT_13 + (UBITS (bit_buf, 13) - 16);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        } else if (bit_buf >= 0x00200000) {
+            tab = DCT_15 + (UBITS (bit_buf, 15) - 16);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        } else {
+            tab = DCT_16 + UBITS (bit_buf, 16);
+            bit_buf <<= 16;
+            GETWORD (bit_buf, bits + 16, bit_ptr);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        }
+        break;        /* illegal, check needed to avoid buffer overflow */
+    }
+    dest[63] ^= mismatch & 16;
+    DUMPBITS (bit_buf, bits, 2);        /* dump end of block code */
+    decoder->bitstream_buf = bit_buf;
+    decoder->bitstream_bits = bits;
+    decoder->bitstream_ptr = bit_ptr;
+    return i;
+}
+
+static void get_mpeg1_intra_block (mpeg2_decoder_t * const decoder)
+{
+    int i;
+    int j;
+    int val;
+    const uint8_t * const scan = decoder->scan;
+    const uint16_t * const quant_matrix = decoder->quantizer_matrix[0];
+    const DCTtab * tab;
+    uint32_t bit_buf;
+    int bits;
+    const uint8_t * bit_ptr;
+    int16_t * const dest = decoder->DCTblock;
+
+    i = 0;
+
+    bit_buf = decoder->bitstream_buf;
+    bits = decoder->bitstream_bits;
+    bit_ptr = decoder->bitstream_ptr;
+
+    NEEDBITS (bit_buf, bits, bit_ptr);
+
+    while (1) {
+        if (bit_buf >= 0x28000000) {
+
+            tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5);
+
+            i += tab->run;
+            if (i >= 64)
+                break;        /* end of block */
+
+        normal_code:
+            j = scan[i];
+            bit_buf <<= tab->len;
+            bits += tab->len + 1;
+            val = (tab->level * quant_matrix[j]) >> 4;
+
+            /* oddification */
+            val = (val - 1) | 1;
+
+            /* if (bitstream_get (1)) val = -val; */
+            val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1);
+
+            SATURATE (val);
+            dest[j] = val;
+
+            bit_buf <<= 1;
+            NEEDBITS (bit_buf, bits, bit_ptr);
+
+            continue;
+
+        } else if (bit_buf >= 0x04000000) {
+
+            tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4);
+
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+
+            /* escape code */
+
+            i += UBITS (bit_buf << 6, 6) - 64;
+            if (i >= 64)
+                break;        /* illegal, check needed to avoid buffer overflow */
+
+            j = scan[i];
+
+            DUMPBITS (bit_buf, bits, 12);
+            NEEDBITS (bit_buf, bits, bit_ptr);
+            val = SBITS (bit_buf, 8);
+            if (! (val & 0x7f)) {
+                DUMPBITS (bit_buf, bits, 8);
+                val = UBITS (bit_buf, 8) + 2 * val;
+            }
+            val = (val * quant_matrix[j]) / 16;
+
+            /* oddification */
+            val = (val + ~SBITS (val, 1)) | 1;
+
+            SATURATE (val);
+            dest[j] = val;
+
+            DUMPBITS (bit_buf, bits, 8);
+            NEEDBITS (bit_buf, bits, bit_ptr);
+
+            continue;
+
+        } else if (bit_buf >= 0x02000000) {
+            tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        } else if (bit_buf >= 0x00800000) {
+            tab = DCT_13 + (UBITS (bit_buf, 13) - 16);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        } else if (bit_buf >= 0x00200000) {
+            tab = DCT_15 + (UBITS (bit_buf, 15) - 16);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        } else {
+            tab = DCT_16 + UBITS (bit_buf, 16);
+            bit_buf <<= 16;
+            GETWORD (bit_buf, bits + 16, bit_ptr);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        }
+        break;        /* illegal, check needed to avoid buffer overflow */
+    }
+    DUMPBITS (bit_buf, bits, 2);        /* dump end of block code */
+    decoder->bitstream_buf = bit_buf;
+    decoder->bitstream_bits = bits;
+    decoder->bitstream_ptr = bit_ptr;
+}
+
+static int get_mpeg1_non_intra_block (mpeg2_decoder_t * const decoder)
+{
+    int i;
+    int j;
+    int val;
+    const uint8_t * const scan = decoder->scan;
+    const uint16_t * const quant_matrix = decoder->quantizer_matrix[1];
+    const DCTtab * tab;
+    uint32_t bit_buf;
+    int bits;
+    const uint8_t * bit_ptr;
+    int16_t * const dest = decoder->DCTblock;
+
+    i = -1;
+
+    bit_buf = decoder->bitstream_buf;
+    bits = decoder->bitstream_bits;
+    bit_ptr = decoder->bitstream_ptr;
+
+    NEEDBITS (bit_buf, bits, bit_ptr);
+    if (bit_buf >= 0x28000000) {
+        tab = DCT_B14DC_5 + (UBITS (bit_buf, 5) - 5);
+        goto entry_1;
+    } else
+        goto entry_2;
+
+    while (1) {
+        if (bit_buf >= 0x28000000) {
+
+            tab = DCT_B14AC_5 + (UBITS (bit_buf, 5) - 5);
+
+        entry_1:
+            i += tab->run;
+            if (i >= 64)
+                break;        /* end of block */
+
+        normal_code:
+            j = scan[i];
+            bit_buf <<= tab->len;
+            bits += tab->len + 1;
+            val = ((2 * tab->level + 1) * quant_matrix[j]) >> 5;
+
+            /* oddification */
+            val = (val - 1) | 1;
+
+            /* if (bitstream_get (1)) val = -val; */
+            val = (val ^ SBITS (bit_buf, 1)) - SBITS (bit_buf, 1);
+
+            SATURATE (val);
+            dest[j] = val;
+
+            bit_buf <<= 1;
+            NEEDBITS (bit_buf, bits, bit_ptr);
+
+            continue;
+
+        }
+
+    entry_2:
+        if (bit_buf >= 0x04000000) {
+
+            tab = DCT_B14_8 + (UBITS (bit_buf, 8) - 4);
+
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+
+            /* escape code */
+
+            i += UBITS (bit_buf << 6, 6) - 64;
+            if (i >= 64)
+                break;        /* illegal, check needed to avoid buffer overflow */
+
+            j = scan[i];
+
+            DUMPBITS (bit_buf, bits, 12);
+            NEEDBITS (bit_buf, bits, bit_ptr);
+            val = SBITS (bit_buf, 8);
+            if (! (val & 0x7f)) {
+                DUMPBITS (bit_buf, bits, 8);
+                val = UBITS (bit_buf, 8) + 2 * val;
+            }
+            val = 2 * (val + SBITS (val, 1)) + 1;
+            val = (val * quant_matrix[j]) / 32;
+
+            /* oddification */
+            val = (val + ~SBITS (val, 1)) | 1;
+
+            SATURATE (val);
+            dest[j] = val;
+
+            DUMPBITS (bit_buf, bits, 8);
+            NEEDBITS (bit_buf, bits, bit_ptr);
+
+            continue;
+
+        } else if (bit_buf >= 0x02000000) {
+            tab = DCT_B14_10 + (UBITS (bit_buf, 10) - 8);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        } else if (bit_buf >= 0x00800000) {
+            tab = DCT_13 + (UBITS (bit_buf, 13) - 16);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        } else if (bit_buf >= 0x00200000) {
+            tab = DCT_15 + (UBITS (bit_buf, 15) - 16);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        } else {
+            tab = DCT_16 + UBITS (bit_buf, 16);
+            bit_buf <<= 16;
+            GETWORD (bit_buf, bits + 16, bit_ptr);
+            i += tab->run;
+            if (i < 64)
+                goto normal_code;
+        }
+        break;        /* illegal, check needed to avoid buffer overflow */
+    }
+    DUMPBITS (bit_buf, bits, 2);        /* dump end of block code */
+    decoder->bitstream_buf = bit_buf;
+    decoder->bitstream_bits = bits;
+    decoder->bitstream_ptr = bit_ptr;
+    return i;
+}
+
+static inline void slice_intra_DCT (mpeg2_decoder_t * const decoder,
+                                    const int cc,
+                                    uint8_t * const dest, const int stride)
+{
+#define bit_buf (decoder->bitstream_buf)
+#define bits (decoder->bitstream_bits)
+#define bit_ptr (decoder->bitstream_ptr)
+    NEEDBITS (bit_buf, bits, bit_ptr);
+    /* Get the intra DC coefficient and inverse quantize it */
+    if (cc == 0)
+        decoder->DCTblock[0] =
+            decoder->dc_dct_pred[0] += get_luma_dc_dct_diff (decoder);
+    else
+        decoder->DCTblock[0] =
+            decoder->dc_dct_pred[cc] += get_chroma_dc_dct_diff (decoder);
+
+    if (decoder->mpeg1) {
+        if (decoder->coding_type != D_TYPE)
+            get_mpeg1_intra_block (decoder);
+    } else if (decoder->intra_vlc_format)
+        get_intra_block_B15 (decoder, decoder->quantizer_matrix[cc ? 2 : 0]);
+    else
+        get_intra_block_B14 (decoder, decoder->quantizer_matrix[cc ? 2 : 0]);
+    mpeg2_idct_copy (decoder->DCTblock, dest, stride);
+#undef bit_buf
+#undef bits
+#undef bit_ptr
+}
+
+static inline void slice_non_intra_DCT (mpeg2_decoder_t * const decoder,
+                                        const int cc,
+                                        uint8_t * const dest, const int stride)
+{
+    int last;
+
+    if (decoder->mpeg1)
+        last = get_mpeg1_non_intra_block (decoder);
+    else
+        last = get_non_intra_block (decoder,
+                                    decoder->quantizer_matrix[cc ? 3 : 1]);
+    mpeg2_idct_add (last, decoder->DCTblock, dest, stride);
+}
+
+#define MOTION_420(table,ref,motion_x,motion_y,size,y)                              \
+    pos_x = 2 * decoder->offset + motion_x;                                      \
+    pos_y = 2 * decoder->v_offset + motion_y + 2 * y;                              \
+    if (unlikely (pos_x > decoder->limit_x)) {                                      \
+        pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x;                      \
+        motion_x = pos_x - 2 * decoder->offset;                                      \
+    }                                                                              \
+    if (unlikely (pos_y > decoder->limit_y_ ## size)) {                              \
+        pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y_ ## size;              \
+        motion_y = pos_y - 2 * decoder->v_offset - 2 * y;                      \
+    }                                                                              \
+    xy_half = ((pos_y & 1) << 1) | (pos_x & 1);                                      \
+    table[xy_half] (decoder->dest[0] + y * decoder->stride + decoder->offset, \
+                    ref[0] + (pos_x >> 1) + (pos_y >> 1) * decoder->stride,   \
+                    decoder->stride, size);                                      \
+    motion_x /= 2;        motion_y /= 2;                                              \
+    xy_half = ((motion_y & 1) << 1) | (motion_x & 1);                              \
+    offset = (((decoder->offset + motion_x) >> 1) +                              \
+              ((((decoder->v_offset + motion_y) >> 1) + y/2) *                      \
+               decoder->uv_stride));                                              \
+    table[4+xy_half] (decoder->dest[1] + y/2 * decoder->uv_stride +              \
+                      (decoder->offset >> 1), ref[1] + offset,                      \
+                      decoder->uv_stride, size/2);                              \
+    table[4+xy_half] (decoder->dest[2] + y/2 * decoder->uv_stride +              \
+                      (decoder->offset >> 1), ref[2] + offset,                      \
+                      decoder->uv_stride, size/2)
+
+#define MOTION_FIELD_420(table,ref,motion_x,motion_y,dest_field,op,src_field) \
+    pos_x = 2 * decoder->offset + motion_x;                                      \
+    pos_y = decoder->v_offset + motion_y;                                      \
+    if (unlikely (pos_x > decoder->limit_x)) {                                      \
+        pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x;                      \
+        motion_x = pos_x - 2 * decoder->offset;                                      \
+    }                                                                              \
+    if (unlikely (pos_y > decoder->limit_y)) {                                      \
+        pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y;                      \
+        motion_y = pos_y - decoder->v_offset;                                      \
+    }                                                                              \
+    xy_half = ((pos_y & 1) << 1) | (pos_x & 1);                                      \
+    table[xy_half] (decoder->dest[0] + dest_field * decoder->stride +              \
+                    decoder->offset,                                              \
+                    (ref[0] + (pos_x >> 1) +                                      \
+                     ((pos_y op) + src_field) * decoder->stride),              \
+                    2 * decoder->stride, 8);                                      \
+    motion_x /= 2;        motion_y /= 2;                                              \
+    xy_half = ((motion_y & 1) << 1) | (motion_x & 1);                              \
+    offset = (((decoder->offset + motion_x) >> 1) +                              \
+              (((decoder->v_offset >> 1) + (motion_y op) + src_field) *              \
+               decoder->uv_stride));                                              \
+    table[4+xy_half] (decoder->dest[1] + dest_field * decoder->uv_stride +    \
+                      (decoder->offset >> 1), ref[1] + offset,                      \
+                      2 * decoder->uv_stride, 4);                              \
+    table[4+xy_half] (decoder->dest[2] + dest_field * decoder->uv_stride +    \
+                      (decoder->offset >> 1), ref[2] + offset,                      \
+                      2 * decoder->uv_stride, 4)
+
+#define MOTION_DMV_420(table,ref,motion_x,motion_y)                              \
+    pos_x = 2 * decoder->offset + motion_x;                                      \
+    pos_y = decoder->v_offset + motion_y;                                      \
+    if (unlikely (pos_x > decoder->limit_x)) {                                      \
+        pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x;                      \
+        motion_x = pos_x - 2 * decoder->offset;                                      \
+    }                                                                              \
+    if (unlikely (pos_y > decoder->limit_y)) {                                      \
+        pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y;                      \
+        motion_y = pos_y - decoder->v_offset;                                      \
+    }                                                                              \
+    xy_half = ((pos_y & 1) << 1) | (pos_x & 1);                                      \
+    offset = (pos_x >> 1) + (pos_y & ~1) * decoder->stride;                      \
+    table[xy_half] (decoder->dest[0] + decoder->offset,                              \
+                    ref[0] + offset, 2 * decoder->stride, 8);                      \
+    table[xy_half] (decoder->dest[0] + decoder->stride + decoder->offset,     \
+                    ref[0] + decoder->stride + offset,                              \
+                    2 * decoder->stride, 8);                                      \
+    motion_x /= 2;        motion_y /= 2;                                              \
+    xy_half = ((motion_y & 1) << 1) | (motion_x & 1);                              \
+    offset = (((decoder->offset + motion_x) >> 1) +                              \
+              (((decoder->v_offset >> 1) + (motion_y & ~1)) *                      \
+               decoder->uv_stride));                                              \
+    table[4+xy_half] (decoder->dest[1] + (decoder->offset >> 1),              \
+                      ref[1] + offset, 2 * decoder->uv_stride, 4);              \
+    table[4+xy_half] (decoder->dest[1] + decoder->uv_stride +                      \
+                      (decoder->offset >> 1),                                      \
+                      ref[1] + decoder->uv_stride + offset,                      \
+                      2 * decoder->uv_stride, 4);                              \
+    table[4+xy_half] (decoder->dest[2] + (decoder->offset >> 1),              \
+                      ref[2] + offset, 2 * decoder->uv_stride, 4);              \
+    table[4+xy_half] (decoder->dest[2] + decoder->uv_stride +                      \
+                      (decoder->offset >> 1),                                      \
+                      ref[2] + decoder->uv_stride + offset,                      \
+                      2 * decoder->uv_stride, 4)
+
+#define MOTION_ZERO_420(table,ref)                                              \
+    table[0] (decoder->dest[0] + decoder->offset,                              \
+              (ref[0] + decoder->offset +                                      \
+               decoder->v_offset * decoder->stride), decoder->stride, 16);    \
+    offset = ((decoder->offset >> 1) +                                              \
+              (decoder->v_offset >> 1) * decoder->uv_stride);                      \
+    table[4] (decoder->dest[1] + (decoder->offset >> 1),                      \
+              ref[1] + offset, decoder->uv_stride, 8);                              \
+    table[4] (decoder->dest[2] + (decoder->offset >> 1),                      \
+              ref[2] + offset, decoder->uv_stride, 8)
+
+#define MOTION_422(table,ref,motion_x,motion_y,size,y)                              \
+    pos_x = 2 * decoder->offset + motion_x;                                      \
+    pos_y = 2 * decoder->v_offset + motion_y + 2 * y;                              \
+    if (unlikely (pos_x > decoder->limit_x)) {                                      \
+        pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x;                      \
+        motion_x = pos_x - 2 * decoder->offset;                                      \
+    }                                                                              \
+    if (unlikely (pos_y > decoder->limit_y_ ## size)) {                              \
+        pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y_ ## size;              \
+        motion_y = pos_y - 2 * decoder->v_offset - 2 * y;                      \
+    }                                                                              \
+    xy_half = ((pos_y & 1) << 1) | (pos_x & 1);                                      \
+    offset = (pos_x >> 1) + (pos_y >> 1) * decoder->stride;                      \
+    table[xy_half] (decoder->dest[0] + y * decoder->stride + decoder->offset, \
+                    ref[0] + offset, decoder->stride, size);                      \
+    offset = (offset + (motion_x & (motion_x < 0))) >> 1;                      \
+    motion_x /= 2;                                                              \
+    xy_half = ((pos_y & 1) << 1) | (motion_x & 1);                              \
+    table[4+xy_half] (decoder->dest[1] + y * decoder->uv_stride +              \
+                      (decoder->offset >> 1), ref[1] + offset,                      \
+                      decoder->uv_stride, size);                              \
+    table[4+xy_half] (decoder->dest[2] + y * decoder->uv_stride +              \
+                      (decoder->offset >> 1), ref[2] + offset,                      \
+                      decoder->uv_stride, size)
+
+#define MOTION_FIELD_422(table,ref,motion_x,motion_y,dest_field,op,src_field) \
+    pos_x = 2 * decoder->offset + motion_x;                                      \
+    pos_y = decoder->v_offset + motion_y;                                      \
+    if (unlikely (pos_x > decoder->limit_x)) {                                      \
+        pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x;                      \
+        motion_x = pos_x - 2 * decoder->offset;                                      \
+    }                                                                              \
+    if (unlikely (pos_y > decoder->limit_y)) {                                      \
+        pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y;                      \
+        motion_y = pos_y - decoder->v_offset;                                      \
+    }                                                                              \
+    xy_half = ((pos_y & 1) << 1) | (pos_x & 1);                                      \
+    offset = (pos_x >> 1) + ((pos_y op) + src_field) * decoder->stride;              \
+    table[xy_half] (decoder->dest[0] + dest_field * decoder->stride +              \
+                    decoder->offset, ref[0] + offset,                              \
+                    2 * decoder->stride, 8);                                      \
+    offset = (offset + (motion_x & (motion_x < 0))) >> 1;                      \
+    motion_x /= 2;                                                              \
+    xy_half = ((pos_y & 1) << 1) | (motion_x & 1);                              \
+    table[4+xy_half] (decoder->dest[1] + dest_field * decoder->uv_stride +    \
+                      (decoder->offset >> 1), ref[1] + offset,                      \
+                      2 * decoder->uv_stride, 8);                              \
+    table[4+xy_half] (decoder->dest[2] + dest_field * decoder->uv_stride +    \
+                      (decoder->offset >> 1), ref[2] + offset,                      \
+                      2 * decoder->uv_stride, 8)
+
+#define MOTION_DMV_422(table,ref,motion_x,motion_y)                              \
+    pos_x = 2 * decoder->offset + motion_x;                                      \
+    pos_y = decoder->v_offset + motion_y;                                      \
+    if (unlikely (pos_x > decoder->limit_x)) {                                      \
+        pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x;                      \
+        motion_x = pos_x - 2 * decoder->offset;                                      \
+    }                                                                              \
+    if (unlikely (pos_y > decoder->limit_y)) {                                      \
+        pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y;                      \
+        motion_y = pos_y - decoder->v_offset;                                      \
+    }                                                                              \
+    xy_half = ((pos_y & 1) << 1) | (pos_x & 1);                                      \
+    offset = (pos_x >> 1) + (pos_y & ~1) * decoder->stride;                      \
+    table[xy_half] (decoder->dest[0] + decoder->offset,                              \
+                    ref[0] + offset, 2 * decoder->stride, 8);                      \
+    table[xy_half] (decoder->dest[0] + decoder->stride + decoder->offset,     \
+                    ref[0] + decoder->stride + offset,                              \
+                    2 * decoder->stride, 8);                                      \
+    offset = (offset + (motion_x & (motion_x < 0))) >> 1;                      \
+    motion_x /= 2;                                                              \
+    xy_half = ((pos_y & 1) << 1) | (motion_x & 1);                              \
+    table[4+xy_half] (decoder->dest[1] + (decoder->offset >> 1),              \
+                      ref[1] + offset, 2 * decoder->uv_stride, 8);              \
+    table[4+xy_half] (decoder->dest[1] + decoder->uv_stride +                      \
+                      (decoder->offset >> 1),                                      \
+                      ref[1] + decoder->uv_stride + offset,                      \
+                      2 * decoder->uv_stride, 8);                              \
+    table[4+xy_half] (decoder->dest[2] + (decoder->offset >> 1),              \
+                      ref[2] + offset, 2 * decoder->uv_stride, 8);              \
+    table[4+xy_half] (decoder->dest[2] + decoder->uv_stride +                      \
+                      (decoder->offset >> 1),                                      \
+                      ref[2] + decoder->uv_stride + offset,                      \
+                      2 * decoder->uv_stride, 8)
+
+#define MOTION_ZERO_422(table,ref)                                              \
+    offset = decoder->offset + decoder->v_offset * decoder->stride;              \
+    table[0] (decoder->dest[0] + decoder->offset,                              \
+              ref[0] + offset, decoder->stride, 16);                              \
+    offset >>= 1;                                                              \
+    table[4] (decoder->dest[1] + (decoder->offset >> 1),                      \
+              ref[1] + offset, decoder->uv_stride, 16);                              \
+    table[4] (decoder->dest[2] + (decoder->offset >> 1),                      \
+              ref[2] + offset, decoder->uv_stride, 16)
+
+#define MOTION_444(table,ref,motion_x,motion_y,size,y)                              \
+    pos_x = 2 * decoder->offset + motion_x;                                      \
+    pos_y = 2 * decoder->v_offset + motion_y + 2 * y;                              \
+    if (unlikely (pos_x > decoder->limit_x)) {                                      \
+        pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x;                      \
+        motion_x = pos_x - 2 * decoder->offset;                                      \
+    }                                                                              \
+    if (unlikely (pos_y > decoder->limit_y_ ## size)) {                              \
+        pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y_ ## size;              \
+        motion_y = pos_y - 2 * decoder->v_offset - 2 * y;                      \
+    }                                                                              \
+    xy_half = ((pos_y & 1) << 1) | (pos_x & 1);                                      \
+    offset = (pos_x >> 1) + (pos_y >> 1) * decoder->stride;                      \
+    table[xy_half] (decoder->dest[0] + y * decoder->stride + decoder->offset, \
+                    ref[0] + offset, decoder->stride, size);                      \
+    table[xy_half] (decoder->dest[1] + y * decoder->stride + decoder->offset, \
+                    ref[1] + offset, decoder->stride, size);                      \
+    table[xy_half] (decoder->dest[2] + y * decoder->stride + decoder->offset, \
+                    ref[2] + offset, decoder->stride, size)
+
+#define MOTION_FIELD_444(table,ref,motion_x,motion_y,dest_field,op,src_field) \
+    pos_x = 2 * decoder->offset + motion_x;                                      \
+    pos_y = decoder->v_offset + motion_y;                                      \
+    if (unlikely (pos_x > decoder->limit_x)) {                                      \
+        pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x;                      \
+        motion_x = pos_x - 2 * decoder->offset;                                      \
+    }                                                                              \
+    if (unlikely (pos_y > decoder->limit_y)) {                                      \
+        pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y;                      \
+        motion_y = pos_y - decoder->v_offset;                                      \
+    }                                                                              \
+    xy_half = ((pos_y & 1) << 1) | (pos_x & 1);                                      \
+    offset = (pos_x >> 1) + ((pos_y op) + src_field) * decoder->stride;              \
+    table[xy_half] (decoder->dest[0] + dest_field * decoder->stride +              \
+                    decoder->offset, ref[0] + offset,                              \
+                    2 * decoder->stride, 8);                                      \
+    table[xy_half] (decoder->dest[1] + dest_field * decoder->stride +              \
+                    decoder->offset, ref[1] + offset,                              \
+                    2 * decoder->stride, 8);                                      \
+    table[xy_half] (decoder->dest[2] + dest_field * decoder->stride +              \
+                    decoder->offset, ref[2] + offset,                              \
+                    2 * decoder->stride, 8)
+
+#define MOTION_DMV_444(table,ref,motion_x,motion_y)                              \
+    pos_x = 2 * decoder->offset + motion_x;                                      \
+    pos_y = decoder->v_offset + motion_y;                                      \
+    if (unlikely (pos_x > decoder->limit_x)) {                                      \
+        pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x;                      \
+        motion_x = pos_x - 2 * decoder->offset;                                      \
+    }                                                                              \
+    if (unlikely (pos_y > decoder->limit_y)) {                                      \
+        pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y;                      \
+        motion_y = pos_y - decoder->v_offset;                                      \
+    }                                                                              \
+    xy_half = ((pos_y & 1) << 1) | (pos_x & 1);                                      \
+    offset = (pos_x >> 1) + (pos_y & ~1) * decoder->stride;                      \
+    table[xy_half] (decoder->dest[0] + decoder->offset,                              \
+                    ref[0] + offset, 2 * decoder->stride, 8);                      \
+    table[xy_half] (decoder->dest[0] + decoder->stride + decoder->offset,     \
+                    ref[0] + decoder->stride + offset,                              \
+                    2 * decoder->stride, 8);                                      \
+    table[xy_half] (decoder->dest[1] + decoder->offset,                              \
+                    ref[1] + offset, 2 * decoder->stride, 8);                      \
+    table[xy_half] (decoder->dest[1] + decoder->stride + decoder->offset,     \
+                    ref[1] + decoder->stride + offset,                              \
+                    2 * decoder->stride, 8);                                      \
+    table[xy_half] (decoder->dest[2] + decoder->offset,                              \
+                    ref[2] + offset, 2 * decoder->stride, 8);                      \
+    table[xy_half] (decoder->dest[2] + decoder->stride + decoder->offset,     \
+                    ref[2] + decoder->stride + offset,                              \
+                    2 * decoder->stride, 8)
+
+#define MOTION_ZERO_444(table,ref)                                              \
+    offset = decoder->offset + decoder->v_offset * decoder->stride;              \
+    table[0] (decoder->dest[0] + decoder->offset,                              \
+              ref[0] + offset, decoder->stride, 16);                              \
+    table[4] (decoder->dest[1] + decoder->offset,                              \
+              ref[1] + offset, decoder->stride, 16);                              \
+    table[4] (decoder->dest[2] + (decoder->offset >> 1),                      \
+              ref[2] + offset, decoder->stride, 16)
+
+#define bit_buf (decoder->bitstream_buf)
+#define bits (decoder->bitstream_bits)
+#define bit_ptr (decoder->bitstream_ptr)
+
+static void motion_mp1 (mpeg2_decoder_t * const decoder,
+                        motion_t * const motion,
+                        mpeg2_mc_fct * const * const table)
+{
+    int motion_x, motion_y;
+    unsigned int pos_x, pos_y, xy_half, offset;
+
+    NEEDBITS (bit_buf, bits, bit_ptr);
+    motion_x = (motion->pmv[0][0] +
+                (get_motion_delta (decoder,
+                                   motion->f_code[0]) << motion->f_code[1]));
+    motion_x = bound_motion_vector (motion_x,
+                                    motion->f_code[0] + motion->f_code[1]);
+    motion->pmv[0][0] = motion_x;
+
+    NEEDBITS (bit_buf, bits, bit_ptr);
+    motion_y = (motion->pmv[0][1] +
+                (get_motion_delta (decoder,
+                                   motion->f_code[0]) << motion->f_code[1]));
+    motion_y = bound_motion_vector (motion_y,
+                                    motion->f_code[0] + motion->f_code[1]);
+    motion->pmv[0][1] = motion_y;
+
+    MOTION_420 (table, motion->ref[0], motion_x, motion_y, 16, 0);
+}
+
+#define MOTION_FUNCTIONS(FORMAT,MOTION,MOTION_FIELD,MOTION_DMV,MOTION_ZERO)   \
+                                                                              \
+static void motion_fr_frame_##FORMAT (mpeg2_decoder_t * const decoder,              \
+                                      motion_t * const motion,                      \
+                                      mpeg2_mc_fct * const * const table)     \
+{                                                                              \
+    int motion_x, motion_y;                                                      \
+    unsigned int pos_x, pos_y, xy_half, offset;                                      \
+                                                                              \
+    NEEDBITS (bit_buf, bits, bit_ptr);                                              \
+    motion_x = motion->pmv[0][0] + get_motion_delta (decoder,                      \
+                                                     motion->f_code[0]);      \
+    motion_x = bound_motion_vector (motion_x, motion->f_code[0]);              \
+    motion->pmv[1][0] = motion->pmv[0][0] = motion_x;                              \
+                                                                              \
+    NEEDBITS (bit_buf, bits, bit_ptr);                                              \
+    motion_y = motion->pmv[0][1] + get_motion_delta (decoder,                      \
+                                                     motion->f_code[1]);      \
+    motion_y = bound_motion_vector (motion_y, motion->f_code[1]);              \
+    motion->pmv[1][1] = motion->pmv[0][1] = motion_y;                              \
+                                                                              \
+    MOTION (table, motion->ref[0], motion_x, motion_y, 16, 0);                      \
+}                                                                              \
+                                                                              \
+static void motion_fr_field_##FORMAT (mpeg2_decoder_t * const decoder,              \
+                                      motion_t * const motion,                      \
+                                      mpeg2_mc_fct * const * const table)     \
+{                                                                              \
+    int motion_x, motion_y, field;                                              \
+    unsigned int pos_x, pos_y, xy_half, offset;                                      \
+                                                                              \
+    NEEDBITS (bit_buf, bits, bit_ptr);                                              \
+    field = UBITS (bit_buf, 1);                                                      \
+    DUMPBITS (bit_buf, bits, 1);                                              \
+                                                                              \
+    motion_x = motion->pmv[0][0] + get_motion_delta (decoder,                      \
+                                                     motion->f_code[0]);      \
+    motion_x = bound_motion_vector (motion_x, motion->f_code[0]);              \
+    motion->pmv[0][0] = motion_x;                                              \
+                                                                              \
+    NEEDBITS (bit_buf, bits, bit_ptr);                                              \
+    motion_y = ((motion->pmv[0][1] >> 1) +                                      \
+                get_motion_delta (decoder, motion->f_code[1]));                      \
+    /* motion_y = bound_motion_vector (motion_y, motion->f_code[1]); */              \
+    motion->pmv[0][1] = motion_y << 1;                                              \
+                                                                              \
+    MOTION_FIELD (table, motion->ref[0], motion_x, motion_y, 0, & ~1, field); \
+                                                                              \
+    NEEDBITS (bit_buf, bits, bit_ptr);                                              \
+    field = UBITS (bit_buf, 1);                                                      \
+    DUMPBITS (bit_buf, bits, 1);                                              \
+                                                                              \
+    motion_x = motion->pmv[1][0] + get_motion_delta (decoder,                      \
+                                                     motion->f_code[0]);      \
+    motion_x = bound_motion_vector (motion_x, motion->f_code[0]);              \
+    motion->pmv[1][0] = motion_x;                                              \
+                                                                              \
+    NEEDBITS (bit_buf, bits, bit_ptr);                                              \
+    motion_y = ((motion->pmv[1][1] >> 1) +                                      \
+                get_motion_delta (decoder, motion->f_code[1]));                      \
+    /* motion_y = bound_motion_vector (motion_y, motion->f_code[1]); */              \
+    motion->pmv[1][1] = motion_y << 1;                                              \
+                                                                              \
+    MOTION_FIELD (table, motion->ref[0], motion_x, motion_y, 1, & ~1, field); \
+}                                                                              \
+                                                                              \
+static void motion_fr_dmv_##FORMAT (mpeg2_decoder_t * const decoder,              \
+                                    motion_t * const motion,                      \
+                                    mpeg2_mc_fct * const * const table)              \
+{                                                                              \
+    int motion_x, motion_y, dmv_x, dmv_y, m, other_x, other_y;                      \
+    unsigned int pos_x, pos_y, xy_half, offset;                                      \
+                                                                              \
+    (void)table;                                                              \
+    NEEDBITS (bit_buf, bits, bit_ptr);                                              \
+    motion_x = motion->pmv[0][0] + get_motion_delta (decoder,                      \
+                                                     motion->f_code[0]);      \
+    motion_x = bound_motion_vector (motion_x, motion->f_code[0]);              \
+    motion->pmv[1][0] = motion->pmv[0][0] = motion_x;                              \
+    NEEDBITS (bit_buf, bits, bit_ptr);                                              \
+    dmv_x = get_dmv (decoder);                                                      \
+                                                                              \
+    motion_y = ((motion->pmv[0][1] >> 1) +                                      \
+                get_motion_delta (decoder, motion->f_code[1]));                      \
+    /* motion_y = bound_motion_vector (motion_y, motion->f_code[1]); */              \
+    motion->pmv[1][1] = motion->pmv[0][1] = motion_y << 1;                      \
+    dmv_y = get_dmv (decoder);                                                      \
+                                                                              \
+    m = decoder->top_field_first ? 1 : 3;                                      \
+    other_x = ((motion_x * m + (motion_x > 0)) >> 1) + dmv_x;                      \
+    other_y = ((motion_y * m + (motion_y > 0)) >> 1) + dmv_y - 1;              \
+    MOTION_FIELD (mpeg2_mc.put, motion->ref[0], other_x, other_y, 0, | 1, 0); \
+                                                                              \
+    m = decoder->top_field_first ? 3 : 1;                                      \
+    other_x = ((motion_x * m + (motion_x > 0)) >> 1) + dmv_x;                      \
+    other_y = ((motion_y * m + (motion_y > 0)) >> 1) + dmv_y + 1;              \
+    MOTION_FIELD (mpeg2_mc.put, motion->ref[0], other_x, other_y, 1, & ~1, 0);\
+                                                                              \
+    MOTION_DMV (mpeg2_mc.avg, motion->ref[0], motion_x, motion_y);              \
+}                                                                              \
+                                                                              \
+static void motion_reuse_##FORMAT (mpeg2_decoder_t * const decoder,              \
+                                   motion_t * const motion,                      \
+                                   mpeg2_mc_fct * const * const table)              \
+{                                                                              \
+    int motion_x, motion_y;                                                      \
+    unsigned int pos_x, pos_y, xy_half, offset;                                      \
+                                                                              \
+    motion_x = motion->pmv[0][0];                                              \
+    motion_y = motion->pmv[0][1];                                              \
+                                                                              \
+    MOTION (table, motion->ref[0], motion_x, motion_y, 16, 0);                      \
+}                                                                              \
+                                                                              \
+static void motion_zero_##FORMAT (mpeg2_decoder_t * const decoder,              \
+                                  motion_t * const motion,                      \
+                                  mpeg2_mc_fct * const * const table)              \
+{                                                                              \
+    unsigned int offset;                                                      \
+                                                                              \
+    motion->pmv[0][0] = motion->pmv[0][1] = 0;                                      \
+    motion->pmv[1][0] = motion->pmv[1][1] = 0;                                      \
+                                                                              \
+    MOTION_ZERO (table, motion->ref[0]);                                      \
+}                                                                              \
+                                                                              \
+static void motion_fi_field_##FORMAT (mpeg2_decoder_t * const decoder,              \
+                                      motion_t * const motion,                      \
+                                      mpeg2_mc_fct * const * const table)     \
+{                                                                              \
+    int motion_x, motion_y;                                                      \
+    uint8_t ** ref_field;                                                      \
+    unsigned int pos_x, pos_y, xy_half, offset;                                      \
+                                                                              \
+    NEEDBITS (bit_buf, bits, bit_ptr);                                              \
+    ref_field = motion->ref2[UBITS (bit_buf, 1)];                              \
+    DUMPBITS (bit_buf, bits, 1);                                              \
+                                                                              \
+    motion_x = motion->pmv[0][0] + get_motion_delta (decoder,                      \
+                                                     motion->f_code[0]);      \
+    motion_x = bound_motion_vector (motion_x, motion->f_code[0]);              \
+    motion->pmv[1][0] = motion->pmv[0][0] = motion_x;                              \
+                                                                              \
+    NEEDBITS (bit_buf, bits, bit_ptr);                                              \
+    motion_y = motion->pmv[0][1] + get_motion_delta (decoder,                      \
+                                                     motion->f_code[1]);      \
+    motion_y = bound_motion_vector (motion_y, motion->f_code[1]);              \
+    motion->pmv[1][1] = motion->pmv[0][1] = motion_y;                              \
+                                                                              \
+    MOTION (table, ref_field, motion_x, motion_y, 16, 0);                      \
+}                                                                              \
+                                                                              \
+static void motion_fi_16x8_##FORMAT (mpeg2_decoder_t * const decoder,              \
+                                     motion_t * const motion,                      \
+                                     mpeg2_mc_fct * const * const table)      \
+{                                                                              \
+    int motion_x, motion_y;                                                      \
+    uint8_t ** ref_field;                                                      \
+    unsigned int pos_x, pos_y, xy_half, offset;                                      \
+                                                                              \
+    NEEDBITS (bit_buf, bits, bit_ptr);                                              \
+    ref_field = motion->ref2[UBITS (bit_buf, 1)];                              \
+    DUMPBITS (bit_buf, bits, 1);                                              \
+                                                                              \
+    motion_x = motion->pmv[0][0] + get_motion_delta (decoder,                      \
+                                                     motion->f_code[0]);      \
+    motion_x = bound_motion_vector (motion_x, motion->f_code[0]);              \
+    motion->pmv[0][0] = motion_x;                                              \
+                                                                              \
+    NEEDBITS (bit_buf, bits, bit_ptr);                                              \
+    motion_y = motion->pmv[0][1] + get_motion_delta (decoder,                      \
+                                                     motion->f_code[1]);      \
+    motion_y = bound_motion_vector (motion_y, motion->f_code[1]);              \
+    motion->pmv[0][1] = motion_y;                                              \
+                                                                              \
+    MOTION (table, ref_field, motion_x, motion_y, 8, 0);                      \
+                                                                              \
+    NEEDBITS (bit_buf, bits, bit_ptr);                                              \
+    ref_field = motion->ref2[UBITS (bit_buf, 1)];                              \
+    DUMPBITS (bit_buf, bits, 1);                                              \
+                                                                              \
+    motion_x = motion->pmv[1][0] + get_motion_delta (decoder,                      \
+                                                     motion->f_code[0]);      \
+    motion_x = bound_motion_vector (motion_x, motion->f_code[0]);              \
+    motion->pmv[1][0] = motion_x;                                              \
+                                                                              \
+    NEEDBITS (bit_buf, bits, bit_ptr);                                              \
+    motion_y = motion->pmv[1][1] + get_motion_delta (decoder,                      \
+                                                     motion->f_code[1]);      \
+    motion_y = bound_motion_vector (motion_y, motion->f_code[1]);              \
+    motion->pmv[1][1] = motion_y;                                              \
+                                                                              \
+    MOTION (table, ref_field, motion_x, motion_y, 8, 8);                      \
+}                                                                              \
+                                                                              \
+static void motion_fi_dmv_##FORMAT (mpeg2_decoder_t * const decoder,              \
+                                    motion_t * const motion,                      \
+                                    mpeg2_mc_fct * const * const table)              \
+{                                                                              \
+    int motion_x, motion_y, other_x, other_y;                                      \
+    unsigned int pos_x, pos_y, xy_half, offset;                                      \
+                                                                              \
+    (void)table;                                                              \
+    NEEDBITS (bit_buf, bits, bit_ptr);                                              \
+    motion_x = motion->pmv[0][0] + get_motion_delta (decoder,                      \
+                                                     motion->f_code[0]);      \
+    motion_x = bound_motion_vector (motion_x, motion->f_code[0]);              \
+    motion->pmv[1][0] = motion->pmv[0][0] = motion_x;                              \
+    NEEDBITS (bit_buf, bits, bit_ptr);                                              \
+    other_x = ((motion_x + (motion_x > 0)) >> 1) + get_dmv (decoder);              \
+                                                                              \
+    motion_y = motion->pmv[0][1] + get_motion_delta (decoder,                      \
+                                                     motion->f_code[1]);      \
+    motion_y = bound_motion_vector (motion_y, motion->f_code[1]);              \
+    motion->pmv[1][1] = motion->pmv[0][1] = motion_y;                              \
+    other_y = (((motion_y + (motion_y > 0)) >> 1) + get_dmv (decoder) +              \
+               decoder->dmv_offset);                                              \
+                                                                              \
+    MOTION (mpeg2_mc.put, motion->ref[0], motion_x, motion_y, 16, 0);              \
+    MOTION (mpeg2_mc.avg, motion->ref[1], other_x, other_y, 16, 0);              \
+}                                                                              \
+
+MOTION_FUNCTIONS (420, MOTION_420, MOTION_FIELD_420, MOTION_DMV_420,
+                  MOTION_ZERO_420)
+MOTION_FUNCTIONS (422, MOTION_422, MOTION_FIELD_422, MOTION_DMV_422,
+                  MOTION_ZERO_422)
+MOTION_FUNCTIONS (444, MOTION_444, MOTION_FIELD_444, MOTION_DMV_444,
+                  MOTION_ZERO_444)
+
+/* like motion_frame, but parsing without actual motion compensation */
+static void motion_fr_conceal (mpeg2_decoder_t * const decoder)
+{
+    int tmp;
+
+    NEEDBITS (bit_buf, bits, bit_ptr);
+    tmp = (decoder->f_motion.pmv[0][0] +
+           get_motion_delta (decoder, decoder->f_motion.f_code[0]));
+    tmp = bound_motion_vector (tmp, decoder->f_motion.f_code[0]);
+    decoder->f_motion.pmv[1][0] = decoder->f_motion.pmv[0][0] = tmp;
+
+    NEEDBITS (bit_buf, bits, bit_ptr);
+    tmp = (decoder->f_motion.pmv[0][1] +
+           get_motion_delta (decoder, decoder->f_motion.f_code[1]));
+    tmp = bound_motion_vector (tmp, decoder->f_motion.f_code[1]);
+    decoder->f_motion.pmv[1][1] = decoder->f_motion.pmv[0][1] = tmp;
+
+    DUMPBITS (bit_buf, bits, 1); /* remove marker_bit */
+}
+
+static void motion_fi_conceal (mpeg2_decoder_t * const decoder)
+{
+    int tmp;
+
+    NEEDBITS (bit_buf, bits, bit_ptr);
+    DUMPBITS (bit_buf, bits, 1); /* remove field_select */
+
+    tmp = (decoder->f_motion.pmv[0][0] +
+           get_motion_delta (decoder, decoder->f_motion.f_code[0]));
+    tmp = bound_motion_vector (tmp, decoder->f_motion.f_code[0]);
+    decoder->f_motion.pmv[1][0] = decoder->f_motion.pmv[0][0] = tmp;
+
+    NEEDBITS (bit_buf, bits, bit_ptr);
+    tmp = (decoder->f_motion.pmv[0][1] +
+           get_motion_delta (decoder, decoder->f_motion.f_code[1]));
+    tmp = bound_motion_vector (tmp, decoder->f_motion.f_code[1]);
+    decoder->f_motion.pmv[1][1] = decoder->f_motion.pmv[0][1] = tmp;
+
+    DUMPBITS (bit_buf, bits, 1); /* remove marker_bit */
+}
+
+#undef bit_buf
+#undef bits
+#undef bit_ptr
+
+#define MOTION_CALL(routine,direction)                                \
+do {                                                                \
+    if ((direction) & MACROBLOCK_MOTION_FORWARD)                \
+        routine (decoder, &(decoder->f_motion), mpeg2_mc.put);        \
+    if ((direction) & MACROBLOCK_MOTION_BACKWARD)                \
+        routine (decoder, &(decoder->b_motion),                        \
+                 ((direction) & MACROBLOCK_MOTION_FORWARD ?        \
+                  mpeg2_mc.avg : mpeg2_mc.put));                \
+} while (0)
+
+#define NEXT_MACROBLOCK                                                        \
+do {                                                                        \
+    decoder->offset += 16;                                                \
+    if (decoder->offset == decoder->width) {                                \
+        do { /* just so we can use the break statement */                \
+            if (decoder->convert) {                                        \
+                decoder->convert (decoder->convert_id, decoder->dest,        \
+                                  decoder->v_offset);                        \
+                if (decoder->coding_type == B_TYPE)                        \
+                    break;                                                \
+            }                                                                \
+            decoder->dest[0] += decoder->slice_stride;                        \
+            decoder->dest[1] += decoder->slice_uv_stride;                \
+            decoder->dest[2] += decoder->slice_uv_stride;                \
+        } while (0);                                                        \
+        decoder->v_offset += 16;                                        \
+        if (decoder->v_offset > decoder->limit_y) {                        \
+            if (mpeg2_cpu_state_restore)                                \
+                mpeg2_cpu_state_restore (&cpu_state);                        \
+            return;                                                        \
+        }                                                                \
+        decoder->offset = 0;                                                \
+    }                                                                        \
+} while (0)
+
+void mpeg2_init_fbuf (mpeg2_decoder_t * decoder, uint8_t * current_fbuf[3],
+                      uint8_t * forward_fbuf[3], uint8_t * backward_fbuf[3])
+{
+    int offset, stride, height, bottom_field;
+
+    stride = decoder->stride_frame;
+    bottom_field = (decoder->picture_structure == BOTTOM_FIELD);
+    offset = bottom_field ? stride : 0;
+    height = decoder->height;
+
+    decoder->picture_dest[0] = current_fbuf[0] + offset;
+    decoder->picture_dest[1] = current_fbuf[1] + (offset >> 1);
+    decoder->picture_dest[2] = current_fbuf[2] + (offset >> 1);
+
+    decoder->f_motion.ref[0][0] = forward_fbuf[0] + offset;
+    decoder->f_motion.ref[0][1] = forward_fbuf[1] + (offset >> 1);
+    decoder->f_motion.ref[0][2] = forward_fbuf[2] + (offset >> 1);
+
+    decoder->b_motion.ref[0][0] = backward_fbuf[0] + offset;
+    decoder->b_motion.ref[0][1] = backward_fbuf[1] + (offset >> 1);
+    decoder->b_motion.ref[0][2] = backward_fbuf[2] + (offset >> 1);
+
+    if (decoder->picture_structure != FRAME_PICTURE) {
+        decoder->dmv_offset = bottom_field ? 1 : -1;
+        decoder->f_motion.ref2[0] = decoder->f_motion.ref[bottom_field];
+        decoder->f_motion.ref2[1] = decoder->f_motion.ref[!bottom_field];
+        decoder->b_motion.ref2[0] = decoder->b_motion.ref[bottom_field];
+        decoder->b_motion.ref2[1] = decoder->b_motion.ref[!bottom_field];
+        offset = stride - offset;
+
+        if (decoder->second_field && (decoder->coding_type != B_TYPE))
+            forward_fbuf = current_fbuf;
+
+        decoder->f_motion.ref[1][0] = forward_fbuf[0] + offset;
+        decoder->f_motion.ref[1][1] = forward_fbuf[1] + (offset >> 1);
+        decoder->f_motion.ref[1][2] = forward_fbuf[2] + (offset >> 1);
+
+        decoder->b_motion.ref[1][0] = backward_fbuf[0] + offset;
+        decoder->b_motion.ref[1][1] = backward_fbuf[1] + (offset >> 1);
+        decoder->b_motion.ref[1][2] = backward_fbuf[2] + (offset >> 1);
+
+        stride <<= 1;
+        height >>= 1;
+    }
+
+    decoder->stride = stride;
+    decoder->uv_stride = stride >> 1;
+    decoder->slice_stride = 16 * stride;
+    decoder->slice_uv_stride =
+        decoder->slice_stride >> (2 - decoder->chroma_format);
+    decoder->limit_x = 2 * decoder->width - 32;
+    decoder->limit_y_16 = 2 * height - 32;
+    decoder->limit_y_8 = 2 * height - 16;
+    decoder->limit_y = height - 16;
+
+    if (decoder->mpeg1) {
+        decoder->motion_parser[0] = motion_zero_420;
+        decoder->motion_parser[MC_FRAME] = motion_mp1;
+        decoder->motion_parser[4] = motion_reuse_420;
+    } else if (decoder->picture_structure == FRAME_PICTURE) {
+        if (decoder->chroma_format == 0) {
+            decoder->motion_parser[0] = motion_zero_420;
+            decoder->motion_parser[MC_FIELD] = motion_fr_field_420;
+            decoder->motion_parser[MC_FRAME] = motion_fr_frame_420;
+            decoder->motion_parser[MC_DMV] = motion_fr_dmv_420;
+            decoder->motion_parser[4] = motion_reuse_420;
+        } else if (decoder->chroma_format == 1) {
+            decoder->motion_parser[0] = motion_zero_422;
+            decoder->motion_parser[MC_FIELD] = motion_fr_field_422;
+            decoder->motion_parser[MC_FRAME] = motion_fr_frame_422;
+            decoder->motion_parser[MC_DMV] = motion_fr_dmv_422;
+            decoder->motion_parser[4] = motion_reuse_422;
+        } else {
+            decoder->motion_parser[0] = motion_zero_444;
+            decoder->motion_parser[MC_FIELD] = motion_fr_field_444;
+            decoder->motion_parser[MC_FRAME] = motion_fr_frame_444;
+            decoder->motion_parser[MC_DMV] = motion_fr_dmv_444;
+            decoder->motion_parser[4] = motion_reuse_444;
+        }
+    } else {
+        if (decoder->chroma_format == 0) {
+            decoder->motion_parser[0] = motion_zero_420;
+            decoder->motion_parser[MC_FIELD] = motion_fi_field_420;
+            decoder->motion_parser[MC_16X8] = motion_fi_16x8_420;
+            decoder->motion_parser[MC_DMV] = motion_fi_dmv_420;
+            decoder->motion_parser[4] = motion_reuse_420;
+        } else if (decoder->chroma_format == 1) {
+            decoder->motion_parser[0] = motion_zero_422;
+            decoder->motion_parser[MC_FIELD] = motion_fi_field_422;
+            decoder->motion_parser[MC_16X8] = motion_fi_16x8_422;
+            decoder->motion_parser[MC_DMV] = motion_fi_dmv_422;
+            decoder->motion_parser[4] = motion_reuse_422;
+        } else {
+            decoder->motion_parser[0] = motion_zero_444;
+            decoder->motion_parser[MC_FIELD] = motion_fi_field_444;
+            decoder->motion_parser[MC_16X8] = motion_fi_16x8_444;
+            decoder->motion_parser[MC_DMV] = motion_fi_dmv_444;
+            decoder->motion_parser[4] = motion_reuse_444;
+        }
+    }
+}
+
+static inline int slice_init (mpeg2_decoder_t * const decoder, int code)
+{
+#define bit_buf (decoder->bitstream_buf)
+#define bits (decoder->bitstream_bits)
+#define bit_ptr (decoder->bitstream_ptr)
+    int offset;
+    const MBAtab * mba;
+
+    decoder->dc_dct_pred[0] = decoder->dc_dct_pred[1] =
+        decoder->dc_dct_pred[2] = 16384;
+
+    decoder->f_motion.pmv[0][0] = decoder->f_motion.pmv[0][1] = 0;
+    decoder->f_motion.pmv[1][0] = decoder->f_motion.pmv[1][1] = 0;
+    decoder->b_motion.pmv[0][0] = decoder->b_motion.pmv[0][1] = 0;
+    decoder->b_motion.pmv[1][0] = decoder->b_motion.pmv[1][1] = 0;
+
+    if (decoder->vertical_position_extension) {
+        code += UBITS (bit_buf, 3) << 7;
+        DUMPBITS (bit_buf, bits, 3);
+    }
+    decoder->v_offset = (code - 1) * 16;
+    offset = 0;
+    if (!(decoder->convert) || decoder->coding_type != B_TYPE)
+        offset = (code - 1) * decoder->slice_stride;
+
+    decoder->dest[0] = decoder->picture_dest[0] + offset;
+    offset >>= (2 - decoder->chroma_format);
+    decoder->dest[1] = decoder->picture_dest[1] + offset;
+    decoder->dest[2] = decoder->picture_dest[2] + offset;
+
+    get_quantizer_scale (decoder);
+
+    /* ignore intra_slice and all the extra data */
+    while (bit_buf & 0x80000000) {
+        DUMPBITS (bit_buf, bits, 9);
+        NEEDBITS (bit_buf, bits, bit_ptr);
+    }
+
+    /* decode initial macroblock address increment */
+    offset = 0;
+    while (1) {
+        if (bit_buf >= 0x08000000) {
+            mba = MBA_5 + (UBITS (bit_buf, 6) - 2);
+            break;
+        } else if (bit_buf >= 0x01800000) {
+            mba = MBA_11 + (UBITS (bit_buf, 12) - 24);
+            break;
+        } else switch (UBITS (bit_buf, 12)) {
+        case 8:                /* macroblock_escape */
+            offset += 33;
+            DUMPBITS (bit_buf, bits, 11);
+            NEEDBITS (bit_buf, bits, bit_ptr);
+            continue;
+        case 15:        /* macroblock_stuffing (MPEG1 only) */
+            bit_buf &= 0xfffff;
+            DUMPBITS (bit_buf, bits, 11);
+            NEEDBITS (bit_buf, bits, bit_ptr);
+            continue;
+        default:        /* error */
+            return 1;
+        }
+    }
+    DUMPBITS (bit_buf, bits, mba->len + 1);
+    decoder->offset = (offset + mba->mba) << 4;
+
+    while (decoder->offset - decoder->width >= 0) {
+        decoder->offset -= decoder->width;
+        if (!(decoder->convert) || decoder->coding_type != B_TYPE) {
+            decoder->dest[0] += decoder->slice_stride;
+            decoder->dest[1] += decoder->slice_uv_stride;
+            decoder->dest[2] += decoder->slice_uv_stride;
+        }
+        decoder->v_offset += 16;
+    }
+    if (decoder->v_offset > decoder->limit_y)
+        return 1;
+
+    return 0;
+#undef bit_buf
+#undef bits
+#undef bit_ptr
+}
+
+void mpeg2_slice (mpeg2_decoder_t * const decoder, const int code,
+                  const uint8_t * const buffer)
+{
+#define bit_buf (decoder->bitstream_buf)
+#define bits (decoder->bitstream_bits)
+#define bit_ptr (decoder->bitstream_ptr)
+    cpu_state_t cpu_state;
+
+    bitstream_init (decoder, buffer);
+
+    if (slice_init (decoder, code))
+        return;
+
+    if (mpeg2_cpu_state_save)
+        mpeg2_cpu_state_save (&cpu_state);
+
+    while (1) {
+        int macroblock_modes;
+        int mba_inc;
+        const MBAtab * mba;
+
+        NEEDBITS (bit_buf, bits, bit_ptr);
+
+        macroblock_modes = get_macroblock_modes (decoder);
+
+        /* maybe integrate MACROBLOCK_QUANT test into get_macroblock_modes ? */
+        if (macroblock_modes & MACROBLOCK_QUANT)
+            get_quantizer_scale (decoder);
+
+        if (macroblock_modes & MACROBLOCK_INTRA) {
+
+            int DCT_offset, DCT_stride;
+            int offset;
+            uint8_t * dest_y;
+
+            if (decoder->concealment_motion_vectors) {
+                if (decoder->picture_structure == FRAME_PICTURE)
+                    motion_fr_conceal (decoder);
+                else
+                    motion_fi_conceal (decoder);
+            } else {
+                decoder->f_motion.pmv[0][0] = decoder->f_motion.pmv[0][1] = 0;
+                decoder->f_motion.pmv[1][0] = decoder->f_motion.pmv[1][1] = 0;
+                decoder->b_motion.pmv[0][0] = decoder->b_motion.pmv[0][1] = 0;
+                decoder->b_motion.pmv[1][0] = decoder->b_motion.pmv[1][1] = 0;
+            }
+
+            if (macroblock_modes & DCT_TYPE_INTERLACED) {
+                DCT_offset = decoder->stride;
+                DCT_stride = decoder->stride * 2;
+            } else {
+                DCT_offset = decoder->stride * 8;
+                DCT_stride = decoder->stride;
+            }
+
+            offset = decoder->offset;
+            dest_y = decoder->dest[0] + offset;
+            slice_intra_DCT (decoder, 0, dest_y, DCT_stride);
+            slice_intra_DCT (decoder, 0, dest_y + 8, DCT_stride);
+            slice_intra_DCT (decoder, 0, dest_y + DCT_offset, DCT_stride);
+            slice_intra_DCT (decoder, 0, dest_y + DCT_offset + 8, DCT_stride);
+            if (likely (decoder->chroma_format == 0)) {
+                slice_intra_DCT (decoder, 1, decoder->dest[1] + (offset >> 1),
+                                 decoder->uv_stride);
+                slice_intra_DCT (decoder, 2, decoder->dest[2] + (offset >> 1),
+                                 decoder->uv_stride);
+                if (decoder->coding_type == D_TYPE) {
+                    NEEDBITS (bit_buf, bits, bit_ptr);
+                    DUMPBITS (bit_buf, bits, 1);
+                }
+            } else if (likely (decoder->chroma_format == 1)) {
+                uint8_t * dest_u = decoder->dest[1] + (offset >> 1);
+                uint8_t * dest_v = decoder->dest[2] + (offset >> 1);
+                DCT_stride >>= 1;
+                DCT_offset >>= 1;
+                slice_intra_DCT (decoder, 1, dest_u, DCT_stride);
+                slice_intra_DCT (decoder, 2, dest_v, DCT_stride);
+                slice_intra_DCT (decoder, 1, dest_u + DCT_offset, DCT_stride);
+                slice_intra_DCT (decoder, 2, dest_v + DCT_offset, DCT_stride);
+            } else {
+                uint8_t * dest_u = decoder->dest[1] + offset;
+                uint8_t * dest_v = decoder->dest[2] + offset;
+                slice_intra_DCT (decoder, 1, dest_u, DCT_stride);
+                slice_intra_DCT (decoder, 2, dest_v, DCT_stride);
+                slice_intra_DCT (decoder, 1, dest_u + DCT_offset, DCT_stride);
+                slice_intra_DCT (decoder, 2, dest_v + DCT_offset, DCT_stride);
+                slice_intra_DCT (decoder, 1, dest_u + 8, DCT_stride);
+                slice_intra_DCT (decoder, 2, dest_v + 8, DCT_stride);
+                slice_intra_DCT (decoder, 1, dest_u + DCT_offset + 8,
+                                 DCT_stride);
+                slice_intra_DCT (decoder, 2, dest_v + DCT_offset + 8,
+                                 DCT_stride);
+            }
+        } else {
+
+            motion_parser_t * parser;
+
+            parser =
+                decoder->motion_parser[macroblock_modes >> MOTION_TYPE_SHIFT];
+            MOTION_CALL (parser, macroblock_modes);
+
+            if (macroblock_modes & MACROBLOCK_PATTERN) {
+                int coded_block_pattern;
+                int DCT_offset, DCT_stride;
+
+                if (macroblock_modes & DCT_TYPE_INTERLACED) {
+                    DCT_offset = decoder->stride;
+                    DCT_stride = decoder->stride * 2;
+                } else {
+                    DCT_offset = decoder->stride * 8;
+                    DCT_stride = decoder->stride;
+                }
+
+                coded_block_pattern = get_coded_block_pattern (decoder);
+
+                if (likely (decoder->chroma_format == 0)) {
+                    int offset = decoder->offset;
+                    uint8_t * dest_y = decoder->dest[0] + offset;
+                    if (coded_block_pattern & 1)
+                        slice_non_intra_DCT (decoder, 0, dest_y, DCT_stride);
+                    if (coded_block_pattern & 2)
+                        slice_non_intra_DCT (decoder, 0, dest_y + 8,
+                                             DCT_stride);
+                    if (coded_block_pattern & 4)
+                        slice_non_intra_DCT (decoder, 0, dest_y + DCT_offset,
+                                             DCT_stride);
+                    if (coded_block_pattern & 8)
+                        slice_non_intra_DCT (decoder, 0,
+                                             dest_y + DCT_offset + 8,
+                                             DCT_stride);
+                    if (coded_block_pattern & 16)
+                        slice_non_intra_DCT (decoder, 1,
+                                             decoder->dest[1] + (offset >> 1),
+                                             decoder->uv_stride);
+                    if (coded_block_pattern & 32)
+                        slice_non_intra_DCT (decoder, 2,
+                                             decoder->dest[2] + (offset >> 1),
+                                             decoder->uv_stride);
+                } else if (likely (decoder->chroma_format == 1)) {
+                    int offset;
+                    uint8_t * dest_y;
+
+                    coded_block_pattern |= bit_buf & (3 << 30);
+                    DUMPBITS (bit_buf, bits, 2);
+
+                    offset = decoder->offset;
+                    dest_y = decoder->dest[0] + offset;
+                    if (coded_block_pattern & 1)
+                        slice_non_intra_DCT (decoder, 0, dest_y, DCT_stride);
+                    if (coded_block_pattern & 2)
+                        slice_non_intra_DCT (decoder, 0, dest_y + 8,
+                                             DCT_stride);
+                    if (coded_block_pattern & 4)
+                        slice_non_intra_DCT (decoder, 0, dest_y + DCT_offset,
+                                             DCT_stride);
+                    if (coded_block_pattern & 8)
+                        slice_non_intra_DCT (decoder, 0,
+                                             dest_y + DCT_offset + 8,
+                                             DCT_stride);
+
+                    DCT_stride >>= 1;
+                    DCT_offset = (DCT_offset + offset) >> 1;
+                    if (coded_block_pattern & 16)
+                        slice_non_intra_DCT (decoder, 1,
+                                             decoder->dest[1] + (offset >> 1),
+                                             DCT_stride);
+                    if (coded_block_pattern & 32)
+                        slice_non_intra_DCT (decoder, 2,
+                                             decoder->dest[2] + (offset >> 1),
+                                             DCT_stride);
+                    if (coded_block_pattern & (2 << 30))
+                        slice_non_intra_DCT (decoder, 1,
+                                             decoder->dest[1] + DCT_offset,
+                                             DCT_stride);
+                    if (coded_block_pattern & (1 << 30))
+                        slice_non_intra_DCT (decoder, 2,
+                                             decoder->dest[2] + DCT_offset,
+                                             DCT_stride);
+                } else {
+                    int offset;
+                    uint8_t * dest_y, * dest_u, * dest_v;
+
+                    coded_block_pattern |= bit_buf & (63 << 26);
+                    DUMPBITS (bit_buf, bits, 6);
+
+                    offset = decoder->offset;
+                    dest_y = decoder->dest[0] + offset;
+                    dest_u = decoder->dest[1] + offset;
+                    dest_v = decoder->dest[2] + offset;
+
+                    if (coded_block_pattern & 1)
+                        slice_non_intra_DCT (decoder, 0, dest_y, DCT_stride);
+                    if (coded_block_pattern & 2)
+                        slice_non_intra_DCT (decoder, 0, dest_y + 8,
+                                             DCT_stride);
+                    if (coded_block_pattern & 4)
+                        slice_non_intra_DCT (decoder, 0, dest_y + DCT_offset,
+                                             DCT_stride);
+                    if (coded_block_pattern & 8)
+                        slice_non_intra_DCT (decoder, 0,
+                                             dest_y + DCT_offset + 8,
+                                             DCT_stride);
+
+                    if (coded_block_pattern & 16)
+                        slice_non_intra_DCT (decoder, 1, dest_u, DCT_stride);
+                    if (coded_block_pattern & 32)
+                        slice_non_intra_DCT (decoder, 2, dest_v, DCT_stride);
+                    if (coded_block_pattern & (32 << 26))
+                        slice_non_intra_DCT (decoder, 1, dest_u + DCT_offset,
+                                             DCT_stride);
+                    if (coded_block_pattern & (16 << 26))
+                        slice_non_intra_DCT (decoder, 2, dest_v + DCT_offset,
+                                             DCT_stride);
+                    if (coded_block_pattern & (8 << 26))
+                        slice_non_intra_DCT (decoder, 1, dest_u + 8,
+                                             DCT_stride);
+                    if (coded_block_pattern & (4 << 26))
+                        slice_non_intra_DCT (decoder, 2, dest_v + 8,
+                                             DCT_stride);
+                    if (coded_block_pattern & (2 << 26))
+                        slice_non_intra_DCT (decoder, 1,
+                                             dest_u + DCT_offset + 8,
+                                             DCT_stride);
+                    if (coded_block_pattern & (1 << 26))
+                        slice_non_intra_DCT (decoder, 2,
+                                             dest_v + DCT_offset + 8,
+                                             DCT_stride);
+                }
+            }
+
+            decoder->dc_dct_pred[0] = decoder->dc_dct_pred[1] =
+                decoder->dc_dct_pred[2] = 16384;
+        }
+
+        NEXT_MACROBLOCK;
+
+        NEEDBITS (bit_buf, bits, bit_ptr);
+        mba_inc = 0;
+        while (1) {
+            if (bit_buf >= 0x10000000) {
+                mba = MBA_5 + (UBITS (bit_buf, 5) - 2);
+                break;
+            } else if (bit_buf >= 0x03000000) {
+                mba = MBA_11 + (UBITS (bit_buf, 11) - 24);
+                break;
+            } else switch (UBITS (bit_buf, 11)) {
+            case 8:                /* macroblock_escape */
+                mba_inc += 33;
+                /* pass through */
+            case 15:        /* macroblock_stuffing (MPEG1 only) */
+                DUMPBITS (bit_buf, bits, 11);
+                NEEDBITS (bit_buf, bits, bit_ptr);
+                continue;
+            default:        /* end of slice, or error */
+                if (mpeg2_cpu_state_restore)
+                    mpeg2_cpu_state_restore (&cpu_state);
+                return;
+            }
+        }
+        DUMPBITS (bit_buf, bits, mba->len);
+        mba_inc += mba->mba;
+
+        if (mba_inc) {
+            decoder->dc_dct_pred[0] = decoder->dc_dct_pred[1] =
+                decoder->dc_dct_pred[2] = 16384;
+
+            if (decoder->coding_type == P_TYPE) {
+                do {
+                    MOTION_CALL (decoder->motion_parser[0],
+                                 MACROBLOCK_MOTION_FORWARD);
+                    NEXT_MACROBLOCK;
+                } while (--mba_inc);
+            } else {
+                do {
+                    MOTION_CALL (decoder->motion_parser[4], macroblock_modes);
+                    NEXT_MACROBLOCK;
+                } while (--mba_inc);
+            }
+        }
+    }
+#undef bit_buf
+#undef bits
+#undef bit_ptr
+}
diff --git a/apps/plugins/mpegplayer/video_out.h b/apps/plugins/mpegplayer/video_out.h
new file mode 100644
index 0000000..342c551
--- /dev/null
+++ b/apps/plugins/mpegplayer/video_out.h
@@ -0,0 +1,58 @@
+/*
+ * video_out.h
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec 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.
+ *
+ * mpeg2dec 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+struct mpeg2_sequence_s;
+struct mpeg2_convert_init_s;
+typedef struct {
+    int (* convert) (int stage, void * id,
+		     const struct mpeg2_sequence_s * sequence,
+		     int stride, uint32_t accel, void * arg,
+		     struct mpeg2_convert_init_s * result);
+} vo_setup_result_t;
+
+typedef struct vo_instance_s vo_instance_t;
+struct vo_instance_s {
+    int (* setup) (vo_instance_t * instance, unsigned int width,
+		   unsigned int height, unsigned int chroma_width,
+		   unsigned int chroma_height, vo_setup_result_t * result);
+    void (* setup_fbuf) (vo_instance_t * instance, uint8_t ** buf, void ** id);
+    void (* set_fbuf) (vo_instance_t * instance, uint8_t ** buf, void ** id);
+    void (* start_fbuf) (vo_instance_t * instance,
+			 uint8_t * const * buf, void * id);
+    void (* draw) (vo_instance_t * instance, uint8_t * const * buf, void * id);
+    void (* discard) (vo_instance_t * instance,
+		      uint8_t * const * buf, void * id);
+    void (* close) (vo_instance_t * instance);
+};
+
+typedef vo_instance_t * vo_open_t (void);
+
+typedef struct {
+    char * name;
+    vo_open_t * open;
+} vo_driver_t;
+
+void vo_accel (uint32_t accel);
+
+/* return NULL terminated array of all drivers */
+vo_driver_t const * vo_drivers (void);
diff --git a/apps/plugins/mpegplayer/video_out_rockbox.c b/apps/plugins/mpegplayer/video_out_rockbox.c
new file mode 100644
index 0000000..786d9d0
--- /dev/null
+++ b/apps/plugins/mpegplayer/video_out_rockbox.c
@@ -0,0 +1,285 @@
+/*
+ * video_out_null.c
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec 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.
+ *
+ * mpeg2dec 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "mpeg2dec_config.h"
+
+#include "plugin.h"
+
+extern struct plugin_api* rb;
+
+#include "mpeg2.h"
+#include "video_out.h"
+
+static int starttick;
+
+#define CSUB_X 2
+#define CSUB_Y 2
+
+static int image_x;
+static int image_y;
+static int image_width;
+static int image_height;
+static int image_chroma_x;
+static int image_chroma_y;
+
+#if (LCD_DEPTH == 16) && \
+    ((LCD_PIXELFORMAT == RGB565) || (LCD_PIXELFORMAT == RGB565SWAPPED))
+
+#define RYFAC (31*257)
+#define GYFAC (63*257)
+#define BYFAC (31*257)
+#define RVFAC 11170     /* 31 * 257 *  1.402    */
+#define GVFAC (-11563)  /* 63 * 257 * -0.714136 */
+#define GUFAC (-5572)   /* 63 * 257 * -0.344136 */
+#define BUFAC 14118     /* 31 * 257 *  1.772    */
+
+#define ROUNDOFFS (127*257)
+
+/* Draw a partial YUV colour bitmap - taken from the Rockbox JPEG viewer */
+void yuv_bitmap_part(unsigned char * const src[3],
+                     int src_x, int src_y, int stride,
+                     int x, int y, int width, int height)
+{
+    fb_data *dst, *dst_end;
+
+    /* nothing to draw? */
+    if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
+        || (x + width <= 0) || (y + height <= 0))
+        return;
+
+    /* clipping */
+    if (x < 0)
+    {
+        width += x;
+        src_x -= x;
+        x = 0;
+    }
+    if (y < 0)
+    {
+        height += y;
+        src_y -= y;
+        y = 0;
+    }
+    if (x + width > LCD_WIDTH)
+        width = LCD_WIDTH - x;
+    if (y + height > LCD_HEIGHT)
+        height = LCD_HEIGHT - y;
+
+    dst = rb->lcd_framebuffer + LCD_WIDTH * y + x;
+    dst_end = dst + LCD_WIDTH * height;
+
+    do
+    {
+        fb_data *dst_row = dst;
+        fb_data *row_end = dst_row + width;
+        const unsigned char *ysrc = src[0] + stride * src_y + src_x;
+        int y, u, v;
+        int red, green, blue;
+        unsigned rbits, gbits, bbits;
+
+        if (CSUB_Y) /* colour */
+        {
+            /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
+            const unsigned char *usrc = src[1] + (stride/CSUB_X) * (src_y/CSUB_Y)
+                                               + (src_x/CSUB_X);
+            const unsigned char *vsrc = src[2] + (stride/CSUB_X) * (src_y/CSUB_Y)
+                                               + (src_x/CSUB_X);
+            int xphase = src_x % CSUB_X;
+            int rc, gc, bc;
+
+            u = *usrc++ - 128;
+            v = *vsrc++ - 128;
+            rc = RVFAC * v + ROUNDOFFS;
+            gc = GVFAC * v + GUFAC * u + ROUNDOFFS;
+            bc = BUFAC * u + ROUNDOFFS;
+
+            do
+            {
+                y = *ysrc++;
+                red   = RYFAC * y + rc;
+                green = GYFAC * y + gc;
+                blue  = BYFAC * y + bc;
+
+                if ((unsigned)red > (RYFAC*255+ROUNDOFFS))
+                {
+                    if (red < 0)
+                        red = 0;
+                    else
+                        red = (RYFAC*255+ROUNDOFFS);
+                }
+                if ((unsigned)green > (GYFAC*255+ROUNDOFFS))
+                {
+                    if (green < 0)
+                        green = 0;
+                    else
+                        green = (GYFAC*255+ROUNDOFFS);
+                }
+                if ((unsigned)blue > (BYFAC*255+ROUNDOFFS))
+                {
+                    if (blue < 0)
+                        blue = 0;
+                    else
+                        blue = (BYFAC*255+ROUNDOFFS);
+                }
+                rbits = ((unsigned)red) >> 16 ;
+                gbits = ((unsigned)green) >> 16 ;
+                bbits = ((unsigned)blue) >> 16 ;
+#if LCD_PIXELFORMAT == RGB565
+                *dst_row++ = (rbits << 11) | (gbits << 5) | bbits;
+#elif LCD_PIXELFORMAT == RGB565SWAPPED
+                *dst_row++ = swap16((rbits << 11) | (gbits << 5) | bbits);
+#endif
+
+                if (++xphase >= CSUB_X)
+                {
+                    u = *usrc++ - 128;
+                    v = *vsrc++ - 128;
+                    rc = RVFAC * v + ROUNDOFFS;
+                    gc = GVFAC * v + GUFAC * u + ROUNDOFFS;
+                    bc = BUFAC * u + ROUNDOFFS;
+                    xphase = 0;
+                }
+            }
+            while (dst_row < row_end);
+        }
+        else /* monochrome */
+        {
+            do
+            {
+                y = *ysrc++;
+                red   = RYFAC * y + ROUNDOFFS;  /* blue == red */
+                green = GYFAC * y + ROUNDOFFS;
+                rbits = ((unsigned)red) >> 16;
+                gbits = ((unsigned)green) >> 16;
+#if LCD_PIXELFORMAT == RGB565
+                *dst_row++ = (rbits << 11) | (gbits << 5) | rbits;
+#elif LCD_PIXELFORMAT == RGB565SWAPPED
+                *dst_row++ = swap16((rbits << 11) | (gbits << 5) | rbits);
+#endif
+            }
+            while (dst_row < row_end);
+        }
+
+        src_y++;
+        dst += LCD_WIDTH;
+    }
+    while (dst < dst_end);
+}
+#endif
+
+static void rockbox_draw_frame (vo_instance_t * instance,
+                                uint8_t * const * buf, void * id)
+{
+    char str[80];
+    static int frame=0;
+    int ticks,fps;
+
+    (void)id;
+    (void)instance;
+
+#if (CONFIG_LCD == LCD_IPODCOLOR || CONFIG_LCD == LCD_IPODNANO) && \
+    !defined(SIMULATOR)
+    rb->lcd_yuv_blit(buf,
+                    0,0,image_width,
+                    image_x,image_y,image_width,image_height);
+#elif (LCD_DEPTH == 16) && \
+    ((LCD_PIXELFORMAT == RGB565) || (LCD_PIXELFORMAT == RGB565SWAPPED))
+    yuv_bitmap_part(buf,0,0,image_width,
+                    image_x,image_y,image_width,image_height);
+    rb->lcd_update_rect(image_x,image_y,image_width,image_height);
+#endif
+
+    if (starttick==0) starttick=*rb->current_tick-1; /* Avoid divby0 */
+
+    /* Calculate fps */
+    frame++;
+    if ((frame % 125) == 0) {
+        ticks=(*rb->current_tick)-starttick;
+
+        fps=(frame*1000)/ticks;
+        rb->snprintf(str,sizeof(str),"%d.%d",(fps/10),fps%10);
+        rb->lcd_putsxy(0,0,str);
+
+        rb->lcd_update_rect(0,0,80,8);
+    }
+}
+
+vo_instance_t static_instance;
+
+static vo_instance_t * internal_open (int setup (vo_instance_t *, unsigned int,
+                                                 unsigned int, unsigned int,
+                                                 unsigned int,
+                                                 vo_setup_result_t *),
+                                      void draw (vo_instance_t *,
+                                                 uint8_t * const *, void *))
+{
+    vo_instance_t * instance;
+
+    instance = (vo_instance_t *) &static_instance;
+    if (instance == NULL)
+        return NULL;
+
+    instance->setup = setup;
+    instance->setup_fbuf = NULL;
+    instance->set_fbuf = NULL;
+    instance->start_fbuf = NULL;
+    instance->draw = draw;
+    instance->discard = NULL;
+    //instance->close = (void (*) (vo_instance_t *)) free;
+
+    return instance;
+}
+
+static int rockbox_setup (vo_instance_t * instance, unsigned int width,
+                          unsigned int height, unsigned int chroma_width,
+                          unsigned int chroma_height,
+                          vo_setup_result_t * result)
+{
+    (void)instance;
+
+    result->convert = NULL;
+
+    image_width=width;
+    image_height=height;
+    image_chroma_x=image_width/chroma_width;
+    image_chroma_y=image_height/chroma_height;
+
+    if (image_width >= LCD_WIDTH) {
+        image_x = 0;
+    } else {
+        image_x = (LCD_WIDTH-image_width)/2;
+    }
+
+    if (image_height >= LCD_HEIGHT) {
+        image_y = 0;
+    } else {
+        image_y = (LCD_HEIGHT-image_height)/2;
+    }
+
+    return 0;
+}
+
+vo_instance_t * vo_rockbox_open (void)
+{
+    return internal_open (rockbox_setup, rockbox_draw_frame);
+}
diff --git a/apps/plugins/mpegplayer/vlc.h b/apps/plugins/mpegplayer/vlc.h
new file mode 100644
index 0000000..7098ee0
--- /dev/null
+++ b/apps/plugins/mpegplayer/vlc.h
@@ -0,0 +1,429 @@
+/*
+ * vlc.h
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec 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.
+ *
+ * mpeg2dec 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define GETWORD(bit_buf,shift,bit_ptr)				\
+do {								\
+    bit_buf |= ((bit_ptr[0] << 8) | bit_ptr[1]) << (shift);	\
+    bit_ptr += 2;						\
+} while (0)
+
+static inline void bitstream_init (mpeg2_decoder_t * decoder,
+				   const uint8_t * start)
+{
+    decoder->bitstream_buf =
+	(start[0] << 24) | (start[1] << 16) | (start[2] << 8) | start[3];
+    decoder->bitstream_ptr = start + 4;
+    decoder->bitstream_bits = -16;
+}
+
+/* make sure that there are at least 16 valid bits in bit_buf */
+#define NEEDBITS(bit_buf,bits,bit_ptr)		\
+do {						\
+    if (unlikely (bits > 0)) {			\
+	GETWORD (bit_buf, bits, bit_ptr);	\
+	bits -= 16;				\
+    }						\
+} while (0)
+
+/* remove num valid bits from bit_buf */
+#define DUMPBITS(bit_buf,bits,num)	\
+do {					\
+    bit_buf <<= (num);			\
+    bits += (num);			\
+} while (0)
+
+/* take num bits from the high part of bit_buf and zero extend them */
+#define UBITS(bit_buf,num) (((uint32_t)(bit_buf)) >> (32 - (num)))
+
+/* take num bits from the high part of bit_buf and sign extend them */
+#define SBITS(bit_buf,num) (((int32_t)(bit_buf)) >> (32 - (num)))
+
+typedef struct {
+    uint8_t modes;
+    uint8_t len;
+} MBtab;
+
+typedef struct {
+    uint8_t delta;
+    uint8_t len;
+} MVtab;
+
+typedef struct {
+    int8_t dmv;
+    uint8_t len;
+} DMVtab;
+
+typedef struct {
+    uint8_t cbp;
+    uint8_t len;
+} CBPtab;
+
+typedef struct {
+    uint8_t size;
+    uint8_t len;
+} DCtab;
+
+typedef struct {
+    uint8_t run;
+    uint8_t level;
+    uint8_t len;
+} DCTtab;
+
+typedef struct {
+    uint8_t mba;
+    uint8_t len;
+} MBAtab;
+
+
+#define INTRA MACROBLOCK_INTRA
+#define QUANT MACROBLOCK_QUANT
+
+static const MBtab MB_I [] = {
+    {INTRA|QUANT, 2}, {INTRA, 1}
+};
+
+#define MC MACROBLOCK_MOTION_FORWARD
+#define CODED MACROBLOCK_PATTERN
+
+static const MBtab MB_P [] = {
+    {INTRA|QUANT, 6}, {CODED|QUANT, 5}, {MC|CODED|QUANT, 5}, {INTRA,    5},
+    {MC,          3}, {MC,          3}, {MC,             3}, {MC,       3},
+    {CODED,       2}, {CODED,       2}, {CODED,          2}, {CODED,    2},
+    {CODED,       2}, {CODED,       2}, {CODED,          2}, {CODED,    2},
+    {MC|CODED,    1}, {MC|CODED,    1}, {MC|CODED,       1}, {MC|CODED, 1},
+    {MC|CODED,    1}, {MC|CODED,    1}, {MC|CODED,       1}, {MC|CODED, 1},
+    {MC|CODED,    1}, {MC|CODED,    1}, {MC|CODED,       1}, {MC|CODED, 1},
+    {MC|CODED,    1}, {MC|CODED,    1}, {MC|CODED,       1}, {MC|CODED, 1}
+};
+
+#define FWD MACROBLOCK_MOTION_FORWARD
+#define BWD MACROBLOCK_MOTION_BACKWARD
+#define INTER MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD
+
+static const MBtab MB_B [] = {
+    {0,                 0}, {INTRA|QUANT,       6},
+    {BWD|CODED|QUANT,   6}, {FWD|CODED|QUANT,   6},
+    {INTER|CODED|QUANT, 5}, {INTER|CODED|QUANT, 5},
+					{INTRA,       5}, {INTRA,       5},
+    {FWD,         4}, {FWD,         4}, {FWD,         4}, {FWD,         4},
+    {FWD|CODED,   4}, {FWD|CODED,   4}, {FWD|CODED,   4}, {FWD|CODED,   4},
+    {BWD,         3}, {BWD,         3}, {BWD,         3}, {BWD,         3},
+    {BWD,         3}, {BWD,         3}, {BWD,         3}, {BWD,         3},
+    {BWD|CODED,   3}, {BWD|CODED,   3}, {BWD|CODED,   3}, {BWD|CODED,   3},
+    {BWD|CODED,   3}, {BWD|CODED,   3}, {BWD|CODED,   3}, {BWD|CODED,   3},
+    {INTER,       2}, {INTER,       2}, {INTER,       2}, {INTER,       2},
+    {INTER,       2}, {INTER,       2}, {INTER,       2}, {INTER,       2},
+    {INTER,       2}, {INTER,       2}, {INTER,       2}, {INTER,       2},
+    {INTER,       2}, {INTER,       2}, {INTER,       2}, {INTER,       2},
+    {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2},
+    {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2},
+    {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2},
+    {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}
+};
+
+#undef INTRA
+#undef QUANT
+#undef MC
+#undef CODED
+#undef FWD
+#undef BWD
+#undef INTER
+
+
+static const MVtab MV_4 [] = {
+    { 3, 6}, { 2, 4}, { 1, 3}, { 1, 3}, { 0, 2}, { 0, 2}, { 0, 2}, { 0, 2}
+};
+
+static const MVtab MV_10 [] = {
+    { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10},
+    { 0,10}, { 0,10}, { 0,10}, { 0,10}, {15,10}, {14,10}, {13,10}, {12,10},
+    {11,10}, {10,10}, { 9, 9}, { 9, 9}, { 8, 9}, { 8, 9}, { 7, 9}, { 7, 9},
+    { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7},
+    { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7},
+    { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}
+};
+
+
+static const DMVtab DMV_2 [] = {
+    { 0, 1}, { 0, 1}, { 1, 2}, {-1, 2}
+};
+
+
+static const CBPtab CBP_7 [] = {
+    {0x11, 7}, {0x12, 7}, {0x14, 7}, {0x18, 7},
+    {0x21, 7}, {0x22, 7}, {0x24, 7}, {0x28, 7},
+    {0x3f, 6}, {0x3f, 6}, {0x30, 6}, {0x30, 6},
+    {0x09, 6}, {0x09, 6}, {0x06, 6}, {0x06, 6},
+    {0x1f, 5}, {0x1f, 5}, {0x1f, 5}, {0x1f, 5},
+    {0x10, 5}, {0x10, 5}, {0x10, 5}, {0x10, 5},
+    {0x2f, 5}, {0x2f, 5}, {0x2f, 5}, {0x2f, 5},
+    {0x20, 5}, {0x20, 5}, {0x20, 5}, {0x20, 5},
+    {0x07, 5}, {0x07, 5}, {0x07, 5}, {0x07, 5},
+    {0x0b, 5}, {0x0b, 5}, {0x0b, 5}, {0x0b, 5},
+    {0x0d, 5}, {0x0d, 5}, {0x0d, 5}, {0x0d, 5},
+    {0x0e, 5}, {0x0e, 5}, {0x0e, 5}, {0x0e, 5},
+    {0x05, 5}, {0x05, 5}, {0x05, 5}, {0x05, 5},
+    {0x0a, 5}, {0x0a, 5}, {0x0a, 5}, {0x0a, 5},
+    {0x03, 5}, {0x03, 5}, {0x03, 5}, {0x03, 5},
+    {0x0c, 5}, {0x0c, 5}, {0x0c, 5}, {0x0c, 5},
+    {0x01, 4}, {0x01, 4}, {0x01, 4}, {0x01, 4},
+    {0x01, 4}, {0x01, 4}, {0x01, 4}, {0x01, 4},
+    {0x02, 4}, {0x02, 4}, {0x02, 4}, {0x02, 4},
+    {0x02, 4}, {0x02, 4}, {0x02, 4}, {0x02, 4},
+    {0x04, 4}, {0x04, 4}, {0x04, 4}, {0x04, 4},
+    {0x04, 4}, {0x04, 4}, {0x04, 4}, {0x04, 4},
+    {0x08, 4}, {0x08, 4}, {0x08, 4}, {0x08, 4},
+    {0x08, 4}, {0x08, 4}, {0x08, 4}, {0x08, 4},
+    {0x0f, 3}, {0x0f, 3}, {0x0f, 3}, {0x0f, 3},
+    {0x0f, 3}, {0x0f, 3}, {0x0f, 3}, {0x0f, 3},
+    {0x0f, 3}, {0x0f, 3}, {0x0f, 3}, {0x0f, 3},
+    {0x0f, 3}, {0x0f, 3}, {0x0f, 3}, {0x0f, 3}
+};
+
+static const CBPtab CBP_9 [] = {
+    {0,    0}, {0x00, 9}, {0x39, 9}, {0x36, 9},
+    {0x37, 9}, {0x3b, 9}, {0x3d, 9}, {0x3e, 9},
+    {0x17, 8}, {0x17, 8}, {0x1b, 8}, {0x1b, 8},
+    {0x1d, 8}, {0x1d, 8}, {0x1e, 8}, {0x1e, 8},
+    {0x27, 8}, {0x27, 8}, {0x2b, 8}, {0x2b, 8},
+    {0x2d, 8}, {0x2d, 8}, {0x2e, 8}, {0x2e, 8},
+    {0x19, 8}, {0x19, 8}, {0x16, 8}, {0x16, 8},
+    {0x29, 8}, {0x29, 8}, {0x26, 8}, {0x26, 8},
+    {0x35, 8}, {0x35, 8}, {0x3a, 8}, {0x3a, 8},
+    {0x33, 8}, {0x33, 8}, {0x3c, 8}, {0x3c, 8},
+    {0x15, 8}, {0x15, 8}, {0x1a, 8}, {0x1a, 8},
+    {0x13, 8}, {0x13, 8}, {0x1c, 8}, {0x1c, 8},
+    {0x25, 8}, {0x25, 8}, {0x2a, 8}, {0x2a, 8},
+    {0x23, 8}, {0x23, 8}, {0x2c, 8}, {0x2c, 8},
+    {0x31, 8}, {0x31, 8}, {0x32, 8}, {0x32, 8},
+    {0x34, 8}, {0x34, 8}, {0x38, 8}, {0x38, 8}
+};
+
+
+static const DCtab DC_lum_5 [] = {
+    {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2},
+    {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2},
+    {0, 3}, {0, 3}, {0, 3}, {0, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3},
+    {4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 4}, {5, 4}, {6, 5}
+};
+
+static const DCtab DC_chrom_5 [] = {
+    {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2},
+    {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2},
+    {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2},
+    {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 4}, {4, 4}, {5, 5}
+};
+
+static const DCtab DC_long [] = {
+    {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, { 6, 5}, { 6, 5},
+    {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, { 6, 5}, { 6, 5},
+    {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, { 7, 6}, { 7, 6},
+    {8, 7}, {8, 7}, {8, 7}, {8, 7}, {9, 8}, {9, 8}, {10, 9}, {11, 9}
+};
+
+
+static const DCTtab DCT_16 [] = {
+    {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0},
+    {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0},
+    {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0},
+    {129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0},
+    {  2,18, 0}, {  2,17, 0}, {  2,16, 0}, {  2,15, 0},
+    {  7, 3, 0}, { 17, 2, 0}, { 16, 2, 0}, { 15, 2, 0},
+    { 14, 2, 0}, { 13, 2, 0}, { 12, 2, 0}, { 32, 1, 0},
+    { 31, 1, 0}, { 30, 1, 0}, { 29, 1, 0}, { 28, 1, 0}
+};
+
+static const DCTtab DCT_15 [] = {
+    {  1,40,15}, {  1,39,15}, {  1,38,15}, {  1,37,15},
+    {  1,36,15}, {  1,35,15}, {  1,34,15}, {  1,33,15},
+    {  1,32,15}, {  2,14,15}, {  2,13,15}, {  2,12,15},
+    {  2,11,15}, {  2,10,15}, {  2, 9,15}, {  2, 8,15},
+    {  1,31,14}, {  1,31,14}, {  1,30,14}, {  1,30,14},
+    {  1,29,14}, {  1,29,14}, {  1,28,14}, {  1,28,14},
+    {  1,27,14}, {  1,27,14}, {  1,26,14}, {  1,26,14},
+    {  1,25,14}, {  1,25,14}, {  1,24,14}, {  1,24,14},
+    {  1,23,14}, {  1,23,14}, {  1,22,14}, {  1,22,14},
+    {  1,21,14}, {  1,21,14}, {  1,20,14}, {  1,20,14},
+    {  1,19,14}, {  1,19,14}, {  1,18,14}, {  1,18,14},
+    {  1,17,14}, {  1,17,14}, {  1,16,14}, {  1,16,14}
+};
+
+static const DCTtab DCT_13 [] = {
+    { 11, 2,13}, { 10, 2,13}, {  6, 3,13}, {  4, 4,13},
+    {  3, 5,13}, {  2, 7,13}, {  2, 6,13}, {  1,15,13},
+    {  1,14,13}, {  1,13,13}, {  1,12,13}, { 27, 1,13},
+    { 26, 1,13}, { 25, 1,13}, { 24, 1,13}, { 23, 1,13},
+    {  1,11,12}, {  1,11,12}, {  9, 2,12}, {  9, 2,12},
+    {  5, 3,12}, {  5, 3,12}, {  1,10,12}, {  1,10,12},
+    {  3, 4,12}, {  3, 4,12}, {  8, 2,12}, {  8, 2,12},
+    { 22, 1,12}, { 22, 1,12}, { 21, 1,12}, { 21, 1,12},
+    {  1, 9,12}, {  1, 9,12}, { 20, 1,12}, { 20, 1,12},
+    { 19, 1,12}, { 19, 1,12}, {  2, 5,12}, {  2, 5,12},
+    {  4, 3,12}, {  4, 3,12}, {  1, 8,12}, {  1, 8,12},
+    {  7, 2,12}, {  7, 2,12}, { 18, 1,12}, { 18, 1,12}
+};
+
+static const DCTtab DCT_B14_10 [] = {
+    { 17, 1,10}, {  6, 2,10}, {  1, 7,10}, {  3, 3,10},
+    {  2, 4,10}, { 16, 1,10}, { 15, 1,10}, {  5, 2,10}
+};
+
+static const DCTtab DCT_B14_8 [] = {
+    { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6},
+    {  3, 2, 7}, {  3, 2, 7}, { 10, 1, 7}, { 10, 1, 7},
+    {  1, 4, 7}, {  1, 4, 7}, {  9, 1, 7}, {  9, 1, 7},
+    {  8, 1, 6}, {  8, 1, 6}, {  8, 1, 6}, {  8, 1, 6},
+    {  7, 1, 6}, {  7, 1, 6}, {  7, 1, 6}, {  7, 1, 6},
+    {  2, 2, 6}, {  2, 2, 6}, {  2, 2, 6}, {  2, 2, 6},
+    {  6, 1, 6}, {  6, 1, 6}, {  6, 1, 6}, {  6, 1, 6},
+    { 14, 1, 8}, {  1, 6, 8}, { 13, 1, 8}, { 12, 1, 8},
+    {  4, 2, 8}, {  2, 3, 8}, {  1, 5, 8}, { 11, 1, 8}
+};
+
+static const DCTtab DCT_B14AC_5 [] = {
+		 {  1, 3, 5}, {  5, 1, 5}, {  4, 1, 5},
+    {  1, 2, 4}, {  1, 2, 4}, {  3, 1, 4}, {  3, 1, 4},
+    {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3},
+    {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, {129, 0, 2},
+    {129, 0, 2}, {129, 0, 2}, {129, 0, 2}, {129, 0, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}
+};
+
+static const DCTtab DCT_B14DC_5 [] = {
+		 {  1, 3, 5}, {  5, 1, 5}, {  4, 1, 5},
+    {  1, 2, 4}, {  1, 2, 4}, {  3, 1, 4}, {  3, 1, 4},
+    {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3},
+    {  1, 1, 1}, {  1, 1, 1}, {  1, 1, 1}, {  1, 1, 1},
+    {  1, 1, 1}, {  1, 1, 1}, {  1, 1, 1}, {  1, 1, 1},
+    {  1, 1, 1}, {  1, 1, 1}, {  1, 1, 1}, {  1, 1, 1},
+    {  1, 1, 1}, {  1, 1, 1}, {  1, 1, 1}, {  1, 1, 1}
+};
+
+static const DCTtab DCT_B15_10 [] = {
+    {  6, 2, 9}, {  6, 2, 9}, { 15, 1, 9}, { 15, 1, 9},
+    {  3, 4,10}, { 17, 1,10}, { 16, 1, 9}, { 16, 1, 9}
+};
+
+static const DCTtab DCT_B15_8 [] = {
+    { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6},
+    {  8, 1, 7}, {  8, 1, 7}, {  9, 1, 7}, {  9, 1, 7},
+    {  7, 1, 7}, {  7, 1, 7}, {  3, 2, 7}, {  3, 2, 7},
+    {  1, 7, 6}, {  1, 7, 6}, {  1, 7, 6}, {  1, 7, 6},
+    {  1, 6, 6}, {  1, 6, 6}, {  1, 6, 6}, {  1, 6, 6},
+    {  5, 1, 6}, {  5, 1, 6}, {  5, 1, 6}, {  5, 1, 6},
+    {  6, 1, 6}, {  6, 1, 6}, {  6, 1, 6}, {  6, 1, 6},
+    {  2, 5, 8}, { 12, 1, 8}, {  1,11, 8}, {  1,10, 8},
+    { 14, 1, 8}, { 13, 1, 8}, {  4, 2, 8}, {  2, 4, 8},
+    {  3, 1, 5}, {  3, 1, 5}, {  3, 1, 5}, {  3, 1, 5},
+    {  3, 1, 5}, {  3, 1, 5}, {  3, 1, 5}, {  3, 1, 5},
+    {  2, 2, 5}, {  2, 2, 5}, {  2, 2, 5}, {  2, 2, 5},
+    {  2, 2, 5}, {  2, 2, 5}, {  2, 2, 5}, {  2, 2, 5},
+    {  4, 1, 5}, {  4, 1, 5}, {  4, 1, 5}, {  4, 1, 5},
+    {  4, 1, 5}, {  4, 1, 5}, {  4, 1, 5}, {  4, 1, 5},
+    {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3},
+    {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3},
+    {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3},
+    {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3},
+    {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3},
+    {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3},
+    {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3},
+    {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3}, {  2, 1, 3},
+    {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4},
+    {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4},
+    {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4},
+    {129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4},
+    {  1, 3, 4}, {  1, 3, 4}, {  1, 3, 4}, {  1, 3, 4},
+    {  1, 3, 4}, {  1, 3, 4}, {  1, 3, 4}, {  1, 3, 4},
+    {  1, 3, 4}, {  1, 3, 4}, {  1, 3, 4}, {  1, 3, 4},
+    {  1, 3, 4}, {  1, 3, 4}, {  1, 3, 4}, {  1, 3, 4},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2}, {  1, 1, 2},
+    {  1, 2, 3}, {  1, 2, 3}, {  1, 2, 3}, {  1, 2, 3},
+    {  1, 2, 3}, {  1, 2, 3}, {  1, 2, 3}, {  1, 2, 3},
+    {  1, 2, 3}, {  1, 2, 3}, {  1, 2, 3}, {  1, 2, 3},
+    {  1, 2, 3}, {  1, 2, 3}, {  1, 2, 3}, {  1, 2, 3},
+    {  1, 2, 3}, {  1, 2, 3}, {  1, 2, 3}, {  1, 2, 3},
+    {  1, 2, 3}, {  1, 2, 3}, {  1, 2, 3}, {  1, 2, 3},
+    {  1, 2, 3}, {  1, 2, 3}, {  1, 2, 3}, {  1, 2, 3},
+    {  1, 2, 3}, {  1, 2, 3}, {  1, 2, 3}, {  1, 2, 3},
+    {  1, 4, 5}, {  1, 4, 5}, {  1, 4, 5}, {  1, 4, 5},
+    {  1, 4, 5}, {  1, 4, 5}, {  1, 4, 5}, {  1, 4, 5},
+    {  1, 5, 5}, {  1, 5, 5}, {  1, 5, 5}, {  1, 5, 5},
+    {  1, 5, 5}, {  1, 5, 5}, {  1, 5, 5}, {  1, 5, 5},
+    { 10, 1, 7}, { 10, 1, 7}, {  2, 3, 7}, {  2, 3, 7},
+    { 11, 1, 7}, { 11, 1, 7}, {  1, 8, 7}, {  1, 8, 7},
+    {  1, 9, 7}, {  1, 9, 7}, {  1,12, 8}, {  1,13, 8},
+    {  3, 3, 8}, {  5, 2, 8}, {  1,14, 8}, {  1,15, 8}
+};
+
+
+static const MBAtab MBA_5 [] = {
+		    {6, 5}, {5, 5}, {4, 4}, {4, 4}, {3, 4}, {3, 4},
+    {2, 3}, {2, 3}, {2, 3}, {2, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3},
+    {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
+    {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}
+};
+
+static const MBAtab MBA_11 [] = {
+    {32, 11}, {31, 11}, {30, 11}, {29, 11},
+    {28, 11}, {27, 11}, {26, 11}, {25, 11},
+    {24, 11}, {23, 11}, {22, 11}, {21, 11},
+    {20, 10}, {20, 10}, {19, 10}, {19, 10},
+    {18, 10}, {18, 10}, {17, 10}, {17, 10},
+    {16, 10}, {16, 10}, {15, 10}, {15, 10},
+    {14,  8}, {14,  8}, {14,  8}, {14,  8},
+    {14,  8}, {14,  8}, {14,  8}, {14,  8},
+    {13,  8}, {13,  8}, {13,  8}, {13,  8},
+    {13,  8}, {13,  8}, {13,  8}, {13,  8},
+    {12,  8}, {12,  8}, {12,  8}, {12,  8},
+    {12,  8}, {12,  8}, {12,  8}, {12,  8},
+    {11,  8}, {11,  8}, {11,  8}, {11,  8},
+    {11,  8}, {11,  8}, {11,  8}, {11,  8},
+    {10,  8}, {10,  8}, {10,  8}, {10,  8},
+    {10,  8}, {10,  8}, {10,  8}, {10,  8},
+    { 9,  8}, { 9,  8}, { 9,  8}, { 9,  8},
+    { 9,  8}, { 9,  8}, { 9,  8}, { 9,  8},
+    { 8,  7}, { 8,  7}, { 8,  7}, { 8,  7},
+    { 8,  7}, { 8,  7}, { 8,  7}, { 8,  7},
+    { 8,  7}, { 8,  7}, { 8,  7}, { 8,  7},
+    { 8,  7}, { 8,  7}, { 8,  7}, { 8,  7},
+    { 7,  7}, { 7,  7}, { 7,  7}, { 7,  7},
+    { 7,  7}, { 7,  7}, { 7,  7}, { 7,  7},
+    { 7,  7}, { 7,  7}, { 7,  7}, { 7,  7},
+    { 7,  7}, { 7,  7}, { 7,  7}, { 7,  7}
+};
diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config
index 7b937a9..0b5ec06 100644
--- a/apps/plugins/viewers.config
+++ b/apps/plugins/viewers.config
@@ -21,4 +21,4 @@
 wav,viewers/mp3_encoder, 00 00 00 00 00 00
 wav,viewers/wavplay,60 7F 05 35 3F 00
 bmp,rocks/rockpaint, 01 10 01 10 01 10
-
+m2v,viewers/mpegplayer,60 7F 05 35 3F 00
diff --git a/firmware/drivers/lcd-ipod.c b/firmware/drivers/lcd-ipod.c
index 52fde25..875bf8f 100644
--- a/firmware/drivers/lcd-ipod.c
+++ b/firmware/drivers/lcd-ipod.c
@@ -400,6 +400,237 @@
     (void)stride;
 }
 
+#define CSUB_X 2
+#define CSUB_Y 2
+
+#define RYFAC (31*257)
+#define GYFAC (63*257)
+#define BYFAC (31*257)
+#define RVFAC 11170     /* 31 * 257 *  1.402    */
+#define GVFAC (-11563)  /* 63 * 257 * -0.714136 */
+#define GUFAC (-5572)   /* 63 * 257 * -0.344136 */
+#define BUFAC 14118     /* 31 * 257 *  1.772    */
+
+#define ROUNDOFFS (127*257)
+
+/* Performance function to blit a YUV bitmap directly to the LCD */
+void lcd_yuv_blit(unsigned char * const src[3],
+                  int src_x, int src_y, int stride,
+                  int x, int y, int width, int height)
+{
+    int y0, x0, y1, x1;
+    int h;
+
+    /* nothing to draw? */
+    if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
+        || (x + width <= 0) || (y + height <= 0))
+        return;
+
+    /* clipping */
+    if (x < 0)
+    {
+        width += x;
+        src_x -= x;
+        x = 0;
+    }
+    if (y < 0)
+    {
+        height += y;
+        src_y -= y;
+        y = 0;
+    }
+    if (x + width > LCD_WIDTH)
+        width = LCD_WIDTH - x;
+    if (y + height > LCD_HEIGHT)
+        height = LCD_HEIGHT - y;
+
+    /* calculate the drawing region */
+#if CONFIG_LCD == LCD_IPODNANO
+    y0 = x;                         /* start horiz */
+    x0 = y;                         /* start vert */
+    y1 = (x + width) - 1;           /* max horiz */
+    x1 = (y + height) - 1;          /* max vert */
+#elif CONFIG_LCD == LCD_IPODCOLOR
+    y0 = y;                         /* start vert */
+    x0 = (LCD_WIDTH - 1) - x;       /* start horiz */
+    y1 = (y + height) - 1;          /* end vert */
+    x1 = (x0 - width) + 1;          /* end horiz */
+#endif
+
+    /* setup the drawing region */
+    if (lcd_type == 0) {
+        lcd_cmd_data(0x12, y0);      /* start vert */
+        lcd_cmd_data(0x13, x0);      /* start horiz */
+        lcd_cmd_data(0x15, y1);      /* end vert */
+        lcd_cmd_data(0x16, x1);      /* end horiz */
+    } else {
+        /* swap max horiz < start horiz */
+        if (y1 < y0) {
+            int t;
+            t = y0;
+            y0 = y1;
+            y1 = t;
+        }
+
+        /* swap max vert < start vert */
+        if (x1 < x0) {
+            int t;
+            t = x0;
+            x0 = x1;
+            x1 = t;
+        }
+
+        /* max horiz << 8 | start horiz */
+        lcd_cmd_data(LCD_CNTL_HORIZ_RAM_ADDR_POS, (y1 << 8) | y0);
+        /* max vert << 8 | start vert */
+        lcd_cmd_data(LCD_CNTL_VERT_RAM_ADDR_POS, (x1 << 8) | x0);
+
+        /* start vert = max vert */
+#if CONFIG_LCD == LCD_IPODCOLOR
+        x0 = x1;
+#endif
+
+        /* position cursor (set AD0-AD15) */
+        /* start vert << 8 | start horiz */
+        lcd_cmd_data(LCD_CNTL_RAM_ADDR_SET, ((x0 << 8) | y0));
+
+        /* start drawing */
+        lcd_send_lo(0x0);
+        lcd_send_lo(LCD_CNTL_WRITE_TO_GRAM);
+    }
+
+    h=0;
+    while (1) {
+        int pixels_to_write;
+        const unsigned char *ysrc = src[0] + stride * src_y + src_x;
+        const unsigned char *row_end = ysrc + width;
+        int y, u, v;
+        int red, green, blue;
+        unsigned rbits, gbits, bbits;
+        fb_data pixel1,pixel2;
+
+        if (h==0) {
+            while ((inl(0x70008a20) & 0x4000000) == 0);
+            outl(0x0, 0x70008a24);
+
+            if (height == 0) break;
+
+            pixels_to_write = (width * height) * 2;
+            h = height;
+
+            /* calculate how much we can do in one go */
+            if (pixels_to_write > 64000) {
+                h = (64000/2) / width;
+                pixels_to_write = (width * h) * 2;
+            }
+
+            height -= h;
+            outl(0x10000080, 0x70008a20);
+            outl((pixels_to_write - 1) | 0xc0010000, 0x70008a24);
+            outl(0x34000000, 0x70008a20);
+        }
+
+        /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
+        const unsigned char *usrc = src[1] + (stride/CSUB_X) * (src_y/CSUB_Y)
+                                           + (src_x/CSUB_X);
+        const unsigned char *vsrc = src[2] + (stride/CSUB_X) * (src_y/CSUB_Y)
+                                           + (src_x/CSUB_X);
+        int rc, gc, bc;
+
+        u = *usrc++ - 128;
+        v = *vsrc++ - 128;
+        rc = RVFAC * v + ROUNDOFFS;
+        gc = GVFAC * v + GUFAC * u + ROUNDOFFS;
+        bc = BUFAC * u + ROUNDOFFS;
+
+        do
+        {
+            y = *ysrc++;
+            red   = RYFAC * y + rc;
+            green = GYFAC * y + gc;
+            blue  = BYFAC * y + bc;
+
+            if ((unsigned)red > (RYFAC*255+ROUNDOFFS))
+            {
+                if (red < 0)
+                    red = 0;
+                else
+                    red = (RYFAC*255+ROUNDOFFS);
+            }
+            if ((unsigned)green > (GYFAC*255+ROUNDOFFS))
+            {
+                if (green < 0)
+                    green = 0;
+                else
+                    green = (GYFAC*255+ROUNDOFFS);
+            }
+            if ((unsigned)blue > (BYFAC*255+ROUNDOFFS))
+            {
+                if (blue < 0)
+                    blue = 0;
+                else
+                    blue = (BYFAC*255+ROUNDOFFS);
+            }
+            rbits = ((unsigned)red) >> 16 ;
+            gbits = ((unsigned)green) >> 16 ;
+            bbits = ((unsigned)blue) >> 16 ;
+
+            pixel1 = swap16((rbits << 11) | (gbits << 5) | bbits);
+
+            y = *ysrc++;
+            red   = RYFAC * y + rc;
+            green = GYFAC * y + gc;
+            blue  = BYFAC * y + bc;
+
+            if ((unsigned)red > (RYFAC*255+ROUNDOFFS))
+            {
+                if (red < 0)
+                    red = 0;
+                else
+                    red = (RYFAC*255+ROUNDOFFS);
+            }
+            if ((unsigned)green > (GYFAC*255+ROUNDOFFS))
+            {
+                if (green < 0)
+                    green = 0;
+                else
+                    green = (GYFAC*255+ROUNDOFFS);
+            }
+            if ((unsigned)blue > (BYFAC*255+ROUNDOFFS))
+            {
+                if (blue < 0)
+                    blue = 0;
+                else
+                    blue = (BYFAC*255+ROUNDOFFS);
+            }
+            rbits = ((unsigned)red) >> 16 ;
+            gbits = ((unsigned)green) >> 16 ;
+            bbits = ((unsigned)blue) >> 16 ;
+
+            pixel2 = swap16((rbits << 11) | (gbits << 5) | bbits);
+
+            u = *usrc++ - 128;
+            v = *vsrc++ - 128;
+            rc = RVFAC * v + ROUNDOFFS;
+            gc = GVFAC * v + GUFAC * u + ROUNDOFFS;
+            bc = BUFAC * u + ROUNDOFFS;
+
+            while ((inl(0x70008a20) & 0x1000000) == 0);
+
+            /* output 2 pixels */
+            outl((pixel2<<16)|pixel1, 0x70008b00);
+        }
+        while (ysrc < row_end);
+
+        src_y++;
+        h--;
+    }
+
+    while ((inl(0x70008a20) & 0x4000000) == 0);
+    outl(0x0, 0x70008a24);
+}
+
+
 /* Update a fraction of the display. */
 void lcd_update_rect(int x, int y, int width, int height)
 {
diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h
index 38561a7..32a958a 100644
--- a/firmware/export/lcd.h
+++ b/firmware/export/lcd.h
@@ -71,6 +71,12 @@
                                   int style);
 extern void lcd_icon(int icon, bool enable);
 
+#if CONFIG_LCD == LCD_IPODCOLOR || CONFIG_LCD == LCD_IPODNANO
+void lcd_yuv_blit(unsigned char * const src[3],
+                  int src_x, int src_y, int stride,
+                  int x, int y, int width, int height);
+#endif
+
 #if defined(SIMULATOR) || defined(HAVE_LCD_BITMAP)
 /* performance function */
 extern void lcd_blit(const fb_data* data, int x, int by, int width,