none
C#调用DXShow RRS feed

  • 问题

  • 我想调用DXShow来播放高分辨率的视频,我想将这段视频分段播放。比如1-3分钟为一段,3-5分钟为一段。。。当我点击按钮的时候可以控制这个视频从那一段开始播放。我用WMP控件能正常播放,但是点击按钮跳转的时候需要等待约1-2秒才开始播放。为了解决这个问题,我选择调用更底层的DXShow来实现。在网上找C#调用DXShow资料比较少,而且MSDN上的也是C++的。

    我通过以下代码实现了简单播放功能,但是播放过程中有点微卡,现在还不知道为什么(还需要解决的),跳转效果比WMP明显好。

    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 System.Threading;
    using DirectShowLib;
    using System.Runtime.InteropServices;
    
    namespace DXShow
    {
        public partial class Form1 : Form
        {
            private const int WMGraphNotify = 0x0400 + 13;
            private Thread t = null;
            private IGraphBuilder graphBuilder = null;   //enable an application to build a filter graph
            private IMediaControl mediaControl = null; //provides methods for controlling the flow of data through the filter graph. 
                                                       //It includes methods for running, pausing, and stopping the graph
            private IMediaEventEx mediaEventEx = null; //contains methods for retrieving(检索) event notifications(通知) and for overriding the filter graph's default handling of events. 
            private IVideoWindow videoWindow = null; //sets properties on the video window. Applications can use it to set the window owner, 
                                                     //the position and dimensions(尺寸) of the window, and other properties.
            private IBasicAudio basicAudio = null;  //controls the volume and balance of the audio stream
            private IBasicVideo basicVideo = null;   //sets video properties such as the destination and source rectangles
            private IMediaSeeking mediaSeeking = null; //contains methods for seeking to a position within a stream, and for setting the playback(播放) rate
            private IMediaPosition mediaPosition = null; //contains methods for seeking to a position within a stream
            private IVideoFrameStep frameStep = null;  //steps through a video stream
            
            public Form1()
            {
                InitializeComponent();
                trackBar2.SetRange(-1000, 0);
            }
            private void updateTimeBarThread() //更新时间
            {
                double time;
                int volu;
                while (true)
                {
                    mediaPosition.get_CurrentPosition(out time); //retrieves(检索、获取) the current position, relative to the total duration of the stream(赋值给time)
                    Console.WriteLine(time);
                    basicAudio.get_Volume(out volu);//retrieves the volume (amplitude) of the audio signal
                    Console.WriteLine(volu);
                    this.BeginInvoke(new MethodInvoker(() =>
                    {
                        trackBar1.Value = (int)time;
                    }));
                    Thread.Sleep(1000);
                }
            }
            private void Form1_Load(object sender, EventArgs e)
            {
                
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                int hr = 0;
                if (this.graphBuilder == null)
                {
                    String filename = textBox1.Text;
    
                    this.graphBuilder = (IGraphBuilder)new FilterGraph();//provides methods for building a filter graph. An application can use it to add filters(过滤器) to the graph, 
                                                                          //connect or disconnect filters, remove filters, and perform other basic operations
    
                    // Have the graph builder construct its the appropriate graph automatically
                    hr = this.graphBuilder.RenderFile(filename, null); //(RenderFile Methord)builds a filter graph that renders the specified file
                    DsError.ThrowExceptionForHR(hr);
    
                    // Query Interface for DirectShow interfaces
                    this.mediaControl = (IMediaControl)this.graphBuilder;
                    this.mediaEventEx = (IMediaEventEx)this.graphBuilder;
                    this.mediaSeeking = (IMediaSeeking)this.graphBuilder;
                    this.mediaPosition = (IMediaPosition)this.graphBuilder;
    
                    // Query for video interfaces, which may not be relevant for audio files
                    this.videoWindow = this.graphBuilder as IVideoWindow;
                    this.basicVideo = this.graphBuilder as IBasicVideo;
    
                    // Query for audio interfaces, which may not be relevant for video-only files
                    this.basicAudio = this.graphBuilder as IBasicAudio;
    
                    hr = this.mediaEventEx.SetNotifyWindow(this.Handle, WMGraphNotify, IntPtr.Zero);//The SetNotifyWindow method registers(注册) a window to process(处理) event notifications
                    //句柄        //Window message to be passed as the notification      //Value to be passed as the lParam parameter for the lMsg message
    
                    DsError.ThrowExceptionForHR(hr);
                    // Setup the video window
                    hr = this.videoWindow.put_Owner(this.Handle); //specifies(指定) a parent window for the video window
                    DsError.ThrowExceptionForHR(hr);
    
                    hr = this.videoWindow.put_WindowStyle(WindowStyle.Child |
                        WindowStyle.ClipSiblings | WindowStyle.ClipChildren); //sets the window styles on the video window
                    DsError.ThrowExceptionForHR(hr);
    
                    this.Focus();
    
                    hr = InitVideoWindow(1, 1);//设置原始比例播放
                    DsError.ThrowExceptionForHR(hr);
                    //double time;
                    //mediaPosition.get_Duration(out time); //retrieves the duration(长短) of the stream
                    //trackBar1.SetRange(0, (int)time);
                    //t = new Thread(new ThreadStart(updateTimeBarThread));
                    //t.IsBackground = true;
                    //t.Start();
                }
                if (button1.Text.Equals("播放"))
                {
                    // Run the graph to play the media file
                    hr = this.mediaControl.Run();
                    DsError.ThrowExceptionForHR(hr);
                    button1.Text = "暂停";
    
                }
                else
                {
                    hr = this.mediaControl.Pause();
                    DsError.ThrowExceptionForHR(hr);
                    button1.Text = "播放";
                    
                   
                }
    
            }
            private int InitVideoWindow(int nMultiplier, int nDivider)//获取片源分辨率,创建窗口
            {
                int hr = 0;
                int lHeight, lWidth;
    
                if (this.basicVideo == null)
                    return 0;
    
                // Read the default video size
                hr = this.basicVideo.GetVideoSize(out lWidth, out lHeight);//retrieves(检索) the native video dimensions(尺寸) 赋值给lWidth,lHeight
                if (hr == DsResults.E_NoInterface)
                    return 0;
    
                // Account for requests of normal, half, or double size
                lWidth = lWidth * nMultiplier*2/ nDivider/5;  // set display width 
                lHeight = lHeight * nMultiplier*2 / nDivider/5;//
    
                this.ClientSize = new Size(lWidth, lHeight + 75);
                Application.DoEvents();
    
                hr = this.videoWindow.SetWindowPosition(0, 80, lWidth, lHeight);
    
                return hr;
            }
            private void closeVideo()
            {
                int hr = 0;
    
                // Stop media playback
                if (this.mediaControl != null)
                    hr = this.mediaControl.Stop();
    
                // Free DirectShow interfaces
                CloseInterfaces();
                button1.Text = "播放";
            }
            private void CloseInterfaces()
            {
                int hr = 0;
    
                try
                {
                    lock (this)
                    {
                        // Relinquish ownership (IMPORTANT!) after hiding video window
    
                        hr = this.videoWindow.put_Visible(OABool.False);//shows or hides the video window
                        DsError.ThrowExceptionForHR(hr);
                        hr = this.videoWindow.put_Owner(IntPtr.Zero);//Specifies a parent window for the video window
                        DsError.ThrowExceptionForHR(hr);
    
    
                        if (this.mediaEventEx != null)
                        {
                            hr = this.mediaEventEx.SetNotifyWindow(IntPtr.Zero, 0, IntPtr.Zero);//Release Window
                            DsError.ThrowExceptionForHR(hr);
                        }
    
                        // Release and zero DirectShow interfaces
                        if (this.mediaEventEx != null)
                            this.mediaEventEx = null;
                        if (this.mediaSeeking != null)
                            this.mediaSeeking = null;
                        if (this.mediaPosition != null)
                            this.mediaPosition = null;
                        if (this.mediaControl != null)
                            this.mediaControl = null;
                        if (this.basicAudio != null)
                            this.basicAudio = null;
                        if (this.basicVideo != null)
                            this.basicVideo = null;
                        if (this.videoWindow != null)
                            this.videoWindow = null;
                        if (this.frameStep != null)
                            this.frameStep = null;
                        if (this.graphBuilder != null)
                            Marshal.ReleaseComObject(this.graphBuilder);//Marshal(元帅、整顿)提供了一个方法集,这些方法用于分配非托管内存、复制非托管内存块、
                                                                        //将托管类型转换为非托管类型,此外还提供了在与非托管代码交互时使用的其他杂项方法
                        //Marshal.ReleaseComObject(Object o)Object o:The COM object to release.
                            this.graphBuilder = null;
    
                            GC.Collect();//GC 控制系统垃圾回收器(一种自动回收未使用内存的服务)
                        //Collect强制进行垃圾回收
                    }
                }
                catch
                {
                }
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
                closeVideo();
                t.Abort();
            }
            private void trackBar1_Scroll(object sender, EventArgs e)
            {
                if (mediaPosition != null)
                {
                    mediaPosition.put_CurrentPosition(trackBar1.Value);
                }
    
            }
    
            private void trackBar2_Scroll(object sender, EventArgs e)
            {
                if (basicAudio != null)
                {
                    basicAudio.put_Volume(trackBar2.Value);
                }
            }
    
            private void button3_Click(object sender, EventArgs e)
            {
                if (mediaPosition != null)
                {
                    mediaPosition.put_CurrentPosition(360);
                }
            }
    
            private void button4_Click(object sender, EventArgs e)
            {
                if (mediaPosition != null)
                {
                    mediaPosition.put_CurrentPosition(150);
                    
                }
            }
    
        }
    }


    
    

    视频文件从点击到开始播放要经过分离音视频、编解码等过程(是通过过滤器来完成的,如下图)

    我现在不知道怎么创建这些过滤器,还有怎么链接这些过滤器上的针。哪位用过C#调用DXShow的指导下呢?

    2013年12月24日 9:37

答案

  • 你好:

    我没有使用DirectShow开发的经验,所以从网上找了一些资料希望能帮到你。

    首先是一个播放器程序,很长时间以前的Project,但是里面的一些代码应该会有用,建议你花点时间浏览一下代码,看有没有跟你的需求相关的功能的实现:

    DirectShow MediaPlayer in C#

    另外我发现一个在.net中使用DirectShow的第三方的类库,如果能用一些现成的类库的话尽量用现成的,毕竟自己写的代码可能功能性,完善性都欠缺点:

    DirectShow.NET

    同时你也可以参考微软的官方DirectShow教程:DirectShow,虽然不是针对C#语言的,但是你也可以试着将一些用法或者代码转换为C#的。


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    2013年12月25日 9:31
    版主