2013-04-10 9 views
8

Próbuję użyć ffmpeg (skompilowanego w systemie Windows z Cygwin) w programie C#, używając klasy Process do odrodzenia instancji ffmpeg. Jednak trafiłem na dość dziwny błąd, który nie ma większego sensu.ffmpeg uruchamiane z powłoki działa poprawnie, ale nie jest wywoływane z poziomu .NET

Kiedy uruchomić ffmpeg bezpośrednio z powłoki (może to być bash Cygwin, w PowerShell, cmd), ffmpeg może poprawnie dekodować i pliki przekodowywać bez żadnych problemów:

PS C:\audio> ffmpeg -i .\sound1.wav -acodec libvorbis -f ogg abc.ogg 
ffmpeg version 1.2 Copyright (c) 2000-2013 the FFmpeg developers 
    built on Apr 8 2013 15:10:40 with gcc 4.5.3 (GCC) 
    configuration: --disable-encoder=vorbis --enable-libvorbis 
    libavutil  52. 18.100/52. 18.100 
    libavcodec  54. 92.100/54. 92.100 
    libavformat 54. 63.104/54. 63.104 
    libavdevice 54. 3.103/54. 3.103 
    libavfilter  3. 42.103/3. 42.103 
    libswscale  2. 2.100/2. 2.100 
    libswresample 0. 17.102/0. 17.102 
[wav @ 0x800538a0] max_analyze_duration 5000000 reached at 5015510 microseconds 
Guessed Channel Layout for Input Stream #0.0 : stereo 
Input #0, wav, from '.\sound1.wav': 
    Metadata: 
    encoder   : Lavf54.63.104 
    Duration: 00:00:05.76, bitrate: 1411 kb/s 
    Stream #0:0: Audio: pcm_s16le ([1][0][0][0]/0x0001), 44100 Hz, stereo, s16, 1411 kb/s 
Output #0, ogg, to 'abc.ogg': 
    Metadata: 
    encoder   : Lavf54.63.104 
    Stream #0:0: Audio: vorbis, 44100 Hz, stereo, fltp 
Stream mapping: 
    Stream #0:0 -> #0:0 (pcm_s16le -> libvorbis) 
Press [q] to stop, [?] for help 
size=  55kB time=00:00:05.74 bitrate= 78.5kbits/s 
video:0kB audio:51kB subtitle:0 global headers:4kB muxing overhead 0.817473% 

Plik odgrywa w porządku i mogę kodować do WAV lub dowolnego innego formatu, który mi się podoba. Jednak, gdy zgłoszę ffmpeg z C# za pomocą następującego kodu:

string tempfile = Path.GetTempFileName(); 
FileStream tempfilestr = File.OpenWrite(tempfile); 
input.CopyTo(tempfilestr); 

ProcessStartInfo pstart = new ProcessStartInfo("ffmpeg", string.Format("-i \"{0}\" -v verbose -y -f wav -", tempfile)); 
pstart.CreateNoWindow = true; 
pstart.ErrorDialog = false; 
pstart.RedirectStandardOutput = true; 
pstart.RedirectStandardError = true; 
pstart.UseShellExecute = false; 


Process proc = new Process(); 
proc.StartInfo = pstart; 
proc.Start(); 
StreamReader stdout = proc.StandardOutput; 
StreamReader stderr = proc.StandardError; 

outtempfilestr = File.OpenRead(outtempfile); 
MemoryStream output = new MemoryStream(); 

stdout.BaseStream.CopyTo(output); 

try { 
    proc.Kill(); 
} 
catch(InvalidOperationException) { } 
catch(Win32Exception) { } 

File.Delete(tempfile); 

return output.ToArray(); 

Ten losowo powoduje błędy w danych wyjściowych:

ffmpeg version 1.2 Copyright (c) 2000-2013 the FFmpeg developers 
    built on Apr 8 2013 15:10:40 with gcc 4.5.3 (GCC) 
    configuration: --disable-encoder=vorbis --enable-libvorbis 
    libavutil  52. 18.100/52. 18.100 
    libavcodec  54. 92.100/54. 92.100 
    libavformat 54. 63.104/54. 63.104 
    libavdevice 54. 3.103/54. 3.103 
    libavfilter  3. 42.103/3. 42.103 
    libswscale  2. 2.100/2. 2.100 
    libswresample 0. 17.102/0. 17.102 
