2012-06-30 2 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 개의 파일이 있습니다. 하드 디스크에 저장을하는 클래스 메신저의 바닥에서

:

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()을 사용할 수도 있습니다. 그 일이 끝나면 어떤 메시지 나 무언가를 던지지 않을 것입니다. 에,

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

마지막 : 그것은이 이벤트를 발생시킬 수 있도록 완료되면, 당신의 방법 내부

public event EventHandler ProcessFinished; 

:

+0

'~ WmvAdapter()'정말 C# 코드입니까? – Jack

+1

@Jack : C# 클래스는 소멸자를 가질 수 있습니다. http://msdn.microsoft.com/en-us/library/66x5fx1b%28v=vs.80%29.aspx – Tudor

답변

1

당신은 프로세스가 완료 귀하의 UI 구성 요소를 말하는위한 이벤트를 사용할 필요가 프로세스를 호출하는 클래스 :

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!"); 
} 

희망이 있습니다.

+0

ivowiblo는 괜찮아 보입니다. 끝낼 때 당신의 방법 안에 썼습니다. 어떤 방법 으로요? WaitUntillDone()을 의미합니까? 이 수업에서 어디에서 끝났습니까? – user1477444

+0

"WaitUntilDone"이 작동하지 않는다는 것은 무엇을 의미합니까? 이 방법은 무엇을합니까? 그것은 오류를 던집니까? 그것은 기다리지 만 당신이 원하는 것을 위해 특별히 도움이되지는 않습니까? 그것은 전혀 기다리지 않습니까? – ivowiblo

1

DoEvents()를 사용하는 자체 WaitUntil 메서드를 구현했습니다. 이것은 까다 롭고 올바르게 진행하기가 어렵습니다.

관련 코드를 Backgoundworker으로 옮기는 것이 훨씬 간단합니다. 그런 다음 Completed 이벤트를 사용하여 신호를 보냅니다.

0

WaitUntilDone 모든 파일이 완료 될 때까지 UI가 반응하며 모든 비디오 프레임에 대한 모든 호출이 취소됩니다. WaitUntilDone 하단에 MessageBox.Show을 추가 할 수 있습니다.

외부 메시지 루프에 대한 제어를 내리지 않고이 루핑을 피하려면 응용 프로그램이 일반적으로 다른 방식으로 처리합니다. 그들은 을 사용하여 그래프 그래프 이벤트를 구독하고 재생이 완료 될 때 창 메시지를 수신합니다. 즉, 파일 처리가 완료되면 메시지가 보내지고 처리기는 처리해야 할 작업을 수행 할 수 있습니다.

더 간단한 옵션은 WaitUntilDone을 수행하지 말고 대신에 IMediaEvent.WaitForCompletion(0, ...과 같은 폴링 타이머를 사용하여 처리가 완료되었는지 확인하는 것입니다.

관련 문제