st/omx: initial OpenMAX support v3
authorChristian König <christian.koenig@amd.com>
Mon, 5 Aug 2013 17:41:27 +0000 (11:41 -0600)
committerChristian König <christian.koenig@amd.com>
Thu, 6 Feb 2014 15:16:34 +0000 (16:16 +0100)
Featuring a full grown MPEG2 and H264 decoder and a couple of hundred bugs.

v2 (Leo): fix an error for pic_order_cnt_type 1
v3 (Leo): implement support for field decoding

Signed-off-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Leo Liu <leo.liu@amd.com>
14 files changed:
configure.ac
src/gallium/state_trackers/Makefile.am
src/gallium/state_trackers/omx/Makefile.am [new file with mode: 0644]
src/gallium/state_trackers/omx/entrypoint.c [new file with mode: 0644]
src/gallium/state_trackers/omx/entrypoint.h [new file with mode: 0644]
src/gallium/state_trackers/omx/vid_dec.c [new file with mode: 0644]
src/gallium/state_trackers/omx/vid_dec.h [new file with mode: 0644]
src/gallium/state_trackers/omx/vid_dec_h264.c [new file with mode: 0644]
src/gallium/state_trackers/omx/vid_dec_mpeg12.c [new file with mode: 0644]
src/gallium/targets/Makefile.am
src/gallium/targets/r600/omx/Makefile.am [new file with mode: 0644]
src/gallium/targets/r600/omx/drm_target.c [new symlink]
src/gallium/targets/radeonsi/omx/Makefile.am [new file with mode: 0644]
src/gallium/targets/radeonsi/omx/drm_target.c [new symlink]

index 9bc7a72540bd63c4c54e1127fa5eba1aebddb8da..8bf9b94412d6739acc294e5cad8122847332c050 100644 (file)
@@ -589,6 +589,11 @@ AC_ARG_ENABLE([vdpau],
          [enable vdpau library @<:@default=auto@:>@])],
    [enable_vdpau="$enableval"],
    [enable_vdpau=auto])
