-2
using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using DirectShowLib;
using System.Windows.Forms;
using System.Collections.Generic;


namespace Polkan.DataSource
{
    internal class WmvAdapter : ISampleGrabberCB, IDisposable
    {
        #region Fields
        //public Image img;
        private IFilterGraph2 _filterGraph;
        private IMediaControl _mediaCtrl;
        private IMediaEvent _mediaEvent;
        private int _width;
        private int _height;
        private readonly string _outFolder;
        private int _frameId;

        #endregion

        #region Constructors and Destructors

        public WmvAdapter(string file, string outFolder)
        {
            _outFolder = outFolder;
            try
            {
                SetupGraph(file);
            }
            catch
            {
                Dispose();
                MessageBox.Show("A codec is required to load this video file. Please use http://www.headbands.com/gspot/ or search the web for the correct codec");
                throw;
            }
        }

        ~WmvAdapter()
        {
            CloseInterfaces();
        }

        #endregion

        public void Dispose()
        {
            CloseInterfaces();
        }

        public void Start()
        {
            int hr = _mediaCtrl.Run();
            WaitUntilDone();
            DsError.ThrowExceptionForHR(hr);
        }

        public void WaitUntilDone()
        {
            int hr;
            const int eAbort = unchecked((int)0x80004004);

            do
            {

                System.Windows.Forms.Application.DoEvents();
                EventCode evCode;
                hr = _mediaEvent.WaitForCompletion(100, out evCode);
            } while 
                (hr == eAbort);

            DsError.ThrowExceptionForHR(hr);


        }

        /// <summary> build the capture graph for grabber. </summary>
        private void SetupGraph(string file)
        {
            ISampleGrabber sampGrabber = null;
            IBaseFilter capFilter = null;
            IBaseFilter nullrenderer = null;

            _filterGraph = (IFilterGraph2)new FilterGraph();
            _mediaCtrl = (IMediaControl)_filterGraph;
            _mediaEvent = (IMediaEvent)_filterGraph;

            var mediaFilt = (IMediaFilter)_filterGraph;

            try
            {
                // Add the video source
                int hr = _filterGraph.AddSourceFilter(file, "Ds.NET FileFilter", out capFilter);
                DsError.ThrowExceptionForHR(hr);

                // Get the SampleGrabber interface
                sampGrabber = new SampleGrabber() as ISampleGrabber;
                var baseGrabFlt = sampGrabber as IBaseFilter;

                ConfigureSampleGrabber(sampGrabber);

                // Add the frame grabber to the graph
                hr = _filterGraph.AddFilter(baseGrabFlt, "Ds.NET Grabber");
                DsError.ThrowExceptionForHR(hr);

                // ---------------------------------
                // Connect the file filter to the sample grabber

                // Hopefully this will be the video pin, we could check by reading it's mediatype
                IPin iPinOut = DsFindPin.ByDirection(capFilter, PinDirection.Output, 0);

                // Get the input pin from the sample grabber
                IPin iPinIn = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Input, 0);

                hr = _filterGraph.Connect(iPinOut, iPinIn);
                DsError.ThrowExceptionForHR(hr);

                // Add the null renderer to the graph
                nullrenderer = new NullRenderer() as IBaseFilter;
                hr = _filterGraph.AddFilter(nullrenderer, "Null renderer");
                DsError.ThrowExceptionForHR(hr);

                // ---------------------------------
                // Connect the sample grabber to the null renderer

                iPinOut = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Output, 0);
                iPinIn = DsFindPin.ByDirection(nullrenderer, PinDirection.Input, 0);

                hr = _filterGraph.Connect(iPinOut, iPinIn);
                DsError.ThrowExceptionForHR(hr);

                // Turn off the clock. This causes the frames to be sent
                // thru the graph as fast as possible
                hr = mediaFilt.SetSyncSource(null);
                DsError.ThrowExceptionForHR(hr);

