2017-04-13 3 views
0

ich webclient bin mit der Bilddaten von einer URL zu erhalten, und zu versuchen, ein Video mit ihm wie so zu generieren:ein Video von Bildern mit avimanager generieren wirft einen Fehler

 //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(); 

Aber es schneidet auf folgende. In der Bibliothek auf dieser Linie

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

ich die folgende Fehlermeldung erhalten:

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

+1

Ändern Sie Ihre Projekteinstellungen "platform target" auf x86 .... Sie haben wahrscheinlich "Any CPU" im Moment ... und diese Bibliothek bietet nicht die richtige Interop-Wrapping um Anrufe auf die 64bit AviFile.dll (welches eine Komponente des Betriebssystems ist). –

+0

@ColinSmith interessant. Das hat funktioniert. Ich gehe davon aus, dass es nur auf 32 bit funktioniert? – 4334738290

Antwort

1

Sie wahrscheinlich im Moment „Any CPU“ haben ... so Ihre App dann wird als 64-Bit-Prozess kompiliert/run (auf einer 64bit Windows Version).

Das Problem scheint zu sein, dass die AVI Wrapper-Bibliothek wurde wahrscheinlich nie mit einer 64-Bit-.NET-App getestet .... es hat nicht definiert die "pinvoke" Definitionen richtig, so dass die Parameter richtig gedrückt/abgesprungen sind der Stack beim Erstellen der 64-Bit-API-Aufrufe.

Ändern Sie Ihre Projekteinstellungen "Plattform Ziel" auf x86 ..., so dass Sie das Problem vermeiden können .... und kann die "avifil32.dll", obwohl im 32-Bit-Modus.

Windows wird mit einer 32-Bit- und 64-Bit-AVI-Bibliothek geliefert. Theoretisch ist es also möglich, eine AVI-Bibliothek als 64-Bit-Prozess aufzurufen ... aber Sie müssen den Interop/Marshalling-Pinvoke richtig definieren.

  • c: \ windows \ system32 \ avifil32.dll (64bit)
  • c: \ windows \ syswow64 \ avifil32.dll (32bit)

In 32bit (Microsoft verwendet das Datenmodell ILP32 ...)

  • ein int 4 Byte
  • ein Zeiger 4 Bytes ist

In 64bit (Microsoft verwendet die LLP64 oder P64-Datenmodell) ....

  • ein int (noch) ist 4 Byte
  • ein Zeiger (jetzt) ​​8 Byte

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

Der Fehler, der häufig auftritt, ist, dass "pinvoke" -Definitionen "int" bei der Definition von Zeigertypen anstelle des korrekteren Typs IntPtr verwendet haben.

So funktioniert der "Anruf" ok auf 32bit (weil ein "int" ist die gleiche Größe wie ein "Zeiger") .... während auf 64bit sind sie unterschiedliche Größen.

Andere Dinge ändern sich, wenn Sie auch 64Bit sind ... wie die Standard-BoundaryAusrichtung ... das kann Offsets von Typen innerhalb von Strukturen ändern - so müssen Sie vorsichtig sein, wenn Sie Ihre pinvoke C# -Strukturen definieren ... damit sie übereinstimmen.

Falls Sie interessiert sind für den Funktionsaufruf AVIFileCreateStream seine WIN32 Signatur wird wie folgt dar:

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

Und die „Typen“ der Parameter sind:

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; 

Das Wrapper-Bibliothek definiert die NET "pinvoke" zu AVIFileCreateStream mit dieser:

//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); 

Sofort können Sie sehen, dass der erste Parameter falsch definiert ist.

Wenn der "Aufruf erfolgt" .... nur 4 Bytes werden auf den Stack für den ersten Parameter platziert ... statt 8, dann für den zweiten Parameter (der ein Zeiger auf einen Zeiger ist) 8 Bytes werden geschoben (weil IntPtr verwendet wurde) (die Adresse, an die eine Adresse geschrieben werden soll), der dritte Parameter ist eine Adresse zu einer AVISTREAMINFO-Struktur.

Also wenn AVIFileCreateStream aufgerufen wird, greift es auf diese Parameter auf dem Stapel zu, aber sie sind im Grunde Junk ..... es wird versuchen, einen Zeiger mit dem falschen Wert zu verwenden (dh nur 4 Bytes der (ersten Parameter) Die Adresse des Zeigers ist auf dem Stack gelandet ... und die restlichen 4 Bytes (des 8-Byte-Zeigers) werden von der "nächsten" Sache auf dem Stapel gefüllt ... daher ist die Zeigeradresse höchstwahrscheinlich Müll. .Welche ist, warum Sie die Zugriffsverletzung erhalten

die Art und Weise definiert werden sollte ist so etwas wie dieses (beachten Sie, gibt es andere Möglichkeiten, das gleiche zu erreichen.):

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