如何使用directshowlib-2005从视频中提取帧?

时间:2017-10-30 08:33:49

标签: c# .net winforms directshow

使用此代码,我可以播放硬盘中的视频文件并在pictureBox1中显示视频。但我想知道如何将视频的所有帧保存到硬盘上的图像文件中?在播放视频或不播放时,我需要以某种方式提取帧并保存它们。

到目前为止,这是我用过的代码:

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {

        IGraphBuilder m_graphBuilder = null;
        IMediaControl m_mediaCtrl = null;
        IMediaEventEx m_mediaEvt = null;
        IMediaPosition m_mediaPos = null;
        IMediaSeeking m_mediaSeeking = null;

        public Form1()
        {
            InitializeComponent();
        }

        void InitInterfaces()
        {
            try
            {
                m_graphBuilder = (IGraphBuilder)new FilterGraph();
                m_mediaCtrl = (IMediaControl)m_graphBuilder;
                m_mediaEvt = (IMediaEventEx)m_graphBuilder;
                m_mediaPos = (IMediaPosition)m_graphBuilder;
                m_mediaSeeking = (IMediaSeeking)m_graphBuilder;
            }
            catch (Exception)
            {
                MessageBox.Show("Couldn't start directshow graph");
            }
        }


        void CloseInterfaces()
        {
            if (m_mediaCtrl != null)
            {
                m_mediaCtrl.StopWhenReady();
            }
            m_mediaCtrl = null;
            m_mediaEvt = null;
            m_mediaPos = null;

            m_mediaSeeking = null;

            if (m_graphBuilder != null)
                Marshal.ReleaseComObject(this.m_graphBuilder);
            m_graphBuilder = null;
        }   


        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void SetuupVideoRenderer()
        {
            IBaseFilter vmrFilter = null;

            vmrFilter = (IBaseFilter)new VideoMixingRenderer();
            m_graphBuilder.AddFilter(vmrFilter, "Video Renderer");

            IVMRFilterConfig FilterConfig = (IVMRFilterConfig)vmrFilter;
            FilterConfig.SetRenderingMode(VMRMode.Windowless);

            IVMRWindowlessControl windowlessCtrl = (IVMRWindowlessControl)vmrFilter;
            windowlessCtrl.SetVideoClippingWindow(this.pictureBox1.Handle);
            windowlessCtrl.SetVideoPosition(null, DsRect.FromRectangle(pictureBox1.ClientRectangle));
            windowlessCtrl.SetAspectRatioMode(VMRAspectRatioMode.LetterBox);

        }
        private void buttonLoad_Click(object sender, EventArgs e)
        {
            openFileDialog1.Filter = "All Files (*.*)|*.*|mp4 (*.mp4)|*.mp4|mov (*.mov)|*.mov||";
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                CloseInterfaces();
                InitInterfaces();

                SetuupVideoRenderer();
                m_graphBuilder.RenderFile(openFileDialog1.FileName, null);

                textBoxDur.Text = ( getDuration() * 0.0000001).ToString();
                m_mediaCtrl.Run();

                timer1.Enabled = true;

            }
        }

        private void GetPosition(out long CurrentPos,out long StopPos)
        {

            m_mediaSeeking.GetPositions(out CurrentPos, out StopPos);

        }
        private long getDuration()
        {
            long duration;
            m_mediaSeeking.GetDuration(out duration);

            return duration;

        }

        private void SetPos(double fPos)
        {
             DsLong startPosition = (DsLong)(10000000 * fPos); 

            m_mediaSeeking.SetPositions(startPosition, AMSeekingSeekingFlags.AbsolutePositioning, null, AMSeekingSeekingFlags.NoPositioning);


        }
        private void buttonPause_Click(object sender, EventArgs e)
        {
            m_mediaCtrl.Pause();
        }

        private void buttonPlay_Click(object sender, EventArgs e)
        {
            m_mediaCtrl.Run();

        }
        private void OnVideoCompleted()
        {
            MessageBox.Show("Video Playback Completed");
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            long iCurPos, iStopPos;

            GetPosition(out iCurPos, out iStopPos);

            if (iCurPos >= iStopPos)
            {
                timer1.Enabled = false;
                OnVideoCompleted();
                return;
            }
            textBoxCurPos.Text = (iCurPos * 0.0000001 ).ToString();


        }

        private void buttonGo_Click(object sender, EventArgs e)
        {
            SetPos(Convert.ToDouble(textBoxNewPos.Text));
            timer1.Enabled = true;
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我认为这是你正在寻找的东西: extract frames of a video

请查看此SO question以及此网页上提供的链接。

  

最简单的方法是使用FFMPEG,因为它的alredy包括一些最常见的编解码器(如果你不介意额外的30 + Mb添加到你的应用程序)。对于包装器,我过去使用AForge包装器并且非常喜欢它,因为它的使用非常简单。以下是其文档中的示例:

// create instance of video reader
VideoFileReader reader = new VideoFileReader();

// open video file
reader.Open( "test.avi");

// read 100 video frames out of it
for ( int i = 0; i < 100; i++)
{
    Bitmap videoFrame = reader.ReadVideoFrame();

    videoFrame.Save(i + ".bmp")

    // dispose the frame when it is no longer required
    videoFrame.Dispose( );
}

reader.Close();