2013-05-16 16 views
8

Napisałem program, który symuluje kamerę i konwertuje wyjście do strumienia wideo. Program musi działać w systemie Windows. Istnieją dwa elementy w systemie:Przesyłanie strumieniowe wideo z obrazu za pomocą FFMPEG na Windows

  1. Symulator aparatu. Program C++, który symuluje kamerę. Kopiuje on wstępnie wygenerowaną ramkę (to jest plik PNG) co 0,1 sekundy, używając polecenia Windows copy, do ścieżki docelowej o strumieniu wideo. Używając FFmpeg, tworzy strumień wideo z kopiowanych obrazów. FFmpeg jest prowadzony za pomocą następującego polecenia: ffmpeg -loop 1 -i ./target/target_image.png -r 10 -vcodec mpeg4 -f mpegts udp://127.0.0.1:1234

Uruchamiając całość razem, to działa dobrze przez kilka sekund, aż przystankach ffmpeg. Oto log podczas pracy w trybie debugowania:

ffmpeg version N-52458-gaa96439 Copyright (c) 2000-2013 the FFmpeg developers 
    built on Apr 24 2013 22:19:32 with gcc 4.8.0 (GCC) 
    configuration: --enable-gpl --enable-version3 --disable-w32threads --enable-avisynth --enable-bzlib --enable-fontconfig --enable-frei0r --enable-gnutls --enable-iconv --enable-libass --enable-libbluray --enable-libcaca --enable-libfreetype --enable-libgsm --enable-libilbc --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libtwolame --enable-libvo-aacenc --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libxavs --enable-libxvid --enable-zlib 
    libavutil  52. 27.101/52. 27.101 
    libavcodec  55. 6.100/55. 6.100 
    libavformat 55. 3.100/55. 3.100 
    libavdevice 55. 0.100/55. 0.100 
    libavfilter  3. 60.101/3. 60.101 
    libswscale  2. 2.100/2. 2.100 
    libswresample 0. 17.102/0. 17.102 
    libpostproc 52. 3.100/52. 3.100 
Splitting the commandline. 
Reading option '-loop' ... matched as AVOption 'loop' with argument '1'. 
Reading option '-i' ... matched as input file with argument './target/target_image.png'. 
Reading option '-r' ... matched as option 'r' (set frame rate (Hz value, fraction or abbreviation)) with argument '10'. 
Reading option '-vcodec' ... matched as option 'vcodec' (force video codec ('copy' to copy stream)) with argument 'mpeg4'. 
Reading option '-f' ... matched as option 'f' (force format) with argument 'mpegts'. 
Reading option 'udp://127.0.0.1:1234' ... matched as output file. 
Reading option '-loglevel' ... matched as option 'loglevel' (set logging level) with argument 'debug'. 
Finished splitting the commandline. 
Parsing a group of options: global . 
Applying option loglevel (set logging level) with argument debug. 
Successfully parsed a group of options. 
Parsing a group of options: input file ./target/target_image.png. 
Successfully parsed a group of options. 
Opening an input file: ./target/target_image.png. 
[AVIOContext @ 02678840] Statistics: 234307 bytes read, 0 seeks 
[AVIOContext @ 02678840] Statistics: 221345 bytes read, 0 seeks 
    Last message repeated 1 times 
[AVIOContext @ 02678840] Statistics: 226329 bytes read, 0 seeks 
    Last message repeated 2 times 
[AVIOContext @ 02678840] Statistics: 228676 bytes read, 0 seeks 
    Last message repeated 2 times 
[AVIOContext @ 02678840] Statistics: 230685 bytes read, 0 seeks 
    Last message repeated 2 times 
[AVIOContext @ 02678840] Statistics: 232697 bytes read, 0 seeks 
    Last message repeated 5 times 
[AVIOContext @ 02678840] Statistics: 234900 bytes read, 0 seeks 
    Last message repeated 2 times 
[AVIOContext @ 02678840] Statistics: 236847 bytes read, 0 seeks 
[image2 @ 02677ac0] Probe buffer size limit of 5000000 bytes reached 
Input #0, image2, from './target/target_image.png': 
    Duration: 00:00:00.04, start: 0.000000, bitrate: N/A 
    Stream #0:0, 22, 1/25: Video: png, rgb24, 1274x772 [SAR 1:1 DAR 637:386], 1/25, 25 fps, 25 tbr, 25 tbn, 25 tbc 
