2013-05-16 11 views
8

Tôi đã viết một chương trình mô phỏng máy ảnh và chuyển đổi đầu ra thành luồng video. Chương trình được yêu cầu để có thể chạy trên Windows. Có hai thành phần trong hệ thống:Streaming video từ một hình ảnh bằng cách sử dụng FFMPEG trên Windows

  1. Máy ảnh mô phỏng. Một chương trình C++ mô phỏng máy ảnh. Nó sao chép khung được tạo trước (tức là tệp PNG) sau mỗi 0,1 giây bằng cách sử dụng lệnh cửa sổ copy, đến đường dẫn đích ./target/target_image.png
  2. Luồng video. Sử dụng FFmpeg, nó tạo ra một luồng video ra khỏi các hình ảnh được sao chép. FFmpeg được chạy với lệnh sau: ffmpeg -loop 1 -i ./target/target_image.png -r 10 -vcodec mpeg4 -f mpegts udp://127.0.0.1:1234

Khi chạy toàn bộ cùng nhau, nó hoạt động tốt trong vài giây cho đến khi ffmpeg dừng lại. Đây là nhật ký khi chạy ở chế độ gỡ lỗi:

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 

Dường như với tôi có một số loại va chạm giữa việc đọc và ghi vào/từ cùng một tệp. Điều thú vị là trên Linux (trong khi thay thế copy với cp) chương trình hoạt động tốt.

Ai đó có thể đề xuất một cách để giải quyết vấn đề này? Các giải pháp thay thế cũng được chấp nhận miễn là luồng công việc hợp lý vẫn giữ nguyên.

Trả lời

3

Sau comment Nick van Tilborg, tôi đã kết thúc bằng image2pipe FFmpeg của. Tính năng này cho phép tinh giản dữ liệu hình ảnh vào FFmpeg, thay vì hai quá trình truy cập cùng một tệp cùng một lúc.

Dưới đây là mã C++ tôi đã viết. Nó có thể không được tối ưu hóa đầy đủ, nhưng nó thực hiện công việc. Nó được biên dịch và thử nghiệm với Visual Studio 2012 trên 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

Sử dụng dòng lệnh hiện tại của bạn, FFmpeg đang chạy ở tốc độ cao nhất có thể. Điều này có nghĩa là FFmpeg đang đọc các khung hình không ở 10 khung hình/giây, nhưng càng nhanh càng tốt. Nó cũng không truyền tải luồng truyền tải ở tốc độ 10 khung hình/giây. Bởi vì chương trình của bạn là khung viết cố định ở 10 khung hình/giây, đây là lý do bạn có thể không đọc được tệp của mình đôi khi, vì tệp được ghi vào những thời điểm cụ thể này.

Để giải quyết vấn đề này, hãy thử sử dụng cờ -re trong dòng lệnh FFmpeg của bạn để buộc FFmpeg đọc đầu vào ở tốc độ khung hình gốc.

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

+0

Cảm ơn! Có vẻ như có một chút cải thiện, vì ffmpeg không thành công sau một thời gian chạy lâu hơn, nhưng vấn đề vẫn còn tồn tại. Tôi vẫn nghĩ rằng đó là sự cố đồng bộ hóa. Ngay cả khi hình ảnh được sao chép ở tốc độ 10 khung hình/giây và ffmpeg đọc hình ảnh ở tốc độ 10 khung hình/giây, thì có khả năng cả hai quy trình sẽ truy cập tệp cùng một lúc, phải không? –

+2

Vâng, đó là sự thật. Có lẽ bạn có thể xem xét một số loại đường ống như sử dụng '-f image2pipe'. Tôi không bao giờ sử dụng nó bản thân mình vì vậy tôi không chắc chắn nếu điều này là đúng. –