aboutsummaryrefslogtreecommitdiff
path: root/lib/libdvd
diff options
context:
space:
mode:
authorPär Björklund <per.bjorklund@gmail.com>2013-02-08 14:03:19 +0100
committerPär Björklund <per.bjorklund@gmail.com>2013-02-08 14:03:19 +0100
commit57e27aff0a152ef53d29c80ff07136cd065e77ff (patch)
tree44ebfbc26b4ed544155846f49253947b4e911cc1 /lib/libdvd
parent421d9fdb0658abb01306a62e5d57da044263b216 (diff)
Added diffs for XBMC changes to libdvd libs
cores.diff is the differences between include files in lib/libdvd and xbmc/cores/dvdplayer/dvdinputstreams/dvdnav
Diffstat (limited to 'lib/libdvd')
-rw-r--r--lib/libdvd/patches/cores.diff545
-rw-r--r--lib/libdvd/patches/libdvdcss.diff365
-rw-r--r--lib/libdvd/patches/libdvdnav.diff766
-rw-r--r--lib/libdvd/patches/libdvdread.diff296
4 files changed, 1972 insertions, 0 deletions
diff --git a/lib/libdvd/patches/cores.diff b/lib/libdvd/patches/cores.diff
new file mode 100644
index 0000000000..bc2a4b651f
--- /dev/null
+++ b/lib/libdvd/patches/cores.diff
@@ -0,0 +1,545 @@
+diff -uw dvdnav_diff/config.h xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/config.h
+--- dvdnav_diff/config.h 2013-02-07 14:42:34 +0100
++++ xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/config.h 2013-01-26 23:33:20 +0100
+@@ -1,56 +1,95 @@
+-/* config.h. Generated by hand. */
++#pragma once
+
+-#ifndef LIBDVDREAD_CONFIG_H
+-#define LIBDVDREAD_CONFIG_H
++/*
++ * Copyright (C) 2005-2012 Team XBMC
++ * http://www.xbmc.org
++ *
++ * This Program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This Program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with XBMC; see the file COPYING. If not, see
++ * <http://www.gnu.org/licenses/>.
++ *
++ */
+
+-#define HAVE_DLFCN_H 1
++/* config.h. Generated by hand. */
++#if defined(_LINUX)
++#include "PlatformInclude.h"
++#else
++#include <windows.h>
++#endif
++#include <stdio.h>
++
++//#define HAVE_DLFCN_H 1
++#define HAVE_DVDCSS_DVDCSS_H 1
+ /* #undef HAVE_DVDCSS_DVDCSS_H*/
+ /* #undef HAVE_INTTYPES_H */
+ #define HAVE_MEMORY_H 1
+-/* #undef HAVE_STDINT_H */
++#define HAVE_STDINT_H 1
+ #define HAVE_STDLIB_H 1
+ #define HAVE_STRINGS_H 1
+ #define HAVE_STRING_H 1
+ #define HAVE_SYS_STAT_H 1
+ #define HAVE_SYS_TYPES_H 1
+ /* #undef HAVE_UNISTD_H */
++#ifndef PACKAGE
+ #define PACKAGE "libdvdread"
++#endif
++#ifndef PACKAGE_BUGREPORT
+ #define PACKAGE_BUGREPORT ""
++#endif
++#ifndef PACKAGE_NAME
+ #define PACKAGE_NAME ""
++#endif
++#ifndef PACKAGE_STRING
+ #define PACKAGE_STRING ""
++#endif
++#ifndef PACKAGE_TARNAME
+ #define PACKAGE_TARNAME ""
++#endif
++#ifndef PACKAGE_VERSION
+ #define PACKAGE_VERSION ""
++#endif
+ #define STDC_HEADERS 1
++#ifndef VERSION
+ #define VERSION "1.2.6"
++#endif
+ /* #undef WORDS_BIGENDIAN */
+ /* #undef __DARWIN__ */
+ /* #undef const */
+ #define inline __inline
+ /* #undef size_t */
+
+-#define ssize_t __int64
++#define ssize_t int
+
+ #ifndef PATH_MAX
+ #define PATH_MAX MAX_PATH
+ #endif
+
++#ifndef strcasecmp
+ #define strcasecmp stricmp
++#endif
++#ifndef strncasecmp
+ #define strncasecmp strnicmp
++#endif
+
++#ifndef S_ISDIR
+ #define S_ISDIR(m) ((m) & _S_IFDIR)
++#endif
++#ifndef S_ISREG
+ #define S_ISREG(m) ((m) & _S_IFREG)
++#endif
++#ifndef S_ISBLK
+ #define S_ISBLK(m) 0
++#endif
++#ifndef S_ISCHR
+ #define S_ISCHR(m) 0
+-
+-/* Fallback types (very x86-centric, sorry) */
+-typedef unsigned char uint8_t;
+-typedef signed char int8_t;
+-typedef unsigned short uint16_t;
+-typedef signed short int16_t;
+-typedef unsigned int uint32_t;
+-typedef signed int int32_t;
+-typedef unsigned __int64 uint64_t;
+-typedef signed __int64 int64_t;
+-typedef unsigned int uintptr_t;
+-
+-#endif /* LIBDVDREAD_CONFIG_H */
++#endif
+diff -uw dvdnav_diff/decoder.h xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/decoder.h
+--- dvdnav_diff/decoder.h 2013-02-07 14:42:34 +0100
++++ xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/decoder.h 2013-02-04 14:58:00 +0100
+@@ -22,6 +22,12 @@
+ #ifndef LIBDVDNAV_DECODER_H
+ #define LIBDVDNAV_DECODER_H
+
++//#include <inttypes.h>
++//#include <sys/time.h>
++
++#include "ifo_types.h" /* vm_cmd_t */
++#include "dvdnav_internal.h"
++
+ /* link command types */
+ typedef enum {
+ LinkNoLink = 0,
+diff -uw dvdnav_diff/dvd_reader.h xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/dvd_reader.h
+--- dvdnav_diff/dvd_reader.h 2013-02-07 14:42:34 +0100
++++ xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/dvd_reader.h 2013-02-04 14:58:00 +0100
+@@ -24,14 +24,14 @@
+ #define LIBDVDREAD_DVD_READER_H
+
+ #ifdef _MSC_VER
+-#include <config.h>
++#include "config.h"
+
+ #include <stdio.h>
+ #include <stdlib.h>
+ #endif
+
+ #include <sys/types.h>
+-#include <inttypes.h>
++//#include <inttypes.h>
+
+ /**
+ * The DVD access interface.
+diff -uw dvdnav_diff/dvd_types.h xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/dvd_types.h
+--- dvdnav_diff/dvd_types.h 2013-02-07 14:42:34 +0100
++++ xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/dvd_types.h 2013-02-04 14:58:00 +0100
+@@ -26,6 +26,8 @@
+ #ifndef LIBDVDNAV_DVD_TYPES_H
+ #define LIBDVDNAV_DVD_TYPES_H
+
++//#include <inttypes.h>
++
+ /*
+ * DVD Menu ID
+ * (see dvdnav_menu_call())
+@@ -60,7 +62,8 @@
+
+ /* the following types are currently unused */
+
+-#if 0
++//XBMC Needs some of these
++#if 1
+
+ /* Domain */
+ typedef enum {
+@@ -222,6 +225,10 @@
+ DVD_DISPLAY_MODE_4x3Letterboxed = 3
+ } DVDDisplayMode_t;
+
++typedef int DVDAudioSampleFreq_t;
++typedef int DVDAudioSampleQuant_t;
++typedef int DVDChannelNumber_t;
++
+ /* Audio attributes */
+ typedef struct {
+ DVDAudioAppMode_t AppMode;
+@@ -233,9 +240,6 @@
+ DVDAudioSampleQuant_t SampleQuantization;
+ DVDChannelNumber_t NumberOfChannels;
+ } DVDAudioAttributes_t;
+-typedef int DVDAudioSampleFreq_t;
+-typedef int DVDAudioSampleQuant_t;
+-typedef int DVDChannelNumber_t;
+
+ /* Subpicture attributes */
+ typedef enum {
+@@ -255,6 +259,8 @@
+ DVDSubpictureLangExt_t LanguageExtension;
+ } DVDSubpictureAttributes_t;
+
++typedef int DVDVideoCompression_t;
++
+ /* Video attributes */
+ typedef struct {
+ DVDBool_t PanscanPermitted;
+@@ -268,7 +274,6 @@
+ DVDBool_t Line21Field2InGop;
+ int more_to_come;
+ } DVDVideoAttributes_t;
+-typedef int DVDVideoCompression_t;
+
+ #endif
+
+diff -uw dvdnav_diff/dvdnav.h xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/dvdnav.h
+--- dvdnav_diff/dvdnav.h 2013-02-07 14:42:34 +0100
++++ xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/dvdnav.h 2013-02-04 14:58:00 +0100
+@@ -32,11 +32,14 @@
+ extern "C" {
+ #endif
+
+-# include <dvdnav/dvd_types.h>
+-# include <dvdread/dvd_reader.h>
+-# include <dvdread/nav_types.h>
+-# include <dvdread/ifo_types.h> /* For vm_cmd_t */
+-# include <dvdnav/dvdnav_events.h>
++# include "dvd_types.h"
++# include "dvd_reader.h"
++# include "nav_types.h"
++# include "ifo_types.h" /* For vm_cmd_t */
++# include "dvdnav_events.h"
++# include "dvd_types.h"
++# include "dvd_reader.h"
++# include "ifo_types.h" /* For vm_cmd_t */
+
+
+
+@@ -63,11 +66,6 @@
+ #define DVDNAV_STATUS_ERR 0
+ #define DVDNAV_STATUS_OK 1
+
+-#define DVDNAV_FORMAT_AC3 0
+-#define DVDNAV_FORMAT_MPEGAUDIO 3
+-#define DVDNAV_FORMAT_LPCM 4
+-#define DVDNAV_FORMAT_DTS 5
+-#define DVDNAV_FORMAT_SDDS 6
+
+ /*********************************************************************
+ * initialisation & housekeeping functions *
+@@ -281,7 +279,7 @@
+ /*
+ * Plays the specified title, starting from the specified program
+ */
+-dvdnav_status_t dvdnav_program_play(dvdnav_t *this, int32_t title, int32_t pgcn, int32_t pgn);
++dvdnav_status_t dvdnav_program_play(dvdnav_t *self, int32_t title, int32_t pgcn, int32_t pgn);
+
+ /*
+ * Stores in *times an array (that the application *must* free) of
+@@ -695,6 +693,15 @@
+ */
+ int8_t dvdnav_is_domain_vts(dvdnav_t *self);
+
++/* XBMC added functions */
++int dvdnav_get_nr_of_subtitle_streams(dvdnav_t *self);
++
++int dvdnav_get_nr_of_audio_streams(dvdnav_t *self);
++
++int dvdnav_get_button_info(dvdnav_t* self, int alpha[2][4], int color[2][4]);
++
++int64_t dvdnav_convert_time(dvd_time_t *time);
++
+ ////////// RATDVD stuff ///////////////
+
+ /*
+diff -uw dvdnav_diff/dvdnav_events.h xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/dvdnav_events.h
+--- dvdnav_diff/dvdnav_events.h 2013-02-07 14:42:34 +0100
++++ xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/dvdnav_events.h 2013-02-04 14:58:00 +0100
+@@ -25,6 +25,10 @@
+ #ifndef LIBDVDNAV_DVDNAV_EVENTS_H
+ #define LIBDVDNAV_DVDNAV_EVENTS_H
+
++#include "ifo_types.h"
++#include "dvd_reader.h"
++#include "nav_types.h"
++
+ /*
+ * DVDNAV_BLOCK_OK
+ *
+diff -uw dvdnav_diff/dvdnav_internal.h xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/dvdnav_internal.h
+--- dvdnav_diff/dvdnav_internal.h 2013-02-07 14:42:34 +0100
++++ xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/dvdnav_internal.h 2013-02-07 14:33:08 +0100
+@@ -1,6 +1,5 @@
+-/* !! DO NO EDIT THIS FILE, it is automatically generated */
+ /*
+- * Copyright (C) 2001 Rich Wareham <richwareham@users.sourceforge.net>
++ * Copyright (C) 2001-2004 Rich Wareham <richwareham@users.sourceforge.net>
+ *
+ * This file is part of libdvdnav, a DVD navigation library.
+ *
+@@ -19,8 +18,8 @@
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+-#ifndef LIBDVDREAD_DVDNAV_INTERNAL_H
+-#define LIBDVDREAD_DVDNAV_INTERNAL_H
++#ifndef LIBDVDNAV_DVDNAV_INTERNAL_H
++#define LIBDVDNAV_DVDNAV_INTERNAL_H
+
+ #ifdef HAVE_CONFIG_H
+ #include "config.h"
+@@ -28,16 +27,47 @@
+
+ #include <stdlib.h>
+ #include <stdio.h>
+-#include <unistd.h>
++//#include <unistd.h>
+ #include <limits.h>
+ #include <string.h>
+-#include <pthread.h>
+
+-#undef WORDS_BIGENDIAN
++#ifdef WIN32
++
++/* pthread_mutex_* wrapper for win32 */
++#ifndef _LINUX
++#include <windows.h>
++#include <process.h>
++typedef CRITICAL_SECTION pthread_mutex_t;
++#define pthread_mutex_init(a, b) InitializeCriticalSection(a)
++#define pthread_mutex_lock(a) EnterCriticalSection(a)
++#define pthread_mutex_unlock(a) LeaveCriticalSection(a)
++#define pthread_mutex_destroy(a) DeleteCriticalSection(a)
++#endif // !_LINUX
++
++#ifndef HAVE_GETTIMEOFDAY
++/* replacement gettimeofday implementation */
++#include <sys/timeb.h>
++static inline int _private_gettimeofday( struct timeval *tv, void *tz )
++{
++ struct timeb t;
++ ftime( &t );
++ tv->tv_sec = t.time;
++ tv->tv_usec = t.millitm * 1000;
++ return 0;
++}
++#define gettimeofday(TV, TZ) _private_gettimeofday((TV), (TZ))
++#endif
++
++#ifndef _LINUX
++#include <io.h> /* read() */
++#define lseek64 _lseeki64
++#endif // !_LINUX
+
+-#include "dvd_reader.h"
+-#include "ifo_read.h"
+-#include "ifo_types.h"
++#else
++
++#include <pthread.h>
++
++#endif /* WIN32 */
+
+ /* Uncomment for VM command tracing */
+ /* #define TRACE */
+@@ -48,7 +78,7 @@
+ #include "vmcmd.h"
+
+ /* where should libdvdnav write its messages (stdout/stderr) */
+-#define MSG_OUT stdout
++#define MSG_OUT stderr
+
+ /* Maximum length of an error string */
+ #define MAX_ERR_LEN 255
+@@ -126,8 +156,6 @@
+ /* General data */
+ char path[MAX_PATH_LEN]; /* Path to DVD device/dir */
+ dvd_file_t *file; /* Currently opened file */
+- int open_vtsN; /* The domain and number of the... */
+- int open_domain; /* ..currently opened VOB */
+
+ /* Position data */
+ vm_position_t position_next;
+@@ -147,6 +175,7 @@
+ int started; /* vm_start has been called? */
+ int use_read_ahead; /* 1 - use read-ahead cache, 0 - don't */
+ int pgc_based; /* positioning works PGC based instead of PG based */
++ int cur_cell_time; /* time expired since the beginning of the current cell, read from the dsi */
+
+ /* VM */
+ vm_t *vm;
+@@ -159,24 +188,38 @@
+ char err_str[MAX_ERR_LEN];
+ };
+
++/** HELPER FUNCTIONS **/
++
++/* converts a dvd_time_t to PTS ticks */
++int64_t dvdnav_convert_time(dvd_time_t *time);
++
++/* XBMC added functions */
++/*
++ * Get current playback state
++ */
++dvdnav_status_t dvdnav_get_state(dvdnav_t *self, dvd_state_t *save_state);
++
++/*
++ * Resume playback state
++ */
++dvdnav_status_t dvdnav_set_state(dvdnav_t *self, dvd_state_t *save_state);
++/* end XBMC */
++
+ /** USEFUL MACROS **/
+
+ #ifdef __GNUC__
+-#define printerrf(format, args...) snprintf(this->err_str, MAX_ERR_LEN, format, ## args);
++#define printerrf(format, args...) \
++ do { if (this) snprintf(this->err_str, MAX_ERR_LEN, format, ## args); } while (0)
+ #else
+ #ifdef _MSC_VER
+-#define printerrf(str) snprintf(this->err_str, MAX_ERR_LEN, str);
++#define printerrf(str) \
++ do { if (this) snprintf(this->err_str, MAX_ERR_LEN, str); } while (0)
+ #else
+-#define printerrf(...) snprintf(this->err_str, MAX_ERR_LEN, __VA_ARGS__);
++#define printerrf(...) \
++ do { if (this) snprintf(this->err_str, MAX_ERR_LEN, __VA_ARGS__); } while (0)
+ #endif /* WIN32 */
+ #endif
+-#define printerr(str) strncpy(this->err_str, str, MAX_ERR_LEN);
+-
+-/* Save my typing */
+-#define S_ERR DVDNAV_STATUS_ERR
+-
+-#ifndef _MSC_VER
+-#define S_OK DVDNAV_STATUS_OK
+-#endif /* MSC_VER */
++#define printerr(str) \
++ do { if (this) strncpy(this->err_str, str, MAX_ERR_LEN - 1); } while (0)
+
+-#endif /* LIBDVDREAD_DVDNAV_INTERNAL_H */
++#endif /* LIBDVDNAV_DVDNAV_INTERNAL_H */
+diff -uw dvdnav_diff/ifo_types.h xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/ifo_types.h
+--- dvdnav_diff/ifo_types.h 2013-02-07 14:42:34 +0100
++++ xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/ifo_types.h 2013-02-04 14:58:00 +0100
+@@ -22,8 +22,8 @@
+ #ifndef LIBDVDREAD_IFO_TYPES_H
+ #define LIBDVDREAD_IFO_TYPES_H
+
+-#include <inttypes.h>
+-#include "dvdread/dvd_reader.h"
++//#include <inttypes.h>
++#include "dvd_reader.h"
+
+
+ #undef ATTRIBUTE_PACKED
+diff -uw dvdnav_diff/nav_types.h xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/nav_types.h
+--- dvdnav_diff/nav_types.h 2013-02-07 14:42:34 +0100
++++ xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/nav_types.h 2013-02-04 14:58:00 +0100
+@@ -28,9 +28,27 @@
+ #ifndef LIBDVDREAD_NAV_TYPES_H
+ #define LIBDVDREAD_NAV_TYPES_H
+
+-#include <inttypes.h>
++//#include <inttypes.h>
+ #include "ifo_types.h" /* only dvd_time_t, vm_cmd_t and user_ops_t */
+
++
++#undef ATTRIBUTE_PACKED
++#undef PRAGMA_PACK_BEGIN
++#undef PRAGMA_PACK_END
++
++#if defined(__GNUC__)
++#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
++#define ATTRIBUTE_PACKED __attribute__ ((packed))
++#define PRAGMA_PACK 0
++#endif
++#endif
++
++#if !defined(ATTRIBUTE_PACKED)
++#define ATTRIBUTE_PACKED
++#define PRAGMA_PACK 1
++#endif
++
++
+ /* The length including the substream id byte. */
+ #define PCI_BYTES 0x3d4
+ #define DSI_BYTES 0x3fa
+@@ -41,6 +59,12 @@
+ /* Remove this */
+ #define DSI_START_BYTE 1031
+
++
++#if PRAGMA_PACK
++#pragma pack(1)
++#endif
++
++
+ /**
+ * PCI General Information
+ */
+diff -uw dvdnav_diff/vm.h xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/vm.h
+--- dvdnav_diff/vm.h 2013-02-07 14:42:34 +0100
++++ xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/vm.h 2013-02-07 14:33:08 +0100
+@@ -23,6 +23,9 @@
+ #ifndef LIBDVDNAV_VM_H
+ #define LIBDVDNAV_VM_H
+
++#include "remap.h"
++#include "dvdnav_internal.h"
++
+ /* DOMAIN enum */
+
+ typedef enum {
+@@ -156,11 +159,8 @@
+ int vm_get_audio_active_stream(vm_t *vm);
+ int vm_get_subp_active_stream(vm_t *vm, int mode);
+ void vm_get_angle_info(vm_t *vm, int *current, int *num_avail);
+-// _XBMC #if 0
+-/* currently unused */
+ void vm_get_audio_info(vm_t *vm, int *current, int *num_avail);
+ void vm_get_subp_info(vm_t *vm, int *current, int *num_avail);
+-// _XBMC #endif
+ void vm_get_video_res(vm_t *vm, int *width, int *height);
+ int vm_get_video_aspect(vm_t *vm);
+ int vm_get_video_scale_permission(vm_t *vm);
+@@ -180,5 +180,7 @@
+ void vm_position_print(vm_t *vm, vm_position_t *position);
+ #endif
+
++/* XBMC added functions */
++vm_t* dvdnav_get_vm(dvdnav_t *self);
+
+ #endif /* LIBDVDNAV_VM_H */
+diff -uw dvdnav_diff/vmcmd.h xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/vmcmd.h
+--- dvdnav_diff/vmcmd.h 2013-02-07 14:42:34 +0100
++++ xbmc/xbmc/cores/dvdplayer/DVDInputStreams/dvdnav/vmcmd.h 2013-02-04 14:58:00 +0100
+@@ -22,6 +22,8 @@
+ #ifndef LIBDVDNAV_VMCMD_H
+ #define LIBDVDNAV_VMCMD_H
+
++//#include <inttypes.h>
++
+ void vm_print_mnemonic(vm_cmd_t *command);
+ void vm_print_cmd(int row, vm_cmd_t *command);
+
diff --git a/lib/libdvd/patches/libdvdcss.diff b/lib/libdvd/patches/libdvdcss.diff
new file mode 100644
index 0000000000..2f0caf5389
--- /dev/null
+++ b/lib/libdvd/patches/libdvdcss.diff
@@ -0,0 +1,365 @@
+diff -uwr libdvdcss-1.2.12/src/device.c xbmc/lib/libdvd/libdvdcss/src/device.c
+--- libdvdcss-1.2.12/src/device.c 2012-03-12 00:07:48 +0100
++++ xbmc/lib/libdvd/libdvdcss/src/device.c 2013-02-07 14:42:34 +0100
+@@ -23,6 +23,10 @@
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *****************************************************************************/
+
++/*
++ Modifications for XBMC are all contained within _XBOX (real xbox hardware) or WITH_CACHE
++*/
++
+ /*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+@@ -368,11 +372,20 @@
+
+ #if defined( WIN32 )
+ dvdcss->b_file = 1;
++#if defined( _XBOX )
++ // If we've passed over the device string make sure we don't try
++ // to use file based handling (libc) - we want Win2k routines ...
++ if (!stricmp(psz_device, "\\Device\\Cdrom0"))
++ dvdcss->b_file = 0;
++ else
++ dvdcss->b_file = stricmp(psz_device, "D:");
++#else
+ /* If device is "X:" or "X:\", we are not actually opening a file. */
+ if (psz_device[0] && psz_device[1] == ':' &&
+ (!psz_device[2] || (psz_device[2] == '\\' && !psz_device[3])))
+ dvdcss->b_file = 0;
+
++#endif // _XBOX
+ /* Initialize readv temporary buffer */
+ dvdcss->p_readv_buffer = NULL;
+ dvdcss->i_readv_buf_size = 0;
+@@ -450,11 +463,13 @@
+ }
+ else /* ASPI */
+ {
++#if !defined(_XBOX)
+ struct w32_aspidev *fd = (struct w32_aspidev *) dvdcss->i_fd;
+
+ /* Unload aspi and free w32_aspidev structure */
+ FreeLibrary( (HMODULE) fd->hASPI );
+ free( (void*) dvdcss->i_fd );
++#endif // !_XBOX
+ }
+
+ /* Free readv temporary buffer */
+@@ -510,9 +525,14 @@
+ #if defined( WIN32 )
+ static int win2k_open ( dvdcss_t dvdcss, char const *psz_device )
+ {
++#ifdef _XBOX
++ char psz_dvd[70];
++ strcpy(psz_dvd, "cdrom0:");
++#else
+ char psz_dvd[7];
+ snprintf( psz_dvd, 7, "\\\\.\\%c:", psz_device[0] );
+
++#endif
+ /* To work around an M$ bug in IOCTL_DVD_READ_STRUCTURE, we need read
+ * _and_ write access to the device (so we can make SCSI Pass Through
+ * Requests). Unfortunately this is only allowed if you have
+@@ -521,17 +541,24 @@
+ * won't send back the right result).
+ * (See Microsoft Q241374: Read and Write Access Required for SCSI
+ * Pass Through Requests) */
++
++#ifdef WITH_CACHE
++ DWORD flags = FILE_FLAG_NO_BUFFERING; /* we handle buffering ourself */
++#else
++ DWORD flags = FILE_FLAG_RANDOM_ACCESS;
++#endif //!_XBOX
++
+ dvdcss->i_fd = (int)
+ CreateFile( psz_dvd, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING,
+- FILE_FLAG_RANDOM_ACCESS, NULL );
++ flags, NULL );
+
+ if( (HANDLE) dvdcss->i_fd == INVALID_HANDLE_VALUE )
+ dvdcss->i_fd = (int)
+ CreateFile( psz_dvd, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING,
+- FILE_FLAG_RANDOM_ACCESS, NULL );
++ flags, NULL );
+
+ if( (HANDLE) dvdcss->i_fd == INVALID_HANDLE_VALUE )
+ {
+@@ -727,6 +754,9 @@
+ static int win2k_seek( dvdcss_t dvdcss, int i_blocks )
+ {
+ LARGE_INTEGER li_seek;
++#ifdef WITH_CACHE
++ int iBytesToSkip;
++#endif
+
+ #ifndef INVALID_SET_FILE_POINTER
+ # define INVALID_SET_FILE_POINTER ((DWORD)-1)
+@@ -738,6 +768,28 @@
+ return i_blocks;
+ }
+
++#ifdef WITH_CACHE
++
++ // if our buffer contains the position which we want to seek too, we can
++ // just decrease dwCacheBufferSize
++ iBytesToSkip = (i_blocks - dvdcss->i_pos) * DVDCSS_BLOCK_SIZE;
++ if (iBytesToSkip > 0 && iBytesToSkip < dvdcss->buffer_size)
++ {
++ dvdcss->buffer_size -= iBytesToSkip;
++ dvdcss->i_pos = i_blocks;
++ return dvdcss->i_pos;
++ }
++ else if (iBytesToSkip < 0 && (DISC_CACHE_SIZE - dvdcss->buffer_size) >= -iBytesToSkip)
++ {
++ // we want to seek backwards, and we have enough old data in our buffer
++ dvdcss->buffer_size -= iBytesToSkip; // since iBytesToSkip is negative, dwCacheBufferSize will get bigger
++ dvdcss->i_pos = i_blocks;
++ return dvdcss->i_pos;
++ }
++ else dvdcss->buffer_size = 0;
++
++#endif
++
+ li_seek.QuadPart = (LONGLONG)i_blocks * DVDCSS_BLOCK_SIZE;
+
+ li_seek.LowPart = SetFilePointer( (HANDLE) dvdcss->i_fd,
+@@ -827,6 +879,66 @@
+ {
+ int i_bytes;
+
++#ifdef WITH_CACHE
++
++ if (dvdcss->buffer_size < i_blocks * DVDCSS_BLOCK_SIZE)
++ {
++ // we don't have enough data in our buffer
++ int iRemaining = i_blocks * DVDCSS_BLOCK_SIZE;
++ int iCopied = 0;
++ // copy data we already have and read again into the cache
++ if (dvdcss->buffer_size > 0) memcpy(p_buffer, dvdcss->buffer + (DISC_CACHE_SIZE - dvdcss->buffer_size), dvdcss->buffer_size);
++ iCopied = dvdcss->buffer_size;
++ iRemaining -= dvdcss->buffer_size;
++ (BYTE*)p_buffer += iCopied;
++ dvdcss->buffer_size = 0;
++
++ // if remaining size is bigger >= DISC_CACHE_SIZE, don't cache it. Just read
++ if (iRemaining >= DISC_CACHE_SIZE)
++ {
++ if (!ReadFile((HANDLE)dvdcss->i_fd, p_buffer, iRemaining, (LPDWORD)&i_bytes, NULL))
++ {
++ dvdcss->i_pos = -1;
++ return -1;
++ }
++ dvdcss->i_pos += (i_bytes + iCopied) / DVDCSS_BLOCK_SIZE;
++ return (i_bytes + iCopied) / DVDCSS_BLOCK_SIZE;
++ }
++ else
++ {
++ // read a chunk into the cache and copy the needed bytes into p_buffer
++ if (!ReadFile((HANDLE)dvdcss->i_fd, dvdcss->buffer, DISC_CACHE_SIZE, &dvdcss->buffer_size, NULL))
++ {
++ // read error, maybe we tried to read to much. Try again but now without cache
++ if (!ReadFile((HANDLE)dvdcss->i_fd, p_buffer, iRemaining, (LPDWORD)&i_bytes, NULL))
++ {
++ dvdcss->i_pos = -1;
++ return -1;
++ }
++ dvdcss->i_pos += (i_bytes + iCopied) / DVDCSS_BLOCK_SIZE;
++ return (i_bytes + iCopied) / DVDCSS_BLOCK_SIZE;
++ }
++ // copy bytes into the buffer
++ memcpy(p_buffer, dvdcss->buffer, iRemaining);
++ dvdcss->buffer_size -= iRemaining;
++ dvdcss->i_pos += (iRemaining + iCopied) / DVDCSS_BLOCK_SIZE;
++ return (iRemaining + iCopied) / DVDCSS_BLOCK_SIZE;
++ }
++ }
++ else
++ {
++ // we have enough data in our cache, just copy it
++ memcpy(p_buffer, dvdcss->buffer + (DISC_CACHE_SIZE - dvdcss->buffer_size), i_blocks * DVDCSS_BLOCK_SIZE);
++ dvdcss->buffer_size -= i_blocks * DVDCSS_BLOCK_SIZE;
++ dvdcss->i_pos += i_blocks;
++ return i_blocks;
++ }
++
++ dvdcss->i_pos = -1;
++ return -1;
++
++#else // WITH_CACHE
++
+ if( !ReadFile( (HANDLE) dvdcss->i_fd, p_buffer,
+ i_blocks * DVDCSS_BLOCK_SIZE,
+ (LPDWORD)&i_bytes, NULL ) )
+@@ -837,6 +949,7 @@
+
+ dvdcss->i_pos += i_bytes / DVDCSS_BLOCK_SIZE;
+ return i_bytes / DVDCSS_BLOCK_SIZE;
++#endif // WITH_CACHE
+ }
+
+ static int aspi_read ( dvdcss_t dvdcss, void *p_buffer, int i_blocks )
+diff -uwr libdvdcss-1.2.12/src/ioctl.c xbmc/lib/libdvd/libdvdcss/src/ioctl.c
+--- libdvdcss-1.2.12/src/ioctl.c 2012-03-12 00:07:48 +0100
++++ xbmc/lib/libdvd/libdvdcss/src/ioctl.c 2013-02-07 14:42:34 +0100
+@@ -373,6 +373,37 @@
+
+ memcpy( p_key, dvdbs.discKeyStructures, DVD_DISCKEY_SIZE );
+
++#elif defined( _XBOX )
++ // the next piece of code will read the disc key on the xbox for all drives (samsung included)
++ // but for some reason it takes 15 - 20 seconds longer to load a dvd if mplayer has the dvd key
++ // so we let this part fail and will only use the modified ioctl_ReadTitleKey code.
++ // don't get this delay, and i'm surprised it worked as the ReadTitleKey function didn't work.
++
++ DWORD dwBytesRead;
++ DVD_READ_STRUCTURE st;
++ char buffer[DVD_DISCKEY_SIZE];
++
++ memset( &buffer, 0, sizeof( buffer ) );
++ memset( &st, 0, sizeof( st ) );
++
++ st.BlockByteOffset.QuadPart = 0;
++ st.SessionId = *pi_agid;
++ st.Format = DvdDiskKeyDescriptor;
++
++ i_ret = DeviceIoControl((HANDLE) i_fd, IOCTL_DVD_READ_STRUCTURE, &st,
++ sizeof(st), buffer, DVD_DISCKEY_SIZE, &dwBytesRead, NULL ) ? 0 : -1;
++
++ if (i_ret < 0) // didn't work
++ {
++ printf("Failed to read disc key\n");
++ return i_ret;
++ }
++
++ // copy the returned key into our key buffer
++ int i;
++ for (i = 0; i < DVD_DISCKEY_SIZE; i++)
++ p_key[i] = buffer[i+4];
++
+ #elif defined( WIN32 )
+ if( WIN2K ) /* NT/2k/XP */
+ {
+@@ -541,6 +572,25 @@
+
+ memcpy( p_key, dvdbs.titleKeyValue, DVD_KEY_SIZE );
+
++#elif defined( _XBOX ) && 0 //Faulty wrong key returned, original for WIN32 works thou so use it instead
++ DWORD dwBytesRead;
++ DVD_READ_STRUCTURE st;
++ char buffer[2048+4];
++
++ memset( &buffer, 0, sizeof( buffer ) );
++
++ st.BlockByteOffset.QuadPart = (LONGLONG) i_pos * 2048 /*DVDCSS_BLOCK_SIZE*/;
++ st.SessionId = *pi_agid;
++ st.Format = DvdDiskKeyDescriptor;
++
++ i_ret = DeviceIoControl((HANDLE) i_fd, IOCTL_DVD_READ_STRUCTURE, &st, sizeof(st), buffer, 2048+4, &dwBytesRead, NULL ) ? 0 : -1;
++ if( i_ret < 0 )
++ {
++ return i_ret;
++ }
++
++ memcpy( p_key, &(buffer[4]), 2048);
++
+ #elif defined( WIN32 )
+ if( WIN2K ) /* NT/2k/XP */
+ {
+@@ -693,8 +743,13 @@
+ ULONG id;
+ DWORD tmp;
+
++#if defined( _XBOX)
++ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_START_SESSION,
++ NULL, 0, &id, sizeof(id), &tmp, NULL ) ? 0 : -1;
++#else
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_START_SESSION,
+ &tmp, 4, &id, sizeof( id ), &tmp, NULL ) ? 0 : -1;
++#endif
+
+ *pi_agid = id;
+ }
+@@ -1336,8 +1391,13 @@
+
+ memcpy( key->KeyData, p_challenge, DVD_CHALLENGE_SIZE );
+
++#if defined(_XBOX)
++ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key,
++ key->KeyLength, NULL, 0, &tmp, NULL ) ? 0 : -1;
++#else
+ i_ret = DeviceIoControl( (HANDLE) i_fd, IOCTL_DVD_SEND_KEY, key,
+ key->KeyLength, key, key->KeyLength, &tmp, NULL ) ? 0 : -1;
++#endif
+ }
+ else
+ {
+diff -uwr libdvdcss-1.2.12/src/ioctl.h xbmc/lib/libdvd/libdvdcss/src/ioctl.h
+--- libdvdcss-1.2.12/src/ioctl.h 2012-03-12 00:07:48 +0100
++++ xbmc/lib/libdvd/libdvdcss/src/ioctl.h 2013-02-07 14:42:34 +0100
+@@ -324,7 +324,11 @@
+ typedef DWORD (CALLBACK *GETASPI32SUPPORTINFO)(VOID);
+ typedef DWORD (CALLBACK *SENDASPI32COMMAND)(LPVOID);
+
++#if defined(_XBOX)
++#define WIN2K 1
++#else
+ #define WIN2K ( GetVersion() < 0x80000000 )
++#endif // _XBOX
+ #define ASPI_HAID 0
+ #define ASPI_TARGET 0
+ #define DTYPE_CDROM 0x05
+diff -uwr libdvdcss-1.2.12/src/libdvdcss.c xbmc/lib/libdvd/libdvdcss/src/libdvdcss.c
+--- libdvdcss-1.2.12/src/libdvdcss.c 2012-03-12 00:07:48 +0100
++++ xbmc/lib/libdvd/libdvdcss/src/libdvdcss.c 2013-02-07 14:42:34 +0100
+@@ -195,6 +195,10 @@
+ dvdcss->b_debug = 0;
+ dvdcss->b_errors = 0;
+
++#ifdef WITH_CACHE
++ dvdcss->buffer_size = 0;
++#endif
++
+ /*
+ * Find verbosity from DVDCSS_VERBOSE environment variable
+ */
+@@ -388,7 +392,7 @@
+ dvdcss->b_scrambled = i_ret;
+ }
+ }
+-
++ /* if wo don't have b_ioctls, we don't have a disk key, make sure area is nulled */
+ memset( dvdcss->css.p_disc_key, 0, KEY_SIZE );
+ /* If disc is CSS protected and the ioctls work, authenticate the drive */
+ if( dvdcss->b_scrambled && dvdcss->b_ioctls )
+@@ -533,8 +537,26 @@
+ goto nocache;
+ }
+
++#ifdef _XBOX
++ //due to xbox file system having a limited length on folders/files,
++ //make separate folder for disk name first
++ if(psz_title[0] == '\0')
++ strcat(psz_title, "NONAME");
++
++ i += sprintf( dvdcss->psz_cachefile + i, "/%s", psz_title);
++
++ i_ret = mkdir( dvdcss->psz_cachefile );
++ if( i_ret < 0 && errno != EEXIST )
++ {
++ print_error( dvdcss, "failed creating cache titledirectory" );
++ dvdcss->psz_cachefile[0] = '\0';
++ goto nocache;
++ }
++ i += sprintf( dvdcss->psz_cachefile + i, "/%s%s", psz_serial, psz_key );
++#else
+ i += sprintf( dvdcss->psz_cachefile + i, "/%s-%s%s", psz_title,
+ psz_serial, psz_key );
++#endif
+ #if !defined( WIN32 ) || defined( SYS_CYGWIN )
+ i_ret = mkdir( dvdcss->psz_cachefile, 0755 );
+ #else
diff --git a/lib/libdvd/patches/libdvdnav.diff b/lib/libdvd/patches/libdvdnav.diff
new file mode 100644
index 0000000000..32f7f0837a
--- /dev/null
+++ b/lib/libdvd/patches/libdvdnav.diff
@@ -0,0 +1,766 @@
+diff -uwr libdvdnav-4.2.0/Makefile xbmc/lib/libdvd/libdvdnav/Makefile
+--- libdvdnav-4.2.0/Makefile 2008-12-30 15:48:46 +0100
++++ xbmc/lib/libdvd/libdvdnav/Makefile 2013-02-07 14:42:34 +0100
+@@ -112,7 +112,7 @@
+ # Clean targets
+
+ clean:
+- rm -rf *~ $(.OBJDIR)/* version.h
++ rm -rf *~ $(.OBJDIR)/*
+
+ pcedit = sed \
+ -e 's,@prefix@,$(PREFIX),' \
+diff -uwr libdvdnav-4.2.0/src/dvdnav/dvdnav.h xbmc/lib/libdvd/libdvdnav/src/dvdnav/dvdnav.h
+--- libdvdnav-4.2.0/src/dvdnav/dvdnav.h 2011-02-26 21:32:32 +0100
++++ xbmc/lib/libdvd/libdvdnav/src/dvdnav/dvdnav.h 2013-02-07 14:42:34 +0100
+@@ -695,6 +695,42 @@
+ */
+ int8_t dvdnav_is_domain_vts(dvdnav_t *self);
+
++////////// RATDVD stuff ///////////////
++
++/*
++ * Get the number of audio streams.
++ */
++int32_t dvdnav_get_audio_stream_count(dvdnav_t * self);
++
++/*
++ * Get the number of subpicture streams.
++ */
++int32_t dvdnav_get_subpicture_stream_count(dvdnav_t * self);
++
++/*
++ * Get attributes of the current audio stream.
++ */
++dvdnav_status_t dvdnav_get_audio_info(dvdnav_t * self, int32_t streamid, audio_attr_t* audio_attributes);
++
++/*
++ * Get attributes of the current subpicture stream.
++ */
++dvdnav_status_t dvdnav_get_stitle_info(dvdnav_t * self, int32_t streamid, subp_attr_t* stitle_attributes);
++
++/*
++ * Get information about the current video stream
++ */
++dvdnav_status_t dvdnav_get_video_info(dvdnav_t * self, video_attr_t* video_attributes);
++
++/*
++ * Select the audio stream to be played
++ */
++dvdnav_status_t dvdnav_audio_change(dvdnav_t *self, int32_t audio);
++
++/*
++ * Select the spu stream to be displayed
++ */
++dvdnav_status_t dvdnav_subpicture_change(dvdnav_t *self, int32_t subpicture);
+
+ #ifdef __cplusplus
+ }
+diff -uwr libdvdnav-4.2.0/src/dvdnav.c xbmc/lib/libdvd/libdvdnav/src/dvdnav.c
+--- libdvdnav-4.2.0/src/dvdnav.c 2010-07-31 01:34:12 +0200
++++ xbmc/lib/libdvd/libdvdnav/src/dvdnav.c 2013-02-07 14:42:34 +0100
+@@ -337,7 +337,9 @@
+ }
+ #endif
+
+- if(num_angle != 0) {
++ /* only use ILVU information if we are at the last vobunit in ILVU */
++ /* otherwise we will miss nav packets from vobunits inbetween */
++ if(num_angle != 0 && (nav_dsi->sml_pbi.category & 0x5000) == 0x5000 ) {
+
+ if((next = nav_pci->nsml_agli.nsml_agl_dsta[angle-1]) != 0) {
+ if((next & 0x3fffffff) != 0) {
+@@ -466,6 +468,10 @@
+ /* Decode nav into pci and dsi. Then get next VOBU info. */
+ if(!dvdnav_decode_packet(this, *buf, &this->dsi, &this->pci)) {
+ printerr("Expected NAV packet but none found.");
++#ifdef _XBMC
++ /* skip this cell as we won't recover from this*/
++ vm_get_next_cell(this->vm);
++#endif
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+@@ -618,9 +624,17 @@
+ cell_event->pgc_length = dvdnav_convert_time(&state->pgc->playback_time);
+
+ cell_event->cell_start = 0;
+- for (i = 1; i < state->cellN; i++)
++ for (i = 0; i < state->cellN; i++)
++ {
++ /* only count the first angle cell */
++ if( state->pgc->cell_playback[i].block_type == BLOCK_TYPE_ANGLE_BLOCK
++ && state->pgc->cell_playback[i].block_mode != BLOCK_MODE_FIRST_CELL )
++ continue;
++
+ cell_event->cell_start +=
+- dvdnav_convert_time(&state->pgc->cell_playback[i - 1].playback_time);
++ dvdnav_convert_time(&state->pgc->cell_playback[i].playback_time);
++ }
++ cell_event->cell_start-= dvdnav_convert_time(&state->pgc->cell_playback[state->cellN-1].playback_time);
+
+ cell_event->pg_start = 0;
+ for (i = 1; i < state->pgc->program_map[state->pgN-1]; i++)
+@@ -769,6 +783,10 @@
+ /* Decode nav into pci and dsi. Then get next VOBU info. */
+ if(!dvdnav_decode_packet(this, *buf, &this->dsi, &this->pci)) {
+ printerr("Expected NAV packet but none found.");
++#ifdef _XBMC
++ /* skip this cell as we won't recover from this */
++ vm_get_next_cell(this->vm);
++#endif
+ pthread_mutex_unlock(&this->vm_lock);
+ return DVDNAV_STATUS_ERR;
+ }
+@@ -1166,6 +1184,10 @@
+
+ ops.ops_int = 0;
+
++ if(!this) {
++ printerr("Passed a NULL pointer.");
++ return ops.ops_struct;
++ }
+ if(!this->started) {
+ printerr("Virtual DVD machine not started.");
+ return ops.ops_struct;
+@@ -1180,3 +1202,263 @@
+
+ return ops.ops_struct;
+ }
++
++#ifdef _XBMC
++
++vm_t* dvdnav_get_vm(dvdnav_t *this) {
++ if(!this) return 0;
++ return this->vm;
++}
++
++int dvdnav_get_nr_of_subtitle_streams(dvdnav_t *this)
++{
++ int i;
++ int count = 0;
++
++ if (this && this->vm && this->vm->state.pgc)
++ {
++ for (i = 0; i < 32; i++)
++ {
++ if (this->vm->state.pgc->subp_control[i] & (1<<31)) count++;
++ }
++ }
++ return count;
++
++ /* old code
++ if(!this || !this->vm || !this->vm->vtsi || !this->vm->vtsi->vtsi_mat) return 0;
++
++ switch ((this->vm->state).domain) {
++ case VTS_DOMAIN:
++ return this->vm->vtsi->vtsi_mat->nr_of_vts_subp_streams;
++ case VTSM_DOMAIN:
++ return this->vm->vtsi->vtsi_mat->nr_of_vtsm_subp_streams; // 1
++ case VMGM_DOMAIN:
++ case FP_DOMAIN:
++ return this->vm->vmgi->vmgi_mat->nr_of_vmgm_subp_streams; // 1
++ }
++
++ return 0;
++ */
++}
++
++int dvdnav_get_nr_of_audio_streams(dvdnav_t *this)
++{
++ int i;
++ int count = 0;
++
++ if (this && this->vm && this->vm->state.pgc)
++ {
++ for (i = 0; i < 8; i++)
++ {
++ if (this->vm->state.pgc->audio_control[i] & (1<<15)) count++;
++ }
++ }
++ return count;
++
++ /* old code
++ if(!this || !this->vm || !this->vm->vtsi || !this->vm->vtsi->vtsi_mat) return 0;
++
++ switch ((this->vm->state).domain) {
++ case VTS_DOMAIN:
++ return this->vm->vtsi->vtsi_mat->nr_of_vts_audio_streams;
++ case VTSM_DOMAIN:
++ return this->vm->vtsi->vtsi_mat->nr_of_vtsm_audio_streams; // 1
++ case VMGM_DOMAIN:
++ case FP_DOMAIN:
++ return this->vm->vmgi->vmgi_mat->nr_of_vmgm_audio_streams; // 1
++ }
++
++ return 0;
++ */
++}
++
++/* return the alpha and color for the current active button
++ * color, alpha [0][] = selection
++ * color, alpha = color
++ *
++ * argsize = [2][4]
++ */
++int dvdnav_get_button_info(dvdnav_t* this, int alpha[2][4], int color[2][4])
++{
++ int current_button, current_button_color, i;
++ pci_t* pci;
++
++ if (!this) return -1;
++
++ pci = dvdnav_get_current_nav_pci(this);
++ if (!pci) return -1;
++
++ dvdnav_get_current_highlight(this, &current_button);
++ current_button_color = pci->hli.btnit[current_button - 1].btn_coln;
++
++ for (i = 0; i < 2; i++)
++ {
++ alpha[i][0] = pci->hli.btn_colit.btn_coli[current_button_color - 1][i] >> 0 & 0xf;
++ alpha[i][1] = pci->hli.btn_colit.btn_coli[current_button_color - 1][i] >> 4 & 0xf;
++ alpha[i][2] = pci->hli.btn_colit.btn_coli[current_button_color - 1][i] >> 8 & 0xf;
++ alpha[i][3] = pci->hli.btn_colit.btn_coli[current_button_color - 1][i] >> 12 & 0xf;
++
++ color[i][0] = pci->hli.btn_colit.btn_coli[current_button_color - 1][i] >> 16 & 0xf;
++ color[i][1] = pci->hli.btn_colit.btn_coli[current_button_color - 1][i] >> 20 & 0xf;
++ color[i][2] = pci->hli.btn_colit.btn_coli[current_button_color - 1][i] >> 24 & 0xf;
++ color[i][3] = pci->hli.btn_colit.btn_coli[current_button_color - 1][i] >> 28 & 0xf;
++ }
++
++ return 0;
++}
++
++/*
++ * the next stuff is taken from ratdvd
++ */
++
++#undef printerr
++#define printerr(str) strncpy(self->err_str, str, MAX_ERR_LEN);
++
++dvdnav_status_t dvdnav_get_audio_info(dvdnav_t * self, int32_t streamid, audio_attr_t* audio_attributes)
++{
++ if(!self) {
++ printerr("Passed a NULL pointer.");
++ return -1;
++ }
++ if(!self->started) {
++ printerr("Virtual DVD machine not started.");
++ return -1;
++ }
++
++ pthread_mutex_lock(&self->vm_lock);
++ audio_attr_t attributes = vm_get_audio_attr(self->vm,streamid);
++ pthread_mutex_unlock(&self->vm_lock);
++ audio_attributes->audio_format = attributes.audio_format;
++ audio_attributes->multichannel_extension = attributes.multichannel_extension;
++ audio_attributes->lang_type = attributes.lang_type;
++ audio_attributes->application_mode = attributes.application_mode;
++ audio_attributes->quantization = attributes.quantization;
++ audio_attributes->sample_frequency = attributes.sample_frequency;
++ audio_attributes->channels = attributes.channels;
++ audio_attributes->lang_code = attributes.lang_code;
++ audio_attributes->lang_extension = attributes.lang_extension;
++ audio_attributes->code_extension = attributes.code_extension;
++ audio_attributes->unknown3 = attributes.unknown3;
++ audio_attributes->app_info = attributes.app_info;
++ return DVDNAV_STATUS_OK;
++}
++
++dvdnav_status_t dvdnav_get_stitle_info(dvdnav_t * self
++ , int32_t streamid, subp_attr_t* stitle_attributes)
++{
++ if(!self) {
++ printerr("Passed a NULL pointer.");
++ return -1;
++ }
++ if(!self->started) {
++ printerr("Virtual DVD machine not started.");
++ return -1;
++ }
++
++ pthread_mutex_lock(&self->vm_lock);
++ subp_attr_t attributes = vm_get_subp_attr(self->vm,streamid);
++ pthread_mutex_unlock(&self->vm_lock);
++ stitle_attributes->code_mode = attributes.code_mode;
++ stitle_attributes->zero1 = attributes.zero1;
++ stitle_attributes->type = attributes.type;
++ stitle_attributes->zero2 = attributes.zero2;
++ stitle_attributes->lang_code = attributes.lang_code;
++ stitle_attributes->lang_extension = attributes.lang_extension;
++ stitle_attributes->code_extension = attributes.code_extension;
++ return DVDNAV_STATUS_OK;
++}
++
++dvdnav_status_t dvdnav_get_video_info(dvdnav_t * self, video_attr_t* video_attributes)
++{
++ if(!self) {
++ printerr("Passed a NULL pointer.");
++ return -1;
++ }
++ if(!self->started) {
++ printerr("Virtual DVD machine not started.");
++ return -1;
++ }
++
++ pthread_mutex_lock(&self->vm_lock);
++ video_attr_t attributes = vm_get_video_attr(self->vm);
++ pthread_mutex_unlock(&self->vm_lock);
++
++ video_attributes->video_format = attributes.video_format;
++ video_attributes->permitted_df = attributes.permitted_df;
++ video_attributes->display_aspect_ratio = attributes.display_aspect_ratio;
++ video_attributes->mpeg_version = attributes.mpeg_version;
++ video_attributes->film_mode = attributes.film_mode;
++ video_attributes->letterboxed = attributes.letterboxed;
++ video_attributes->picture_size = attributes.picture_size;
++ video_attributes->bit_rate = attributes.bit_rate;
++ video_attributes->unknown1 = attributes.unknown1;
++ video_attributes->line21_cc_2 = attributes.line21_cc_2;
++ video_attributes->line21_cc_1 = attributes.line21_cc_1;
++ return DVDNAV_STATUS_OK;
++}
++
++dvdnav_status_t dvdnav_audio_change(dvdnav_t *self, int32_t audio)
++{
++ int32_t num;
++
++ if(!self) {
++ printerr("Passed a NULL pointer.");
++ return DVDNAV_STATUS_ERR;
++ }
++
++ num = dvdnav_get_nr_of_audio_streams(self);
++ pthread_mutex_lock(&self->vm_lock);
++ /* Set subp AUDIO if valid */
++ if((audio >= 0) && (audio <= num)) {
++ self->vm->state.AST_REG = audio;
++ } else {
++ //printerr("Passed an invalid audio number.");
++ pthread_mutex_unlock(&self->vm_lock);
++ return DVDNAV_STATUS_ERR;
++ }
++ pthread_mutex_unlock(&self->vm_lock);
++
++ return DVDNAV_STATUS_OK;
++}
++
++dvdnav_status_t dvdnav_subpicture_change(dvdnav_t *self, int32_t subpicture)
++{
++ int32_t num;
++
++ if(!self) {
++ printerr("Passed a NULL pointer.");
++ return DVDNAV_STATUS_ERR;
++ }
++
++ num = dvdnav_get_nr_of_subtitle_streams(self);
++ pthread_mutex_lock(&self->vm_lock);
++ /* Set subp SPRM if valid */
++ if((subpicture >= 0) && (subpicture <= num)) {
++ self->vm->state.SPST_REG = subpicture | 0x40;
++ } else if (subpicture & 0x80) {
++ self->vm->state.SPST_REG = subpicture & ~0x80;
++ } else {
++ self->vm->state.SPST_REG = subpicture;
++ //printerr("Passed an invalid subpicture number.");
++ //pthread_mutex_unlock(&self->vm_lock);
++ //return DVDNAV_STATUS_ERR;
++ }
++ pthread_mutex_unlock(&self->vm_lock);
++
++ return DVDNAV_STATUS_OK;
++}
++
++void dvdnav_lock(dvdnav_t *self)
++{
++ // we do not check for null pointer problems
++ pthread_mutex_lock(&self->vm_lock);
++}
++
++void dvdnav_unlock(dvdnav_t *self)
++{
++ // we do not check for null pointer problems
++ pthread_mutex_unlock(&self->vm_lock);
++}
++
++#endif // _XBMC
++
+diff -uwr libdvdnav-4.2.0/src/dvdnav_internal.h xbmc/lib/libdvd/libdvdnav/src/dvdnav_internal.h
+--- libdvdnav-4.2.0/src/dvdnav_internal.h 2010-06-01 12:02:38 +0200
++++ xbmc/lib/libdvd/libdvdnav/src/dvdnav_internal.h 2013-02-07 14:42:34 +0100
+@@ -175,6 +175,18 @@
+ /* converts a dvd_time_t to PTS ticks */
+ int64_t dvdnav_convert_time(dvd_time_t *time);
+
++/* XBMC added functions */
++/*
++ * Get current playback state
++ */
++dvdnav_status_t dvdnav_get_state(dvdnav_t *this, dvd_state_t *save_state);
++
++/*
++ * Resume playback state
++ */
++dvdnav_status_t dvdnav_set_state(dvdnav_t *this, dvd_state_t *save_state);
++/* end XBMC */
++
+ /** USEFUL MACROS **/
+
+ #ifdef __GNUC__
+diff -uwr libdvdnav-4.2.0/src/read_cache.c xbmc/lib/libdvd/libdvdnav/src/read_cache.c
+--- libdvdnav-4.2.0/src/read_cache.c 2008-12-30 15:48:46 +0100
++++ xbmc/lib/libdvd/libdvdnav/src/read_cache.c 2013-02-07 14:42:34 +0100
+@@ -338,7 +338,7 @@
+ pthread_mutex_lock(&cache->lock);
+ for (i = 0; i < READ_CACHE_CHUNKS; i++) {
+ if (cache->chunk[i].cache_buffer && buf >= cache->chunk[i].cache_buffer &&
+- buf < cache->chunk[i].cache_buffer + cache->chunk[i].cache_malloc_size * DVD_VIDEO_LB_LEN) {
++ buf < cache->chunk[i].cache_buffer + cache->chunk[i].cache_malloc_size * DVD_VIDEO_LB_LEN && cache->chunk[i].usage_count > 0) {
+ cache->chunk[i].usage_count--;
+ }
+ }
+diff -uwr libdvdnav-4.2.0/src/searching.c xbmc/lib/libdvd/libdvdnav/src/searching.c
+--- libdvdnav-4.2.0/src/searching.c 2011-10-07 19:06:24 +0200
++++ xbmc/lib/libdvd/libdvdnav/src/searching.c 2013-02-07 14:42:34 +0100
+@@ -121,6 +121,12 @@
+ return DVDNAV_STATUS_ERR;
+ }
+
++ if((state->pgc->prohibited_ops.title_or_time_play == 1) ||
++ (this->pci.pci_gi.vobu_uop_ctl.title_or_time_play == 1 )){
++ printerr("operation forbidden.");
++ pthread_mutex_unlock(&this->vm_lock);
++ return DVDNAV_STATUS_ERR;
++ }
+
+ this->cur_cell_time = 0;
+ if (this->pgc_based) {
+@@ -136,24 +142,109 @@
+ last_cell_nr = state->pgc->nr_of_cells;
+ }
+
++ /* FIXME: using time map is not going to work unless we are pgc_based */
++ /* we'd need to recalculate the time to be relative to full pgc first*/
++ if(!this->pgc_based)
++ {
++#ifdef LOG_DEBUG
++ fprintf(MSG_OUT, "libdvdnav: time_search - not pgc based\n");
++#endif
++ goto timemapdone;
++ }
++
++ if(!this->vm->vtsi->vts_tmapt){
++ /* no time map for this program chain */
++#ifdef LOG_DEBUG
++ fprintf(MSG_OUT, "libdvdnav: time_search - no time map for this program chain\n");
++#endif
++ goto timemapdone;
++ }
++
++ if(this->vm->vtsi->vts_tmapt->nr_of_tmaps < state->pgcN){
++ /* to few time maps for this program chain */
++#ifdef LOG_DEBUG
++ fprintf(MSG_OUT, "libdvdnav: time_search - to few time maps for this program chain\n");
++#endif
++ goto timemapdone;
++ }
++
++ /* get the tmpat corresponding to the pgc */
++ vts_tmap_t *tmap = &(this->vm->vtsi->vts_tmapt->tmap[state->pgcN-1]);
++
++ if(tmap->tmu == 0){
++ /* no time unit for this time map */
++#ifdef LOG_DEBUG
++ fprintf(MSG_OUT, "libdvdnav: time_search - no time unit for this time map\n");
++#endif
++ goto timemapdone;
++ }
++
++ /* time is in pts (90khz clock), get the number of tmu's that represent */
++ /* first entry defines at time tmu not time zero */
++ int entry = time / tmap->tmu / 90000 - 1;
++ if(entry > tmap->nr_of_entries)
++ entry = tmap->nr_of_entries -1;
++
++ if(entry > 0)
++ {
++ /* get the table entry, disregarding marking of discontinuity */
++ target = tmap->map_ent[entry] & 0x7fffffff;
++ }
++ else
++ {
++ /* start from first vobunit */
++ target = state->pgc->cell_playback[first_cell_nr-1].first_sector;;
++ }
++
++ /* if we have an additional entry we can interpolate next position */
++ /* allowed only if next entry isn't discontinious */
++
++ if( entry < tmap->nr_of_entries - 1)
++ {
++ const uint32_t target2 = tmap->map_ent[entry+1];
++ const uint64_t timeunit = tmap->tmu*90000;
++ if( !( target2 & 0x80000000) )
++ {
++ length = target2 - target;
++ target += (uint32_t) (length * ( time - (entry+1)*timeunit ) / timeunit);
++ }
++ }
++ found = 1;
++
++timemapdone:
++
+ found = 0;
+- for(cell_nr = first_cell_nr; (cell_nr <= last_cell_nr) && !found; cell_nr ++) {
++ for(cell_nr = first_cell_nr; cell_nr <= last_cell_nr; cell_nr ++) {
+ cell = &(state->pgc->cell_playback[cell_nr-1]);
+ if(cell->block_type == BLOCK_TYPE_ANGLE_BLOCK && cell->block_mode != BLOCK_MODE_FIRST_CELL)
+ continue;
++
++ if(found) {
++
++ if (target >= cell->first_sector
++ && target <= cell->last_sector)
++ break;
++
++ } else {
++
+ length = dvdnav_convert_time(&cell->playback_time);
+- if (target >= length) {
+- target -= length;
++ if (time >= length) {
++ time -= length;
+ } else {
+ /* FIXME: there must be a better way than interpolation */
+- target = target * (cell->last_sector - cell->first_sector + 1) / length;
++ target = time * (cell->last_sector - cell->first_sector + 1) / length;
+ target += cell->first_sector;
+
++ #ifdef LOG_DEBUG
++ if( cell->first_sector > target || target > cell->last_sector )
++ fprintf(MSG_OUT, "libdvdnav: time_search - sector is not within cell min:%u, max:%u, cur:%u\n", cell->first_sector, cell->last_sector, target);
++ #endif
++
+ found = 1;
+ break;
+ }
+ }
+-
++ }
+ if(found) {
+ uint32_t vobu;
+ #ifdef LOG_DEBUG
+@@ -202,6 +293,7 @@
+
+ result = dvdnav_get_position(this, &target, &length);
+ if(!result) {
++ printerr("Cannot get current position");
+ return DVDNAV_STATUS_ERR;
+ }
+
+@@ -213,7 +305,7 @@
+ return DVDNAV_STATUS_ERR;
+ }
+ #ifdef LOG_DEBUG
+- fprintf(MSG_OUT, "libdvdnav: seeking to offset=%lu pos=%u length=%u\n", offset, target, length);
++ fprintf(MSG_OUT, "libdvdnav: seeking to offset=%llu pos=%u length=%u\n", offset, target, length);
+ fprintf(MSG_OUT, "libdvdnav: Before cellN=%u blockN=%u\n", state->cellN, state->blockN);
+ #endif
+
+@@ -654,3 +746,62 @@
+ free(tmp);
+ return retval;
+ }
++
++dvdnav_status_t dvdnav_get_state(dvdnav_t *this, dvd_state_t *save_state)
++{
++ if(!this || !this->vm) return DVDNAV_STATUS_ERR;
++
++ pthread_mutex_lock(&this->vm_lock);
++
++ if( !vm_get_state(this->vm, save_state) )
++ {
++ printerr("Failed to get vm state.");
++ pthread_mutex_unlock(&this->vm_lock);
++ return DVDNAV_STATUS_ERR;
++ }
++
++ pthread_mutex_unlock(&this->vm_lock);
++ return DVDNAV_STATUS_OK;
++}
++
++dvdnav_status_t dvdnav_set_state(dvdnav_t *this, dvd_state_t *save_state)
++{
++ if(!this || !this->vm)
++ {
++ printerr("Passed a NULL pointer.");
++ return DVDNAV_STATUS_ERR;
++ }
++
++ if(!this->started) {
++ printerr("Virtual DVD machine not started.");
++ return DVDNAV_STATUS_ERR;
++ }
++
++ pthread_mutex_lock(&this->vm_lock);
++
++ /* reset the dvdnav state */
++ memset(&this->pci,0,sizeof(this->pci));
++ memset(&this->dsi,0,sizeof(this->dsi));
++ this->last_cmd_nav_lbn = SRI_END_OF_CELL;
++
++ /* Set initial values of flags */
++ this->position_current.still = 0;
++ this->skip_still = 0;
++ this->sync_wait = 0;
++ this->sync_wait_skip = 0;
++ this->spu_clut_changed = 0;
++
++
++ /* set the state. this will also start the vm on that state */
++ /* means the next read block should be comming from that new */
++ /* state */
++ if( !vm_set_state(this->vm, save_state) )
++ {
++ printerr("Failed to set vm state.");
++ pthread_mutex_unlock(&this->vm_lock);
++ return DVDNAV_STATUS_ERR;
++ }
++
++ pthread_mutex_unlock(&this->vm_lock);
++ return DVDNAV_STATUS_OK;
++}
+diff -uwr libdvdnav-4.2.0/src/vm/vm.c xbmc/lib/libdvd/libdvdnav/src/vm/vm.c
+--- libdvdnav-4.2.0/src/vm/vm.c 2010-11-22 00:59:44 +0100
++++ xbmc/lib/libdvd/libdvdnav/src/vm/vm.c 2013-02-07 14:42:34 +0100
+@@ -255,6 +255,15 @@
+ fprintf(MSG_OUT, "libdvdnav: ifoRead_TITLE_VOBU_ADMAP vtsi failed\n");
+ return 0;
+ }
++ if(!ifoRead_VTS_TMAPT(vm->vtsi)) {
++ fprintf(MSG_OUT, "libdvdnav: ifoRead_VTS_TMAPT vtsi failed\n");
++ return 0;
++ }
++ if(!ifoRead_TITLE_C_ADT(vm->vtsi)) {
++ fprintf(MSG_OUT, "libdvdnav: ifoRead_TITLE_C_ADT vtsi failed\n");
++ return 0;
++ }
++
+ (vm->state).vtsN = vtsN;
+
+ return 1;
+@@ -390,7 +399,15 @@
+ /* return 0; Not really used for now.. */
+ }
+ /* ifoRead_TXTDT_MGI(vmgi); Not implemented yet */
++#ifdef _XBMC
++ if(DVDUDFVolumeInfo(vm->dvd, vm->dvd_name, sizeof(vm->dvd_name), NULL, 0))
++ if(DVDISOVolumeInfo(vm->dvd, vm->dvd_name, sizeof(vm->dvd_name), NULL, 0))
++ strcpy(vm->dvd_name, "");
++
++ fprintf(MSG_OUT, "libdvdnav: vm: DVD Title: %s\n", vm->dvd_name);
++#else
+ dvd_read_name(vm->dvd_name, vm->dvd_serial, dvdroot);
++#endif
+ vm->map = remap_loadmap(vm->dvd_name);
+ }
+ if (vm->vmgi) {
+@@ -846,7 +863,7 @@
+ }
+ }
+
+-#if 0
++// XBMC #if 0
+ /* currently unused */
+ void vm_get_audio_info(vm_t *vm, int *current, int *num_avail) {
+ switch ((vm->state).domain) {
+@@ -884,7 +901,7 @@
+ break;
+ }
+ }
+-#endif
++// XBMC #endif
+
+ void vm_get_video_res(vm_t *vm, int *width, int *height) {
+ video_attr_t attr = vm_get_video_attr(vm);
+@@ -1981,6 +1998,50 @@
+ ifoClose(ifo);
+ }
+
++int vm_get_state(vm_t *vm, dvd_state_t *save_state) {
++ *save_state = vm->state;
++
++ /* remove the pgc pointer as it might not be valid later*/
++ save_state->pgc = NULL;
++
++ return 1;
++}
++
++int vm_set_state(vm_t *vm, dvd_state_t *save_state) {
++
++ /* restore state from save_state as taken from ogle */
++
++ /* open the needed vts */
++ if( !ifoOpenNewVTSI(vm, vm->dvd, save_state->vtsN) ) return 0;
++ // sets state.vtsN
++
++ vm->state = *save_state;
++ /* set state.domain before calling */
++ //calls get_pgcit()
++ // needs state.domain and sprm[0] set
++ // sets pgcit depending on state.domain
++ //writes: state.pgc
++ // state.pgN
++ // state.TT_PGCN_REG
++
++ if( !set_PGCN(vm, save_state->pgcN) ) return 0;
++ save_state->pgc = vm->state.pgc;
++
++ /* set the rest of state after the call */
++ vm->state = *save_state;
++
++ /* if we are not in standard playback, we must get all data */
++ /* otherwise we risk loosing stillframes, and overlays */
++ if(vm->state.domain != VTS_DOMAIN)
++ vm->state.blockN = 0;
++
++ /* force a flush of data here */
++ /* we don't need a hop seek here as it's a complete state*/
++ vm->hop_channel++;
++
++ return 1;
++}
++
+ /* Debug functions */
+
+ #ifdef TRACE
+diff -uwr libdvdnav-4.2.0/src/vm/vm.h xbmc/lib/libdvd/libdvdnav/src/vm/vm.h
+--- libdvdnav-4.2.0/src/vm/vm.h 2010-07-31 01:34:16 +0200
++++ xbmc/lib/libdvd/libdvdnav/src/vm/vm.h 2013-02-07 14:42:34 +0100
+@@ -156,11 +156,11 @@
+ int vm_get_audio_active_stream(vm_t *vm);
+ int vm_get_subp_active_stream(vm_t *vm, int mode);
+ void vm_get_angle_info(vm_t *vm, int *current, int *num_avail);
+-#if 0
++// _XBMC #if 0
+ /* currently unused */
+ void vm_get_audio_info(vm_t *vm, int *current, int *num_avail);
+ void vm_get_subp_info(vm_t *vm, int *current, int *num_avail);
+-#endif
++// _XBMC #endif
+ void vm_get_video_res(vm_t *vm, int *width, int *height);
+ int vm_get_video_aspect(vm_t *vm);
+ int vm_get_video_scale_permission(vm_t *vm);
+@@ -170,6 +170,9 @@
+ ifo_handle_t *vm_get_title_ifo(vm_t *vm, uint32_t title);
+ void vm_ifo_close(ifo_handle_t *ifo);
+
++int vm_get_state(vm_t *vm, dvd_state_t *save_state);
++int vm_set_state(vm_t *vm, dvd_state_t *save_state);
++
+ /* Uncomment for VM command tracing */
+ /* #define TRACE */
+ #ifdef TRACE
+Only in xbmc/lib/libdvd/libdvdnav: version.h
diff --git a/lib/libdvd/patches/libdvdread.diff b/lib/libdvd/patches/libdvdread.diff
new file mode 100644
index 0000000000..fbf185f0dd
--- /dev/null
+++ b/lib/libdvd/patches/libdvdread.diff
@@ -0,0 +1,296 @@
+diff -uwr libdvdread-4.2.0/Makefile xbmc/lib/libdvd/libdvdread/Makefile
+--- libdvdread-4.2.0/Makefile 2008-12-31 09:43:04 +0100
++++ xbmc/lib/libdvd/libdvdread/Makefile 2013-02-07 14:42:34 +0100
+@@ -121,7 +121,7 @@
+ # Clean targets
+
+ clean:
+- rm -rf *~ $(.OBJDIR)/* version.h
++ rm -rf *~ $(.OBJDIR)/*
+
+
+ distclean: clean
+diff -uwr libdvdread-4.2.0/src/dvd_input.h xbmc/lib/libdvd/libdvdread/src/dvd_input.h
+--- libdvdread-4.2.0/src/dvd_input.h 2010-06-01 19:07:14 +0200
++++ xbmc/lib/libdvd/libdvdread/src/dvd_input.h 2013-02-07 14:42:34 +0100
+@@ -34,6 +34,13 @@
+ #if defined( __MINGW32__ )
+ # undef lseek
+ # define lseek _lseeki64
++# undef fseeko
++# define fseeko fseeko64
++# undef ftello
++# define ftello ftello64
++# define flockfile(...)
++# define funlockfile(...)
++# define getc_unlocked getc
+ # undef off_t
+ # define off_t off64_t
+ # undef stat
+diff -uwr libdvdread-4.2.0/src/dvd_reader.c xbmc/lib/libdvd/libdvdread/src/dvd_reader.c
+--- libdvdread-4.2.0/src/dvd_reader.c 2011-06-15 20:09:16 +0200
++++ xbmc/lib/libdvd/libdvdread/src/dvd_reader.c 2013-02-07 14:42:34 +0100
+@@ -32,6 +32,11 @@
+ #include <unistd.h>
+ #include <limits.h>
+ #include <dirent.h>
++#ifndef WIN32
++#include <paths.h>
++#endif
++
++#define WITH_CACHE
+
+ /* misc win32 helpers */
+ #ifdef WIN32
+@@ -105,6 +110,10 @@
+ uint32_t lb_start;
+ uint32_t seek_pos;
+
++#ifdef WITH_CACHE
++ char cache[DVD_VIDEO_LB_LEN];
++ uint32_t lb_cache;
++#endif
+ /* Information required for a directory path drive. */
+ size_t title_sizes[ TITLES_MAX ];
+ dvd_input_t title_devs[ TITLES_MAX ];
+@@ -617,6 +626,10 @@
+ memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
+ dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
+
++#ifdef WITH_CACHE
++ dvd_file->lb_cache = -1;
++#endif
++
+ return dvd_file;
+ }
+
+@@ -628,6 +641,18 @@
+ */
+ static int findDirFile( const char *path, const char *file, char *filename )
+ {
++#if defined(_XBMC)
++ struct stat fileinfo;
++
++ // no emulated opendir function in xbmc, so we'll
++ // check if the file exists by stat'ing it ...
++ sprintf(filename, "%s%s%s", path,
++ ( ( path[ strlen( path ) - 1 ] == '/' ) ? "" : "/" ),
++ file );
++
++ if (stat(filename, &fileinfo) == 0) return 0;
++
++#else
+ DIR *dir;
+ struct dirent *ent;
+
+@@ -644,6 +669,7 @@
+ }
+ }
+ closedir(dir);
++#endif // _XBMC
+ return -1;
+ }
+
+@@ -722,6 +748,9 @@
+ dvd_file->title_devs[ 0 ] = dev;
+ dvd_file->filesize = dvd_file->title_sizes[ 0 ];
+
++#ifdef WITH_CACHE
++ dvd_file->lb_cache = -1;
++#endif
+ return dvd_file;
+ }
+
+@@ -749,6 +778,9 @@
+ memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
+ dvd_file->filesize = len / DVD_VIDEO_LB_LEN;
+
++#ifdef WITH_CACHE
++ dvd_file->lb_cache = -1;
++#endif
+ /* Calculate the complete file size for every file in the VOBS */
+ if( !menu ) {
+ int cur;
+@@ -792,6 +824,10 @@
+ memset( dvd_file->title_devs, 0, sizeof( dvd_file->title_devs ) );
+ dvd_file->filesize = 0;
+
++#ifdef WITH_CACHE
++ dvd_file->lb_cache = -1;
++#endif
++
+ if( menu ) {
+ dvd_input_t dev;
+
+@@ -1203,6 +1239,100 @@
+ return ret + ret2;
+ }
+
++#ifdef WITH_CACHE
++
++/* returns true aslong as the sector isn't all zeros */
++int DVDCheckSector(unsigned char *data, int offset)
++{
++ int i = 0;
++ int32_t *p = (int32_t*)data + (DVD_VIDEO_LB_LEN>>2)*offset;
++ for(;i<(DVD_VIDEO_LB_LEN<<2);i++) {
++ if(*(p+i) != 0)
++ break;
++ }
++ return (i!=(DVD_VIDEO_LB_LEN>>2));
++}
++
++int DVDReadBlocksCached( dvd_file_t *dvd_file, int offset,
++ size_t block_count, unsigned char *data, int encrypted )
++{
++ int ret=0;
++ /* Check arguments. */
++ if( dvd_file == NULL || offset < 0 || data == NULL )
++ return -1;
++
++ if(encrypted & DVDINPUT_READ_DECRYPT) {
++ /* Hack, and it will still fail for multiple opens in a threaded app ! */
++ if( dvd_file->dvd->css_title != dvd_file->css_title ) {
++ dvd_file->dvd->css_title = dvd_file->css_title;
++ if( dvd_file->dvd->isImageFile ) {
++ dvdinput_title( dvd_file->dvd->dev, (int)dvd_file->lb_start );
++ }
++ /* Here each vobu has it's own dvdcss handle, so no need to update
++ else {
++ dvdinput_title( dvd_file->title_devs[ 0 ], (int)dvd_file->lb_start );
++ }*/
++ }
++ }
++
++ /* check if first sector is in cache */
++ int cachehit = 0;
++ if( offset == dvd_file->lb_cache ) {
++ memcpy( data, dvd_file->cache, DVD_VIDEO_LB_LEN );
++ block_count--;
++ offset++;
++ data+=DVD_VIDEO_LB_LEN;
++ cachehit = 1;
++ }
++
++
++ if( block_count > 0 )
++ {
++ if( dvd_file->dvd->isImageFile )
++ ret = DVDReadBlocksUDF( dvd_file, (uint32_t)offset,
++ block_count, data, encrypted );
++ else
++ ret = DVDReadBlocksPath( dvd_file, (unsigned int)offset,
++ block_count, data, encrypted );
++
++ if(ret<0)
++ return ret;
++
++ /* here is a hack for drive wich don't handle layerchange properly */
++ /* they start returning zero data while laser is shifting position */
++ /* normally just doing a reread will get the correct data */
++ if( dvd_file->dvd->isImageFile )
++ {
++ /* check sectors from the back */
++ int count = ret; /* previous call could have returned fewer than requested */
++ int i = count-1;
++ for(;i>=0;i--)
++ if(!DVDCheckSector(data, i)) break;
++
++ if(i>=0) {
++ fprintf( stderr, "libdvdread: potential layer change. %d zero sectors detected starting at %d!\n", i+1, offset);
++
++ /* reread the invalid sectors */
++ count = DVDReadBlocksUDF( dvd_file, (uint32_t)offset+i,
++ count-i, data+DVD_VIDEO_LB_LEN*i, encrypted );
++
++ if(count<0)
++ return count;
++ }
++ }
++
++ }
++
++ if(ret>0)
++ { /* store last sector read into cache */
++ dvd_file->lb_cache = offset+ret-1;
++ memcpy( dvd_file->cache, data+(DVD_VIDEO_LB_LEN*(ret-1)), DVD_VIDEO_LB_LEN );
++ }
++
++ return (ssize_t)(ret+cachehit);
++}
++#endif
++
+ /* This is broken reading more than 2Gb at a time is ssize_t is 32-bit. */
+ ssize_t DVDReadBlocks( dvd_file_t *dvd_file, int offset,
+ size_t block_count, unsigned char *data )
+@@ -1213,6 +1343,10 @@
+ if( dvd_file == NULL || offset < 0 || data == NULL )
+ return -1;
+
++#ifdef WITH_CACHE
++ return (ssize_t)DVDReadBlocksCached( dvd_file, offset, block_count, data, DVDINPUT_READ_DECRYPT );
++#endif
++
+ /* Hack, and it will still fail for multiple opens in a threaded app ! */
+ if( dvd_file->dvd->css_title != dvd_file->css_title ) {
+ dvd_file->dvd->css_title = dvd_file->css_title;
+@@ -1295,6 +1429,10 @@
+ return 0;
+ }
+
++#ifdef WITH_CACHE
++ ret = DVDReadBlocksCached( dvd_file, (uint32_t) seek_sector,
++ (size_t) numsec, secbuf, DVDINPUT_NOFLAGS );
++#else
+ if( dvd_file->dvd->isImageFile ) {
+ ret = DVDReadBlocksUDF( dvd_file, (uint32_t) seek_sector,
+ (size_t) numsec, secbuf, DVDINPUT_NOFLAGS );
+@@ -1302,6 +1440,7 @@
+ ret = DVDReadBlocksPath( dvd_file, seek_sector,
+ (size_t) numsec, secbuf, DVDINPUT_NOFLAGS );
+ }
++#endif
+
+ if( ret != (int) numsec ) {
+ free( secbuf_base );
+Only in xbmc/lib/libdvd/libdvdread: version.h
+diff -uwr libdvdread-4.2.0/version.sh xbmc/lib/libdvd/libdvdread/version.sh
+--- libdvdread-4.2.0/version.sh 2008-05-01 11:27:16 +0200
++++ xbmc/lib/libdvd/libdvdread/version.sh 2013-02-07 14:42:34 +0100
+@@ -1,18 +1,18 @@
+-#!/bin/sh
+-
+-svn_revision=`cd "$1" && LC_ALL=C svn info 2> /dev/null | grep Revision | cut -d' ' -f2`
+-test $svn_revision || svn_revision=`cd "$1" && grep revision .svn/entries 2>/dev/null | \
+- cut -d '"' -f2 2> /dev/null`
+-test $svn_revision || svn_revision=UNKNOWN
+-
+-if test "$svn_revision" = UNKNOWN && test -n "$2"; then
+- NEW_REVISION="#define VERSION \"$2\""
+-else
+- NEW_REVISION="#define VERSION \"SVN-r$svn_revision\""
+-fi
+-OLD_REVISION=`cat version.h 2> /dev/null`
+-
+-# Update version.h only on revision changes to avoid spurious rebuilds
+-if test "$NEW_REVISION" != "$OLD_REVISION"; then
+- echo "$NEW_REVISION" > version.h
+-fi
++##!/bin/sh
++#
++#svn_revision=`cd "$1" && LC_ALL=C svn info 2> /dev/null | grep Revision | cut -d' ' -f2`
++#test $svn_revision || svn_revision=`cd "$1" && grep revision .svn/entries 2>/dev/null | \
++# cut -d '"' -f2 2> /dev/null`
++#test $svn_revision || svn_revision=UNKNOWN
++#
++#if test "$svn_revision" = UNKNOWN && test -n "$2"; then
++# NEW_REVISION="#define VERSION \"$2\""
++#else
++# NEW_REVISION="#define VERSION \"SVN-r$svn_revision\""
++#fi
++#OLD_REVISION=`cat version.h 2> /dev/null`
++#
++## Update version.h only on revision changes to avoid spurious rebuilds
++#if test "$NEW_REVISION" != "$OLD_REVISION"; then
++# echo "$NEW_REVISION" > version.h
++#fi