Successfully opened the file. 
Parsing a group of options: output file udp://127.0.0.1:1234. 
Applying option r (set frame rate (Hz value, fraction or abbreviation)) with argument 10. 
Applying option vcodec (force video codec ('copy' to copy stream)) with argument mpeg4. 
Applying option f (force format) with argument mpegts. 
Successfully parsed a group of options. 
Opening an output file: udp://127.0.0.1:1234. 
Successfully opened the file. 
[graph 0 input from stream 0:0 @ 02769280] Setting 'video_size' to value '1274x772' 
[graph 0 input from stream 0:0 @ 02769280] Setting 'pix_fmt' to value '2' 
[graph 0 input from stream 0:0 @ 02769280] Setting 'time_base' to value '1/25' 
[graph 0 input from stream 0:0 @ 02769280] Setting 'pixel_aspect' to value '1/1' 
[graph 0 input from stream 0:0 @ 02769280] Setting 'sws_param' to value 'flags=2' 
[graph 0 input from stream 0:0 @ 02769280] Setting 'frame_rate' to value '25/1' 
[graph 0 input from stream 0:0 @ 02769280] w:1274 h:772 pixfmt:rgb24 tb:1/25 fr:25/1 sar:1/1 sws_param:flags=2 
[format @ 02768ba0] compat: called with args=[yuv420p] 
[format @ 02768ba0] Setting 'pix_fmts' to value 'yuv420p' 
[auto-inserted scaler 0 @ 02768740] Setting 'w' to value '0' 
[auto-inserted scaler 0 @ 02768740] Setting 'h' to value '0' 
[auto-inserted scaler 0 @ 02768740] Setting 'flags' to value '0x4' 
[auto-inserted scaler 0 @ 02768740] w:0 h:0 flags:'0x4' interl:0 
[format @ 02768ba0] auto-inserting filter 'auto-inserted scaler 0' between the filter 'Parsed_null_0' and the filter 'format' 
[AVFilterGraph @ 026772c0] query_formats: 4 queried, 3 merged, 1 already done, 0 delayed 
[auto-inserted scaler 0 @ 02768740] w:1274 h:772 fmt:rgb24 sar:1/1 -> w:1274 h:772 fmt:yuv420p sar:1/1 flags:0x4 
[mpeg4 @ 02785020] detected 4 logical cores 
[mpeg4 @ 02785020] intra_quant_bias = 0 inter_quant_bias = -64 
[mpegts @ 0277da40] muxrate VBR, pcr every 1 pkts, sdt every 200, pat/pmt every 40 pkts 
Output #0, mpegts, to 'udp://127.0.0.1:1234': 
    Metadata: 
    encoder   : Lavf55.3.100 
    Stream #0:0, 0, 1/90000: Video: mpeg4, yuv420p, 1274x772 [SAR 1:1 DAR 637:386], 1/10, q=2-31, 200 kb/s, 90k tbn, 10 tbc 
Stream mapping: 
    Stream #0:0 -> #0:0 (png -> mpeg4) 
Press [q] to stop, [?] for help 
*** drop! 
    Last message repeated 10 times 
frame= 11 fps=0.0 q=4.0 size=  118kB time=00:00:01.10 bitrate= 875.1kbits/s dup=0 drop=11  
Statistics: 242771 bytes read, 0 seeks 
[AVIOContext @ 02674a60] Statistics: 246525 bytes read, 0 seeks 
*** drop! 
[AVIOContext @ 02674a60] Statistics: 230678 bytes read, 0 seeks 
[AVIOContext @ 02674a60] Statistics: 244023 bytes read, 0 seeks 
*** drop! 
[AVIOContext @ 02674a60] Statistics: 246389 bytes read, 0 seeks 

*** drop! 
[AVIOContext @ 02674a60] Statistics: 224478 bytes read, 0 seeks 
[AVIOContext @ 02674a60] Statistics: 228013 bytes read, 0 seeks 
*** drop! 
[image2 @ 02677ac0] Could not open file : ./target/target_image.png 
./target/target_image.png: Input/output error 
[output stream 0:0 @ 02768c20] EOF on sink link output stream 0:0:default. 
No more output streams to write to, finishing. 
frame= 164 fps= 17 q=31.0 Lsize=  959kB time=00:00:16.40 bitrate= 478.9kbits/s dup=0 drop=240  

