2017-04-13 51 views
0

我使用Web客戶端獲取某個URL的圖像數據,並試圖產生像這樣與它的視頻:從使用avimanager圖像的視頻被拋出一個錯誤

 //http://www.codeproject.com/Articles/7388/A-Simple-C-Wrapper-for-the-AviFile-Library 

     WebClient client = new WebClient(); 

     System.Net.WebRequest request = System.Net.WebRequest.Create(images); 
     System.Net.WebResponse response = request.GetResponse(); 
     System.IO.Stream responseStream = response.GetResponseStream(); 
     Bitmap bitmap = new Bitmap(responseStream); 


     //create a new AVI file 
     AviManager aviManager = new AviManager(@"C:\Users\Laptop\Documents\tada.avi", false); 

     //add a new video stream and one frame to the new file 
     //set IsCompressed = false 
     VideoStream aviStream = aviManager.AddVideoStream(false, 2, bitmap); 

     aviManager.Close(); 

但它減少了對下列。在這條線上

int result = Avi.AVIFileCreateStream(aviFile, out aviStream, ref strhdr); 

我收到以下錯誤庫:

System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'

+1

將您的項目設置「平臺目標」更改爲x86 ....您目前可能擁有「任何CPU」...並且該庫不提供正確的互操作環繞來調用64位AviFile.dll(這是OS的一個組件)。 –

+0

@ColinSmith有趣。這工作。我會假設它只能在32位上工作? – 4334738290

回答

1

你可能有「Any CPU」此刻...所以你的應用程序,然後被編譯/運行的64位進程(在64位Windows版本上)。

問題似乎是,AVI Wrapper庫可能從未使用64位.NET應用程序進行過測試....它沒有正確定義「pinvoke」定義,以便正確地推送/彈出參數在進行64位API調用時的堆棧。

將您的項目設置「platform target」更改爲x86 ...以便您可以避免該問題....並且可以調用「avifil32.dll」,儘管它處於32位模式。

Windows確實附帶了一個32位和64位的AVI庫,因此理論上可以在您是64位進程時調用AVI庫....但您需要正確定義互操作/編組結果。

  • C:\ Windows \ System32下\ avifil32.dll(64位)
  • C:\ WINDOWS \ SysWow64資料\ avifil32.dll(32位)

在32位(Microsoft使用ILP32數據模型)...

  • 一個int是4個字節
  • 指針爲4個字節

在64位(Microsoft使用LLP64或P64數據模型)....

  • 一個int是(仍然)4字節
  • 一個指針是(現在)的8個字節

(請參見https://msdn.microsoft.com/en-us/library/windows/desktop/aa384083(v=vs.85).aspx

經常發生的錯誤是,「pinvoke」定義在定義指針類型時使用了「int」,而不是更正確的IntPtr類型。因此,「呼叫」在32位上工作正常(因爲「int」與「指針」的大小相同)......而在64位上它們的大小不同。

當你是64位的時候,其他的東西也會改變...比如默認的邊界對齊......這可以改變結構中類型的偏移 - 所以當你定義你的pinvoke c#結構時你必須小心......所以他們匹配。

如果你有興趣的函數調用AVIFileCreateStream其WIN32簽名如下:

STDAPI AVIFileCreateStream(
    PAVIFILE  pfile, 
    PAVISTREAM  *ppavi, 
    AVISTREAMINFO *psi 
); 

而且其參數的「類型」是:

typedef IAVIFile *PAVIFILE; // i.e. just a pointer 

typedef IAVIStream *PAVISTREAM; // i.e. just a pointer 

typedef struct { 
    DWORD fccType; 
    DWORD fccHandler; 
    DWORD dwFlags; 
    DWORD dwCaps; 
    WORD wPriority; 
    WORD wLanguage; 
    DWORD dwScale; 
    DWORD dwRate; 
    DWORD dwStart; 
    DWORD dwLength; 
    DWORD dwInitialFrames; 
    DWORD dwSuggestedBufferSize; 
    DWORD dwQuality; 
    DWORD dwSampleSize; 
    RECT rcFrame; 
    DWORD dwEditCount; 
    DWORD dwFormatChangeCount; 
    TCHAR szName[64]; 
} AVISTREAMINFO; 

這個封裝庫中定義的NET「pinvoke」至AVIFileCreateStream使用此項:

//Create a new stream in an open AVI file 
[DllImport("avifil32.dll")] 
public static extern int AVIFileCreateStream(
    int pfile, 
    out IntPtr ppavi, 
    ref AVISTREAMINFO ptr_streaminfo); 

立即,您可以看到第一個參數定義錯誤。

當「進行調用」時......只有4個字節將被放置到堆棧中,而不是8,然後是第二個參數(它是指向指針的指針)8字節被推送(因爲使用了IntPtr)(「寫入」地址的地址),第三個參數是AVISTREAMINFO結構的地址。

因此,當調用AVIFileCreateStream它訪問堆棧上的這些參數,但它們基本上是垃圾.....它將嘗試使用具有錯誤值的指針(即只有4個字節的(第一個參數)指針地址已經通過堆棧...並且剩餘的4字節(8字節指​​針)從堆棧中的「下一個」事物中填充...因此指針地址很可能是垃圾... 。其中就是爲什麼你的訪問衝突

它應該被定義方式是這樣的(注意:還有其他的方法來達到同樣的):

[DllImport("avifil32.dll", SetLastError=true)] 
public static extern int AVIFileCreateStream(IntPtr pfile, out IntPtr ppavi, ref AVISTREAMINFO psi);