+AC_ARG_ENABLE([omx],
+   [AS_HELP_STRING([--enable-omx],
+         [enable OpenMAX library @<:@default=no@:>@])],
+   [enable_omx="$enableval"],
+   [enable_omx=no])
 AC_ARG_ENABLE([opencl],
    [AS_HELP_STRING([--enable-opencl],
          [enable OpenCL library NOTE: Enabling this option will also enable
@@ -661,6 +666,7 @@ if test "x$enable_opengl" = xno -a \
         "x$enable_xa" = xno -a \
         "x$enable_xvmc" = xno -a \
         "x$enable_vdpau" = xno -a \
+        "x$enable_omx" = xno -a \
         "x$enable_opencl" = xno; then
     AC_MSG_ERROR([at least one API should be enabled])
 fi
@@ -1306,6 +1312,10 @@ if test -n "$with_gallium_drivers"; then
     if test "x$enable_vdpau" = xauto; then
        PKG_CHECK_EXISTS([vdpau], [enable_vdpau=yes], [enable_vdpau=no])
     fi
+
+    if test "x$enable_omx" = xauto; then
+       PKG_CHECK_EXISTS([libomxil-bellagio], [enable_omx=yes], [enable_omx=no])
+    fi
 fi
 
 if test "x$enable_xvmc" = xyes; then
@@ -1320,6 +1330,12 @@ if test "x$enable_vdpau" = xyes; then
 fi
 AM_CONDITIONAL(HAVE_ST_VDPAU, test "x$enable_vdpau" = xyes)
 
+if test "x$enable_omx" = xyes; then
+    PKG_CHECK_MODULES([OMX], [libomxil-bellagio >= 0.0 x11-xcb xcb-dri2 >= 1.8])
+    GALLIUM_STATE_TRACKERS_DIRS="$GALLIUM_STATE_TRACKERS_DIRS omx"
+fi
+AM_CONDITIONAL(HAVE_ST_OMX, test "x$enable_omx" = xyes)
+
 dnl
 dnl OpenCL configuration
 dnl
@@ -1653,6 +1669,13 @@ AC_ARG_WITH([vdpau-libdir],
     [VDPAU_LIB_INSTALL_DIR='${libdir}/vdpau'])
 AC_SUBST([VDPAU_LIB_INSTALL_DIR])
 
+AC_ARG_WITH([omx-libdir],
+    [AS_HELP_STRING([--with-omx-libdir=DIR],
+        [directory for the OMX libraries])],
+    [OMX_LIB_INSTALL_DIR="$withval"],
+    [OMX_LIB_INSTALL_DIR=`$PKG_CONFIG --variable=pluginsdir libomxil-bellagio`])
+AC_SUBST([OMX_LIB_INSTALL_DIR])
+
 dnl Directory for OpenCL libs
 AC_ARG_WITH([opencl-libdir],
     [AS_HELP_STRING([--with-opencl-libdir=DIR],
@@ -1683,6 +1706,9 @@ gallium_check_st() {
     if test "x$enable_vdpau" = xyes && test "x$5" != x; then
          GALLIUM_TARGET_DIRS="$GALLIUM_TARGET_DIRS $5"
     fi
+    if test "x$enable_omx" = xyes && test "x$6" != x; then
+         GALLIUM_TARGET_DIRS="$GALLIUM_TARGET_DIRS $7"
+    fi
 }
 
 gallium_require_llvm() {
@@ -1780,7 +1806,7 @@ if test "x$with_gallium_drivers" != x; then
             if test "x$enable_opencl" = xyes; then
                 LLVM_COMPONENTS="${LLVM_COMPONENTS} bitreader asmparser"
             fi
-            gallium_check_st "radeon/drm" "r600/dri" "" "r600/xvmc" "r600/vdpau"
+            gallium_check_st "radeon/drm" "r600/dri" "" "r600/xvmc" "r600/vdpau" "r600/omx"
             DRICOMMON_NEED_LIBDRM=yes
             ;;
         xradeonsi)
@@ -1789,7 +1815,7 @@ if test "x$with_gallium_drivers" != x; then
             gallium_require_drm_loader
             GALLIUM_DRIVERS_DIRS="$GALLIUM_DRIVERS_DIRS radeonsi"
             radeon_llvm_check
-            gallium_check_st "radeon/drm" "radeonsi/dri" "" "" "radeonsi/vdpau"
+            gallium_check_st "radeon/drm" "radeonsi/dri" "" "" "radeonsi/vdpau" "radeonsi/omx"
             DRICOMMON_NEED_LIBDRM=yes
             ;;
         xnouveau)
@@ -2003,6 +2029,7 @@ AC_CONFIG_FILES([Makefile
                src/gallium/state_trackers/gbm/Makefile
                src/gallium/state_trackers/glx/xlib/Makefile
                src/gallium/state_trackers/osmesa/Makefile
+               src/gallium/state_trackers/omx/Makefile
                src/gallium/state_trackers/vdpau/Makefile
                src/gallium/state_trackers/vega/Makefile
                src/gallium/state_trackers/xa/Makefile
@@ -2021,9 +2048,11 @@ AC_CONFIG_FILES([Makefile
                src/gallium/targets/osmesa/osmesa.pc
                src/gallium/targets/pipe-loader/Makefile
                src/gallium/targets/radeonsi/dri/Makefile
+               src/gallium/targets/radeonsi/omx/Makefile
                src/gallium/targets/radeonsi/vdpau/Makefile
                src/gallium/targets/r300/dri/Makefile
                src/gallium/targets/r600/dri/Makefile
+               src/gallium/targets/r600/omx/Makefile
                src/gallium/targets/r600/vdpau/Makefile
                src/gallium/targets/r600/xvmc/Makefile
                src/gallium/targets/libgl-xlib/Makefile
index 03666c4a202aa4d040c3588c39f1d43be5e57503..209856041eee5e792146224a5baed1eba650ce0b 100644 (file)
@@ -60,3 +60,7 @@ endif
 if HAVE_CLOVER
 SUBDIRS += clover
 endif
+
+if HAVE_ST_OMX
+SUBDIRS += omx
+endif
diff --git a/src/gallium/state_trackers/omx/Makefile.am b/src/gallium/state_trackers/omx/Makefile.am
new file mode 100644 (file)
index 0000000..1983248
--- /dev/null
@@ -0,0 +1,35 @@
+# Copyright © 2012 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+include $(top_srcdir)/src/gallium/Automake.inc
+
+AM_CFLAGS = \
+       $(GALLIUM_CFLAGS) \
+       $(OMX_CFLAGS)
+
+noinst_LTLIBRARIES = libomxtracker.la
+
+libomxtracker_la_SOURCES = \
+       entrypoint.c \
+       vid_dec.c \
+       vid_dec_mpeg12.c \
+       vid_dec_h264.c
diff --git a/src/gallium/state_trackers/omx/entrypoint.c b/src/gallium/state_trackers/omx/entrypoint.c
new file mode 100644 (file)
index 0000000..bc8664b
--- /dev/null
@@ -0,0 +1,100 @@
+/**************************************************************************
+ *
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/*
+ * Authors:
+ *      Christian König <christian.koenig@amd.com>
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+
+#include "os/os_thread.h"
+#include "util/u_memory.h"
+
+#include "entrypoint.h"
+#include "vid_dec.h"
+
+pipe_static_mutex(omx_lock);
+static Display *omx_display = NULL;
+static struct vl_screen *omx_screen = NULL;
+static unsigned omx_usecount = 0;
+
+int omx_component_library_Setup(stLoaderComponentType **stComponents)
+{
+   OMX_ERRORTYPE r;
+
+   if (stComponents == NULL)
+      return 1;
+
+   r = vid_dec_LoaderComponent(stComponents[0]);
+   if (r != OMX_ErrorNone)
+      return r;
+
+   return 1;
+}
+
+struct vl_screen *omx_get_screen(void)
+{
+   pipe_mutex_lock(omx_lock);
+
+   if (!omx_display) {
+      omx_display = XOpenDisplay(NULL);
+      if (!omx_display) {
+         pipe_mutex_unlock(omx_lock);
+         return NULL;
+      }
+   }
+
+   if (!omx_screen) {
+      omx_screen = vl_screen_create(omx_display, 0);
+      if (!omx_screen) {
+         pipe_mutex_unlock(omx_lock);
+         return NULL;
+      }
+   }
+
+   ++omx_usecount;
+
+   pipe_mutex_unlock(omx_lock);
+   return omx_screen;
+}
+
+void omx_put_screen(void)
+{
+   pipe_mutex_lock(omx_lock);
+   if ((--omx_usecount) == 0) {
+      vl_screen_destroy(omx_screen);
+      XCloseDisplay(omx_display);
+      omx_screen = NULL;
+      omx_display = NULL;
+   }
+   pipe_mutex_unlock(omx_lock);
+}
diff --git a/src/gallium/state_trackers/omx/entrypoint.h b/src/gallium/state_trackers/omx/entrypoint.h
new file mode 100644 (file)
index 0000000..41454be
--- /dev/null
@@ -0,0 +1,46 @@
+/**************************************************************************
+ *
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/*
+ * Authors:
+ *      Christian König <christian.koenig@amd.com>
+ *
+ */
+
+#ifndef OMX_ENTRYPOINT_H
+#define OMX_ENTRYPOINT_H
+
+#include <bellagio/st_static_component_loader.h>
+
+#include "vl/vl_winsys.h"
+
+extern int omx_component_library_Setup(stLoaderComponentType **stComponents);
+
+struct vl_screen *omx_get_screen(void);
+void omx_put_screen(void);
+
+#endif
diff --git a/src/gallium/state_trackers/omx/vid_dec.c b/src/gallium/state_trackers/omx/vid_dec.c
new file mode 100644 (file)
index 0000000..7be1dad
--- /dev/null
@@ -0,0 +1,584 @@
+/**************************************************************************
+ *
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/*
+ * Authors:
+ *      Christian König <christian.koenig@amd.com>
+ *
+ */
+
+
+#include <assert.h>
+
+#include <OMX_Video.h>
+
+/* bellagio defines a DEBUG macro that we don't want */
+#ifndef DEBUG
+#include <bellagio/omxcore.h>
+#undef DEBUG
+#else
+#include <bellagio/omxcore.h>
+#endif
+
+#include <bellagio/omx_base_video_port.h>
+
+#include "pipe/p_screen.h"
+#include "pipe/p_video_codec.h"
+#include "util/u_memory.h"
+#include "util/u_surface.h"
+#include "vl/vl_vlc.h"
+
+#include "entrypoint.h"
+#include "vid_dec.h"
+
+static OMX_ERRORTYPE vid_dec_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING name);
+static OMX_ERRORTYPE vid_dec_Destructor(OMX_COMPONENTTYPE *comp);
+static OMX_ERRORTYPE vid_dec_SetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param);
+static OMX_ERRORTYPE vid_dec_GetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param);
+static OMX_ERRORTYPE vid_dec_MessageHandler(OMX_COMPONENTTYPE *comp, internalRequestMessageType *msg);
+static OMX_ERRORTYPE vid_dec_DecodeBuffer(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf);
+static OMX_ERRORTYPE vid_dec_FreeDecBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf);
+static void vid_dec_FrameDecoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input, OMX_BUFFERHEADERTYPE* output);
+
+static void vid_dec_name(char str[OMX_MAX_STRINGNAME_SIZE])
+{
+   snprintf(str, OMX_MAX_STRINGNAME_SIZE, OMX_VID_DEC_BASE_NAME, driver_descriptor.name);
+}
+
+static void vid_dec_name_mpeg2(char str[OMX_MAX_STRINGNAME_SIZE])
+{
+   snprintf(str, OMX_MAX_STRINGNAME_SIZE, OMX_VID_DEC_MPEG2_NAME, driver_descriptor.name);
+}
+
+static void vid_dec_name_avc(char str[OMX_MAX_STRINGNAME_SIZE])
+{
+   snprintf(str, OMX_MAX_STRINGNAME_SIZE, OMX_VID_DEC_AVC_NAME, driver_descriptor.name);
+}
+
+OMX_ERRORTYPE vid_dec_LoaderComponent(stLoaderComponentType *comp)
+{
+   comp->componentVersion.s.nVersionMajor = 0;
+   comp->componentVersion.s.nVersionMinor = 0;
+   comp->componentVersion.s.nRevision = 0;
+   comp->componentVersion.s.nStep = 1;
+   comp->name_specific_length = 2;
+
+   comp->name = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);
+   if (comp->name == NULL)
+      goto error;
+
+   comp->name_specific = CALLOC(comp->name_specific_length, sizeof(char *));
+   if (comp->name_specific == NULL)
+      goto error;
+
+   comp->name_specific[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);
+   if (comp->name_specific[0] == NULL)
+      goto error;
+
+   comp->name_specific[1] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);
+   if (comp->name_specific[1] == NULL)
+      goto error;
+
+   comp->role_specific = CALLOC(comp->name_specific_length, sizeof(char *));
+   if (comp->role_specific == NULL)
+      goto error;
+
+   comp->role_specific[0] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);
+   if (comp->role_specific[0] == NULL)
+      goto error;
+
+   comp->role_specific[1] = CALLOC(1, OMX_MAX_STRINGNAME_SIZE);
+   if (comp->role_specific[1] == NULL)
+      goto error;
+
+   vid_dec_name(comp->name);
+   vid_dec_name_mpeg2(comp->name_specific[0]);
+   vid_dec_name_avc(comp->name_specific[1]);
+
+   strcpy(comp->role_specific[0], OMX_VID_DEC_MPEG2_ROLE);
+   strcpy(comp->role_specific[1], OMX_VID_DEC_AVC_ROLE);
+
+   comp->constructor = vid_dec_Constructor;
+   return OMX_ErrorNone;
+
+error:
+
+   FREE(comp->name);
+
+   if (comp->name_specific) {
+      FREE(comp->name_specific[0]);
+      FREE(comp->name_specific[1]);
+      FREE(comp->name_specific);
+   }
+
+   if (comp->role_specific) {
+      FREE(comp->role_specific[0]);
+      FREE(comp->role_specific[1]);
+      FREE(comp->role_specific);
+   }
+
+   return OMX_ErrorInsufficientResources;
+}
+
+static OMX_ERRORTYPE vid_dec_Constructor(OMX_COMPONENTTYPE *comp, OMX_STRING name)
+{
+   char tmpstr[OMX_MAX_STRINGNAME_SIZE];
+   vid_dec_PrivateType *priv;
+   omx_base_video_PortType *port;
+   struct pipe_screen *screen;
+   OMX_ERRORTYPE r;
+   int i;
+
+   assert(!comp->pComponentPrivate);
+
+   priv = comp->pComponentPrivate = CALLOC(1, sizeof(vid_dec_PrivateType));
+   if (!priv)
+      return OMX_ErrorInsufficientResources;
+
+   r = omx_base_filter_Constructor(comp, name);
+   if (r)
+       return r;
+
+   priv->profile = PIPE_VIDEO_PROFILE_UNKNOWN;
+
+   vid_dec_name_mpeg2(tmpstr);
+   if (!strcmp(name, tmpstr))
+      priv->profile = PIPE_VIDEO_PROFILE_MPEG2_MAIN;
+
+   vid_dec_name_avc(tmpstr);
+   if (!strcmp(name, tmpstr))
+      priv->profile = PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH;
+
+   priv->BufferMgmtCallback = vid_dec_FrameDecoded;
+   priv->messageHandler = vid_dec_MessageHandler;
+   priv->destructor = vid_dec_Destructor;
+
+   comp->SetParameter = vid_dec_SetParameter;
+   comp->GetParameter = vid_dec_GetParameter;
+
+   priv->screen = omx_get_screen();
+   if (!priv->screen)
+      return OMX_ErrorInsufficientResources;
+
+   screen = priv->screen->pscreen;
+   priv->pipe = screen->context_create(screen, priv->screen);
+   if (!priv->pipe)
+      return OMX_ErrorInsufficientResources;
+
+   priv->sPortTypesParam[OMX_PortDomainVideo].nStartPortNumber = 0;
+   priv->sPortTypesParam[OMX_PortDomainVideo].nPorts = 2;
+   priv->ports = CALLOC(2, sizeof(omx_base_PortType *));
+   if (!priv->ports)
+      return OMX_ErrorInsufficientResources;
+
+   for (i = 0; i < 2; ++i) {
+      priv->ports[i] = CALLOC(1, sizeof(omx_base_video_PortType));
+      if (!priv->ports[i])
+         return OMX_ErrorInsufficientResources;
+
+      base_video_port_Constructor(comp, &priv->ports[i], i, i == 0);
+   }
+
+   port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];
+   strcpy(port->sPortParam.format.video.cMIMEType,"video/MPEG2");
+   port->sPortParam.nBufferCountMin = 8;
+   port->sPortParam.nBufferCountActual = 8;
+   port->sPortParam.nBufferSize = DEFAULT_OUT_BUFFER_SIZE;
+   port->sPortParam.format.video.nFrameWidth = 176;
+   port->sPortParam.format.video.nFrameHeight = 144;
+   port->sPortParam.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG2;
+   port->sVideoParam.eCompressionFormat = OMX_VIDEO_CodingMPEG2;
+   port->Port_SendBufferFunction = vid_dec_DecodeBuffer;
+   port->Port_FreeBuffer = vid_dec_FreeDecBuffer;
+
+   port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX];
+   port->sPortParam.nBufferCountActual = 8;
+   port->sPortParam.nBufferCountMin = 4;
+   port->sPortParam.format.video.nFrameWidth = 176;
+   port->sPortParam.format.video.nFrameHeight = 144;
+   port->sPortParam.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+   port->sVideoParam.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
+
+   return OMX_ErrorNone;
+}
+
+static OMX_ERRORTYPE vid_dec_Destructor(OMX_COMPONENTTYPE *comp)
+{
+   vid_dec_PrivateType* priv = comp->pComponentPrivate;
+   int i;
+
+   if (priv->ports) {
+      for (i = 0; i < priv->sPortTypesParam[OMX_PortDomainVideo].nPorts; ++i) {
+         if(priv->ports[i])
+            priv->ports[i]->PortDestructor(priv->ports[i]);
+      }
+      FREE(priv->ports);
+      priv->ports=NULL;
+   }
+
+   if (priv->pipe)
+      priv->pipe->destroy(priv->pipe);
+
+   if (priv->screen)
+      omx_put_screen();
+
+   omx_base_filter_Destructor(comp);
+   return OMX_ErrorNone;
+}
+
+static OMX_ERRORTYPE vid_dec_SetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param)
+{
+   OMX_COMPONENTTYPE *comp = handle;
+   vid_dec_PrivateType *priv = comp->pComponentPrivate;
+   OMX_ERRORTYPE r;
+
+   if (!param)
+      return OMX_ErrorBadParameter;
+
+   switch(idx) {
+   case OMX_IndexParamPortDefinition: {
+      OMX_PARAM_PORTDEFINITIONTYPE *def = param;
+
+      r = omx_base_component_SetParameter(handle, idx, param);
+      if (r)
+         return r;
+
+      if (def->nPortIndex == OMX_BASE_FILTER_INPUTPORT_INDEX) {
+         omx_base_video_PortType *port;
+         unsigned framesize = def->format.video.nFrameWidth * def->format.video.nFrameHeight;
+
+         port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];
+         port->sPortParam.nBufferSize = framesize * 512 / (16*16);
+
+         port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX];
+         port->sPortParam.format.video.nFrameWidth = def->format.video.nFrameWidth;
+         port->sPortParam.format.video.nFrameHeight = def->format.video.nFrameHeight;
+         port->sPortParam.format.video.nStride = def->format.video.nFrameWidth;
+         port->sPortParam.format.video.nSliceHeight = def->format.video.nFrameHeight;
+         port->sPortParam.nBufferSize = framesize*3/2;
+
+         priv->callbacks->EventHandler(comp, priv->callbackData, OMX_EventPortSettingsChanged,
+                                       OMX_BASE_FILTER_OUTPUTPORT_INDEX, 0, NULL);
+      }
+      break;
+   }
+   case OMX_IndexParamStandardComponentRole: {
+      OMX_PARAM_COMPONENTROLETYPE *role = param;
+
+      r = checkHeader(param, sizeof(OMX_PARAM_COMPONENTROLETYPE));
+      if (r)
+         return r;
+      if (!strcmp((char *)role->cRole, OMX_VID_DEC_MPEG2_ROLE)) {
+         priv->profile = PIPE_VIDEO_PROFILE_MPEG2_MAIN;
+      } else if (!strcmp((char *)role->cRole, OMX_VID_DEC_AVC_ROLE)) {
+         priv->profile = PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH;
+      } else {
+         return OMX_ErrorBadParameter;
+      }
+
+      break;
+   }
+   case OMX_IndexParamVideoPortFormat: {
+      OMX_VIDEO_PARAM_PORTFORMATTYPE *format = param;
+      omx_base_video_PortType *port;
+
+      r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
+      if (r)
+         return r;
+
+      if (format->nPortIndex > 1)
+         return OMX_ErrorBadPortIndex;
+
+      port = (omx_base_video_PortType *)priv->ports[format->nPortIndex];
+      memcpy(&port->sVideoParam, format, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
+      break;
+   }
+   default:
+      return omx_base_component_SetParameter(handle, idx, param);
+   }
+   return OMX_ErrorNone;
+}
+
+static OMX_ERRORTYPE vid_dec_GetParameter(OMX_HANDLETYPE handle, OMX_INDEXTYPE idx, OMX_PTR param)
+{
+   OMX_COMPONENTTYPE *comp = handle;
+   vid_dec_PrivateType *priv = comp->pComponentPrivate;
+   OMX_ERRORTYPE r;
+
+   if (!param)
+      return OMX_ErrorBadParameter;
+
+   switch(idx) {
+   case OMX_IndexParamStandardComponentRole: {
+      OMX_PARAM_COMPONENTROLETYPE *role = param;
+
+      r = checkHeader(param, sizeof(OMX_PARAM_COMPONENTROLETYPE));
+      if (r)
+         return r;
+
+      if (priv->profile == PIPE_VIDEO_PROFILE_MPEG2_MAIN)
+         strcpy((char *)role->cRole, OMX_VID_DEC_MPEG2_ROLE);
+      else if (priv->profile == PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH)
+         strcpy((char *)role->cRole, OMX_VID_DEC_AVC_ROLE);
+      break;
+   }
+
+   case OMX_IndexParamVideoInit:
+      r = checkHeader(param, sizeof(OMX_PORT_PARAM_TYPE));
+      if (r)
+         return r;
+
+      memcpy(param, &priv->sPortTypesParam[OMX_PortDomainVideo], sizeof(OMX_PORT_PARAM_TYPE));
+      break;
+
+   case OMX_IndexParamVideoPortFormat: {
+      OMX_VIDEO_PARAM_PORTFORMATTYPE *format = param;
+      omx_base_video_PortType *port;
+
+      r = checkHeader(param, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
+      if (r)
+         return r;
+
+      if (format->nPortIndex > 1)
+         return OMX_ErrorBadPortIndex;
+
+      port = (omx_base_video_PortType *)priv->ports[format->nPortIndex];
+      memcpy(format, &port->sVideoParam, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
+      break;
+   }
+
+   default:
+      return omx_base_component_GetParameter(handle, idx, param);
+
+   }
+   return OMX_ErrorNone;
+}
+
+static OMX_ERRORTYPE vid_dec_MessageHandler(OMX_COMPONENTTYPE* comp, internalRequestMessageType *msg)
+{
+   vid_dec_PrivateType* priv = comp->pComponentPrivate;
+
+   if (msg->messageType == OMX_CommandStateSet) {
+      if ((msg->messageParam == OMX_StateIdle ) && (priv->state == OMX_StateLoaded)) {
+
+         struct pipe_video_codec templat = {};
+         omx_base_video_PortType *port;
+
+         port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];
+
+         templat.profile = priv->profile;
+         templat.entrypoint = PIPE_VIDEO_ENTRYPOINT_BITSTREAM;
+         templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
+         templat.width = port->sPortParam.format.video.nFrameWidth;
+         templat.height = port->sPortParam.format.video.nFrameHeight;
+         templat.max_references = 2;
+         templat.expect_chunked_decode = true;
+
+         priv->codec = priv->pipe->create_video_codec(priv->pipe, &templat);
+
+         if (priv->profile == PIPE_VIDEO_PROFILE_MPEG2_MAIN)
+            vid_dec_mpeg12_Init(priv);
+         else if (priv->profile == PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH)
+            vid_dec_h264_Init(priv);
+
+      } else if ((msg->messageParam == OMX_StateLoaded) && (priv->state == OMX_StateIdle)) {
+         if (priv->shadow) {
+            priv->shadow->destroy(priv->shadow);
+            priv->shadow = NULL;
+         }
+         if (priv->codec) {
+            priv->codec->destroy(priv->codec);
+            priv->codec = NULL;
+         }
+      }
+   }
+
+   return omx_base_component_MessageHandler(comp, msg);
+}
+
+void vid_dec_NeedTarget(vid_dec_PrivateType *priv)
+{
+   struct pipe_video_buffer templat = {};
+   omx_base_video_PortType *port;
+
+   port = (omx_base_video_PortType *)priv->ports[OMX_BASE_FILTER_INPUTPORT_INDEX];
+
+   if (!priv->target) {
+      templat.buffer_format = PIPE_FORMAT_NV12;
+      templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
+      templat.width = port->sPortParam.format.video.nFrameWidth;
+      templat.height = port->sPortParam.format.video.nFrameHeight;
+      templat.interlaced = false;
+      priv->target = priv->pipe->create_video_buffer(priv->pipe, &templat);
+   }
+}
+
+static void vid_dec_FreeInputPortPrivate(OMX_BUFFERHEADERTYPE *buf)
+{
+   struct pipe_video_buffer *vbuf = buf->pInputPortPrivate;
+   if (!vbuf)
+      return;
+
+   vbuf->destroy(vbuf);
+   buf->pInputPortPrivate = NULL;
+}
+
+static OMX_ERRORTYPE vid_dec_DecodeBuffer(omx_base_PortType *port, OMX_BUFFERHEADERTYPE *buf)
+{
+   OMX_COMPONENTTYPE* comp = port->standCompContainer;
+   vid_dec_PrivateType *priv = comp->pComponentPrivate;
+   unsigned i = priv->num_in_buffers++;
+   OMX_ERRORTYPE r;
+
+   priv->in_buffers[i] = buf;
+   priv->sizes[i] = buf->nFilledLen;
+   priv->inputs[i] = buf->pBuffer;
+
+   while (priv->num_in_buffers > (!!(buf->nFlags & OMX_BUFFERFLAG_EOS) ? 0 : 1)) {
+      bool eos = !!(priv->in_buffers[0]->nFlags & OMX_BUFFERFLAG_EOS);
+      unsigned min_bits_left = eos ? 32 : MAX2(buf->nFilledLen * 8, 32);
+      struct vl_vlc vlc;
+
+      vl_vlc_init(&vlc, priv->num_in_buffers, priv->inputs, priv->sizes);
+
+      if (priv->slice)
+         priv->bytes_left = vl_vlc_bits_left(&vlc) / 8;
+
+      while (vl_vlc_bits_left(&vlc) > min_bits_left) {
+         priv->Decode(priv, &vlc, min_bits_left);
+         vl_vlc_fillbits(&vlc);
+      }
+
+      if (priv->slice) {
+         unsigned bytes = priv->bytes_left - vl_vlc_bits_left(&vlc) / 8;
+
+         priv->codec->decode_bitstream(priv->codec, priv->target, &priv->picture.base,
+                                       1, &priv->slice, &bytes);
+
+         if (priv->num_in_buffers)
+            priv->slice = priv->inputs[1];
+         else
+            priv->slice = NULL;
+      }
+
+      if (eos && priv->frame_started)
+         priv->EndFrame(priv);
+
+      if (priv->frame_finished) {
+         priv->frame_finished = false;
+         priv->in_buffers[0]->nFilledLen = priv->in_buffers[0]->nAllocLen;
+         r = base_port_SendBufferFunction(port, priv->in_buffers[0]);
+      } else if (eos) {
+         vid_dec_FreeInputPortPrivate(priv->in_buffers[0]);
+         priv->in_buffers[0]->nFilledLen = priv->in_buffers[0]->nAllocLen;
+         r = base_port_SendBufferFunction(port, priv->in_buffers[0]);
+      } else {
+         priv->in_buffers[0]->nFilledLen = 0;
+         r = port->ReturnBufferFunction(port, priv->in_buffers[0]);
+      }
+
+      if (--priv->num_in_buffers) {
+         unsigned delta = (min_bits_left - vl_vlc_bits_left(&vlc)) / 8;
+
+         priv->in_buffers[0] = priv->in_buffers[1];
+         priv->sizes[0] = priv->sizes[1] - delta;
+         priv->inputs[0] = priv->inputs[1] + delta;
+      }
+
+      if (r)
+         return r;
+   }
+   return OMX_ErrorNone;
+}
+
+static OMX_ERRORTYPE vid_dec_FreeDecBuffer(omx_base_PortType *port, OMX_U32 idx, OMX_BUFFERHEADERTYPE *buf)
+{
+   vid_dec_FreeInputPortPrivate(buf);
+   return base_port_FreeBuffer(port, idx, buf);
+}
+
+static void vid_dec_FillOutput(vid_dec_PrivateType *priv, struct pipe_video_buffer *buf,
+                               OMX_BUFFERHEADERTYPE* output)
+{
+   omx_base_PortType *port = priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX];
+   OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video;
+
+   struct pipe_sampler_view **views;
+   struct pipe_transfer *transfer;
+   struct pipe_box box = { };
+
+   uint8_t *src, *dst;
+
+   views = buf->get_sampler_view_planes(buf);
+
+   dst = output->pBuffer;
+
+   box.width = def->nFrameWidth;
+   box.height = def->nFrameHeight;
+   box.depth = 1;
+
+   src = priv->pipe->transfer_map(priv->pipe, views[0]->texture, 0,
+                                  PIPE_TRANSFER_READ, &box, &transfer);
+   util_copy_rect(dst, views[0]->texture->format, def->nStride, 0, 0,
+                  box.width, box.height, src, transfer->stride, 0, 0);
+   pipe_transfer_unmap(priv->pipe, transfer);
+
+   dst = ((uint8_t*)output->pBuffer) + (def->nStride * box.height);
+
+   box.width = def->nFrameWidth / 2;
+   box.height = def->nFrameHeight / 2;
+   src = priv->pipe->transfer_map(priv->pipe, views[1]->texture, 0,
+                                  PIPE_TRANSFER_READ, &box, &transfer);
+   util_copy_rect(dst, views[1]->texture->format, def->nStride, 0, 0,
+                  box.width, box.height, src, transfer->stride, 0, 0);
+   pipe_transfer_unmap(priv->pipe, transfer);
+
+   output->nFilledLen = output->nAllocLen;
+}
+
+static void vid_dec_FrameDecoded(OMX_COMPONENTTYPE *comp, OMX_BUFFERHEADERTYPE* input,
+                                 OMX_BUFFERHEADERTYPE* output)
+{
+   vid_dec_PrivateType *priv = comp->pComponentPrivate;
+   bool eos = !!(input->nFlags & OMX_BUFFERFLAG_EOS);
+
+   if (!input->pInputPortPrivate)
+      input->pInputPortPrivate = priv->Flush(priv);
+
+   if (input->pInputPortPrivate)
+      vid_dec_FillOutput(priv, input->pInputPortPrivate, output);
+
+   if (eos && input->pInputPortPrivate)
+      vid_dec_FreeInputPortPrivate(input);
+   else
+      input->nFilledLen = 0;
+}
diff --git a/src/gallium/state_trackers/omx/vid_dec.h b/src/gallium/state_trackers/omx/vid_dec.h
new file mode 100644 (file)
index 0000000..d6c35b5
--- /dev/null
@@ -0,0 +1,119 @@
+/**************************************************************************
+ *
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/*
+ * Authors:
+ *      Christian König <christian.koenig@amd.com>
+ *
+ */
+
+#ifndef OMX_VID_DEC_H
+#define OMX_VID_DEC_H
+
+#include <X11/Xlib.h>
+
+#include <string.h>
+
+#include <OMX_Types.h>
+#include <OMX_Component.h>
+#include <OMX_Core.h>
+
+#include <bellagio/st_static_component_loader.h>
+#include <bellagio/omx_base_filter.h>
+
+#include "pipe/p_video_state.h"
+#include "state_tracker/drm_driver.h"
+#include "os/os_thread.h"
+#include "util/u_double_list.h"
+
+#define OMX_VID_DEC_BASE_NAME "OMX.%s.video_decoder"
+
+#define OMX_VID_DEC_MPEG2_NAME "OMX.%s.video_decoder.mpeg2"
+#define OMX_VID_DEC_MPEG2_ROLE "video_decoder.mpeg2"
+
+#define OMX_VID_DEC_AVC_NAME "OMX.%s.video_decoder.avc"
+#define OMX_VID_DEC_AVC_ROLE "video_decoder.avc"
+
+struct vl_vlc;
+
+DERIVEDCLASS(vid_dec_PrivateType, omx_base_filter_PrivateType)
+#define vid_dec_PrivateType_FIELDS omx_base_filter_PrivateType_FIELDS \
+   enum pipe_video_profile profile; \
+   struct vl_screen *screen; \
+   struct pipe_context *pipe; \
+   struct pipe_video_codec *codec; \
+   void (*Decode)(vid_dec_PrivateType *priv, struct vl_vlc *vlc, unsigned min_bits_left); \
+   void (*EndFrame)(vid_dec_PrivateType *priv); \
+   struct pipe_video_buffer *(*Flush)(vid_dec_PrivateType *priv); \
+   struct pipe_video_buffer *target, *shadow; \
+   union { \
+      struct { \
+         uint8_t intra_matrix[64]; \
+         uint8_t non_intra_matrix[64]; \
+      } mpeg12; \
+      struct { \
+         unsigned nal_ref_idc; \
+         bool IdrPicFlag; \
+         unsigned idr_pic_id; \
+         unsigned pic_order_cnt_lsb; \
+         unsigned pic_order_cnt_msb; \
+         unsigned delta_pic_order_cnt_bottom; \
+         unsigned delta_pic_order_cnt[2]; \
+         unsigned prevFrameNumOffset; \
+         struct pipe_h264_sps sps[32]; \
+         struct pipe_h264_pps pps[256]; \
+         struct list_head dpb_list; \
+         unsigned dpb_num; \
+      } h264; \
+   } codec_data; \
+   union { \
+      struct pipe_picture_desc base; \
+      struct pipe_mpeg12_picture_desc mpeg12; \
+      struct pipe_h264_picture_desc h264; \
+   } picture; \
+   unsigned num_in_buffers; \
+   OMX_BUFFERHEADERTYPE *in_buffers[2]; \
+   const void *inputs[2]; \
+   unsigned sizes[2]; \
+   bool frame_finished; \
+   bool frame_started; \
+   unsigned bytes_left; \
+   const void *slice;
+ENDCLASS(vid_dec_PrivateType)
+
+OMX_ERRORTYPE vid_dec_LoaderComponent(stLoaderComponentType *comp);
+
+/* used by MPEG12 and H264 implementation */
+void vid_dec_NeedTarget(vid_dec_PrivateType *priv);
+
+/* vid_dec_mpeg12.c */
+void vid_dec_mpeg12_Init(vid_dec_PrivateType *priv);
+
+/* vid_dec_h264.c */
+void vid_dec_h264_Init(vid_dec_PrivateType *priv);
+
+#endif
diff --git a/src/gallium/state_trackers/omx/vid_dec_h264.c b/src/gallium/state_trackers/omx/vid_dec_h264.c
new file mode 100644 (file)
index 0000000..20a6d9f
--- /dev/null
@@ -0,0 +1,980 @@
+/**************************************************************************
+ *
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/*
+ * Authors:
+ *      Christian König <christian.koenig@amd.com>
+ *
+ */
+
+#include "pipe/p_video_codec.h"
+#include "util/u_memory.h"
+#include "vl/vl_rbsp.h"
+
+#include "entrypoint.h"
+#include "vid_dec.h"
+
+#define DPB_MAX_SIZE 5
+
+struct dpb_list {
+   struct list_head list;
+   struct pipe_video_buffer *buffer;
+   unsigned poc;
+};
+
+static const uint8_t Default_4x4_Intra[16] = {
+    6, 13, 13, 20, 20, 20, 28, 28,
+   28, 28, 32, 32, 32, 37, 37, 42
+};
+
+static const uint8_t Default_4x4_Inter[16] = {
+   10, 14, 14, 20, 20, 20, 24, 24,
+   24, 24, 27, 27, 27, 30, 30, 34
+};
+
+static const uint8_t Default_8x8_Intra[64] = {
+    6, 10, 10, 13, 11, 13, 16, 16,
+   16, 16, 18, 18, 18, 18, 18, 23,
+   23, 23, 23, 23, 23, 25, 25, 25,
+   25, 25, 25, 25, 27, 27, 27, 27,
+   27, 27, 27, 27, 29, 29, 29, 29,
+   29, 29, 29, 31, 31, 31, 31, 31,
+   31, 33, 33, 33, 33, 33, 36, 36,
+   36, 36, 38, 38, 38, 40, 40, 42
+};
+
+static const uint8_t Default_8x8_Inter[64] = {
+    9, 13, 13, 15, 13, 15, 17, 17,
+   17, 17, 19, 19, 19, 19, 19, 21,
+   21, 21, 21, 21, 21, 22, 22, 22,
+   22, 22, 22, 22, 24, 24, 24, 24,
+   24, 24, 24, 24, 25, 25, 25, 25,
+   25, 25, 25, 27, 27, 27, 27, 27,
+   27, 28, 28, 28, 28, 28, 30, 30,
+   30, 30, 32, 32, 32, 33, 33, 35
+};
+
+static void vid_dec_h264_Decode(vid_dec_PrivateType *priv, struct vl_vlc *vlc, unsigned min_bits_left);
+static void vid_dec_h264_EndFrame(vid_dec_PrivateType *priv);
+static struct pipe_video_buffer *vid_dec_h264_Flush(vid_dec_PrivateType *priv);
+
+void vid_dec_h264_Init(vid_dec_PrivateType *priv)
+{
+   priv->picture.base.profile = PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH;
+
+   priv->Decode = vid_dec_h264_Decode;
+   priv->EndFrame = vid_dec_h264_EndFrame;
+   priv->Flush = vid_dec_h264_Flush;
+   
+   LIST_INITHEAD(&priv->codec_data.h264.dpb_list);
+   priv->picture.h264.field_order_cnt[0] = priv->picture.h264.field_order_cnt[1] = INT_MAX;
+}
+
+static void vid_dec_h264_BeginFrame(vid_dec_PrivateType *priv)
+{
+   //TODO: sane buffer handling
+
+   if (priv->frame_started)
+      return;
+
+   vid_dec_NeedTarget(priv);
+
+   priv->picture.h264.num_ref_frames = priv->picture.h264.pps->sps->max_num_ref_frames;
+
+   priv->codec->begin_frame(priv->codec, priv->target, &priv->picture.base);
+   priv->frame_started = true;
+}
+
+static struct pipe_video_buffer *vid_dec_h264_Flush(vid_dec_PrivateType *priv)
+{
+   struct dpb_list *entry, *result = NULL;
+   struct pipe_video_buffer *buf;
+
+   /* search for the lowest poc and break on zeros */
+   LIST_FOR_EACH_ENTRY(entry, &priv->codec_data.h264.dpb_list, list) {
+
+      if (result && entry->poc == 0)
+         break;
+
+      if (!result || entry->poc < result->poc)
+         result = entry;
+   }
+
+   if (!result)
+      return NULL;
+
+   buf = result->buffer;
+
+   --priv->codec_data.h264.dpb_num;
+   LIST_DEL(&result->list);
+   FREE(result);
+
+   return buf;
+}
+
+static void vid_dec_h264_EndFrame(vid_dec_PrivateType *priv)
+{
+   struct dpb_list *entry;
+   struct pipe_video_buffer *tmp;
+   bool top_field_first;
+
+   if (!priv->frame_started)
+      return;
+
+   priv->codec->end_frame(priv->codec, priv->target, &priv->picture.base);
+   priv->frame_started = false;
+
+   // TODO: implement frame number handling
+   priv->picture.h264.frame_num_list[0] = priv->picture.h264.frame_num;
+   priv->picture.h264.field_order_cnt_list[0][0] = priv->picture.h264.frame_num;
+   priv->picture.h264.field_order_cnt_list[0][1] = priv->picture.h264.frame_num;
+
+   top_field_first = priv->picture.h264.field_order_cnt[0] <  priv->picture.h264.field_order_cnt[1];
+
+   if (priv->picture.h264.field_pic_flag && priv->picture.h264.bottom_field_flag != top_field_first)
+      return;
+
+   /* add the decoded picture to the dpb list */
+   entry = CALLOC_STRUCT(dpb_list);
+   if (!entry)
+      return;
+
+   entry->buffer = priv->target;
+   entry->poc = MIN2(priv->picture.h264.field_order_cnt[0], priv->picture.h264.field_order_cnt[1]);
+   LIST_ADDTAIL(&entry->list, &priv->codec_data.h264.dpb_list);
+   ++priv->codec_data.h264.dpb_num;
+   priv->target = NULL;
+   priv->picture.h264.field_order_cnt[0] = priv->picture.h264.field_order_cnt[1] = INT_MAX;
+
+   if (priv->codec_data.h264.dpb_num <= DPB_MAX_SIZE)
+      return;
+
+   tmp = priv->in_buffers[0]->pInputPortPrivate;
+   priv->in_buffers[0]->pInputPortPrivate = vid_dec_h264_Flush(priv);
+   priv->target = tmp;
+   priv->frame_finished = priv->in_buffers[0]->pInputPortPrivate != NULL;
+}
+
+static void vui_parameters(struct vl_rbsp *rbsp)
+{
+   // TODO
+}
+
+static void scaling_list(struct vl_rbsp *rbsp, uint8_t *scalingList, unsigned sizeOfScalingList,
+                         const uint8_t *defaultList, const uint8_t *fallbackList)
+{
+   unsigned lastScale = 8, nextScale = 8;
+   unsigned i;
+
+   /* (pic|seq)_scaling_list_present_flag[i] */
+   if (!vl_rbsp_u(rbsp, 1)) {
+      if (fallbackList)
+         memcpy(scalingList, fallbackList, sizeOfScalingList);
+      return;
+   }
+
+   for (i = 0; i < sizeOfScalingList; ++i ) {
+
+      if (nextScale != 0) {
+         signed delta_scale = vl_rbsp_se(rbsp);
+         nextScale = (lastScale + delta_scale + 256) % 256;
+         if (i == 0 && nextScale == 0) {
+            memcpy(scalingList, defaultList, sizeOfScalingList);
+            return;
+         }
+      }
+      scalingList[i] = nextScale == 0 ? lastScale : nextScale;
+      lastScale = scalingList[i];
+   }
+}
+
+static struct pipe_h264_sps *seq_parameter_set_id(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp)
+{
+   unsigned id = vl_rbsp_ue(rbsp);
+   if (id >= Elements(priv->codec_data.h264.sps))
+      return NULL; /* invalid seq_parameter_set_id */
+
+   return &priv->codec_data.h264.sps[id];
+}
+
+static void seq_parameter_set(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp)
+{
+   struct pipe_h264_sps *sps;
+   unsigned profile_idc;
+   unsigned i;
+
+   /* Sequence parameter set */
+   profile_idc = vl_rbsp_u(rbsp, 8);
+
+   /* constraint_set0_flag */
+   vl_rbsp_u(rbsp, 1);
+
+   /* constraint_set1_flag */
+   vl_rbsp_u(rbsp, 1);
+
+   /* constraint_set2_flag */
+   vl_rbsp_u(rbsp, 1);
+
+   /* constraint_set3_flag */
+   vl_rbsp_u(rbsp, 1);
+
+   /* constraint_set4_flag */
+   vl_rbsp_u(rbsp, 1);
+
+   /* constraint_set5_flag */
+   vl_rbsp_u(rbsp, 1);
+
+   /* reserved_zero_2bits */
+   vl_rbsp_u(rbsp, 2);
+
+   /* level_idc */
+   vl_rbsp_u(rbsp, 8);
+
+   sps = seq_parameter_set_id(priv, rbsp);
+   if (!sps)
+      return;
+
+   memset(sps, 0, sizeof(*sps));
+   memset(sps->ScalingList4x4, 16, sizeof(sps->ScalingList4x4));
+   memset(sps->ScalingList8x8, 16, sizeof(sps->ScalingList8x8));
+
+   if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 244 ||
+       profile_idc == 44 || profile_idc == 83 || profile_idc == 86 || profile_idc == 118 ||
+       profile_idc == 128 || profile_idc == 138) {
+
+      sps->chroma_format_idc = vl_rbsp_ue(rbsp);
+
+      if (sps->chroma_format_idc == 3)
+         sps->separate_colour_plane_flag = vl_rbsp_u(rbsp, 1);
+
+      sps->bit_depth_luma_minus8 = vl_rbsp_ue(rbsp);
+
+      sps->bit_depth_chroma_minus8 = vl_rbsp_ue(rbsp);
+
+      /* qpprime_y_zero_transform_bypass_flag */
+      vl_rbsp_u(rbsp, 1);
+
+      sps->seq_scaling_matrix_present_flag = vl_rbsp_u(rbsp, 1);
+      if (sps->seq_scaling_matrix_present_flag) {
+
+         scaling_list(rbsp, sps->ScalingList4x4[0], 16, Default_4x4_Intra, Default_4x4_Intra);
+         scaling_list(rbsp, sps->ScalingList4x4[1], 16, Default_4x4_Intra, sps->ScalingList4x4[0]);
+         scaling_list(rbsp, sps->ScalingList4x4[2], 16, Default_4x4_Intra, sps->ScalingList4x4[1]);
+         scaling_list(rbsp, sps->ScalingList4x4[3], 16, Default_4x4_Inter, Default_4x4_Inter);
+         scaling_list(rbsp, sps->ScalingList4x4[4], 16, Default_4x4_Inter, sps->ScalingList4x4[3]);
+         scaling_list(rbsp, sps->ScalingList4x4[5], 16, Default_4x4_Inter, sps->ScalingList4x4[4]);
+
+         scaling_list(rbsp, sps->ScalingList8x8[0], 64, Default_8x8_Intra, Default_8x8_Intra);
+         scaling_list(rbsp, sps->ScalingList8x8[1], 64, Default_8x8_Inter, Default_8x8_Inter);
+         if (sps->chroma_format_idc == 3) {
+            scaling_list(rbsp, sps->ScalingList8x8[2], 64, Default_8x8_Intra, sps->ScalingList8x8[0]);
+            scaling_list(rbsp, sps->ScalingList8x8[3], 64, Default_8x8_Inter, sps->ScalingList8x8[1]);
+            scaling_list(rbsp, sps->ScalingList8x8[4], 64, Default_8x8_Intra, sps->ScalingList8x8[2]);
+            scaling_list(rbsp, sps->ScalingList8x8[5], 64, Default_8x8_Inter, sps->ScalingList8x8[3]);
+         }
+      }
+   } else if (profile_idc == 183)
+      sps->chroma_format_idc = 0;
+   else
+      sps->chroma_format_idc = 1;
+
+   sps->log2_max_frame_num_minus4 = vl_rbsp_ue(rbsp);
+
+   sps->pic_order_cnt_type = vl_rbsp_ue(rbsp);
+
+   if (sps->pic_order_cnt_type == 0)
+      sps->log2_max_pic_order_cnt_lsb_minus4 = vl_rbsp_ue(rbsp);
+   else {
+      sps->delta_pic_order_always_zero_flag = vl_rbsp_u(rbsp, 1);
+
+      sps->offset_for_non_ref_pic = vl_rbsp_se(rbsp);
+
+      sps->offset_for_top_to_bottom_field = vl_rbsp_se(rbsp);
+
+      sps->num_ref_frames_in_pic_order_cnt_cycle = vl_rbsp_ue(rbsp);
+
+      for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; ++i)
+         sps->offset_for_ref_frame[i] = vl_rbsp_se(rbsp);
+   }
+
+   sps->max_num_ref_frames = vl_rbsp_ue(rbsp);
+
+   /* gaps_in_frame_num_value_allowed_flag */
+   vl_rbsp_u(rbsp, 1);
+
+   /* pic_width_in_mbs_minus1 */
+   vl_rbsp_ue(rbsp);
+
+   /* pic_height_in_map_units_minus1 */
+   vl_rbsp_ue(rbsp);
+
+   sps->frame_mbs_only_flag = vl_rbsp_u(rbsp, 1);
+   if (!sps->frame_mbs_only_flag)
+      sps->mb_adaptive_frame_field_flag = vl_rbsp_u(rbsp, 1);
+
+   sps->direct_8x8_inference_flag = vl_rbsp_u(rbsp, 1);
+
+   /* frame_cropping_flag */
+   if (vl_rbsp_u(rbsp, 1)) {
+      /* frame_crop_left_offset */
+      vl_rbsp_ue(rbsp);
+
+      /* frame_crop_right_offset */
+      vl_rbsp_ue(rbsp);
+
+      /* frame_crop_top_offset */
+      vl_rbsp_ue(rbsp);
+
+      /* frame_crop_bottom_offset */
+      vl_rbsp_ue(rbsp);
+   }
+
+   /* vui_parameters_present_flag */
+   if (vl_rbsp_u(rbsp, 1))
+      vui_parameters(rbsp);
+}
+
+static struct pipe_h264_pps *pic_parameter_set_id(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp)
+{
+   unsigned id = vl_rbsp_ue(rbsp);
+   if (id >= Elements(priv->codec_data.h264.pps))
+      return NULL; /* invalid pic_parameter_set_id */
+
+   return &priv->codec_data.h264.pps[id];
+}
+
+static void picture_parameter_set(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp)
+{
+   struct pipe_h264_sps *sps;
+   struct pipe_h264_pps *pps;
+   unsigned i;
+
+   pps = pic_parameter_set_id(priv, rbsp);
+   if (!pps)
+      return;
+
+   memset(pps, 0, sizeof(*pps));
+
+   sps = pps->sps = seq_parameter_set_id(priv, rbsp);
+   if (!sps)
+      return;
+
+   memcpy(pps->ScalingList4x4, sps->ScalingList4x4, sizeof(pps->ScalingList4x4));
+   memcpy(pps->ScalingList8x8, sps->ScalingList8x8, sizeof(pps->ScalingList8x8));
+
+   pps->entropy_coding_mode_flag = vl_rbsp_u(rbsp, 1);
+
+   pps->bottom_field_pic_order_in_frame_present_flag = vl_rbsp_u(rbsp, 1);
+
+   pps->num_slice_groups_minus1 = vl_rbsp_ue(rbsp);
+   if (pps->num_slice_groups_minus1 > 0) {
+      pps->slice_group_map_type = vl_rbsp_ue(rbsp);
+
+      if (pps->slice_group_map_type == 0) {
+
+         for (i = 0; i <= pps->num_slice_groups_minus1; ++i)
+            /* run_length_minus1[i] */
+            vl_rbsp_ue(rbsp);
+
+      } else if (pps->slice_group_map_type == 2) {
+
+         for (i = 0; i <= pps->num_slice_groups_minus1; ++i) {
+            /* top_left[i] */
+            vl_rbsp_ue(rbsp);
+
+            /* bottom_right[i] */
+            vl_rbsp_ue(rbsp);
+         }
+
+      } else if (pps->slice_group_map_type >= 3 && pps->slice_group_map_type <= 5) {
+
+         /* slice_group_change_direction_flag */
+         vl_rbsp_u(rbsp, 1);
+
+         pps->slice_group_change_rate_minus1 = vl_rbsp_ue(rbsp);
+
+      } else if (pps->slice_group_map_type == 6) {
+
+         unsigned pic_size_in_map_units_minus1;
+
+         pic_size_in_map_units_minus1 = vl_rbsp_ue(rbsp);
+
+         for (i = 0; i <= pic_size_in_map_units_minus1; ++i)
+            /* slice_group_id[i] */
+            vl_rbsp_u(rbsp, log2(pps->num_slice_groups_minus1 + 1));
+      }
+   }
+
+   pps->num_ref_idx_l0_default_active_minus1 = vl_rbsp_ue(rbsp);
+
+   pps->num_ref_idx_l1_default_active_minus1 = vl_rbsp_ue(rbsp);
+
+   pps->weighted_pred_flag = vl_rbsp_u(rbsp, 1);
+
+   pps->weighted_bipred_idc = vl_rbsp_u(rbsp, 2);
+
+   pps->pic_init_qp_minus26 = vl_rbsp_se(rbsp);
+
+   /* pic_init_qs_minus26 */
+   vl_rbsp_se(rbsp);
+
+   pps->chroma_qp_index_offset = vl_rbsp_se(rbsp);
+
+   pps->deblocking_filter_control_present_flag = vl_rbsp_u(rbsp, 1);
+
+   pps->constrained_intra_pred_flag = vl_rbsp_u(rbsp, 1);
+
+   pps->redundant_pic_cnt_present_flag = vl_rbsp_u(rbsp, 1);
+
+   if (vl_rbsp_more_data(rbsp)) {
+      pps->transform_8x8_mode_flag = vl_rbsp_u(rbsp, 1);
+
+      /* pic_scaling_matrix_present_flag */
+      if (vl_rbsp_u(rbsp, 1)) {
+
+         scaling_list(rbsp, pps->ScalingList4x4[0], 16, Default_4x4_Intra,
+                      sps->seq_scaling_matrix_present_flag ? NULL : Default_4x4_Intra);
+         scaling_list(rbsp, pps->ScalingList4x4[1], 16, Default_4x4_Intra, pps->ScalingList4x4[0]);
+         scaling_list(rbsp, pps->ScalingList4x4[2], 16, Default_4x4_Intra, pps->ScalingList4x4[1]);
+         scaling_list(rbsp, pps->ScalingList4x4[3], 16, Default_4x4_Inter,
+                      sps->seq_scaling_matrix_present_flag ? NULL : Default_4x4_Inter);
+         scaling_list(rbsp, pps->ScalingList4x4[4], 16, Default_4x4_Inter, pps->ScalingList4x4[3]);
+         scaling_list(rbsp, pps->ScalingList4x4[5], 16, Default_4x4_Inter, pps->ScalingList4x4[4]);
+
+         if (pps->transform_8x8_mode_flag) {
+            scaling_list(rbsp, pps->ScalingList8x8[0], 64, Default_8x8_Intra,
+                         sps->seq_scaling_matrix_present_flag ? NULL : Default_8x8_Intra);
+            scaling_list(rbsp, pps->ScalingList8x8[1], 64, Default_8x8_Inter,
+                         sps->seq_scaling_matrix_present_flag ? NULL :  Default_8x8_Inter);
+            if (sps->chroma_format_idc == 3) {
+               scaling_list(rbsp, pps->ScalingList8x8[2], 64, Default_8x8_Intra, pps->ScalingList8x8[0]);
+               scaling_list(rbsp, pps->ScalingList8x8[3], 64, Default_8x8_Inter, pps->ScalingList8x8[1]);
+               scaling_list(rbsp, pps->ScalingList8x8[4], 64, Default_8x8_Intra, pps->ScalingList8x8[2]);
+               scaling_list(rbsp, pps->ScalingList8x8[5], 64, Default_8x8_Inter, pps->ScalingList8x8[3]);
+            }
+         }
+      }
+
+      pps->second_chroma_qp_index_offset = vl_rbsp_se(rbsp);
+   }
+}
+
+static void ref_pic_list_mvc_modification(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp)
+{
+   // TODO
+   assert(0);
+}
+
+static void ref_pic_list_modification(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp,
+                                      enum pipe_h264_slice_type slice_type)
+{
+   unsigned modification_of_pic_nums_idc;
+
+   if (slice_type != 2 && slice_type != 4) {
+      /* ref_pic_list_modification_flag_l0 */
+      if (vl_rbsp_u(rbsp, 1)) {
+         do {
+            modification_of_pic_nums_idc = vl_rbsp_ue(rbsp);
+            if (modification_of_pic_nums_idc == 0 ||
+                modification_of_pic_nums_idc == 1)
+               /* abs_diff_pic_num_minus1 */
+               vl_rbsp_ue(rbsp);
+            else if (modification_of_pic_nums_idc == 2)
+               /* long_term_pic_num */
+               vl_rbsp_ue(rbsp);
+         } while (modification_of_pic_nums_idc != 3);
+      }
+   }
+
+   if (slice_type == 1) {
+      /* ref_pic_list_modification_flag_l1 */
+      if (vl_rbsp_u(rbsp, 1)) {
+         do {
+            modification_of_pic_nums_idc = vl_rbsp_ue(rbsp);
+            if (modification_of_pic_nums_idc == 0 ||
+                modification_of_pic_nums_idc == 1)
+               /* abs_diff_pic_num_minus1 */
+               vl_rbsp_ue(rbsp);
+            else if (modification_of_pic_nums_idc == 2)
+               /* long_term_pic_num */
+               vl_rbsp_ue(rbsp);
+         } while (modification_of_pic_nums_idc != 3);
+      }
+   }
+}
+
+static void pred_weight_table(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp,
+                              struct pipe_h264_sps *sps, enum pipe_h264_slice_type slice_type)
+{
+   unsigned ChromaArrayType = sps->separate_colour_plane_flag ? 0 : sps->chroma_format_idc;
+   unsigned i, j;
+
+   /* luma_log2_weight_denom */
+   vl_rbsp_ue(rbsp);
+
+   if (ChromaArrayType != 0)
+      /* chroma_log2_weight_denom */
+      vl_rbsp_ue(rbsp);
+
+   for (i = 0; i <= priv->picture.h264.num_ref_idx_l0_active_minus1; ++i) {
+      /* luma_weight_l0_flag */
+      if (vl_rbsp_u(rbsp, 1)) {
+         /* luma_weight_l0[i] */
+         vl_rbsp_se(rbsp);
+         /* luma_offset_l0[i] */
+         vl_rbsp_se(rbsp);
+      }
+      if (ChromaArrayType != 0) {
+         /* chroma_weight_l0_flag */
+         if (vl_rbsp_u(rbsp, 1)) {
+            for (j = 0; j < 2; ++j) {
+               /* chroma_weight_l0[i][j] */
+               vl_rbsp_se(rbsp);
+               /* chroma_offset_l0[i][j] */
+               vl_rbsp_se(rbsp);
+            }
+         }
+      }
+   }
+
+   if (slice_type == 1) {
+      for (i = 0; i <= priv->picture.h264.num_ref_idx_l1_active_minus1; ++i) {
+         /* luma_weight_l1_flag */
+         if (vl_rbsp_u(rbsp, 1)) {
+            /* luma_weight_l1[i] */
+            vl_rbsp_se(rbsp);
+            /* luma_offset_l1[i] */
+            vl_rbsp_se(rbsp);
+         }
+         if (ChromaArrayType != 0) {
+            /* chroma_weight_l1_flag */
+            if (vl_rbsp_u(rbsp, 1)) {
+               for (j = 0; j < 2; ++j) {
+                  /* chroma_weight_l1[i][j] */
+                  vl_rbsp_se(rbsp);
+                  /* chroma_offset_l1[i][j] */
+                  vl_rbsp_se(rbsp);
+               }
+            }
+         }
+      }
+   }
+}
+
+static void dec_ref_pic_marking(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp,
+                                bool IdrPicFlag)
+{
+   unsigned memory_management_control_operation;
+
+   if (IdrPicFlag) {
+      /* no_output_of_prior_pics_flag */
+      vl_rbsp_u(rbsp, 1);
+      /* long_term_reference_flag */
+      vl_rbsp_u(rbsp, 1);
+   } else {
+      /* adaptive_ref_pic_marking_mode_flag */
+      if (vl_rbsp_u(rbsp, 1)) {
+         do {
+            memory_management_control_operation = vl_rbsp_ue(rbsp);
+
+            if (memory_management_control_operation == 1 ||
+                memory_management_control_operation == 3)
+               /* difference_of_pic_nums_minus1 */
+               vl_rbsp_ue(rbsp);
+
+            if (memory_management_control_operation == 2)
+               /* long_term_pic_num */
+               vl_rbsp_ue(rbsp);
+
+            if (memory_management_control_operation == 3 ||
+                memory_management_control_operation == 6)
+               /* long_term_frame_idx */
+               vl_rbsp_ue(rbsp);
+
+            if (memory_management_control_operation == 4)
+               /* max_long_term_frame_idx_plus1 */
+               vl_rbsp_ue(rbsp);
+         } while (memory_management_control_operation != 0);
+      }
+   }
+}
+
+static void slice_header(vid_dec_PrivateType *priv, struct vl_rbsp *rbsp,
+                         unsigned nal_ref_idc, unsigned nal_unit_type)
+{
+   enum pipe_h264_slice_type slice_type;
+   struct pipe_h264_pps *pps;
+   struct pipe_h264_sps *sps;
+   unsigned frame_num, prevFrameNum;
+   bool IdrPicFlag = nal_unit_type == 5;
+
+   if (IdrPicFlag != priv->codec_data.h264.IdrPicFlag)
+      vid_dec_h264_EndFrame(priv);
+
+   priv->codec_data.h264.IdrPicFlag = IdrPicFlag;
+
+   /* first_mb_in_slice */
+   vl_rbsp_ue(rbsp);
+
+   slice_type = vl_rbsp_ue(rbsp) % 5;
+
+   pps = pic_parameter_set_id(priv, rbsp);
+   if (!pps)
+      return;
+
+   sps = pps->sps;
+   if (!sps)
+      return;
+
+   if (pps != priv->picture.h264.pps)
+      vid_dec_h264_EndFrame(priv);
+
+   priv->picture.h264.pps = pps;
+
+   if (sps->separate_colour_plane_flag == 1 )
+      /* colour_plane_id */
+      vl_rbsp_u(rbsp, 2);
+
+   frame_num = vl_rbsp_u(rbsp, sps->log2_max_frame_num_minus4 + 4);
+
+   if (frame_num != priv->picture.h264.frame_num)
+      vid_dec_h264_EndFrame(priv);
+
+   prevFrameNum = priv->picture.h264.frame_num;
+   priv->picture.h264.frame_num = frame_num;
+
+   priv->picture.h264.field_pic_flag = 0;
+   priv->picture.h264.bottom_field_flag = 0;
+
+   if (!sps->frame_mbs_only_flag) {
+      unsigned field_pic_flag = vl_rbsp_u(rbsp, 1);
+
+      if (!field_pic_flag && field_pic_flag != priv->picture.h264.field_pic_flag)
+         vid_dec_h264_EndFrame(priv);
+
+      priv->picture.h264.field_pic_flag = field_pic_flag;
+
+      if (priv->picture.h264.field_pic_flag) {
+         unsigned bottom_field_flag = vl_rbsp_u(rbsp, 1);
+
+         if (bottom_field_flag != priv->picture.h264.bottom_field_flag);
+            vid_dec_h264_EndFrame(priv);
+
+         priv->picture.h264.bottom_field_flag = bottom_field_flag;
+      }
+   }
+
+   if (IdrPicFlag) {
+      unsigned idr_pic_id = vl_rbsp_ue(rbsp);
+
+      if (idr_pic_id != priv->codec_data.h264.idr_pic_id)
+         vid_dec_h264_EndFrame(priv);
+
+      priv->codec_data.h264.idr_pic_id = idr_pic_id;
+   }
+
+   if (sps->pic_order_cnt_type == 0) {
+      unsigned log2_max_pic_order_cnt_lsb = sps->log2_max_pic_order_cnt_lsb_minus4 + 4;
+      unsigned max_pic_order_cnt_lsb = 1 << log2_max_pic_order_cnt_lsb;
+      unsigned pic_order_cnt_lsb = vl_rbsp_u(rbsp, log2_max_pic_order_cnt_lsb);
+      unsigned pic_order_cnt_msb;
+
+      if (pic_order_cnt_lsb != priv->codec_data.h264.pic_order_cnt_lsb)
+         vid_dec_h264_EndFrame(priv);
+
+      if ((pic_order_cnt_lsb < priv->codec_data.h264.pic_order_cnt_lsb) &&
+          (priv->codec_data.h264.pic_order_cnt_lsb - pic_order_cnt_lsb) >= (max_pic_order_cnt_lsb / 2))
+         pic_order_cnt_msb = priv->codec_data.h264.pic_order_cnt_msb + max_pic_order_cnt_lsb;
+
+      else if ((pic_order_cnt_lsb > priv->codec_data.h264.pic_order_cnt_lsb) &&
+          (pic_order_cnt_lsb - priv->codec_data.h264.pic_order_cnt_lsb) > (max_pic_order_cnt_lsb / 2))
+         pic_order_cnt_msb = priv->codec_data.h264.pic_order_cnt_msb - max_pic_order_cnt_lsb;
+
+      else
+         pic_order_cnt_msb = priv->codec_data.h264.pic_order_cnt_msb;
+
+      priv->codec_data.h264.pic_order_cnt_msb = pic_order_cnt_msb;
+      priv->codec_data.h264.pic_order_cnt_lsb = pic_order_cnt_lsb;
+
+      if (pps->bottom_field_pic_order_in_frame_present_flag && !priv->picture.h264.field_pic_flag) {
+         unsigned delta_pic_order_cnt_bottom = vl_rbsp_se(rbsp);
+
+         if (delta_pic_order_cnt_bottom != priv->codec_data.h264.delta_pic_order_cnt_bottom)
+            vid_dec_h264_EndFrame(priv);
+
+         priv->codec_data.h264.delta_pic_order_cnt_bottom = delta_pic_order_cnt_bottom;
+      }
+
+      priv->picture.h264.field_order_cnt[0] = pic_order_cnt_msb + pic_order_cnt_lsb;
+      priv->picture.h264.field_order_cnt[1] = pic_order_cnt_msb + pic_order_cnt_lsb;
+      if (!priv->picture.h264.field_pic_flag)
+         priv->picture.h264.field_order_cnt[1] += priv->codec_data.h264.delta_pic_order_cnt_bottom;
+
+   } else if (sps->pic_order_cnt_type == 1) {
+      unsigned MaxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4);
+      unsigned FrameNumOffset, absFrameNum, expectedPicOrderCnt;
+
+      if (!sps->delta_pic_order_always_zero_flag) {
+         unsigned delta_pic_order_cnt[2];
+
+         delta_pic_order_cnt[0] = vl_rbsp_se(rbsp);
+
+         if (delta_pic_order_cnt[0] != priv->codec_data.h264.delta_pic_order_cnt[0])
+            vid_dec_h264_EndFrame(priv);
+
+         priv->codec_data.h264.delta_pic_order_cnt[0] = delta_pic_order_cnt[0];
+
+         if (pps->bottom_field_pic_order_in_frame_present_flag && !priv->picture.h264.field_pic_flag) {
+            delta_pic_order_cnt[1] = vl_rbsp_se(rbsp);
+
+            if (delta_pic_order_cnt[1] != priv->codec_data.h264.delta_pic_order_cnt[1])
+               vid_dec_h264_EndFrame(priv);
+
+            priv->codec_data.h264.delta_pic_order_cnt[1] = delta_pic_order_cnt[1];
+         }
+      }
+
+      if (IdrPicFlag)
+         FrameNumOffset = 0;
+      else if (prevFrameNum > frame_num)
+         FrameNumOffset = priv->codec_data.h264.prevFrameNumOffset + MaxFrameNum;
+      else
+         FrameNumOffset = priv->codec_data.h264.prevFrameNumOffset;
+
+      if (sps->num_ref_frames_in_pic_order_cnt_cycle != 0)
+         absFrameNum = FrameNumOffset + frame_num;
+      else
+         absFrameNum = 0;
+
+      if (nal_ref_idc == 0 && absFrameNum > 0)
+         absFrameNum = absFrameNum - 1;
+
+      if (absFrameNum > 0) {
+         unsigned picOrderCntCycleCnt = (absFrameNum - 1) / sps->num_ref_frames_in_pic_order_cnt_cycle;
+         unsigned frameNumInPicOrderCntCycle = (absFrameNum - 1) % sps->num_ref_frames_in_pic_order_cnt_cycle;
+         signed ExpectedDeltaPerPicOrderCntCycle = 0;
+         unsigned i;
+
+         for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; ++i)
+            ExpectedDeltaPerPicOrderCntCycle += sps->offset_for_ref_frame[i];
+
+         expectedPicOrderCnt = picOrderCntCycleCnt * ExpectedDeltaPerPicOrderCntCycle;
+         for (i = 0; i <= frameNumInPicOrderCntCycle; ++i)
+            expectedPicOrderCnt += sps->offset_for_ref_frame[i];
+
+      } else
+         expectedPicOrderCnt = 0;
+
+      if (nal_ref_idc == 0)
+         expectedPicOrderCnt += sps->offset_for_non_ref_pic;
+
+      if (!priv->picture.h264.field_pic_flag) {
+         priv->picture.h264.field_order_cnt[0] = expectedPicOrderCnt + priv->codec_data.h264.delta_pic_order_cnt[0];
+         priv->picture.h264.field_order_cnt[1] = priv->picture.h264.field_order_cnt[0] +
+            sps->offset_for_top_to_bottom_field + priv->codec_data.h264.delta_pic_order_cnt[1];
+         
+      } else if (!priv->picture.h264.bottom_field_flag)
+         priv->picture.h264.field_order_cnt[0] = expectedPicOrderCnt + priv->codec_data.h264.delta_pic_order_cnt[0];
+      else
+         priv->picture.h264.field_order_cnt[1] = expectedPicOrderCnt + sps->offset_for_top_to_bottom_field +
+            priv->codec_data.h264.delta_pic_order_cnt[0];
+
+   } else if (sps->pic_order_cnt_type == 2) {
+      unsigned MaxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4);
+      unsigned FrameNumOffset, tempPicOrderCnt;
+
+      if (IdrPicFlag)
+         FrameNumOffset = 0;
+      else if (prevFrameNum > frame_num)
+         FrameNumOffset = priv->codec_data.h264.prevFrameNumOffset + MaxFrameNum;
+      else
+         FrameNumOffset = priv->codec_data.h264.prevFrameNumOffset;
+
+      if (IdrPicFlag)
+         tempPicOrderCnt = 0;
+      else if (nal_ref_idc == 0)
+         tempPicOrderCnt = 2 * (FrameNumOffset + frame_num) - 1;
+      else
+         tempPicOrderCnt = 2 * (FrameNumOffset + frame_num);
+
+      if (!priv->picture.h264.field_pic_flag) {
+         priv->picture.h264.field_order_cnt[0] = tempPicOrderCnt;
+         priv->picture.h264.field_order_cnt[1] = tempPicOrderCnt;
+         
+      } else if (!priv->picture.h264.bottom_field_flag)
+         priv->picture.h264.field_order_cnt[0] = tempPicOrderCnt;
+      else
+         priv->picture.h264.field_order_cnt[1] = tempPicOrderCnt;
+   }
+
+   if (pps->redundant_pic_cnt_present_flag)
+      /* redundant_pic_cnt */
+      vl_rbsp_ue(rbsp);
+
+   if (slice_type == PIPE_H264_SLICE_TYPE_B)
+      /* direct_spatial_mv_pred_flag */
+      vl_rbsp_u(rbsp, 1);
+
+   priv->picture.h264.num_ref_idx_l0_active_minus1 = pps->num_ref_idx_l0_default_active_minus1;
+   priv->picture.h264.num_ref_idx_l1_active_minus1 = pps->num_ref_idx_l1_default_active_minus1;
+   if (slice_type == PIPE_H264_SLICE_TYPE_P ||
+       slice_type == PIPE_H264_SLICE_TYPE_SP ||
+       slice_type == PIPE_H264_SLICE_TYPE_B) {
+
+      /* num_ref_idx_active_override_flag */
+      if (vl_rbsp_u(rbsp, 1)) {
+         priv->picture.h264.num_ref_idx_l0_active_minus1 = vl_rbsp_ue(rbsp);
+
+         if (slice_type == PIPE_H264_SLICE_TYPE_B)
+            priv->picture.h264.num_ref_idx_l1_active_minus1 = vl_rbsp_ue(rbsp);
+      }
+   }
+
+   if (nal_unit_type == 20 || nal_unit_type == 21)
+      ref_pic_list_mvc_modification(priv, rbsp);
+   else
+      ref_pic_list_modification(priv, rbsp, slice_type);
+
+   if ((pps->weighted_pred_flag && (slice_type == PIPE_H264_SLICE_TYPE_P || slice_type == PIPE_H264_SLICE_TYPE_SP)) ||
+       (pps->weighted_bipred_idc == 1 && slice_type == PIPE_H264_SLICE_TYPE_B))
+      pred_weight_table(priv, rbsp, sps, slice_type);
+
+   if (nal_ref_idc != 0)
+      dec_ref_pic_marking(priv, rbsp, IdrPicFlag);
+
+   if (pps->entropy_coding_mode_flag && slice_type != PIPE_H264_SLICE_TYPE_I && slice_type != PIPE_H264_SLICE_TYPE_SI)
+      /* cabac_init_idc */
+      vl_rbsp_ue(rbsp);
+
+   /* slice_qp_delta */
+   vl_rbsp_se(rbsp);
+
+   if (slice_type == PIPE_H264_SLICE_TYPE_SP || slice_type == PIPE_H264_SLICE_TYPE_SI) {
+      if (slice_type == PIPE_H264_SLICE_TYPE_SP)
+         /* sp_for_switch_flag */
+         vl_rbsp_u(rbsp, 1);
+
+      /*slice_qs_delta */
+      vl_rbsp_se(rbsp);
+   }
+
+   if (pps->deblocking_filter_control_present_flag) {
+      unsigned disable_deblocking_filter_idc = vl_rbsp_ue(rbsp);
+
+      if (disable_deblocking_filter_idc != 1) {
+         /* slice_alpha_c0_offset_div2 */
+         vl_rbsp_se(rbsp);
+
+         /* slice_beta_offset_div2 */
+         vl_rbsp_se(rbsp);
+      }
+   }
+
+   if (pps->num_slice_groups_minus1 > 0 && pps->slice_group_map_type >= 3 && pps->slice_group_map_type <= 5)
+      /* slice_group_change_cycle */
+      vl_rbsp_u(rbsp, 2);
+}
+
+static void vid_dec_h264_Decode(vid_dec_PrivateType *priv, struct vl_vlc *vlc, unsigned min_bits_left)
+{
+   unsigned nal_ref_idc, nal_unit_type;
+
+   if (!vl_vlc_search_byte(vlc, vl_vlc_bits_left(vlc) - min_bits_left, 0x00))
+      return;
+
+   if (vl_vlc_peekbits(vlc, 24) != 0x000001) {
+      vl_vlc_eatbits(vlc, 8);
+      return;
+   }
+
+   if (priv->slice) {
+      unsigned bytes = priv->bytes_left - (vl_vlc_bits_left(vlc) / 8);
+      priv->codec->decode_bitstream(priv->codec, priv->target, &priv->picture.base,
+                                    1, &priv->slice, &bytes);
+      priv->slice = NULL;
+   }
+
+   vl_vlc_eatbits(vlc, 24);
+
+   /* forbidden_zero_bit */
+   vl_vlc_eatbits(vlc, 1);
+
+   nal_ref_idc = vl_vlc_get_uimsbf(vlc, 2);
+
+   if (nal_ref_idc != priv->codec_data.h264.nal_ref_idc &&
+       (nal_ref_idc * priv->codec_data.h264.nal_ref_idc) == 0)
+      vid_dec_h264_EndFrame(priv);
+
+   priv->codec_data.h264.nal_ref_idc = nal_ref_idc;
+
+   nal_unit_type = vl_vlc_get_uimsbf(vlc, 5);
+
+   if (nal_unit_type != 1 && nal_unit_type != 5)
+      vid_dec_h264_EndFrame(priv);
+
+   if (nal_unit_type == 7) {
+      struct vl_rbsp rbsp;
+      vl_rbsp_init(&rbsp, vlc, ~0);
+      seq_parameter_set(priv, &rbsp);
+
+   } else if (nal_unit_type == 8) {
+      struct vl_rbsp rbsp;
+      vl_rbsp_init(&rbsp, vlc, ~0);
+      picture_parameter_set(priv, &rbsp);
+
+   } else if (nal_unit_type == 1 || nal_unit_type == 5) {
+      /* Coded slice of a non-IDR or IDR picture */
+      unsigned bits = vl_vlc_valid_bits(vlc);
+      unsigned bytes = bits / 8 + 4;
+      struct vl_rbsp rbsp;
+      uint8_t buf[8];
+      const void *ptr = buf;
+      unsigned i;
+
+      buf[0] = 0x0;
+      buf[1] = 0x0;
+      buf[2] = 0x1;
+      buf[3] = (nal_ref_idc << 5) | nal_unit_type;
+      for (i = 4; i < bytes; ++i)
+         buf[i] = vl_vlc_peekbits(vlc, bits) >> ((bytes - i - 1) * 8);
+
+      priv->bytes_left = (vl_vlc_bits_left(vlc) - bits) / 8;
+      priv->slice = vlc->data;
+
+      vl_rbsp_init(&rbsp, vlc, 128);
+      slice_header(priv, &rbsp, nal_ref_idc, nal_unit_type);
+
+      vid_dec_h264_BeginFrame(priv);
+
+      priv->codec->decode_bitstream(priv->codec, priv->target, &priv->picture.base,
+                                    1, &ptr, &bytes);
+   }
+
+   /* resync to byte boundary */
+   vl_vlc_eatbits(vlc, vl_vlc_valid_bits(vlc) % 8);
+}
diff --git a/src/gallium/state_trackers/omx/vid_dec_mpeg12.c b/src/gallium/state_trackers/omx/vid_dec_mpeg12.c
new file mode 100644 (file)
index 0000000..de4c69a
--- /dev/null
@@ -0,0 +1,367 @@
+/**************************************************************************
+ *
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/*
+ * Authors:
+ *      Christian König <christian.koenig@amd.com>
+ *
+ */
+
+#include "pipe/p_video_codec.h"
+#include "vl/vl_vlc.h"
+#include "vl/vl_zscan.h"
+
+#include "vid_dec.h"
+
+static uint8_t default_intra_matrix[64] = {
+    8, 16, 19, 22, 26, 27, 29, 34,
+   16, 16, 19, 22, 22, 22, 22, 26,
+   26, 27, 22, 26, 26, 27, 29, 24,
+   27, 27, 29, 32, 27, 29, 29, 32,
+   35, 29, 34, 34, 35, 40, 34, 34,
+   37, 40, 48, 37, 38, 40, 48, 58,
+   26, 27, 29, 34, 38, 46, 56, 69,
+   27, 29, 35, 38, 46, 56, 69, 83
+};
+
+static uint8_t default_non_intra_matrix[64] = {
+   16, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 16, 16,
+   16, 16, 16, 16, 16, 16, 16, 16
+};
+
+static void vid_dec_mpeg12_Decode(vid_dec_PrivateType *priv, struct vl_vlc *vlc, unsigned min_bits_left);
+static void vid_dec_mpeg12_EndFrame(vid_dec_PrivateType *priv);
+static struct pipe_video_buffer *vid_dec_mpeg12_Flush(vid_dec_PrivateType *priv);
+
+void vid_dec_mpeg12_Init(vid_dec_PrivateType *priv)
+{
+   priv->picture.base.profile = PIPE_VIDEO_PROFILE_MPEG2_MAIN;
+   priv->picture.mpeg12.intra_matrix = default_intra_matrix;
+   priv->picture.mpeg12.non_intra_matrix = default_non_intra_matrix;
+
+   priv->Decode = vid_dec_mpeg12_Decode;
+   priv->EndFrame = vid_dec_mpeg12_EndFrame;
+   priv->Flush = vid_dec_mpeg12_Flush;
+}
+
+static void BeginFrame(vid_dec_PrivateType *priv)
+{
+   if (priv->picture.mpeg12.picture_coding_type != PIPE_MPEG12_PICTURE_CODING_TYPE_B) {
+      priv->picture.mpeg12.ref[0] = priv->picture.mpeg12.ref[1];
+      priv->picture.mpeg12.ref[1] = NULL;
+   }
+
+   if (priv->target == priv->picture.mpeg12.ref[0]) {
+      struct pipe_video_buffer *tmp = priv->target;
+      priv->target = priv->shadow;
+      priv->shadow = tmp;
+   }
+
+   vid_dec_NeedTarget(priv);
+
+   priv->codec->begin_frame(priv->codec, priv->target, &priv->picture.base);
+   priv->frame_started = true;
+}
+
+static void vid_dec_mpeg12_EndFrame(vid_dec_PrivateType *priv)
+{
+   struct pipe_video_buffer *done;
+
+   priv->codec->end_frame(priv->codec, priv->target, &priv->picture.base);
+   priv->frame_started = false;
+
+   if (priv->picture.mpeg12.picture_coding_type != PIPE_MPEG12_PICTURE_CODING_TYPE_B) {
+
+      priv->picture.mpeg12.ref[1] = priv->target;
+      done = priv->picture.mpeg12.ref[0];
+      if (!done) {
+         priv->target = NULL;
+         return;
+      }
+
+   } else
+      done = priv->target;
+
+   priv->frame_finished = true;
+   priv->target = priv->in_buffers[0]->pInputPortPrivate;
+   priv->in_buffers[0]->pInputPortPrivate = done;
+}
+
+static struct pipe_video_buffer *vid_dec_mpeg12_Flush(vid_dec_PrivateType *priv)
+{
+   struct pipe_video_buffer *result = priv->picture.mpeg12.ref[1];
+   priv->picture.mpeg12.ref[1] = NULL;
+   return result;
+}
+
+static void vid_dec_mpeg12_Decode(vid_dec_PrivateType *priv, struct vl_vlc *vlc, unsigned min_bits_left)
+{
+   uint8_t code;
+   unsigned i;
+
+   if (!vl_vlc_search_byte(vlc, vl_vlc_bits_left(vlc) - min_bits_left, 0x00))
+      return;
+
+   if (vl_vlc_peekbits(vlc, 24) != 0x000001) {
+      vl_vlc_eatbits(vlc, 8);
+      return;
+   }
+
+   if (priv->slice) {
+      unsigned bytes = priv->bytes_left - (vl_vlc_bits_left(vlc) / 8);
+      priv->codec->decode_bitstream(priv->codec, priv->target, &priv->picture.base,
+                                    1, &priv->slice, &bytes);
+      priv->slice = NULL;
+   }
+
+   vl_vlc_eatbits(vlc, 24);
+   code = vl_vlc_get_uimsbf(vlc, 8);
+
+   if (priv->frame_started && (code == 0x00 || code > 0xAF))
+      vid_dec_mpeg12_EndFrame(priv);
+
+   if (code == 0xB3) {
+      /* sequence header code */
+      vl_vlc_fillbits(vlc);
+
+      /* horizontal_size_value */
+      vl_vlc_get_uimsbf(vlc, 12);
+
+      /* vertical_size_value */
+      vl_vlc_get_uimsbf(vlc, 12);
+
+      /* aspect_ratio_information */
+      vl_vlc_get_uimsbf(vlc, 4);
+
+      /* frame_rate_code */
+      vl_vlc_get_uimsbf(vlc, 4);
+
+      vl_vlc_fillbits(vlc);
+
+      /* bit_rate_value */
+      vl_vlc_get_uimsbf(vlc, 18);
+
+      /* marker_bit */
+      vl_vlc_get_uimsbf(vlc, 1);
+
+      /* vbv_buffer_size_value */
+      vl_vlc_get_uimsbf(vlc, 10);
+
+      /* constrained_parameters_flag */
+      vl_vlc_get_uimsbf(vlc, 1);
+
+      vl_vlc_fillbits(vlc);
+
+      /* load_intra_quantiser_matrix */
+      if (vl_vlc_get_uimsbf(vlc, 1)) {
+         /* intra_quantiser_matrix */
+         priv->picture.mpeg12.intra_matrix = priv->codec_data.mpeg12.intra_matrix;
+         for (i = 0; i < 64; ++i) {
+            priv->codec_data.mpeg12.intra_matrix[vl_zscan_normal[i]] = vl_vlc_get_uimsbf(vlc, 8);
+            vl_vlc_fillbits(vlc);
+         }
+      } else
+         priv->picture.mpeg12.intra_matrix = default_intra_matrix;
+
+      /* load_non_intra_quantiser_matrix */
+      if (vl_vlc_get_uimsbf(vlc, 1)) {
+         /* non_intra_quantiser_matrix */
+         priv->picture.mpeg12.non_intra_matrix = priv->codec_data.mpeg12.non_intra_matrix;
+         for (i = 0; i < 64; ++i) {
+            priv->codec_data.mpeg12.non_intra_matrix[i] = vl_vlc_get_uimsbf(vlc, 8);
+            vl_vlc_fillbits(vlc);
+         }
+      } else
+         priv->picture.mpeg12.non_intra_matrix = default_non_intra_matrix;
+
+   } else if (code == 0x00) {
+      /* picture start code */
+      vl_vlc_fillbits(vlc);
+
+      /* temporal_reference */
+      vl_vlc_get_uimsbf(vlc, 10);
+
+      priv->picture.mpeg12.picture_coding_type = vl_vlc_get_uimsbf(vlc, 3);
+
+      /* vbv_delay */
+      vl_vlc_get_uimsbf(vlc, 16);
+
+      vl_vlc_fillbits(vlc);
+      if (priv->picture.mpeg12.picture_coding_type == 2 ||
+          priv->picture.mpeg12.picture_coding_type == 3) {
+         priv->picture.mpeg12.full_pel_forward_vector = vl_vlc_get_uimsbf(vlc, 1);
+         /* forward_f_code */
+         priv->picture.mpeg12.f_code[0][0] = vl_vlc_get_uimsbf(vlc, 3) - 1;
+         priv->picture.mpeg12.f_code[0][1] = priv->picture.mpeg12.f_code[0][0];
+      } else {
+         priv->picture.mpeg12.full_pel_forward_vector = 0;
+         priv->picture.mpeg12.f_code[0][1] = priv->picture.mpeg12.f_code[0][0] = 14;
+      }
+
+      if (priv->picture.mpeg12.picture_coding_type == 3) {
+         priv->picture.mpeg12.full_pel_backward_vector = vl_vlc_get_uimsbf(vlc, 1);
+         /* backward_f_code */
+         priv->picture.mpeg12.f_code[1][0] = vl_vlc_get_uimsbf(vlc, 3) - 1;
+         priv->picture.mpeg12.f_code[1][1] = priv->picture.mpeg12.f_code[1][0];
+      } else {
+         priv->picture.mpeg12.full_pel_backward_vector = 0;
+         priv->picture.mpeg12.f_code[0][1] = priv->picture.mpeg12.f_code[0][0] = 14;
+      }
+
+      /* extra_bit_picture */
+      while (vl_vlc_get_uimsbf(vlc, 1)) {
+         /* extra_information_picture */
+         vl_vlc_get_uimsbf(vlc, 8);
+         vl_vlc_fillbits(vlc);
+      }
+
+   } else if (code == 0xB5) {
+      /* extension start code */
+      vl_vlc_fillbits(vlc);
+
+      /* extension_start_code_identifier */
+      switch (vl_vlc_get_uimsbf(vlc, 4)) {
+      case 0x3: /* quant matrix extension */
+
+         /* load_intra_quantiser_matrix */
+         if (vl_vlc_get_uimsbf(vlc, 1)) {
+            /* intra_quantiser_matrix */
+            priv->picture.mpeg12.intra_matrix = priv->codec_data.mpeg12.intra_matrix;
+            for (i = 0; i < 64; ++i) {
+               priv->codec_data.mpeg12.intra_matrix[vl_zscan_normal[i]] = vl_vlc_get_uimsbf(vlc, 8);
+               vl_vlc_fillbits(vlc);
+            }
+         } else
+            priv->picture.mpeg12.intra_matrix = default_intra_matrix;
+
+         /* load_non_intra_quantiser_matrix */
+         if (vl_vlc_get_uimsbf(vlc, 1)) {
+            /* non_intra_quantiser_matrix */
+            priv->picture.mpeg12.non_intra_matrix = priv->codec_data.mpeg12.non_intra_matrix;
+            for (i = 0; i < 64; ++i) {
+               priv->codec_data.mpeg12.non_intra_matrix[i] = vl_vlc_get_uimsbf(vlc, 8);
+               vl_vlc_fillbits(vlc);
+            }
+         } else
+            priv->picture.mpeg12.intra_matrix = default_non_intra_matrix;
+
+         break;
+
+      case 0x8: /* picture coding extension */
+
+         priv->picture.mpeg12.f_code[0][0] = vl_vlc_get_uimsbf(vlc, 4) - 1;
+         priv->picture.mpeg12.f_code[0][1] = vl_vlc_get_uimsbf(vlc, 4) - 1;
+         priv->picture.mpeg12.f_code[1][0] = vl_vlc_get_uimsbf(vlc, 4) - 1;
+         priv->picture.mpeg12.f_code[1][1] = vl_vlc_get_uimsbf(vlc, 4) - 1;
+         priv->picture.mpeg12.intra_dc_precision = vl_vlc_get_uimsbf(vlc, 2);
+         priv->picture.mpeg12.picture_structure = vl_vlc_get_uimsbf(vlc, 2);
+         priv->picture.mpeg12.top_field_first = vl_vlc_get_uimsbf(vlc, 1);
+         priv->picture.mpeg12.frame_pred_frame_dct = vl_vlc_get_uimsbf(vlc, 1);
+         priv->picture.mpeg12.concealment_motion_vectors = vl_vlc_get_uimsbf(vlc, 1);
+         priv->picture.mpeg12.q_scale_type = vl_vlc_get_uimsbf(vlc, 1);
+         priv->picture.mpeg12.intra_vlc_format = vl_vlc_get_uimsbf(vlc, 1);
+         priv->picture.mpeg12.alternate_scan = vl_vlc_get_uimsbf(vlc, 1);
+
+         /* repeat_first_field */
+         vl_vlc_get_uimsbf(vlc, 1);
+
+         /* chroma_420_type */
+         vl_vlc_get_uimsbf(vlc, 1);
+
+         vl_vlc_fillbits(vlc);
+
+         /* progressive_frame */
+         vl_vlc_get_uimsbf(vlc, 1);
+
+         /* composite_display_flag */
+         if (vl_vlc_get_uimsbf(vlc, 1)) {
+
+            /* v_axis */
+            vl_vlc_get_uimsbf(vlc, 1);
+
+            /* field_sequence */
+            vl_vlc_get_uimsbf(vlc, 3);
+
+            /* sub_carrier */
+            vl_vlc_get_uimsbf(vlc, 1);
+
+            /* burst_amplitude */
+            vl_vlc_get_uimsbf(vlc, 7);
+
+            /* sub_carrier_phase */
+            vl_vlc_get_uimsbf(vlc, 8);
+         }
+         break;
+      }
+
+   } else if (code <= 0xAF) {
+      /* slice start */
+      unsigned bytes = (vl_vlc_valid_bits(vlc) / 8) + 4;
+      uint8_t buf[12];
+      const void *ptr = buf;
+      unsigned i;
+
+      if (!priv->frame_started)
+         BeginFrame(priv);
+
+      buf[0] = 0x00;
+      buf[1] = 0x00;
+      buf[2] = 0x01;
+      buf[3] = code;
+      for (i = 4; i < bytes; ++i)
+         buf[i] = vl_vlc_get_uimsbf(vlc, 8);
+
+      priv->codec->decode_bitstream(priv->codec, priv->target, &priv->picture.base,
+                                    1, &ptr, &bytes);
+
+      priv->bytes_left = vl_vlc_bits_left(vlc) / 8;
+      priv->slice = vlc->data;
+
+   } else if (code == 0xB2) {
+      /* user data start */
+
+   } else if (code == 0xB4) {
+      /* sequence error */
+   } else if (code == 0xB7) {
+      /* sequence end */
+   } else if (code == 0xB8) {
+      /* group start */
+   } else if (code >= 0xB9) {
+      /* system start */
+   } else {
+      /* reserved */
+   }
+
+   /* resync to byte boundary */
+   vl_vlc_eatbits(vlc, vl_vlc_valid_bits(vlc) % 8);
+}
index e356020cead3dbf604496492a76ecfb4ef26a6c3..a3369140844bc5ff3f6518f144ee3af994fc88c4 100644 (file)
@@ -84,6 +84,10 @@ endif
 if HAVE_ST_VDPAU
 SUBDIRS += r600/vdpau
 endif
