ffmpeg - ffserver configuration to handle a large webm stream

16
2014-04
  • CoryG

    I'm setting up an ffserver for CCTV streams with 16 cameras - all the individual channels are streaming well with a config like:

    <Feed 0.ffm>
    File /tmp/0.ffm
    FileMaxSize 5M
    ACL allow 10.1.2.2
    </Feed>
    
    <Feed 0_webm.ffm>
    File /tmp/0_webm.ffm
    FileMaxSize 5M
    ACL allow localhost
    </Feed>
    
    <Stream 0.mpg>
    Feed 0.ffm
    Format mpeg1video
    NoAudio
    VideoFrameRate 24
    VideoBitRate 256
    VideoSize 320x240
    VideoBufferSize 40
    VideoGopSize 12
    </Stream>
    
    <Stream 0.webm>
    Feed 0_webm.ffm
    Format webm
    NoAudio
    VideoCodec libvpx
    VideoSize 320x240
    VideoFrameRate 24
    AVOptionVideo flags +global_header
    AVOptionVideo cpu-used 0
    AVOptionVideo qmin 1
    AVOptionVideo qmax 31
    AVOptionVideo quality good
    PreRoll 0
    StartSendOnKey
    VideoBitRate 500K
    </Stream>
    

    And the associated ffmpeg calls made into upstart processes:

    ffmpeg -f video4linux2 -standard ntsc -i /dev/video0 http://10.1.2.1:8090/0.ffm
    

    and

    ffmpeg -f mpegvideo -i http://localhost:8090/0.mpg -vcodec libvpx http://localhost:8090/0_webm.ffm
    

    However when it comes to the large 4x4 grid overview of all the channels I'm having some issues with the ffserver.conf configuration. Using this ffmpeg call made into a daemon I can reliably manage about 24-25 FPS (and have tested that it works by saving to a local file and playing it back via ffplay):

    ffmpeg -i http://localhost:8090/0.webm -i http://localhost:8090/1.webm -i http://localhost:8090/2.webm -i http://localhost:8090/3.webm -i http://localhost:8090/4.webm -i http://localhost:8090/5.webm -i http://localhost:8090/6.webm -i http://localhost:8090/7.webm -i http://localhost:8090/8.webm -i http://localhost:8090/9.webm -i http://localhost:8090/10.webm -i http://localhost:8090/11.webm -i http://localhost:8090/12.webm -i http://localhost:8090/13.webm -i http://localhost:8090/14.webm -i http://localhost:8090/15.webm -filter_complex "
    nullsrc=size=1280x960 [bg];
    [0:v] setpts=PTS-STARTPTS [v0];
    [1:v] setpts=PTS-STARTPTS [v1];
    [2:v] setpts=PTS-STARTPTS [v2];
    [3:v] setpts=PTS-STARTPTS [v3];
    [4:v] setpts=PTS-STARTPTS [v4];
    [5:v] setpts=PTS-STARTPTS [v5];
    [6:v] setpts=PTS-STARTPTS [v6];
    [7:v] setpts=PTS-STARTPTS [v7];
    [8:v] setpts=PTS-STARTPTS [v8];
    [9:v] setpts=PTS-STARTPTS [v9];
    [10:v] setpts=PTS-STARTPTS [v10];
    [11:v] setpts=PTS-STARTPTS [v11];
    [12:v] setpts=PTS-STARTPTS [v12];
    [13:v] setpts=PTS-STARTPTS [v13];
    [14:v] setpts=PTS-STARTPTS [v14];
    [15:v] setpts=PTS-STARTPTS [v15];
    [bg][v0] overlay=shortest=1 [bg];
    [bg][v1] overlay=shortest=1:x=320 [bg];
    [bg][v2] overlay=shortest=1:x=640 [bg];
    [bg][v3] overlay=shortest=1:x=960 [bg];
    [bg][v4] overlay=shortest=1:y=240 [bg];
    [bg][v5] overlay=shortest=1:x=320:y=240 [bg];
    [bg][v6] overlay=shortest=1:x=640:y=240 [bg];
    [bg][v7] overlay=shortest=1:x=960:y=240 [bg];
    [bg][v8] overlay=shortest=1:y=480 [bg];[bg]
    [v9] overlay=shortest=1:x=320:y=480 [bg];
    [bg][v10] overlay=shortest=1:x=640:y=480 [bg];
    [bg][v11] overlay=shortest=1:x=960:y=480 [bg];
    [bg][v12] overlay=shortest=1:y=720 [bg];
    [bg][v13] overlay=shortest=1:x=320:y=720 [bg];
    [bg][v14] overlay=shortest=1:x=640:y=720 [bg];
    [bg][v15] overlay=shortest=1:x=960:y=720" http://localhost:8090/all_webm.ffm
    

    the issue comes when linking it to the ffserver - neither the ffmpeg process nor the ffserver process crash, yet the stream is inaccessible (while the single-channel .webm's work fine). I've tried the same configuration as the smaller .webm's with the resolution changed along with this:

    <Feed all_webm.ffm>
    File /tmp/all_webm.ffm
    FileMaxSize 20M
    ACL allow localhost
    </Feed>
    
    <Stream all.webm>
    Feed all_webm.ffm
    Format webm
    NoAudio
    VideoCodec libvpx
    VideoSize 1280x960
    VideoFrameRate 24
    AVOptionVideo flags +global_header
    AVOptionVideo cpu-used 0
    AVOptionVideo qmin [1|10]
    AVOptionVideo qmax [31|42]
    AVOptionVideo quality good
    PreRoll 0
    StartSendOnKey
    VideoBitRate [512|700|800|1024|3M|3686400]
    </Stream>
    

    With every combination of the parameters shown with brackets around them and a few I can't remember. Does anyone have a working configuration to stream large webm files with ffserver?

    Edit: Added the feeds I'm using (no actual change, the all.webm stream is still broken in some unspecified manner). Also I should have included this initially, but the ffplay output is as follows (it just hangs indefinitely):

    ffplay http://10.1.1.15:8090/all.webm
    ffplay version git-2013-03-17-ef3c888 Copyright (c) 2003-2013 the FFmpeg developers
      built on Mar 17 2013 19:21:22 with gcc 4.6 (Ubuntu/Linaro 4.6.3-1ubuntu5)
      configuration: --enable-gpl --enable-libass --enable-libfaac --enable-libfdk-aac --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libspeex --enable-librtmp --enable-libtheora --enable-libvorbis --enable-libvpx --enable-x11grab --enable-libx264 --enable-nonfree --enable-version3
      libavutil      52. 19.101 / 52. 19.101
      libavcodec     55.  1.100 / 55.  1.100
      libavformat    55.  0.100 / 55.  0.100
      libavdevice    55.  0.100 / 55.  0.100
      libavfilter     3. 47.102 /  3. 47.102
      libswscale      2.  2.100 /  2.  2.100
      libswresample   0. 17.102 /  0. 17.102
      libpostproc    52.  2.100 / 52.  2.100
        nan A-V:  0.000 fd=   0 aq=    0KB vq=    0KB sq=    0B f=0/0
    

    Another Edit:

    Tested with the following:

    ffmpeg -r 29.97 -f lavfi -i testsrc -s 1280x960 -r 29.97 http://localhost:8090/all_webm.ffm
    

    Which works to stream the test stream (though slowly, it has to stop every couple of seconds to catch up in chrome, fails after the same period in firefox) - only gets 13 FPS. So I tried breaking up the test and webm conversion portions as follows:

    ffmpeg -f lavfi -i testsrc -s 1280x960 -r 29.97 http://localhost:8090/all.ffm
    ffmpeg -r 29.97 -f mpegvideo -i http://localhost:8090/all.mpg -r 29.97 -vcodec libvpx http://localhost:8090/all_webm.ffm
    

    The first command gets 29.97+ FPS, the second comes in at 13 FPS.

    I'm not so worried about the FPS (13 FPS would be fine for the 4x4 grid), however this leads me to believe the issue may exist betweeh the long ffmpeg command (with the -format_complex option) and the import into ffserver in spite of the fact it records a perfectly valid .webm file when send to a local file instead of ffserver - still need help.

    Another Edit:

    Adding the tail of the large ffmpeg output being send to http:// localhost:8090/all_webm.ffm below, I've seen similar output in the smaller mpeg --> webm converting ffmpeg processes that work but the rate at which it differs so I didn't think it mattered (by having it record to a local .webm file and counting the duration being recorded while walking out in front of one of the cameras and back to the time I stopped the process the times synced up and the playback showed smooth 25 FPS motion), but I don't know enough about the process to rule it out completely (what follows is the end of the console output after pressing "q" to stop ffmpeg):

    [Parsed_overlay_26 @ 0x37464e0] Buffer queue overflow, dropping.
        Last message repeated 19 times
    Buffer queue overflow, dropping. size=       4kB time=00:36:21.64 bitrate=   0.0kbits/s
    [Parsed_overlay_25 @ 0x374db20] Buffer queue overflow, dropping.
        Last message repeated 28 times
    [Parsed_overlay_17 @ 0x374ba40] Buffer queue overflow, dropping.
        Last message repeated 11 times
    [Parsed_overlay_20 @ 0x374e3c0] Buffer queue overflow, dropping.
        Last message repeated 30 times
    [Parsed_overlay_19 @ 0x374e4a0] Buffer queue overflow, dropping.
        Last message repeated 28 times
    [Parsed_overlay_32 @ 0x3749b20] Buffer queue overflow, dropping.
        Last message repeated 17 times
    [Parsed_overlay_24 @ 0x3745fc0] Buffer queue overflow, dropping.
        Last message repeated 2 times
    [Parsed_overlay_23 @ 0x3751060] Buffer queue overflow, dropping.
    Buffer queue overflow, dropping. size=       4kB time=00:36:22.28 bitrate=   0.0kbits/s
    [Parsed_overlay_17 @ 0x374ba40] Buffer queue overflow, dropping.
        Last message repeated 6 times
    Buffer queue overflow, dropping. size=       4kB time=00:36:23.04 bitrate=   0.0kbits/s
    [Parsed_overlay_17 @ 0x374ba40] Buffer queue overflow, dropping.
        Last message repeated 22 times
    Buffer queue overflow, dropping. size=       4kB time=00:36:23.68 bitrate=   0.0kbits/s
    [Parsed_overlay_17 @ 0x374ba40] Buffer queue overflow, dropping.
        Last message repeated 10 times
    Buffer queue overflow, dropping. size=       4kB time=00:36:24.12 bitrate=   0.0kbits/s
    [Parsed_overlay_17 @ 0x374ba40] Buffer queue overflow, dropping.
        Last message repeated 9 times
    Buffer queue overflow, dropping. size=       4kB time=00:36:24.84 bitrate=   0.0kbits/s
    [Parsed_overlay_17 @ 0x374ba40] Buffer queue overflow, dropping.
        Last message repeated 1 times
    Buffer queue overflow, dropping. size=       4kB time=00:36:25.32 bitrate=   0.0kbits/s
    frame=54637 fps= 25 q=24.8 Lq=0.0 size=      48kB time=00:36:25.44 bitrate=   0.2kbits/s
    video:172039kB audio:0kB subtitle:0 global headers:0kB muxing overhead -99.972099%
    
  • Answers
  • Nick van Tilborg

    Did you provide a <feed all_webm.ffm> ... </feed> before your <Stream all.webm>? I think that should do the trick, because probably FFserver doesn't know where to get the feed from.

    If that doesn't work you can also test your feed from FFmpeg using ffplay http://localhost:8090/all_webm.ffm


  • Related Question

    ffmpeg - Creating MP4 videos ready for HTTP streaming
  • abrahab

    How can I convert some.flv or some.avi or some.wmv with FFmpeg to be sure that this video will be playable and seekable in JW Player?


  • Related Answers
  • slhck

    This is an answer to last comment by you @abrahab.

    You don't need to mp4box a file to be able to pseudo stream it via nginx. The MP4 streaming module takes care of it irrespective of positioning of moov atoms (mp4box shifts the moov atom to beginning of file).


    Now for the 500 server error, are you using "-frag" option with mp4box? MP4 streaming module can't read fragmented MP4 files. Good use of mp4box for pseudo streaming is to interleave the videos for better seeking. Moov atom shifting is an added advantage.

    I always do this to mp4box an FFmpeg-encoded file

    MP4Box -add MyVideo.mp4 -isma Myvideo-box.mp4
    

    This will also interleave the MP4 file in 500 milliseconds of chunks by default.

  • slhck

    Generally, you want to create x264 video within an MP4 container, so the following should be enough. Make sure to replace input name and CRF options. The latter sets the quality, where sane values range from 19 to 25 – lower means better quality, but also higher bitrate:

    ffmpeg -i input.avi -c:v libx264 -crf 22 -c:a libfaac -movflags faststart output.mp4

    You can also use Handbrake for encoding if you like the GUI way.

    Now, what you need to do is move the MP4 container's MOOV atom to the beginning. This atom (in essence, a unit of data in the MP4 container) will contains important metadata about the video/audio streams themselves. -movflags faststart should do exactly that.

    If your FFmpeg version doesn't have this option, consider upgrading. If you cannot upgrade, you can achieve the same thing with any of the below tools:

    • QTIndexSwapper, an Adobe AIR application

    • MP4Box, free and open source, running a command similar to the following, where you can change the interval (here, 500):

      mp4box -inter 500 input.mp4

    • qt-faststart in Python, which works everywhere where Python is installed.

      qtfaststart input.mp4

    That's about it. The rest of the toolchain is actually more complicated than that. You need to properly set up your web server so it handles h.264 content if you want HTTP pseudo-streaming. Check JW Player's documentation for more:

    Video Delivery: HTTP Pseudo-Streaming | LongTail Video | Home of the JW Player

    You need the h.264 streaming module for Apache, Lighttpd, IIS and NginX and then continue with the JW Player setup. As this is not in the scope of this question and a far broader topic, any problems that might occur during streaming need proper debugging – but the video encoding stage should not matter that much.

  • Indrek

    You can try this with ffmpeg:

    ffmpeg.exe -i "INPUT_FILE.AVI" -threads 2 -s 800x600 -r 25.00 -threads 1 -pix_fmt yuv420p -g 300 -qmin 3 -b 2048k -async 1 -acodec pcm_s16le -ar 22050 -ac 1 -ab 128k -y "OUTPUT_FILE.mp4"