Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I am working with DirectShow for video playback and trying to get the video displayed on a D3D9 texture via SlimDX. I am using IVMRSurfaceAllocator9, IVMRImagePresenter9 for getting a surface from the video as soon as a frame is available.

Everything is working fine if I am doing my main loop rendering inside the presentImage function but if I try to do the rendering separately and getting the texture from the presentImage function and then trying to display it in my main loop then a flickering video is being played.

I have tried a solution that says that changing rendering target to YUV solves the problem but I did it and is not getting the desired results. Can any one please help me out to resolve this problem?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SlimDX;
using SlimDX.Direct3D9;
using DirectShowLib;
using System.Collections;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace WindowsFormsApplication1
{
  public partial class Form1 : Form,IVMRSurfaceAllocator9,IVMRImagePresenter9
  {

    #region slimdxVariables

    Device Device;
    PresentParameters PresentParameters;
    Direct3D Direct3D;
    Surface renderTarget = null;
    private Hashtable textures = null;
    private Hashtable surfaces = null;
    private Texture privateTexture;
    private Surface privateSurface = null;
    private VertexBuffer vertexBuffer = null;
    private const int E_FAIL = unchecked((int)0x80004005);
    private VertexDeclaration vertexDecl;
    private SlimDX.Direct3D9.Font Font; 
    #endregion

    #region DirectShowVariables

    private IVMRSurfaceAllocatorNotify9 vmrSurfaceAllocatorNotify = null;
    private IntPtr[] unmanagedSurfaces = null;
    private FilterGraph FilterGraph =null ;
    private IGraphBuilder graph = null;
    private IBaseFilter filter = null;
    private IMediaControl mediaControl = null;
    private IVMRMixerControl9 pMix;
    private VideoMixingRenderer9 VMR;
    private IntPtr userId = new IntPtr(unchecked((int)0xACDCACDC));
    #endregion

    #region Form VAriables
    OpenFileDialog openFileDialog;

    #endregion

    public Form1()
    {
        path = GetMoviePath();
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        StartGraph();
    }

    #region FunCtions For the Form Class

    private string GetMoviePath()
    {
        openFileDialog = new OpenFileDialog();
        if (openFileDialog.ShowDialog(this) == DialogResult.OK)
        {
            return openFileDialog.FileName;
        }
        else
            return string.Empty;
    }

    private void SetAllocatorPresenter()
    {
        int hr = 0;

        IVMRSurfaceAllocatorNotify9 vmrSurfAllocNotify = (IVMRSurfaceAllocatorNotify9)filter;

        try
        {


            hr = vmrSurfAllocNotify.AdviseSurfaceAllocator(userId, this);
            DsError.ThrowExceptionForHR(hr);

            hr = this.AdviseNotify(vmrSurfAllocNotify);
            DsError.ThrowExceptionForHR(hr);
        }
        catch(SlimDXException e)
        {
            MessageBox.Show("Couldn't run: " + e.Message); 
            throw;
        }
    }
    string path;
    int i = 0;
    VMR9MixerPrefs dwpref;
    VMR9MixerPrefs prefs;
    private void StartGraph()
    {
        dwpref = new VMR9MixerPrefs();

        onCreateDevice(); 
        int hr = 0;

        FilterGraph = new FilterGraph();


        if (path == string.Empty)
            return;

        try
        {
            VMR =new VideoMixingRenderer9 ();
            //graph = (IGraphBuilder)FilterGraph;

            filter = (IBaseFilter)VMR;
            graph = new FilterGraphNoThread() as IGraphBuilder; 

            IVMRFilterConfig9 filterConfig = (IVMRFilterConfig9)filter;
            graph.AddFilter(filter, "VMR");
            hr = filterConfig.SetRenderingMode(VMR9Mode.Renderless);

            IEnumPins pinEnum;

            filter.EnumPins(out pinEnum);
            hr = filterConfig.SetNumberOfStreams(2);
            DsError.ThrowExceptionForHR(hr);


            pMix = (IVMRMixerControl9)filter;
            //if (pMix != null)
            {
                pMix.GetMixingPrefs(out prefs);
                prefs &= ~VMR9MixerPrefs.RenderTargetMask;
                prefs |= VMR9MixerPrefs.RenderTargetYUV;
                prefs |= VMR9MixerPrefs.NonSquareMixing;

                pMix.SetMixingPrefs(prefs);
            }



            SetAllocatorPresenter();

            hr = graph.AddFilter(filter, "Video Mixing Renderer 9");
            DsError.ThrowExceptionForHR(hr);

            hr = graph.RenderFile(path, null);
            DsError.ThrowExceptionForHR(hr);

            mediaControl = (IMediaControl)graph;


            hr = mediaControl.Run();
            DsError.ThrowExceptionForHR(hr);

        }
        catch(SlimDXException e)
        {
            MessageBox.Show(e.Message);
        }
    }

    #endregion
    private void onCreateDevice()
    {

        Direct3D = new Direct3D();
        PresentParameters = new PresentParameters();
        //PresentParameters.BackBufferCount = 0;
        PresentParameters.BackBufferHeight = Screen.PrimaryScreen.Bounds.Height;
        PresentParameters.BackBufferWidth = Screen.PrimaryScreen.Bounds.Width;
        PresentParameters.PresentFlags = PresentFlags.Video;
        PresentParameters.PresentationInterval = PresentInterval.Default;
        PresentParameters.BackBufferFormat = Direct3D.Adapters[0].CurrentDisplayMode.Format;
        PresentParameters.DeviceWindowHandle = this.Handle;
        PresentParameters.SwapEffect = SwapEffect.Copy;
        //PresentParameters.Windowed = false; 
        Device = new Device(Direct3D,Direct3D.Adapters.DefaultAdapter.Adapter,DeviceType.Hardware,this.Handle,CreateFlags.SoftwareVertexProcessing | CreateFlags.Multithreaded,PresentParameters);
        renderTarget = Device.GetRenderTarget(0);
        vertexBuffer = new VertexBuffer(Device, 6 * Vertex.SizeBytes, Usage.WriteOnly, VertexFormat.None, Pool.Managed);

        // write the new vertex information into the buffer
        DataStream stream = vertexBuffer.Lock(0, 0, LockFlags.None);
        stream.WriteRange(BuildVertexData());
        vertexBuffer.Unlock();
        var vertexElems = new[] {
            new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position , 0),
            new VertexElement(0, 12 , DeclarationType.Float2, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 0),
            VertexElement.VertexDeclarationEnd

        };

        vertexDecl = new VertexDeclaration(Device, vertexElems);
        Font = new SlimDX.Direct3D9.Font(Device, 50, 0, FontWeight.Regular, 1, false, CharacterSet.Default, Precision.Default, FontQuality.Default, PitchAndFamily.Default, "");
        txt = new Texture(Device, 1650, 1080, 0, 0, Format.X8R8G8B8, Pool.Default);
        privateTexture = new Texture(Device, 1360,
                                                  768,
                                                  0,
                                                  Usage.None,
                                                  Format.X8R8G8B8, Pool.Default); 
    }

    private void DeleteSurfaces()
    {
        lock (this)
        {
            if (privateTexture != null)
            {
                privateTexture.Dispose();
                privateTexture = null;
            }

            if (privateSurface != null)
            {
                privateSurface.Dispose();
                privateSurface = null;
            }

            if (textures != null)
            {
                foreach (Texture tex in textures.Values)
                {
                    tex.Dispose();
                }
                textures = null;
            }

            if (surfaces != null)
            {
                foreach (Surface surf in surfaces.Values)
                {
                    surf.Dispose();
                }
                surfaces = null;
            }
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    struct Vertex
    {
        public Vector3 Position;
        public float Tu;
        public float Tv;
        public float Tu1;
        public float Tv1;
        public static int SizeBytes
        {
            get { return Marshal.SizeOf(typeof(Vertex)); }
        }


    }


    private Vertex[] BuildVertexData()
    {
        Vertex[] vertexData = new Vertex[6];

        vertexData[0].Position = new Vector3(-1.0f, 1.0f, 0.0f);
        vertexData[0].Tu = 0.0f;
        vertexData[0].Tv = 0.0f;

        vertexData[1].Position = new Vector3(-1.0f, -1.0f, 0.0f);
        vertexData[1].Tu = 0.0f;
        vertexData[1].Tv = 1.0f;

        vertexData[2].Position = new Vector3(1.0f, 1.0f, 0.0f);
        vertexData[2].Tu = 1.0f;
        vertexData[2].Tv = 0.0f;


        vertexData[3].Position = new Vector3(-1.0f, -1.0f, 0.0f);
        vertexData[3].Tu = 0.0f;
        vertexData[3].Tv = 1.0f;


        vertexData[4].Position = new Vector3(1.0f, -1.0f, 0.0f);
        vertexData[4].Tu = 1.0f;
        vertexData[4].Tv = 1.0f;


        vertexData[5].Position = new Vector3(1.0f, 1.0f, 0.0f);
        vertexData[5].Tu = 1.0f;
        vertexData[5].Tv = 0.0f;


        return vertexData;
    }
    Sprite Sprite,FontSprite;
    public int Init(Device d3dDev)
    {
        try
        {

            d3dDev.SetRenderState(RenderState.CullMode,false);
            d3dDev.SetRenderState(RenderState.Lighting,false);


            //d3dDev.SetSamplerState(0, SamplerState.MipFilter, TextureFilter.Linear);

            d3dDev.SetSamplerState(0, SamplerState.MinFilter, TextureFilter.Linear);

            d3dDev.SetSamplerState(0, SamplerState.MagFilter, TextureFilter.Linear);
            //Device.SetRenderTarget(0, renderTarget);

            Sprite = new Sprite(Device);
            FontSprite = new Sprite(Device);

        }
        catch (SlimDXException e)
        {
            MessageBox.Show(e.Message);
        }
        catch
        {
            return E_FAIL;
        }

        return 0;
    }
    float xpos=1650f;

    public void RenderVideo()
    {

        pMix.SetMixingPrefs(prefs);


        Device.SetRenderTarget(0, renderTarget);
        if (xpos < 0) { xpos = 1650; }
        Device.SetRenderTarget(0, renderTarget);
        // clear the scene so we don't have any articats left

        {

            Device.SetRenderTarget(0, renderTarget);


            Device.BeginScene();

            xpos -=5f;




            Device.SetTexture(0, privateTexture);




            Device.VertexDeclaration = vertexDecl;
            Device.SetStreamSource(0, vertexBuffer, 0, Vertex.SizeBytes);



            FontSprite.Begin(SpriteFlags.AlphaBlend);

            Font.DrawString(FontSprite, "Texture Rendering of the video by the help of slimdx Direct3d9 surface ", (int)xpos, 900, Color.Red);

            FontSprite.End();

            Device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);



            Device.EndScene();



            Device.Present();

            IsframeAvailable = false;
        }






        //Sprite.Begin(SpriteFlags.None);

        //Sprite.Draw(txt, Color.Transparent);




    }
    private bool NeedToHandleDisplayChange()
    {
        if (vmrSurfaceAllocatorNotify == null)
            return false;

        IntPtr currentMonitor = Direct3D.GetAdapterMonitor(Device.CreationParameters.AdapterOrdinal);
        IntPtr defaultMonitor = Direct3D.GetAdapterMonitor(Direct3D.Adapters[0].Adapter);

        return currentMonitor != defaultMonitor;
    }
    public bool IsframeAvailable = false;
    public Texture txt;
    public int PresentHelper(VMR9PresentationInfo lpPresInfo)
    {
        Device.Clear(ClearFlags.ZBuffer , Color.AliceBlue, 1.0f, 0);
        Device.SetRenderTarget(0, renderTarget); 
        int hr = 0;

        try
        {


            if (privateTexture != null)
            {
                Marshal.AddRef(lpPresInfo.lpSurf);
                using (Surface surface =Surface.FromPointer(lpPresInfo.lpSurf))
                {
                    Device.StretchRectangle(surface,new Rectangle(0, 0, surface.Description.Width, surface.Description.Height),privateSurface,
                        new Rectangle(0, 0, privateSurface.Description.Width, privateSurface.Description.Height),
                        TextureFilter.None
                        );
                }

                //hr = DrawScene(Device, privateTexture);

                //txt = privateTexture; 
                //IsframeAvailable = true;
                if (hr < 0)
                    return hr;
            }
            else
            {
                if (textures.ContainsKey(lpPresInfo.lpSurf))
                {


                    privateTexture = textures[lpPresInfo.lpSurf] as Texture;

                    if (hr < 0)
                        return hr;
                }
                else
                    hr = E_FAIL;
            }


            return 0;
        }
        catch (SlimDXException e)
        {
            MessageBox.Show(e.Message);
            return 0;
        }
        catch
        {
            return E_FAIL;
        }
    }


    #region IVMRSurfaceAllocator9 Members

    public int AdviseNotify(IVMRSurfaceAllocatorNotify9 lpIVMRSurfAllocNotify)
    {


        lock (this)
        {
            vmrSurfaceAllocatorNotify = lpIVMRSurfAllocNotify;

            IntPtr unmanagedDevice = Device.ComPointer;
            IntPtr hMonitor = Direct3D.GetAdapterMonitor(0 );

            return vmrSurfaceAllocatorNotify.SetD3DDevice(unmanagedDevice, hMonitor);
        }
    }

    public int GetSurface(IntPtr dwUserID, int SurfaceIndex, int SurfaceFlags, out IntPtr lplpSurface)
    {


        lplpSurface = IntPtr.Zero;

        if (SurfaceIndex > unmanagedSurfaces.Length)
            return E_FAIL;

        lock (this)
        {

            lplpSurface = unmanagedSurfaces[SurfaceIndex];

            //pMix.SetMixingPrefs(prefs);
            Marshal.AddRef(lplpSurface);

            return 0;
        }
    }
    private static IntPtr GetComPointer(object comObj)
    {
        if (!Marshal.IsComObject(comObj))
            throw new ArgumentException("The argument is not a COM object", "COMObj");

        IntPtr pComObj = Marshal.GetIUnknownForObject(comObj);

        /* Get IUnknownForObject adds a reference count
         * to the COM object so we remove a reference count
         * before we return the pointer to avoid any possible
         * memory leaks with COM */
        Marshal.Release(pComObj);

        return pComObj;
    }
    private IntPtr GetAdapterMonitor(uint adapterOrdinal)
    {
        IntPtr pMonitor = Direct3D.GetAdapterMonitor(Direct3D.Adapters.DefaultAdapter.Adapter);

        return pMonitor;
    }
    public int InitializeDevice(IntPtr dwUserID, ref VMR9AllocationInfo lpAllocInfo, ref int lpNumBuffers)
    {
        //int width = 1;
        //int height = 1;
        //float fTU = 1.0f;
        //float fTV = 1.0f;



        int hr = 0;

        try
        {

            //IntPtr hMonitor = Direct3D.GetAdapterMonitor(Direct3D.Adapters[0].Monitor);

            //hr = vmrSurfaceAllocatorNotify.SetD3DDevice(unmanagedDevice, hMonitor);
            //DsError.ThrowExceptionForHR(hr);

            //var pDevice = GetComPointer(Device);
            //var pMonitor = GetAdapterMonitor(0);
            //hr = vmrSurfaceAllocatorNotify.SetD3DDevice(pDevice, pMonitor);
            //DsError.ThrowExceptionForHR(hr);
            lpAllocInfo.dwFlags |= VMR9SurfaceAllocationFlags.TextureSurface;


            //DeleteSurfaces();

            unmanagedSurfaces = new IntPtr[lpNumBuffers];

            hr = vmrSurfaceAllocatorNotify.AllocateSurfaceHelper(ref lpAllocInfo, ref lpNumBuffers, unmanagedSurfaces);


            // If we couldn't create a texture surface and 
            // the format is not an alpha format,
            // then we probably cannot create a texture.
            // So what we need to do is create a private texture
            // and copy the decoded images onto it.


            //{
            surfaces = new Hashtable(unmanagedSurfaces.Length);
            textures = new Hashtable(unmanagedSurfaces.Length);

            for (int i = 0; i < lpNumBuffers; i++)
            {
                Surface surf = Surface.FromPointer(unmanagedSurfaces[i]);
                Texture text = surf.GetContainer<Texture>();
                surfaces.Add(unmanagedSurfaces[i], surf);
                textures.Add(unmanagedSurfaces[i], text);
            }
            //}



            return Init(Device);
        }
        catch (SlimDXException  e)
        {
            MessageBox.Show(e.Message ) ;
            return 0;
        }
        catch
        {
            return E_FAIL;
        }
    }

    public int TerminateDevice(IntPtr dwID)
    {
        DeleteSurfaces();
        return 0;
    }

    #endregion

    #region IVMRImagePresenter9 Members

    public int PresentImage(IntPtr dwUserID, ref VMR9PresentationInfo lpPresInfo)
    {

        Device.SetRenderTarget(0, renderTarget);
        //IsframeAvailable = true;
        int hr = 0;

        lock (this)
        {
            try
            {
                // if we are in the middle of the display change
                if (NeedToHandleDisplayChange())
                {
                    // NOTE: this piece of code is left as a user exercise.  
                    // The D3DDevice here needs to be switched
                    // to the device that is using another adapter
                }

                hr = PresentHelper(lpPresInfo);

                IsframeAvailable = true;
                return hr;
            }

            catch (SlimDXException e)
            {
                MessageBox.Show(e.Message);
                return 0;
            }
            catch
            {
                return E_FAIL;
            }
        }
    }

    public int StartPresenting(IntPtr dwUserID)

    {

        lock (this)
        {
            if (Device == null)
                return E_FAIL;

            return 0;
        }
    }

    public int StopPresenting(IntPtr dwUserID)
    {

        return 0;
    }

    #endregion
    //private bool IsFullScreenFlag=true;
    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Alt && e.KeyCode == Keys.Enter)
        {
            int hr = 0;
            graph = (IGraphBuilder)FilterGraph;
            filter = (IBaseFilter)new VideoMixingRenderer9();

            IVMRFilterConfig9 filterConfig = (IVMRFilterConfig9)filter;

            hr = filterConfig.SetRenderingMode(VMR9Mode.Renderless);
            DsError.ThrowExceptionForHR(hr);

            hr = filterConfig.SetNumberOfStreams(2);
            DsError.ThrowExceptionForHR(hr);

            SetAllocatorPresenter();

            hr = graph.AddFilter(filter, "Video Mixing Renderer 9");
            DsError.ThrowExceptionForHR(hr);

            hr = graph.RenderFile(path, null);
            DsError.ThrowExceptionForHR(hr);

            mediaControl = (IMediaControl)graph;

            hr = mediaControl.Run();
            DsError.ThrowExceptionForHR(hr);

            }
         }
     }
}