+
+if HAVE_ST_OMX
+SUBDIRS += r600/omx
+endif
 endif
 
 if HAVE_GALLIUM_RADEONSI
@@ -94,6 +98,10 @@ endif
 if HAVE_ST_VDPAU
 SUBDIRS += radeonsi/vdpau
 endif
+
+if HAVE_ST_OMX
+SUBDIRS += radeonsi/omx
+endif
 endif
 
 if HAVE_GALLIUM_NOUVEAU
diff --git a/src/gallium/targets/r600/omx/Makefile.am b/src/gallium/targets/r600/omx/Makefile.am
new file mode 100644 (file)
index 0000000..7660a8d
--- /dev/null
@@ -0,0 +1,77 @@
+# Copyright © 2012 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+include $(top_srcdir)/src/gallium/Automake.inc
+
+AM_CFLAGS = \
+       $(GALLIUM_CFLAGS) \
+       $(PTHREAD_CFLAGS) \
+       $(LIBDRM_CFLAGS)
+AM_CPPFLAGS = \
+       -I$(top_srcdir)/src/gallium/drivers \
+       -I$(top_srcdir)/src/gallium/winsys
+
+omxdir = $(OMX_LIB_INSTALL_DIR)
+omx_LTLIBRARIES = libomx_r600.la
+
+EXPORTS = '^(omx_component_library_Setup|radeon_drm_winsys_create)$$'
+
+libomx_r600_la_SOURCES = \
+       drm_target.c \
+       $(top_srcdir)/src/gallium/auxiliary/vl/vl_winsys_dri.c
+
+libomx_r600_la_LDFLAGS = \
+       -module \
+       -export-symbols-regex $(EXPORTS) \
+       -shared \
+       -no-undefined
+
+libomx_r600_la_LIBADD = \
+       $(top_builddir)/src/gallium/auxiliary/libgallium.la \
+       $(top_builddir)/src/gallium/drivers/r600/libr600.la \
+       $(top_builddir)/src/gallium/state_trackers/omx/libomxtracker.la \
+       $(top_builddir)/src/gallium/winsys/radeon/drm/libradeonwinsys.la \
+       $(top_builddir)/src/gallium/drivers/trace/libtrace.la \
+       $(GALLIUM_DRI_LIB_DEPS) \
+       $(OMX_LIBS) \
+       $(LIBDRM_LIBS) \
+       $(RADEON_LIBS) \
+       -lstdc++
+
+if HAVE_MESA_LLVM
+libomx_r600_la_LINK = $(CXXLINK) $(libomx_r600_la_LDFLAGS)
+# Mention a dummy pure C++ file to trigger generation of the $(LINK) variable
+nodist_EXTRA_libomx_r600_la_SOURCES = dummy-cpp.cpp
+
+libomx_r600_la_LDFLAGS += $(LLVM_LDFLAGS)
+libomx_r600_la_LIBADD += $(LLVM_LIBS)
+else
+libomx_r600_la_LINK = $(LINK) $(libomx_r600_la_LDFLAGS)
+# Mention a dummy pure C file to trigger generation of the $(LINK) variable
+nodist_EXTRA_libomx_r600_la_SOURCES = dummy-c.c
+endif
+
+# Provide compatibility with scripts for the old Mesa build system for
+# a while by putting a link to the driver into /lib of the build tree.
+all-local: libomx_r600.la
+       $(MKDIR_P) $(top_builddir)/$(LIB_DIR)/gallium
+       ln -f .libs/libomx_r600.so* $(top_builddir)/$(LIB_DIR)/gallium/
diff --git a/src/gallium/targets/r600/omx/drm_target.c b/src/gallium/targets/r600/omx/drm_target.c
new file mode 120000 (symlink)
index 0000000..6955421
--- /dev/null
@@ -0,0 +1 @@
+../common/drm_target.c
\ No newline at end of file
diff --git a/src/gallium/targets/radeonsi/omx/Makefile.am b/src/gallium/targets/radeonsi/omx/Makefile.am
new file mode 100644 (file)
index 0000000..5eea303
--- /dev/null
@@ -0,0 +1,68 @@
+# Copyright © 2012 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+include $(top_srcdir)/src/gallium/Automake.inc
+
+AM_CFLAGS = \
+       $(GALLIUM_CFLAGS) \
+       $(PTHREAD_CFLAGS) \
+       $(LIBDRM_CFLAGS)
+AM_CPPFLAGS = \
+       -I$(top_srcdir)/src/gallium/drivers \
+       -I$(top_srcdir)/src/gallium/winsys
+
+omxdir = $(OMX_LIB_INSTALL_DIR)
+omx_LTLIBRARIES = libomx_radeonsi.la
+
+EXPORTS = '^(omx_component_library_Setup|radeon_drm_winsys_create)$$'
+
+libomx_radeonsi_la_SOURCES = \
+       drm_target.c \
+       $(top_srcdir)/src/gallium/auxiliary/vl/vl_winsys_dri.c
+
+libomx_radeonsi_la_LDFLAGS = \
+       -module \
+       -export-symbols-regex $(EXPORTS) \
+       -shared \
+       -no-undefined
+
+libomx_radeonsi_la_LIBADD = \
+       $(top_builddir)/src/gallium/auxiliary/libgallium.la \
+       $(top_builddir)/src/gallium/drivers/radeonsi/libradeonsi.la \
+       $(top_builddir)/src/gallium/state_trackers/omx/libomxtracker.la \
+       $(top_builddir)/src/gallium/winsys/radeon/drm/libradeonwinsys.la \
+       $(top_builddir)/src/gallium/drivers/trace/libtrace.la \
+       $(GALLIUM_DRI_LIB_DEPS) \
+       $(OMX_LIBS) \
+       $(LIBDRM_LIBS) \
+       $(RADEON_LIBS)
+
+if HAVE_MESA_LLVM
+libomx_radeonsi_la_LDFLAGS += $(LLVM_LDFLAGS)
+libomx_radeonsi_la_LIBADD += $(LLVM_LIBS)
+endif
+
+# Provide compatibility with scripts for the old Mesa build system for
+# a while by putting a link to the driver into /lib of the build tree.
+all-local: libomx_radeonsi.la
+       $(MKDIR_P) $(top_builddir)/$(LIB_DIR)/gallium
+       ln -f .libs/libomx_radeonsi.so* $(top_builddir)/$(LIB_DIR)/gallium/
diff --git a/src/gallium/targets/radeonsi/omx/drm_target.c b/src/gallium/targets/radeonsi/omx/drm_target.c
new file mode 120000 (symlink)
index 0000000..6955421
--- /dev/null
@@ -0,0 +1 @@
+../common/drm_target.c
\ No newline at end of file