From d3ebcf8c9422852c1812d88163103dfd659db69b Mon Sep 17 00:00:00 2001
From: mrstef <mrstef@nowhere.com>
Date: Sat, 9 Aug 2014 17:41:15 +0200
Subject: [PATCH] Add Dynamic Audio Delay 1.8

Detects the FPS of the currently started playback and adjusts
the audio delay in LAV Audio Decoder to match a Samsung LE46C755
which introduces a video delay of a specific number of frames.

Rebased to tag 1.8
---
 mediaportal/Core/Core.csproj                      |   1 +
 mediaportal/Core/Player/AudioPlayerVMR.cs         |   6 +
 mediaportal/Core/Player/BDPlayer.cs               |   6 +
 mediaportal/Core/Player/BaseStreamBufferPlayer.cs |   6 +
 mediaportal/Core/Player/BaseTSReaderPlayer.cs     |   6 +
 mediaportal/Core/Player/DVDPlayer.cs              |   6 +
 mediaportal/Core/Player/IPlayer.cs                |   9 +
 mediaportal/Core/Player/LAVFilters.cs             | 688 ++++++++++++++++++++++
 mediaportal/Core/Player/RTSPPlayer.cs             |   6 +
 mediaportal/Core/Player/VideoPlayerVMR7.cs        |   6 +
 mediaportal/Core/Player/g_player.cs               |  55 ++
 11 files changed, 795 insertions(+)
 create mode 100644 mediaportal/Core/Player/LAVFilters.cs

diff --git a/mediaportal/Core/Core.csproj b/mediaportal/Core/Core.csproj
index e003075..6d5905b 100644
--- a/mediaportal/Core/Core.csproj
+++ b/mediaportal/Core/Core.csproj
@@ -389,6 +389,7 @@
     <Compile Include="Player\FFDShow\Interfaces\IffdshowBase.cs" />
     <Compile Include="Player\FFDShow\Interfaces\IffdshowDec.cs" />
     <Compile Include="Player\FFDShow\Interfaces\IffdshowDecVideo.cs" />
+    <Compile Include="Player\LAVFilters.cs" />
     <Compile Include="Player\MediaInfoWrapper.cs" />
     <Compile Include="Player\PostProcessing\PostProcessingEngine.cs" />
     <Compile Include="Player\RefreshRateChanger.cs" />
diff --git a/mediaportal/Core/Player/AudioPlayerVMR.cs b/mediaportal/Core/Player/AudioPlayerVMR.cs
index a8cccc6..22b8c6f 100644
--- a/mediaportal/Core/Player/AudioPlayerVMR.cs
+++ b/mediaportal/Core/Player/AudioPlayerVMR.cs
@@ -71,6 +71,12 @@ namespace MediaPortal.Player
 
     public AudioPlayerVMR7() {}
 
+    public override DirectShowLib.IGraphBuilder getGraphBuilder()
+    {
+      Log.Info("Dynamic Audio Delay: AudioPlayerVMR: Returning handle to graphBuilder: " + graphBuilder);
+      return graphBuilder;
+    }
+
     public override bool Play(string strFile)
     {
       m_iVolume = 100;
diff --git a/mediaportal/Core/Player/BDPlayer.cs b/mediaportal/Core/Player/BDPlayer.cs
index e88290a..ab3f498 100644
--- a/mediaportal/Core/Player/BDPlayer.cs
+++ b/mediaportal/Core/Player/BDPlayer.cs
@@ -897,6 +897,12 @@ namespace MediaPortal.Player
       return Strings.Unknown;
     }
 
+    public override DirectShowLib.IGraphBuilder getGraphBuilder()
+    {
+      Log.Info("Dynamic Audio Delay: BDPlayer: Returning handle to graphBuilder: " + _graphBuilder);
+      return _graphBuilder;
+    }
+
     public override bool Play(string strFile)
     {
       Log.Info("BDPlayer play: {0}", strFile);
diff --git a/mediaportal/Core/Player/BaseStreamBufferPlayer.cs b/mediaportal/Core/Player/BaseStreamBufferPlayer.cs
index 7fabb4b..947c67f 100644
--- a/mediaportal/Core/Player/BaseStreamBufferPlayer.cs
+++ b/mediaportal/Core/Player/BaseStreamBufferPlayer.cs
@@ -143,6 +143,12 @@ namespace MediaPortal.Player
       get { return false; }
     }
 
+    public override DirectShowLib.IGraphBuilder getGraphBuilder()
+    {
+      Log.Info("Dynamic Audio Delay: BaseStreamBufferPlayer: Returning handle to graphBuilder: " + _graphBuilder);
+      return _graphBuilder;
+    }
+
     public override bool Play(string strFile)
     {
       Log.Info("Streambufferplayer play:{0}", strFile);
diff --git a/mediaportal/Core/Player/BaseTSReaderPlayer.cs b/mediaportal/Core/Player/BaseTSReaderPlayer.cs
index 2f5e0fb..9a786c2 100644
--- a/mediaportal/Core/Player/BaseTSReaderPlayer.cs
+++ b/mediaportal/Core/Player/BaseTSReaderPlayer.cs
@@ -527,6 +527,12 @@ namespace MediaPortal.Player
       get { return false; }
     }
 