This is the code that I have written in the main form class and in the program class of windows form where my main method resides is

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using SlimDX.Windows;
namespace WindowsFormsApplication1
 {
   static class Program
  {
    static Form1 form = new Form1(); 
    /// <summary>
    /// The main entry point for the application.
    /// </summary>

    [STAThread]
    static void Main()
    {          

        MessagePump.Run(form, () => {

            form.RenderVideo();

        }); 




      }
  }
}

If I run the main loop in accordance with the present image function that is when a frame is available then only my main loop should render a frame then every thing is going fine but if I don't do the same then the text that I am trying to display over my video is flickering as present image changes the render target each time I think and the whole rendering is disturbed. And lastly this the class for counting frames per second

share|improve this question

closed as off-topic by Josh Petrie Dec 21 '13 at 1:46

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Programming questions that aren't specific to game development are off-topic here, but can be asked on Stack Overflow. A good rule of thumb is to ask yourself "would a professional game developer give me a better/different/more specific answer to this question than other programmers?"" – Josh Petrie
If this question can be reworded to fit the rules in the help center, please edit the question.

    
You should post some code. –  Josh Petrie Sep 22 '11 at 14:56
    
Hi! I have given the whole code I am using in my application. –  Yashwinder Sep 23 '11 at 6:14
    
There's a ton of code in there, and you only ever seem to be calling RenderVideo (even though you have what looks like two other rendering functions that never get invoked). You should pare it down to exactly the set of code that still reproduces the problem; the minimal set of text I could copy-paste into a project, if I wanted to, and see the bug. –  Josh Petrie Sep 23 '11 at 15:49
    
Hi! Josh Petrie, I have edited the code to minimum that shows my persisting problem of flickering text over the video. You can easily run this project by pasting code stated above in Form.cs class and the code just below that in Program.cs class in a simple windows form application of visual studio and by adding the references to SlimDX and DirectShowLib-2005.dll . Any help will be appreciated. –  Yashwinder Oct 31 '11 at 7:23
add comment

Browse other questions tagged or ask your own question.