Direct3D上传视频纹理

时间:2012-12-29 15:36:48

标签: c# slimdx direct3d9

我正在尝试在Direct3D 9设备上播放视频,使用:

  1. nVLC - 用于从文件
  2. 获取RGB32帧
  3. SlimDX - 实际使用纹理在视频设备上显示帧。
  4. 这是我接收RGB32帧的代码;

        _videoWrapper.SetCallback(delegate(Bitmap frame)
                                {
                                    if (_mainContentSurface == null || _dead) 
                                        return;
    
                                    var bmpData = frame.LockBits(new Rectangle(0, 0, frame.Width, frame.Height), ImageLockMode.ReadOnly, frame.PixelFormat);
                                    var ptr = bmpData.Scan0;
    
                                    var size = bmpData.Stride * frame.Height;
                                    _mainContentSurface.Buffer = new byte[size];
    
                                    System.Runtime.InteropServices.Marshal.Copy(ptr, _mainContentSurface.Buffer, 0, size);
    
                                    _mainContentSurface.SetTexture(_mainContentSurface.Buffer, frame.Width, frame.Height);
                                    _secondaryContentSurface.SetTexture(_mainContentSurface.Buffer, frame.Width, frame.Height); // same buffer to second WINDOW
    
                                    _mainContentSurface.VideoFrameRate.Value =_videoWrapper.ActualFrameRate;
    
                                    frame.UnlockBits(bmpData);
                                });
    

    这是我对SetTexture的实际用法并将纹理映射到square:

    public void SetTexture(byte[] image, int width, int height)
    {
        if (Context9 != null && Context9.Device != null)
        {
            if (IsFormClosed)
                return;
    
            // rendering is seperate from the "FRAME FETCH" thread, if it makes sense.
            // also note that we recreate video texture if needed.
            _renderWindow.BeginInvoke(new Action(() =>
                                    {
                                        if (_image == null || _currentVideoTextureWidth != width || _currentVideoTextureHeight != height)
                                        {
                                            if(_image != null)
                                                _image.Dispose();
    
                                            _image = new Texture(Context9.Device, width, height, 0, Usage.Dynamic, Format.A8R8G8B8,
                                                                Pool.Default);
    
                                            _currentVideoTextureWidth = width;
                                            _currentVideoTextureHeight = height;
    
                                            if(_image == null)
                                                throw new Exception("Video card does not support textures power of TWO or dynamic textures. Get a video card");
                                        }
    
                                        //upload data into texture.
                                        var data = _image.LockRectangle(0, LockFlags.None);
                                        data.Data.Write(image, 0, image.Length);
                                        _image.UnlockRectangle(0);
                                    }));
        }
    }
    

    最后是实际渲染:

        Context9.Device.SetStreamSource(0, _videoVertices, 0, Vertex.SizeBytes);
        Context9.Device.VertexFormat = Vertex.Format;
    
        // Setup our texture. Using Textures introduces the texture stage states,
        // which govern how Textures get blended together (in the case of multiple
        // Textures) and lighting information.
        Context9.Device.SetTexture(0, _image);
    
        // The sampler states govern how smooth the texture is displayed.
        Context9.Device.SetSamplerState(0, SamplerState.MinFilter, TextureFilter.Linear);
        Context9.Device.SetSamplerState(0, SamplerState.MagFilter, TextureFilter.Linear);
        Context9.Device.SetSamplerState(0, SamplerState.MipFilter, TextureFilter.Linear);
    
        // Now drawing 2 triangles, for a quad.
        Context9.Device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);
    

    现在,它适用于我的机器。没有问题。随着每个视频文件和每个位置。但是当我检查WinXP时,图片完全被破坏了。这是一个非工作和工作的屏幕夹;

    http://www.upload.ee/image/2941734/untitled.PNG

    http://www.upload.ee/image/2941762/Untitled2.png

    请注意,在第一张图片中,它们是_maincontentSurface和_secondaryContentSurface。有谁知道可能是什么问题?

1 个答案:

答案 0 :(得分:0)

您不需要每次都重新创建纹理,只需将其创建为动态:

this.Texture = new Texture(device, w, h, 1, Usage.Dynamic, Format.X8R8G8B8, Pool.Default);

关于副本问题可能来自步幅(因为填充行长度可能不同):

获取纹理的行间距:

    public int GetRowPitch()
    {
        if (rowpitch == -1)
        {
            DataRectangle dr = this.Texture.LockRectangle(0, LockFlags.Discard);
            this.rowpitch = dr.Pitch;
            this.Texture.UnlockRectangle(0);
        }
        return rowpitch;
    }

如果你的纹理行间距等于你的帧间距,你可以复制你的方式,否则你可以这样做:

    public void WriteDataPitch(IntPtr ptr, int len)
    {
        DataRectangle dr = this.Texture.LockRectangle(0, LockFlags.Discard);

        int pos = 0;
        int stride = this.Width * 4;

        byte* data = (byte*)ptr.ToPointer();
        for (int i = 0; i < this.Height; i++)
        {
            dr.Data.WriteRange((IntPtr)data, this.Width * 4);

            pos += dr.Pitch;
            dr.Data.Position = pos;
            data += stride;
        }
        this.Texture.UnlockRectangle(0);
    }

如果你想要一个带有slimdx的全功能vlc播放器的例子让我知道了(需要很好地包装它)