+    public override DirectShowLib.IGraphBuilder getGraphBuilder()
+    {
+      Log.Info("Dynamic Audio Delay: BaseTSReaderPlayer: Returning handle to graphBuilder: " + _graphBuilder);
+      return _graphBuilder;
+    }
+
     public override bool Play(string strFile)
     {
       _endOfFileDetected = false;
diff --git a/mediaportal/Core/Player/DVDPlayer.cs b/mediaportal/Core/Player/DVDPlayer.cs
index b2e52ab..076ccac 100644
--- a/mediaportal/Core/Player/DVDPlayer.cs
+++ b/mediaportal/Core/Player/DVDPlayer.cs
@@ -194,6 +194,12 @@ namespace MediaPortal.Player
       }
     }
 
+    public override DirectShowLib.IGraphBuilder getGraphBuilder()
+    {
+      Log.Info("Dynamic Audio Delay: DVDPlayer: Returning handle to graphBuilder: " + _graphBuilder);
+      return _graphBuilder;
+    }
+
     public override bool Play(string file)
     {
       if (String.IsNullOrEmpty(file))
diff --git a/mediaportal/Core/Player/IPlayer.cs b/mediaportal/Core/Player/IPlayer.cs
index b0aeaeb..1e8f722 100644
--- a/mediaportal/Core/Player/IPlayer.cs
+++ b/mediaportal/Core/Player/IPlayer.cs
@@ -704,6 +704,15 @@ namespace MediaPortal.Player
     public virtual bool IsTimeShifting
     {
       get { return false; }
+    }
+
+    /// <summary>
+    /// Gets the current graphBuilder
+    /// </summary>
+    public virtual DirectShowLib.IGraphBuilder getGraphBuilder()
+    {
+      Log.Info("Dynamic Audio Delay: IPlayer: Returning default handle to graphBuilder which is NULL");
+      return null;
     }
 
     public virtual void ContinueGraph() {}
diff --git a/mediaportal/Core/Player/LAVFilters.cs b/mediaportal/Core/Player/LAVFilters.cs
new file mode 100644
index 0000000..c9e9959
--- /dev/null
+++ b/mediaportal/Core/Player/LAVFilters.cs
@@ -0,0 +1,688 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.IO;
+using System.Reflection;
+
+namespace Test.LAVFilters.Interfaces
+{
+	#region "LAV COM classes"
+
+	// use these if LAV is already registered (regsvr32)
+	// you will need the apropriate architecture (ie. if your player is 64 bits a 64 bit LAv filter must be installed)
+	// if you want to use your own supplied LAV filter without registration see FilterProvider class
+
+	[ComImport, Guid("E8E73B6B-4CB3-44A4-BE99-4F7BCB96E491")]
+	public class LAVAudio
+	{
+	}
+	[ComImport, Guid("B98D13E7-55DB-4385-A33D-09FD1BA26338")]
+	public class LAVSplitterSource
+	{
+	}
+	[ComImport, Guid("171252A0-8820-4AFE-9DF8-5C92B2D66B04")]
+	public class LAVSplitter
+	{
+	}
+
+	[ComImport, Guid("EE30215D-164F-4A92-A4EB-9D4C13390F9F")]
+	public class LAVVideo
+	{
+	}
+
+	#endregion
+
+	#region "Lav Video settings interface, implemented by LAVVideo"
+
+
+	// Codecs supported in the LAV Video configuration
+	// Codecs not listed here cannot be turned off. You can request codecs to be added to this list, if you wish.
+	public enum LAVVideoCodec
+	{
+		Codec_H264,
+		Codec_VC1,
+		Codec_MPEG1,
+		Codec_MPEG2,
+		Codec_MPEG4,
+		Codec_MSMPEG4,
+		Codec_VP8,
+		Codec_WMV3,
+		Codec_WMV12,
+		Codec_MJPEG,
+		Codec_Theora,
+		Codec_FLV1,
+		Codec_VP6,
+		Codec_SVQ,
+		Codec_H261,
+		Codec_H263,
+		Codec_Indeo,
+		Codec_TSCC,
+		Codec_Fraps,
+		Codec_HuffYUV,
+		Codec_QTRle,
+		Codec_DV,
+		Codec_Bink,
+		Codec_Smacker,
+		Codec_RV12,
+		Codec_RV34,
+		Codec_Lagarith,
+		Codec_Cinepak,
+		Codec_Camstudio,
+		Codec_QPEG,
+		Codec_ZLIB,
+		Codec_QTRpza,
+		Codec_PNG,
+		Codec_MSRLE,
+		Codec_ProRes,
+		Codec_UtVideo,
+		Codec_Dirac,
+		Codec_DNxHD,
+		Codec_MSVideo1,
+		Codec_8BPS,
+		Codec_LOCO,
+		Codec_ZMBV,
+		Codec_VCR1,
+		Codec_Snow,
+		Codec_FFV1,
+		Codec_v210,
+		//Codec_NB            // Number of entrys (do not use when dynamically linking)
+	};
+
+	// Codecs with hardware acceleration
+	public enum LAVVideoHWCodec
+	{
+		HWCodec_H264 = LAVVideoCodec.Codec_H264,
+		HWCodec_VC1 = LAVVideoCodec.Codec_VC1,
+		HWCodec_MPEG2 = LAVVideoCodec.Codec_MPEG2,
+		HWCodec_MPEG4 = LAVVideoCodec.Codec_MPEG4,
+
+		HWCodec_NB = LAVVideoHWCodec.HWCodec_MPEG4 + 1
+	};
+
+	// Type of hardware accelerations
+	public enum LAVHWAccel
+	{
+		HWAccel_None,
+		HWAccel_CUDA,
+		HWAccel_QuickSync,
+		HWAccel_DXVA2,
+		HWAccel_DXVA2CopyBack = HWAccel_DXVA2,
+		HWAccel_DXVA2Native
+	};
+
+	// Deinterlace algorithms offered by the hardware decoders
+	public enum LAVHWDeintModes
+	{
+		HWDeintMode_Weave,
+		HWDeintMode_BOB,
+		HWDeintMode_Hardware
+	};
+
+	// Software deinterlacing algorithms
+	public enum LAVSWDeintModes
+	{
+		SWDeintMode_None,
+		SWDeintMode_YADIF
+	};
+
+	// Type of deinterlacing to perform
+	// - FramePerField re-constructs one frame from every field, resulting in 50/60 fps.
+	// - FramePer2Field re-constructs one frame from every 2 fields, resulting in 25/30 fps.
+	// Note: Weave will always use FramePer2Field
+	public enum LAVDeintOutput
+	{
+		DeintOutput_FramePerField,
+		DeintOutput_FramePer2Field
+	};
+
+	// Control the field order of the deinterlacer
+	public enum LAVDeintFieldOrder
+	{
+		DeintFieldOrder_Auto,
+		DeintFieldOrder_TopFieldFirst,
+		DeintFieldOrder_BottomFieldFirst,
+	};
+
+	// Supported output pixel formats
+	public enum LAVOutPixFmts
+	{
+		LAVOutPixFmt_None = -1,
+		LAVOutPixFmt_YV12,            // 4:2:0, 8bit, planar
+		LAVOutPixFmt_NV12,            // 4:2:0, 8bit, Y planar, U/V packed
+		LAVOutPixFmt_YUY2,            // 4:2:2, 8bit, packed
+		LAVOutPixFmt_UYVY,            // 4:2:2, 8bit, packed
+		LAVOutPixFmt_AYUV,            // 4:4:4, 8bit, packed
+		LAVOutPixFmt_P010,            // 4:2:0, 10bit, Y planar, U/V packed
+		LAVOutPixFmt_P210,            // 4:2:2, 10bit, Y planar, U/V packed
+		LAVOutPixFmt_Y410,            // 4:4:4, 10bit, packed
+		LAVOutPixFmt_P016,            // 4:2:0, 16bit, Y planar, U/V packed
+		LAVOutPixFmt_P216,            // 4:2:2, 16bit, Y planar, U/V packed
+		LAVOutPixFmt_Y416,            // 4:4:4, 16bit, packed
+		LAVOutPixFmt_RGB32,           // 32-bit RGB (BGRA)
+		LAVOutPixFmt_RGB24,           // 24-bit RGB (BGR)
+
+		LAVOutPixFmt_v210,            // 4:2:2, 10bit, packed
+		LAVOutPixFmt_v410,            // 4:4:4, 10bit, packed
+
+		LAVOutPixFmt_YV16,            // 4:2:2, 8-bit, planar
+		LAVOutPixFmt_YV24,            // 4:4:4, 8-bit, planar
+
+		//LAVOutPixFmt_NB               // Number of formats
+	};
+
+	// dithering mode used by the filter
+	public enum LAVDitherMode
+	{
+		LAVDither_Ordered,
+		LAVDither_Random
+	};
+
+	// LAV Video configuration interface
+	[ComVisible(true), ComImport, SuppressUnmanagedCodeSecurity,
+		 Guid("FA40D6E9-4D38-4761-ADD2-71A9EC5FD32F"),
+		 InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+	public interface ILAVVideoSettings
+	{
+		// Switch to Runtime Config mode. This will reset all settings to default, and no changes to the settings will be saved
+		// You can use this to programmatically configure LAV Audio without interfering with the users settings in the registry.
+		// Subsequent calls to this function will reset all settings back to defaults, even if the mode does not change.
+		//
+		// Note that calling this function during playback is not supported and may exhibit undocumented behaviour. 
+		// For smooth operations, it must be called before LAV Audio is connected to other filters.
+		[PreserveSig]
+		int SetRuntimeConfig(bool bRuntimeConfig);
+
+		// Configure which codecs are enabled
+		// If vCodec is invalid (possibly a version difference), Get will return FALSE, and Set E_FAIL.
+		[PreserveSig]
+		bool GetFormatConfiguration(LAVVideoCodec vCodec);
+		[PreserveSig]
+		int SetFormatConfiguration(LAVVideoCodec vCodec, bool bEnabled);
+
+		// Set the number of threads to use for Multi-Threaded decoding (where available)
+		//  0 = Auto Detect (based on number of CPU cores)
+		//  1 = 1 Thread -- No Multi-Threading
+		// >1 = Multi-Threading with the specified number of threads
+		[PreserveSig]
+		int SetNumThreads(int dwNum);
+
+		// Get the number of threads to use for Multi-Threaded decoding (where available)
+		//  0 = Auto Detect (based on number of CPU cores)
+		//  1 = 1 Thread -- No Multi-Threading
+		// >1 = Multi-Threading with the specified number of threads
+		[PreserveSig]
+		int GetNumThreads();
+
+		// Set wether the aspect ratio encoded in the stream should be forwarded to the renderer,
+		// or the aspect ratio specified by the source filter should be kept.
+		// TRUE  = AR from the Stream
+		// FALSE = AR from the source filter
+		[PreserveSig]
+		int SetStreamAR(bool bStreamAR);
+
+		// Get wether the aspect ratio encoded in the stream should be forwarded to the renderer,
+		// or the aspect ratio specified by the source filter should be kept.
+		// TRUE  = AR from the Stream
+		// FALSE = AR from the source filter
+		[PreserveSig]
+		bool GetStreamAR();
+
+		// Configure which pixel formats are enabled for output
+		// If pixFmt is invalid, Get will return FALSE and Set E_FAIL
+		[PreserveSig]
+		bool GetPixelFormat(LAVOutPixFmts pixFmt);
+		[PreserveSig]
+		int SetPixelFormat(LAVOutPixFmts pixFmt, bool bEnabled);
+
+		// Set the RGB output range for the YUV->RGB conversion
+		// 0 = Auto (same as input), 1 = Limited (16-235), 2 = Full (0-255)
+		[PreserveSig]
+		int SetRGBOutputRange(int dwRange);
+
+		// Get the RGB output range for the YUV->RGB conversion
+		// 0 = Auto (same as input), 1 = Limited (16-235), 2 = Full (0-255)
+		[PreserveSig]
+		int GetRGBOutputRange();
+
+		// Set the deinterlacing field order of the hardware decoder
+		[PreserveSig]
+		int SetDeintFieldOrder(LAVDeintFieldOrder fieldOrder);
+
+		// get the deinterlacing field order of the hardware decoder
+		[PreserveSig]
+		LAVDeintFieldOrder GetDeintFieldOrder();
+
+		// Set wether all frames should be deinterlaced if the stream is flagged interlaced
+		[PreserveSig]
+		int SetDeintAggressive(bool bAggressive);
+
+		// Get wether all frames should be deinterlaced if the stream is flagged interlaced
+		[PreserveSig]
+		bool GetDeintAggressive();
+
+		// Set wether all frames should be deinterlaced, even ones marked as progressive
+		[PreserveSig]
+		int SetDeintForce(bool bForce);
+
+		// Get wether all frames should be deinterlaced, even ones marked as progressive
+		[PreserveSig]
+		bool GetDeintForce();
+
+		// Check if the specified HWAccel is supported
+		// Note: This will usually only check the availability of the required libraries (ie. for NVIDIA if a recent enough NVIDIA driver is installed)
+		// and not check actual hardware support
+		// Returns: 0 = Unsupported, 1 = Supported, 2 = Currently running
+		[PreserveSig]
+		int CheckHWAccelSupport(LAVHWAccel hwAccel);
+
+		// Set which HW Accel method is used
+		// See LAVHWAccel for options.
+		[PreserveSig]
+		int SetHWAccel(LAVHWAccel hwAccel);
+
+		// Get which HW Accel method is active
+		[PreserveSig]
+		LAVHWAccel GetHWAccel();
+
+		// Set which codecs should use HW Acceleration
+		[PreserveSig]
+		int SetHWAccelCodec(LAVVideoHWCodec hwAccelCodec, bool bEnabled);
+
+		// Get which codecs should use HW Acceleration
+		[PreserveSig]
+		bool GetHWAccelCodec(LAVVideoHWCodec hwAccelCodec);
+
+		// Set the deinterlacing mode used by the hardware decoder
+		[PreserveSig]
+		int SetHWAccelDeintMode(LAVHWDeintModes deintMode);
+
+		// Get the deinterlacing mode used by the hardware decoder
+		[PreserveSig]
+		LAVHWDeintModes GetHWAccelDeintMode();
+
+		// Set the deinterlacing output for the hardware decoder
+		[PreserveSig]
+		int SetHWAccelDeintOutput(LAVDeintOutput deintOutput);
+
+		// Get the deinterlacing output for the hardware decoder
+		[PreserveSig]
+		LAVDeintOutput GetHWAccelDeintOutput();
+
+		// Set wether the hardware decoder should force high-quality deinterlacing
+		// Note: this option is not supported on all decoder implementations and/or all operating systems
+		[PreserveSig]
+		int SetHWAccelDeintHQ(bool bHQ);
+
+		// Get wether the hardware decoder should force high-quality deinterlacing
+		// Note: this option is not supported on all decoder implementations and/or all operating systems
+		[PreserveSig]
+		bool GetHWAccelDeintHQ();
+
+		// Set the software deinterlacing mode used
+		[PreserveSig]
+		int SetSWDeintMode(LAVSWDeintModes deintMode);
+
+		// Get the software deinterlacing mode used
+		[PreserveSig]
+		LAVSWDeintModes GetSWDeintMode();
+
+		// Set the software deinterlacing output
+		[PreserveSig]
+		int SetSWDeintOutput(LAVDeintOutput deintOutput);
+
+		// Get the software deinterlacing output
+		[PreserveSig]
+		LAVDeintOutput GetSWDeintOutput();
+
+		// Set wether all content is treated as progressive, and any interlaced flags are ignored
+		[PreserveSig]
+		int SetDeintTreatAsProgressive(bool bEnabled);
+
+		// Get wether all content is treated as progressive, and any interlaced flags are ignored
+		[PreserveSig]
+		bool GetDeintTreatAsProgressive();
+
+		// Set the dithering mode used
+		[PreserveSig]
+		int SetDitherMode(LAVDitherMode ditherMode);
+
+		// Get the dithering mode used
+		[PreserveSig]
+		LAVDitherMode GetDitherMode();
+	};
+
+	#endregion
+
+	#region "Lav Audio settings and status interfaces, implemented by LavAudio"
+
+	// Codecs supported in the LAV Audio configuration
+	// Codecs not listed here cannot be turned off. You can request codecs to be added to this list, if you wish.
+	public enum LAVAudioCodec
+	{
+		Codec_AAC,
+		Codec_AC3,
+		Codec_EAC3,
+		Codec_DTS,
+		Codec_MP2,
+		Codec_MP3,
+		Codec_TRUEHD,
+		Codec_FLAC,
+		Codec_VORBIS,
+		Codec_LPCM,
+		Codec_PCM,
+		Codec_WAVPACK,
+		Codec_TTA,
+		Codec_WMA2,
+		Codec_WMAPRO,
+		Codec_Cook,
+		Codec_RealAudio
+
+		//Codec_NB            // Number of entrys (do not use when dynamically linking)
+	};
+
+	// Bitstreaming Codecs supported in LAV Audio
+	public enum LAVBitstreamCodec
+	{
+		Bitstream_AC3,
+		Bitstream_EAC3,
+		Bitstream_TRUEHD,
+		Bitstream_DTS,
+		Bitstream_DTSHD
+
+		//Bitstream_NB        // Number of entrys (do not use when dynamically linking)
+	};
+
+
+	// Supported Sample Formats in LAV Audio
+	public enum LAVAudioSampleFormat
+	{
+		SampleFormat_16,
+		SampleFormat_24,
+		SampleFormat_32,
+		SampleFormat_U8,
+		SampleFormat_FP32,
+		SampleFormat_Bitstream
+
+		//SampleFormat_NB     // Number of entrys (do not use when dynamically linking)
+	};
+
+	// LAV Audio status interface
+	[ComVisible(true), ComImport, SuppressUnmanagedCodeSecurity,
+		 Guid("A668B8F2-BA87-4F63-9D41-768F7DE9C50E"),
+		 InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+	public interface ILAVAudioStatus
+	{
+		// Check if the given sample format is supported by the current playback chain
+		[PreserveSig]
+		bool IsSampleFormatSupported(LAVAudioSampleFormat sfCheck);
+
+		// Get details about the current decoding format
+		[PreserveSig]
+		int GetDecodeDetails([MarshalAs(UnmanagedType.LPStr)]out string pCodec, [MarshalAs(UnmanagedType.LPStr)]out string pDecodeFormat, out int pnChannels, out int pSampleRate, out int pChannelMask);
+
+		// Get details about the current output format
+		[PreserveSig]
+		int GetOutputDetails([MarshalAs(UnmanagedType.LPStr)]out string pOutputFormat, out int pnChannels, out int pSampleRate, out int pChannelMask);
+
+		// Enable Volume measurements
+		[PreserveSig]
+		int EnableVolumeStats();
+
+		// Disable Volume measurements
+		[PreserveSig]
+		int DisableVolumeStats();
+
+		// Get Volume Average for the given channel
+		[PreserveSig]
+		int GetChannelVolumeAverage(int nChannel, out float pfDb);
+	};
+
+	// LAV Audio configuration interface
+	[ComVisible(true), ComImport, SuppressUnmanagedCodeSecurity,
+		 Guid("4158A22B-6553-45D0-8069-24716F8FF171"),
+		 InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+	public interface ILAVAudioSettings
+	{
+		// Switch to Runtime Config mode. This will reset all settings to default, and no changes to the settings will be saved
+		// You can use this to programmatically configure LAV Audio without interfering with the users settings in the registry.
+		// Subsequent calls to this function will reset all settings back to defaults, even if the mode does not change.
+		//
+		// Note that calling this function during playback is not supported and may exhibit undocumented behaviour. 
+		// For smooth operations, it must be called before LAV Audio is connected to other filters.
+		[PreserveSig]
+		int SetRuntimeConfig(bool bRuntimeConfig);
+
+		// Dynamic Range Compression
+		// pbDRCEnabled: The state of DRC
+		// piDRCLevel:   The DRC strength (0-100, 100 is maximum)
+		[PreserveSig]
+		int GetDRC(out bool pbDRCEnabled, out int piDRCLevel);
+		[PreserveSig]
+		int SetDRC(bool bDRCEnabled, int iDRCLevel);
+
+		// Configure which codecs are enabled
+		// If aCodec is invalid (possibly a version difference), Get will return FALSE, and Set E_FAIL.
+		[PreserveSig]
+		bool GetFormatConfiguration(LAVAudioCodec aCodec);
+		[PreserveSig]
+		int SetFormatConfiguration(LAVAudioCodec aCodec, bool bEnabled);
+
+		// Control Bitstreaming
+		// If bsCodec is invalid (possibly a version difference), Get will return FALSE, and Set E_FAIL.
+		[PreserveSig]
+		bool GetBitstreamConfig(LAVBitstreamCodec bsCodec);
+		[PreserveSig]
+		int SetBitstreamConfig(LAVBitstreamCodec bsCodec, bool bEnabled);
+
+		// Should "normal" DTS frames be encapsulated in DTS-HD frames when bitstreaming?
+		[PreserveSig]
+		bool GetDTSHDFraming();
+		[PreserveSig]
+		int SetDTSHDFraming(bool bHDFraming);
+
+		// Control Auto A/V syncing
+		[PreserveSig]
+		bool GetAutoAVSync();
+		[PreserveSig]
+		int SetAutoAVSync(bool bAutoSync);
+
+		// Convert all Channel Layouts to standard layouts
+		// Standard are: Mono, Stereo, 5.1, 6.1, 7.1
+		[PreserveSig]
+		bool GetOutputStandardLayout();
+		[PreserveSig]
+		int SetOutputStandardLayout(bool bStdLayout);
+
+		// Expand Mono to Stereo by simply doubling the audio
+		[PreserveSig]
+		bool GetExpandMono();
+		[PreserveSig]
+		int SetExpandMono(bool bExpandMono);
+
+		// Expand 6.1 to 7.1 by doubling the back center
+		[PreserveSig]
+		bool GetExpand61();
+		[PreserveSig]
+		int SetExpand61(bool bExpand61);
+
+		// Allow Raw PCM and SPDIF encoded input
+		[PreserveSig]
+		bool GetAllowRawSPDIFInput();
+		[PreserveSig]
+		int SetAllowRawSPDIFInput(bool bAllow);
+
+		// Configure which sample formats are enabled
+		// Note: SampleFormat_Bitstream cannot be controlled by this
+		[PreserveSig]
+		bool GetSampleFormat(LAVAudioSampleFormat format);
+		[PreserveSig]
+		int SetSampleFormat(LAVAudioSampleFormat format, bool bEnabled);
+
+		// Configure a delay for the audio
+		[PreserveSig]
+		int GetAudioDelay(out bool pbEnabled, out int pDelay);
+		[PreserveSig]
+		int SetAudioDelay(bool bEnabled, int delay);
+	}
+
+	#endregion
+
+	#region "Lav splitter settings interface, implemented by LAVSplitter and LAVSplitterSource"
+
+	public enum LAVSubtitleMode
+	{
+		LAVSubtitleMode_NoSubs = 0,
+		LAVSubtitleMode_ForcedOnly,
+		LAVSubtitleMode_Default,
+		LAVSubtitleMode_Advanced
+	};
+
+	[ComVisible(true), ComImport, SuppressUnmanagedCodeSecurity,
+	 Guid("774A919D-EA95-4A87-8A1E-F48ABE8499C7"),
+	 InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+	public interface ILAVSplitterSettings
+	{
+		// Switch to Runtime Config mode. This will reset all settings to default, and no changes to the settings will be saved
+		// You can use this to programmatically configure LAV Splitter without interfering with the users settings in the registry.
+		// Subsequent calls to this function will reset all settings back to defaults, even if the mode does not change.
+		//
+		// Note that calling this function during playback is not supported and may exhibit undocumented behaviour. 
+		// For smooth operations, it must be called before LAV Splitter opens a file.
+		[PreserveSig]
+		int SetRuntimeConfig(bool runtime);
+
+
+		// Retrieve the preferred languages as ISO 639-2 language codes, comma seperated
+		// If the result is NULL, no language has been set
+		// Memory for the string will be allocated, and has to be free'ed by the caller with CoTaskMemFree
+		[PreserveSig]
+		int GetPreferredLanguages([MarshalAs(UnmanagedType.LPWStr)]out string langs);
+
+		// Set the preferred languages as ISO 639-2 language codes, comma seperated
+		// To reset to no preferred language, pass NULL or the empty string
+		[PreserveSig]
+		int SetPreferredLanguages([MarshalAs(UnmanagedType.LPWStr)]string langs);
+
+		// Retrieve the preferred subtitle languages as ISO 639-2 language codes, comma seperated
+		// If the result is NULL, no language has been set
+		// If no subtitle language is set, the main language preference is used.
+		// Memory for the string will be allocated, and has to be free'ed by the caller with CoTaskMemFree
+		[PreserveSig]
+		int GetPreferredSubtitleLanguages([MarshalAs(UnmanagedType.LPWStr)]out string langs);
+
+		// Set the preferred subtitle languages as ISO 639-2 language codes, comma seperated
+		// To reset to no preferred language, pass NULL or the empty string
+		// If no subtitle language is set, the main language preference is used.
+		[PreserveSig]
+		int SetPreferredSubtitleLanguages([MarshalAs(UnmanagedType.LPWStr)]string langs);
+
+		// Get the current subtitle mode
+		// See enum for possible values
+		[PreserveSig]
+		LAVSubtitleMode GetSubtitleMode();
+
+		// Set the current subtitle mode
+		// See enum for possible values
+		[PreserveSig]
+		int SetSubtitleMode(LAVSubtitleMode mode);
+
+		// Get the subtitle matching language flag
+		// TRUE = Only subtitles with a language in the preferred list will be used; FALSE = All subtitles will be used
+		// @deprecated - do not use anymore, deprecated and non-functional, replaced by advanced subtitle mode
+		[PreserveSig]
+		bool GetSubtitleMatchingLanguage();
+
+		// Set the subtitle matching language flag
+		// TRUE = Only subtitles with a language in the preferred list will be used; FALSE = All subtitles will be used
+		// @deprecated - do not use anymore, deprecated and non-functional, replaced by advanced subtitle mode
+		[PreserveSig]
+		int SetSubtitleMatchingLanguage(bool mode);
+
+		// Control wether a special "Forced Subtitles" stream will be created for PGS subs
+		[PreserveSig]
+		bool GetPGSForcedStream();
+
+		// Control wether a special "Forced Subtitles" stream will be created for PGS subs
+		[PreserveSig]
+		int SetPGSForcedStream(bool enabled);
+
+		// Get the PGS forced subs config
+		// TRUE = only forced PGS frames will be shown, FALSE = all frames will be shown
+		[PreserveSig]
+		bool GetPGSOnlyForced();
+
+		// Set the PGS forced subs config
+		// TRUE = only forced PGS frames will be shown, FALSE = all frames will be shown
+		[PreserveSig]
+		int SetPGSOnlyForced(bool forced);
+
+		// Get the VC-1 Timestamp Processing mode
+		// 0 - No Timestamp Correction, 1 - Always Timestamp Correction, 2 - Auto (Correction for Decoders that need it)
+		[PreserveSig]
+		int GetVC1TimestampMode();
+
+		// Set the VC-1 Timestamp Processing mode
+		// 0 - No Timestamp Correction, 1 - Always Timestamp Correction, 2 - Auto (Correction for Decoders that need it)
+		[PreserveSig]
+		int SetVC1TimestampMode(short enabled);
+
+		// Set whether substreams (AC3 in TrueHD, for example) should be shown as a seperate stream
+		[PreserveSig]
+		int SetSubstreamsEnabled(bool enabled);
+
+		// Check whether substreams (AC3 in TrueHD, for example) should be shown as a seperate stream
+		[PreserveSig]
+		bool GetSubstreamsEnabled();
+
+		// Set if the ffmpeg parsers should be used for video streams
+		[PreserveSig]
+		int SetVideoParsingEnabled(bool enabled);
+
+		// Query if the ffmpeg parsers are being used for video streams
+		[PreserveSig]
+		bool GetVideoParsingEnabled();
+
+		// Set if LAV Splitter should try to fix broken HD-PVR streams
+		[PreserveSig]
+		int SetFixBrokenHDPVR(bool enabled);
+
+		// Query if LAV Splitter should try to fix broken HD-PVR streams
+		[PreserveSig]
+		bool GetFixBrokenHDPVR();
+
+		// Control wether the givne format is enabled
+		[PreserveSig]
+		int SetFormatEnabled([MarshalAs(UnmanagedType.LPStr)]string strFormat, bool bEnabled);
+
+		// Check if the given format is enabled
+		[PreserveSig]
+		bool IsFormatEnabled([MarshalAs(UnmanagedType.LPStr)]string strFormat);
+
+		// Set if LAV Splitter should always completely remove the filter connected to its Audio Pin when the audio stream is changed
+		[PreserveSig]
+		int SetStreamSwitchRemoveAudio(bool enabled);
+
+		// Query if LAV Splitter should always completely remove the filter connected to its Audio Pin when the audio stream is changed
+		[PreserveSig]
+		bool GetStreamSwitchRemoveAudio();
+
+		// Advanced Subtitle configuration. Refer to the documention for details.
+		// If no advanced config exists, will be NULL.
+		// Memory for the string will be allocated, and has to be free'ed by the caller with CoTaskMemFree
+		[PreserveSig]
+		int GetAdvancedSubtitleConfig([MarshalAs(UnmanagedType.LPWStr)]out string ec);
+
+		// Advanced Subtitle configuration. Refer to the documention for details.
+		// To reset the config, pass NULL or the empty string.
+		// If no subtitle language is set, the main language preference is used.
+		[PreserveSig]
+		int SetAdvancedSubtitleConfig([MarshalAs(UnmanagedType.LPWStr)]string config);
+
+	}
+
+	#endregion
+
+}
diff --git a/mediaportal/Core/Player/RTSPPlayer.cs b/mediaportal/Core/Player/RTSPPlayer.cs
index 2d18ff8..75d892b 100644
--- a/mediaportal/Core/Player/RTSPPlayer.cs
+++ b/mediaportal/Core/Player/RTSPPlayer.cs
@@ -622,6 +622,12 @@ namespace MediaPortal.Player
       get { return (_mediaType == g_Player.MediaType.TV || _mediaType == g_Player.MediaType.Radio); }
     }
 
+    public override DirectShowLib.IGraphBuilder getGraphBuilder()
+    {
+      Log.Info("Dynamic Audio Delay: RTSPPlayer: Returning handle to graphBuilder: " + graphBuilder);
+      return graphBuilder;
+    }
+
     public override bool Play(string strFile)
     {
       updateTimer = DateTime.Now;
diff --git a/mediaportal/Core/Player/VideoPlayerVMR7.cs b/mediaportal/Core/Player/VideoPlayerVMR7.cs
index e430b1b..1856643 100644
--- a/mediaportal/Core/Player/VideoPlayerVMR7.cs
+++ b/mediaportal/Core/Player/VideoPlayerVMR7.cs
@@ -287,6 +287,12 @@ namespace MediaPortal.Player
       _mediaType = type;
     }
 
+    public override DirectShowLib.IGraphBuilder getGraphBuilder()
+    {
+      Log.Info("Dynamic Audio Delay: VideoPlayerVMR7: Returning handle to graphBuilder: " + graphBuilder);
+      return graphBuilder;
+    }
+
     public override bool Play(string strFile)
     {
       updateTimer = DateTime.Now;
diff --git a/mediaportal/Core/Player/g_player.cs b/mediaportal/Core/Player/g_player.cs
index 0ca310e..106ab21 100644
--- a/mediaportal/Core/Player/g_player.cs
+++ b/mediaportal/Core/Player/g_player.cs
@@ -39,6 +39,9 @@ using Un4seen.Bass;
 using Un4seen.Bass.AddOn.Cd;
 using Action = MediaPortal.GUI.Library.Action;
 using MediaPortal.Player.Subtitles;
+using Test.LAVFilters.Interfaces;
+using DirectShowLib;
+using DShowNET.Helper;
 
 namespace MediaPortal.Player
 {
@@ -1594,6 +1597,58 @@ namespace MediaPortal.Player
           }
           else if (_player != null && _player.Playing)
           {
+            {
+              // Dynamic Audio Delay
+              Log.Info("Dynamic Audio Delay: Video/TV playback detected, trying to get a handle to the graph");
+              IGraphBuilder graphBuilder = _player.getGraphBuilder();
+              if (graphBuilder == null)
+              {
+                Log.Info("Dynamic Audio Delay: Unable to get any graphBuilder for this player!");
+              }
+              else
+              {
+                Log.Info("Dynamic Audio Delay: Trying to get the LAV Audio Decoder filter");
+                IBaseFilter lavAudioDecoder = DirectShowUtil.GetFilterByName(graphBuilder, "LAV Audio Decoder");
+                // Alternativ approach:
+                //IBaseFilter MSVideoCodec = null;
+                //_graphBuilder.FindFilterByName("Microsoft DTV-DVD Video Decoder", out MSVideoCodec);
+                if (lavAudioDecoder == null)
+                {
+                  Log.Info("Dynamic Audio Delay: Could not get the LAV Audio Decoder filter from the graph!");
+                }
+                else
+                {
+                  Log.Info("Dynamic Audio Delay: Successfully got a handle to the LAV Audio Decoder filter! Trying to determine FPS...");
+                  double fps = 50.0;
+                  if (Util.Utils.IsLiveTv(strFile))
+                  {
+                    // Assume 50 FPS for live TV
+                    fps = 50.0;
+                    Log.Info("Dynamic Audio Delay: Detected live TV, assuming 50 FPS");
+                  }
+                  else
+                  {
+                    // Try to get it from the video graph
+                    Log.Info("Dynamic Audio Delay: It was not live TV, checking media info from g_Player...");
+                    fps = g_Player.MediaInfo.Framerate;
+                    Log.Info("Dynamic Audio Delay: Got FPS from g_Player: " + fps);
+                  }
+                  Log.Info("Dynamic Audio Delay: FPS seems to be: " + fps);
+                  // Sanity check
+                  if (fps < 1.0)
+                  {
+                    Log.Info("Dynamic Audio Delay: Strange FPS value detected: " + fps + ", resetting it to 50 FPS!");
+                    fps = 50.0;
+                  }
+
+                  // Calculate and set the delay for LAV Audio Filter
+                  int delay = (int)(6 * 1000 / fps); // Delay of Samsung LE46C755 is 6 frames@24p and 7 frames@50p
+                  Log.Info("Dynamic Audio Delay: Changing audio delay of LAV Audio Decoder to " + delay + " to match the current fps of " + fps);
+                  ILAVAudioSettings lavAudioSettings = (ILAVAudioSettings)lavAudioDecoder;
+                  lavAudioSettings.SetAudioDelay(true, delay);
+                }
+              }
+            }
             _isInitialized = false;
             _currentFilePlaying = _player.CurrentFile;
             //if (_chapters == null)
-- 
1.8.0.msysgit.0