video:869kB audio:0kB subtitle:0 global headers:0kB muxing overhead 10.285235% 
404 frames successfully decoded, 0 decoding errors 
[AVIOContext @ 026779c0] Statistics: 0 seeks, 746 writeouts 

Wydaje mi się tam jakaś kolizji między czytania i pisania do/z tego samego pliku. Co ciekawe, na Linuksie (zastępując copy z cp) program działa dobrze.

Czy ktoś może zaproponować sposób rozwiązania tego problemu? Rozwiązania alternatywne są również dopuszczalne, o ile logiczny przepływ pracy pozostaje taki sam.

Odpowiedz

3

następujący komentarz Nick van Tilborg za, skończyło się za pomocą image2pipe FFmpeg. Ta funkcja pozwala na uproszczenie danych obrazu w FFmpeg, zamiast dwóch procesów uzyskujących jednocześnie dostęp do tego samego pliku.

Poniżej znajduje się napisany przeze mnie kod C++. Może nie być w pełni zoptymalizowany, ale spełnia swoją rolę. Został skompilowany i przetestowany w Visual Studio 2012 na Windows 7.

#include "stdafx.h" 
#include "windows.h" 
#include "iostream" 

#include "stdio.h" 

using namespace std; 

#pragma warning (disable : 4996) 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    int count; 
    int times = 2200; 
    FILE *pPipe; 
    FILE * pFile; 
    long lSize; 
    char * buffer; 
    size_t result; 

    // open a pipe to FFmpeg 
    if((pPipe = _popen("ffmpeg -re -f image2pipe -vcodec mjpeg -i - -vcodec h264 -r 10 -f mpegts udp://127.0.0.1:1234", "wb")) == NULL) {exit(1);} 

    for (count = 1; count <= times; count++) { 
     char filename[40]; 
     sprintf(&filename[0], ".\\images\\image-%07d.jpg", count); 

     pFile = fopen (filename , "rb"); 
     if (pFile==NULL) {fputs ("File error",stderr); exit (2);} 

     // obtain file size: 
     fseek (pFile , 0 , SEEK_END); 
     lSize = ftell (pFile); 
     rewind (pFile); 

     // allocate memory to contain the whole file: 
     buffer = (char*) malloc (sizeof(char)*lSize); 
     if (buffer == NULL) {fputs ("Memory error",stderr); exit (3);} 

     // copy the file into the buffer: 
     result = fread (buffer, 1, lSize, pFile); 
     if (result != lSize) {fputs ("Reading error",stderr); exit (4);} 

     // write to pipe 
     fwrite(buffer, 1, lSize, pPipe); 
     fflush(pPipe); 

     // clean 
     fclose (pFile); 
     free (buffer); 

     // 
     Sleep(100); 
    } 

    // 
    return 0; 
} 
2

Przy użyciu aktualnej linii poleceń FFmpeg pracuje z najwyższą możliwą prędkością. Oznacza to, że FFmpeg odczytuje ramki nie przy 10 fps, ale tak szybko jak to możliwe. Nie transmituje również strumienia transportowego z szybkością 10 fps. Ponieważ twój program ma ustalone klatki zapisu z szybkością 10 klatek na sekundę, jest to powód, dla którego prawdopodobnie nie możesz odczytać pliku, ponieważ plik jest zapisywany w tym konkretnym czasie.

Aby rozwiązać ten problem, spróbuj użyć flagi -re w linii komend FFmpeg, aby zmusić FFmpeg do wczytania danych wejściowych w natywnej liczbie klatek na sekundę.

ffmpeg -re -loop 1 -i ./target/target_image.png -r 10 -vcodec mpeg4 -f mpegts udp://127.0.0.1:1234

+0

Dzięki! Wydaje się, że jest niewielka poprawa, ponieważ ffmpeg ulega awarii po dłuższym czasie działania, ale problem nadal występuje. Nadal uważam, że jest to problem z synchronizacją. Nawet jeśli obrazy są kopiowane z prędkością 10 klatek na sekundę, a ffmpeg odczytuje obraz z prędkością 10 klatek na sekundę, jest szansa, że ​​oba procesy uzyskają dostęp do pliku w tym samym czasie, prawda? –

+2

Tak, to prawda. Być może możesz spojrzeć w kierunku rurociągu, jak przy użyciu '-f image2pipe'. Nigdy tego nie używałem, więc nie jestem pewien, czy to prawda. –

Powiązane problemy