0

I'm trying to restream with ffmpeg. I don't care if it will be mjpeg or whatever else, as long as it will be playable in modern browsers. But latency is critical, it would be great to have <5 sec delay added.

I was trying to make hls stream, then gave up and tried mjpeg.So far I came up with something like this:

hls

ffmpeg -i input -an -c:v libx264 -crf 21 -preset veryfast -fflags nobuffer -flags low_delay  -f hls -hls_time 6 -hls_list_size 10 -hls_flags delete_segments restreamed.m3u8

(I have this outputing to folder which is server via nginx, so I could test if I can play the stream in browser or vlc)

The main issue with this is that the m38u file is always missing the last segment: ffmpeg creates restreamed0.ts, there is no m3u8 file. After given time, the (restreamed)0.ts is done, and it starts another chunk 1.ts. At this point, m3u8 is created, but it only has 0.ts in it. When the 1.ts if finished, another chunk 2.ts is started, and the 1.ts is written to the m3u8 file, and so on. This obviously creates the delay of the length of one segment, which is too much.

I tried tweaking with the -hls_time and -hls_list_size parameters and other flags I came across while Googling, but without any success. I've been trying to get this working for two days and it this point, I've completely lost track of what doesn't work at all, and what is somewhat working (usually it either takes insanely long for vlc to start playing the stream, or there is a huge delay, but I had no success creating perfect stream). I'm totally lost and I would appreciate some help.

mjpeg

I then gave up ad tried doing mjpeg stream, but it ended similar. My best result is this:

 ffmpeg -i input -vcodec mjpeg -f segment -segment_time 10  -segment_list video.m3u8  -max_delay 0    out%d.mjpg

ffmpeg output:

Input #0, mpjpeg, from '...':
  Duration: N/A, bitrate: N/A
    Stream #0:0: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown), 640x480, 25 tbr, 25 tbn, 25 tbc
Stream mapping:
  Stream #0:0 -> #0:0 (mjpeg (native) -> mjpeg (native))
Press [q] to stop, [?] for help
[segment @ 0x1d62900] Opening 'out0.mjpg' for writing
Output #0, segment, to 'out%d.mjpg':
  Metadata:
    encoder         : Lavf58.20.100
    Stream #0:0: Video: mjpeg, yuvj420p(pc), 640x480, q=2-31, 200 kb/s, 25 fps, 25 tbn, 25 tbc
    Metadata:
      encoder         : Lavc58.35.100 mjpeg
    Side data:
      cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1
[segment @ 0x1d62900] Opening 'video.m3u8.tmp' for writingte=N/A speed=0.403x
[segment @ 0x1d62900] Opening 'out1.mjpg' for writing
[segment @ 0x1d62900] Opening 'video.m3u8.tmp' for writingte=N/A speed=0.401x    
[segment @ 0x1d62900] Opening 'out2.mjpg' for writing
[segment @ 0x1d62900] Opening 'video.m3u8.tmp' for writingte=N/A speed=0.401x    
[segment @ 0x1d62900] Opening 'out3.mjpg' for writing
[segment @ 0x1d62900] Opening 'video.m3u8.tmp' for writingte=N/A speed=0.401x    

I had no success loading that m3u8 file in vlc or in bowser (html video element). (However, if I try to play one of the .mjpg files, it's working as expected (except it plays faster, but I think that's caused by the source stream being 10fps, I can deal with this later)). The m3u8 file looks like this:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:10
#EXTINF:10.000000,
out0.mjpg
#EXTINF:10.000000,
out1.mjpg
#EXTINF:10.000000,
out2.mjpg

and apart from not being able to play it in vlc, neither in browser (I tried solutions offered in this question), it's always missing the last segment.

Could you please tell me what I'm doing wrong or point me in the right direction?

0

First of all: .m3u8 files are not expected to work with mJPEG in any portable way, so this is a dead end.

Concerning HLS: The .m3u8 file always only contains the finished segments, so the one just being created is never in the list. Due to consumption via a browser this is necessary and can't be circumvented.

What you can do is to make that last segment short - by making all segments short: Try

ffmpeg -i input -an -c:v libx264 -crf 21 -preset veryfast -fflags nobuffer -flags low_delay  -f hls -hls_time 1 -hls_list_size 3 -hls_flags delete_segments restreamed.m3u8

The -hls_time 1 wil reduce the length of all segments to one second, so the delay while creating the last segment is a maximum of a second. The -hls_list_size 3 will shorten the list to 3 segments of a second each.

5
  • Thanks, but even with this, new segments are created every 10 seconds. When I open the m3u8 in vlc, it plays the segment faster in 2-3 seconds, and then waits the rest for anohter segment. Also ffmpeg runs at speed of about 0.3 Could this be because the source stream is only 10fps? – Adam Ježek Dec 30 '19 at 13:29
  • This will not help. One second segments are rather inefficient. Also, the default keyframe interval for libx264 is 250 frames, and ffmpeg can only split segments at those. Choose a lower GOP size with -g, see: superuser.com/questions/908280. Finally, use -re -i <input> to stream in realtime from the original source. – slhck Dec 30 '19 at 16:47
  • @slhck with HLS latency and efficiency are connected - sith efficient 10 sec segments you can't get less than 10 sec latency. – Eugen Rieck Jan 1 '20 at 16:57
  • Exactly, which is why I suggested to lower the GOP size, so you can achieve smaller segments. 1 second however is usually too small – typically you'd choose around 4–6 seconds. (Unless you are doing low latency HLS with partial segments or similar tricks.) – slhck Jan 2 '20 at 8:19
  • The OP specially asked for <5 sec latency, so your "typically you'd choose around 4–6 seconds" is not a good idea. It is why I chose single seconds as a suggestion. – Eugen Rieck Jan 2 '20 at 9:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.