[wav @ 0x80053860] parser not found for codec pcm_s16le, packets or times may be invalid. 
    Last message repeated 1 times 
[wav @ 0x80053860] max_analyze_duration 5000000 reached at 5015510 microseconds 
Guessed Channel Layout for Input Stream #0.0 : stereo 
Input #0, wav, from 'C:\Users\Bevin\AppData\Local\Temp\tmp1CCE.tmp': 
    Duration: 00:00:05.20, bitrate: 1411 kb/s 
    Stream #0:0: Audio: pcm_s16le ([1][0][0][0]/0x0001), 44100 Hz, stereo, s16, 1411 kb/s 
[graph 0 input from stream 0:0 @ 0x8011f320] tb:1/44100 samplefmt:s16 samplerate:44100 chlayout:0x3 
Output #0, wav, to 'pipe:': 
    Metadata: 
    ISFT   : Lavf54.63.104 
    Stream #0:0: Audio: pcm_s16le ([1][0][0][0]/0x0001), 44100 Hz, stereo, s16, 1411 kb/s 
Stream mapping: 
    Stream #0:0 -> #0:0 (pcm_s16le -> pcm_s16le) 
Press [q] to stop, [?] for help 
Multiple frames in a packet from stream 0 
[pcm_s16le @ 0x8005c160] Invalid PCM packet, data has size 3 but at least a size of 4 was expected 
Error while decoding stream #0:0: Invalid data found when processing input 
No more output streams to write to, finishing. 
size=  896kB time=00:00:05.20 bitrate=1411.3kbits/s  
video:0kB audio:896kB subtitle:0 global headers:0kB muxing overhead 0.008719% 

Zauważ, że błędy te nie zawsze występują. Czasami zdarzają się pewne pliki, czasem nie. Próbowałem różnych kombinacji przekierowań strumieniowych i plików tymczasowych, żaden z nich nie działa. Sprawdziłem również integralność plików tymczasowych, a wszystko się sprawdzi. Wyodrębniłem nawet plik tymczasowy przed jego usunięciem i zdekodowałem go w powłoce bez żadnych problemów.

Wszelkie pomysły?

Edycja: Próbowałem już uruchomić ffmpeg ze skryptu powłoki uruchamianego przez C#. Daje te same problemy. Kompilowanie ffmpeg przez MinGW daje ten sam problem, jak również.

+0

Czy próbowałeś ustawić właściwy * katalog roboczy *? Po uruchomieniu aplikacji z powłoki jako katalog roboczy używana jest ścieżka powłoki (głównie katalog aplikacji), a po uruchomieniu z .net katalog roboczy określony jest katalogiem aplikacji .NET .NET. –

+0

@Gam Erix - Ścieżki plików przekazane do ffmpeg są absolutne, więc nie sądzę, że istnieje jakiś problem w tym zakresie. – Bevin

+0

@Bevin Jak próbowałeś skompilować ffmpeg z statycznie połączonymi bibliotekami? Może to pomoże w tym problemie. Dodatkowo ffmpeg może szukać kodeków (lub 'libavcodec') w katalogu roboczym. Czy możesz spróbować ustawić katalog roboczy (['Environment.CurrentDirectory'] (http://msdn.microsoft.com/en-us/library/system.environment.currentdirectory.aspx)) tuż przed' proc.Start() 'zadzwoń? – Jesse

Odpowiedz

8

Dzieje się tak ze względu na sposób przekazywania argumentów. Zrób to:

Process process = new Process(); 
process.StartInfo.RedirectStandardOutput = true; 
process.StartInfo.RedirectStandardError = true; 
process.StartInfo.FileName = Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName) + 
         @"\bin\ffmpeg.exe"; 

process.StartInfo.Arguments = "-i .\sound1.wav -acodec libvorbis -f ogg abc.ogg"; 


process.StartInfo.UseShellExecute = false; 
process.StartInfo.CreateNoWindow = true; 
process.Start(); 

To działa idealnie.

+0

Zgadzam się z Omidem i jeśli coś chcesz wymyślić, musisz użyć znaku escape dla wszystkich znaków specjalnych. – MarmiK

+0

Nie powinien być potrzebny ciąg literowy lub uciec od odwrotnego ukośnika podczas przypisywania argumentu, np. '. \ Sound1 .wav' byłby błąd. –

Powiązane problemy