                // Read and cache the image sizes
                SaveSizeInfo(sampGrabber);
            }
            finally
            {
                if (capFilter != null)
                {
                    Marshal.ReleaseComObject(capFilter);
                }
                if (sampGrabber != null)
                {
                    Marshal.ReleaseComObject(sampGrabber);
                }
                if (nullrenderer != null)
                {
                    Marshal.ReleaseComObject(nullrenderer);
                }
                GC.Collect();
            }
        }

        private void SaveSizeInfo(ISampleGrabber sampGrabber)
        {
            // Get the media type from the SampleGrabber
            var media = new AMMediaType();
            int hr = sampGrabber.GetConnectedMediaType(media);
            DsError.ThrowExceptionForHR(hr);

            if ((media.formatType != FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero))
            {
                throw new NotSupportedException("Unknown Grabber Media Format");
            }

            // Grab the size info
            var videoInfoHeader = (VideoInfoHeader)Marshal.PtrToStructure(media.formatPtr, typeof(VideoInfoHeader));
            _width = videoInfoHeader.BmiHeader.Width;
            _height = videoInfoHeader.BmiHeader.Height;

            DsUtils.FreeAMMediaType(media);
            GC.Collect();
        }

        private void ConfigureSampleGrabber(ISampleGrabber sampGrabber)
        {
            var media = new AMMediaType
            {
                majorType = MediaType.Video,
                subType = MediaSubType.RGB24,
                formatType = FormatType.VideoInfo
            };
            int hr = sampGrabber.SetMediaType(media);
            DsError.ThrowExceptionForHR(hr);

            DsUtils.FreeAMMediaType(media);
            GC.Collect();
            hr = sampGrabber.SetCallback(this, 1);
            DsError.ThrowExceptionForHR(hr);
        }

        private void CloseInterfaces()
        {
            try
            {
                if (_mediaCtrl != null)
                {
                    _mediaCtrl.Stop();
                    _mediaCtrl = null;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }

            if (_filterGraph != null)
            {
                Marshal.ReleaseComObject(_filterGraph);
                _filterGraph = null;
            }
            GC.Collect();
        }

        int ISampleGrabberCB.SampleCB(double sampleTime, IMediaSample pSample)
        {
            Marshal.ReleaseComObject(pSample);
            return 0;
        }

        //add a boolean property to indicate the save-mode
        public bool SaveToDisc { get; set; }
        //the list for the bitmaps
        public List<Bitmap> Images { get; set; }

        int ISampleGrabberCB.BufferCB(double sampleTime, IntPtr pBuffer, int bufferLen)
        {
            using (var bitmap = new Bitmap(_width, _height, _width * 3, PixelFormat.Format24bppRgb, pBuffer))
            {
                bitmap.RotateFlip(RotateFlipType.Rotate180FlipX);
                if (SaveToDisc)
                {
                    String tempFile = _outFolder + _frameId + ".bmp";
                    if (File.Exists(tempFile))
                    {

                    }
                    else
                    {
                        bitmap.Save(Path.Combine(_outFolder, _frameId.ToString("D6") + ".bmp"));

                    }
                    _frameId++;
                }
                else
                {
                    if (Images == null)
                        Images = new List<Bitmap>();
                    Images.Add((Bitmap)bitmap.Clone());
                }
            }
            return 0;
        }


    }
}

该类正在从视频文件中提取帧到硬盘。

在我的情况下,例如硬盘上的 47 个文件。

在课程的底部,我正在保存到硬盘:

bitmap.Save(Path.Combine(_outFolder, _frameId.ToString("D6") + ".bmp"));

在类的上面有一个名为:WaitUntillDone() 的函数,它对我有帮助。

我想要的是,当它完成将所有文件提取到硬盘时,它会给我一个 messagebox.show 或者只是标签上的一条消息,或者说“过程已经完成”

在 Form1 按钮单击事件中,我使用如下类:

wmv = new Polkan.DataSource.WmvAdapter(@"d:\VIDEO0040.3gp", sf);
            wmv.SaveToDisc = true;
            wmv.Start();

视频名称,sf是硬盘上解压的目录。

然后是真的,所以它会将它保存到硬盘而不是内存帧。

并开始。

我也可以在 Form1 中做按钮点击事件 wmv.WaitUntillDone(); 但完成后它不会抛出任何消息或东西。

4

3 回答 3

1

您需要使用事件来告诉您的 UI 组件该过程已完成:

public event EventHandler ProcessFinished; 

在您的方法内部,当它完成时让它引发事件:

if(ProcessFinished != null)
    ProcessFinished(this, EventArgs.Empty);

最后,在调用进程的类中:

wmv = new Polkan.DataSource.WmvAdapter(@"d:\VIDEO0040.3gp", sf);
wmv.SaveToDisc = true;
wmv.ProcessFinished += OnProcessFinished;
wmv.Start();

OnProcessFinished 将类似于:

public void OnProcessFinished(object sender, EventArgs e){
    MessageBox.Show("done!");
}

希望能帮助到你。

于 2012-06-30T16:36:26.870 回答
1

您已经实现了自己的使用 DoEvents() 的 WaitUntil 方法。这是棘手的,很难做到正确。

将相关代码移动到Backgoundworker要简单得多。然后只需使用 Completed 事件来表示结束。

于 2012-06-30T16:40:00.677 回答
0

WaitUntilDone循环让您的 UI 响应,直到整个文件播放完成,每个视频帧都会返回所有调用。您可以添加MessageBox.ShowWaitUntilDone.

为了避免这种循环而不将控制权交给外部消息循环,应用程序通常以不同的方式执行此操作。它们用于IMediaEventEx.SetNotifyWindow订阅过滤图形事件并在播放完成时收到窗口消息。也就是说,一旦文件的处理完成,您会收到一条消息发送给您,并且您的处理程序有机会做它必须做的事情。

对您来说,一个可能更简单的选择是不做任何事情WaitUntilDone,而是有一个计时器来轮询,例如每秒一次,IMediaEvent.WaitForCompletion(0, ...以查看处理是否完成。

于 2012-06-30T17:23:56.453 回答