2012-06-30 49 views
-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個文件。

在類IM做保存到硬盤的底部:

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

及以上的班上有一個叫功能:WaitUntillDone()至極dosent幫助我。

我要的是,當其整理的所有文件解壓到硬盤中,它會給我一個標籤或某事上messagebox.show或只是一個消息,說是「過程中所做的」

在Form1按鈕點擊事件即時通訊使用類似這樣的:

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

視頻名稱,SF是在硬盤上提取的目錄。

然後如此,它將它保存到硬盤而不是記憶幀。

然後開始。

我也可以在Form1中做按鈕點擊事件wmv.WaitUntillDone();但它完成後不會拋出任何消息或其他東西。

+0

'〜WmvAdapter()'這真的是C#代碼? – Jack

+1

@Jack:C#類可以有析構函數:http://msdn.microsoft.com/en-us/library/66x5fx1b%28v=vs.80%29.aspx – Tudor

回答

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將如此mething like:

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

希望它有幫助。

+0

ivowiblo看起來沒問題。當它完成時,你寫在你的方法裏讓它升起......用什麼方法?你的意思是WaitUntillDone()?這堂課在哪裏完成? – user1477444

+0

「WaitUntilDone」是什麼意思?該方法做什麼?它會拋出一個錯誤?它等待着,但它並沒有幫助你專門爲你想要的?它不等所有? – ivowiblo

1

您已經實現了您自己的使用DoEvents()的WaitUntil方法。這是棘手的,很難得到正確的。

將相關代碼移動到Backgoundworker要簡單得多。然後,只需使用Completed事件即可告知結束。

0

WaitUntilDone循環讓你的用戶界面響應,直到整個文件播放完成,所有的呼叫都會對每個視頻幀產生反感。您可以將MessageBox.Show添加到WaitUntilDone的底部。

爲了避免這種循環而不對外部消息循環進行控制,應用程序通常以不同的方式進行操作。他們使用IMediaEventEx.SetNotifyWindow訂閱過濾器圖形事件,並在播放完成時收到窗口消息。也就是說,一旦文件處理完成,你就會發送一條消息給你,你的處理程序有機會做它必須做的事情。

這裏的一個可能更簡單的選項是不做任何WaitUntilDone,而是有一個計時器輪詢,例如每秒一次,用IMediaEvent.WaitForCompletion(0, ...查看處理是否完成。

相關問題