How to stream to multiple destinations with ffmpeg - ffmpeg

I want to stream my video to 4 destinations. My input signal needs to be recoded to "H.264 AAC", so I want to send it to my server. This works already.
Client -> Server with ffmpeg -> Destinations
Now I have a performance problem: One should get the stream in 1080p and two in 720p.
So it would make sense to first get the stream in the desired formats H.264 1080p and AAC with 30 FPS and then calculate the stream once, send it 1:1 to the two HD targets.
and create a 720p stream in parallel and send it to the two remaining destinations.
What is the best way to do this on a Ubuntu 16.04 machine?
My previous approach:
ffmpeg -i rtmp://livestream.domain.example/live/<key> \
-threads 2 -s hd1080 -preset veryfast -f flv rtmp://destination1.example/live2/<key> \
-threads 2 -s hd1080 -preset veryfast -f flv rtmp://destination2.example/live2/<key> \
-threads 1 -s hd720 -c:v libx264 -c:a aac -preset veryfast -r 30 -g 60 -b:v 3000k -f flv rtmp://destination3.example/x/<key> \
-threads 1 -s hd720 -c:v libx264 -preset veryfast -c:a aac -f flv 'rtmps://destination4.exmple/rtmp/<key>'
You can see the repetitions in the code. :-/

Use the tee muxer:
ffmpeg -i rtmp://livestream.domain.example/live/<key> \
-filter_complex "[0:v]scale=-2:1080,fps=30,split=outputs=2[1080a][1080b];[0:v]scale=-2:720,fps=30,split=outputs=2[720a][720b]" \
-map "[1080a]" -map "[1080b]" -map "[720a]" -map "[720b]" -map 0:a \
-c:v libx264 -c:a aac -preset veryfast -g 60 -b:v 3000k -maxrate 3000k -bufsize 6000k -f tee \
"[select=\'v:0,a\':f=flv:onfail=ignore]rtmp://destination1.example/live2/<key>| \
[select=\'v:1,a\':f=flv:onfail=ignore]rtmp://destination2.example/live2/<key>| \
[select=\'v:2,a\':f=flv:onfail=ignore]rtmp://destination3.example/live2/<key>| \
[select=\'v:3,a\':f=flv:onfail=ignore]rtmp://destination4.example/live2/<key>"

Related

ffmpeg streaming to youtube

I've used the following command to stream mp4 file to youtube :
ffmpeg -re -i merge.mp4 \
-c:v libx264 -preset veryfast -maxrate 3000k \
-bufsize 6000k -pix_fmt yuv420p -g 50 -c:a aac -b:a 160k -ac 2 \
-ar 44100 -f flv rtmp://a.rtmp.youtube.com/live2/<MYKEY>
I see the ffmpeg streams the data like that:
but yet the youtube streaming page shows nothing yet received:
Any idea what am I missing?

FFMPEG stream to multiples servers using the same -filter_complex options

I want to stream a video to two rtmp servers, I have some options like scaling the resolution from 1080p to 576p or adding a logo. These options are serving in the first rtmp server which the signal was sent, but in the second rtmp it is sending 1080p without any of these options, what am I doing wrong?
ffmpeg -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect 1 -reconnect_delay_max 4 -i video.mp4 -i hello.jpg -filter_complex "overlay=1650:950,scale=1024:576" -vcodec libx264 -preset veryfast -b:v 1300k -acodec aac -b:a 128k -f flv rtmp://test -vcodec libx264 -preset veryfast -b:v 1300k -acodec aac -b:a 128k -f flv rtmp://test2
Unlike input streams, you can only consume a filtergraph output stream only once, and the first rtmp output is snatching it up. If you want to use it on both outputs, split the output of the filter:
ffmpeg -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect 1 -reconnect_delay_max 4 \
-i video.mp4 -i hello.jpg \
-filter_complex "overlay=1650:950,scale=1024:576,split=2[v1][v2]" \
-map [v1] -map 0:a -vcodec libx264 -preset veryfast -b:v 1300k -acodec aac -b:a 128k \
-f flv rtmp://test \
-map [v2] -map 0:a -vcodec libx264 -preset veryfast -b:v 1300k \
-acodec aac -b:a 128k -f flv rtmp://test2
Another, likely preferred, option if you are outputting identical streams is to use tee muxer. It should look something like this:
ffmpeg -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect 1 -reconnect_delay_max 4 \
-i video.mp4 -i hello.jpg \
-filter_complex "overlay=1650:950,scale=1024:576[vout]" \
-map [vout] -map 0:a -vcodec libx264 -preset veryfast -b:v 1300k -acodec aac -b:a 128k \
-f tee "[f=flv]rtmp://test|[f=flv] rtmp://test2"

Ffmpeg - How can I create HLS multiple language streams, in multiple qualities?

Preface
I'm working on converting videos from 4k to multiple qualities with multiple languages but am having issues with the multiple languages overlaying, sometimes losing quality and sometimes being out of sync. (this is less of a problem in the German audio, as this is voice over anyhow)
We as a team are complete noobs in terms of Video / Audio + HLS -- I'm a front end developer who has no experience of this so apologies if my question is poorly phrased
Videos
I have the video in a 4k format and have removed the original sound as I have English and German audio files that need to be overlayed. I am then taking these files and throwing them together into a .ts file like this:
$ ffmpeg -i ep03-ns-4k.mp4 -i nkit-ep3-de-output.m4a -i nkit-ep3-en-output.m4a \
> -thread 0 -muxdelay 0 -y \
> -map 0:v -map 1 -map 2 -movflags +faststart -refs 1 \
> -vcodec libx264 -acodec aac -profile:v baseline -level 30 -ar 44100 -ab 64k -f mpegts out.ts
This outputs a 4k out.ts video, with both audio tracks playing.
The hard part
This is where I'm finding it tricky, I now need to convert this single file into multiple quality levels (480, 720, 1080, 1920) and I attempt this with the following command:
ffmpeg -hide_banner -y -i out.ts \
-crf 20 -sc_threshold 0 -g 48 -keyint_min 48 -ar 48000 \
-map 0:v:0 -map 0:v:0 -map 0:v:0 -map 0:v:0 \
-c:v:0 h264 -profile:v:0 main -filter:v:0 "scale=w=848:h=480:force_original_aspect_ratio=decrease" -b:v:0 1400k -maxrate:v:0 1498k -bufsize:v:0 2100k \
-c:v:1 h264 -profile:v:1 main -filter:v:1 "scale=w=1280:h=720:force_original_aspect_ratio=decrease" -b:v:1 2800k -maxrate:v:1 2996k -bufsize:v:1 4200k \
-c:v:2 h264 -profile:v:2 main -filter:v:2 "scale=w=1920:h=1080:force_original_aspect_ratio=decrease" -b:v:2 5600k -maxrate:v:2 5992k -bufsize:v:2 8400k \
-c:v:3 h264 -profile:v:3 main -filter:v:3 "scale=w=3840:h=1920:force_original_aspect_ratio=decrease" -b:v:3 11200k -maxrate:v:3 11984k -bufsize:v:3 16800k \
-var_stream_map "v:0 v:1 v:2 v:3" \
-master_pl_name master.m3u8 \
-f hls -hls_time 4 -hls_playlist_type vod -hls_list_size 0 \
-hls_segment_filename "%v/episode-%03d.ts" "%v/episode.m3u8"
This creates the required qualities, but I'm now at a loss of how this might work with the audio
Audio
For the audio I run this command:
ffmpeg -i out.ts -threads 0 -muxdelay 0 -y -map 0:a:0 -codec copy -f segment -segment_time 4 -segment_list_size 0 -segment_list audio-de/audio-de.m3u8 -segment_format mpegts audio-de/audio-de_%d.aac
ffmpeg -i out.ts -threads 0 -muxdelay 0 -y -map 0:a:1 -codec copy -f segment -segment_time 4 -segment_list_size 0 -segment_list audio-en/audio-en.m3u8 -segment_format mpegts audio-en/audio-en_%d.aac
This creates the required audio segments.
The question
I realise this is quite an ask, but is there anything wrong with our inputs? Is there a way that this can be done a bit more streamlined?
Any answers are greatly appreciated.
Lets say you have:
VideoA
AudioB-> Language 1
AudioC-> Language 2
AudioD-> Language 3
Although it can be done all together, it is better to use different commands for each language instance.
Note that the following are schematics only- some values and parameters will need to be filled in by you. However, this provides a scheme of how to connect the entities. Also I have simply set the size, and NOT used a scale filter. You can use a scale filter instead. Filters will go in place of the size parameter (-s 1280x720 etc).
ffmpeg -i VideoA -i AudioB -map [0:v] -map [1:a] -s 1280x720 -acodec aac -b:a 128k \
-vcodec libx264 -pix_fmt yuv420p [your other parameters go here] -movflags +faststart \
OutputAB_720p.mp4 -map [0:v] -map [1:a] -s 1920x1080 -acodec aac -b:a 128k -vcodec \
libx264 -pix_fmt yuv420p [your other parameters go here] -movflags +faststart \
OutputAB_1080p.mp4
The above shows a scheme for 2 resolutions, 720p and 1080p, merging VideoA with AudioB. To do the same scheme for AudioC you would repeat:
ffmpeg -i VideoA -i AudioC -map [0:v] -map [1:a] -s 1280x720 -acodec aac -b:a 128k \
-vcodec libx264 -pix_fmt yuv420p [your other parameters go here] -movflags +faststart \
OutputAC_720p.mp4 -map [0:v] -map [1:a] -s 1920x1080 -acodec aac -b:a 128k -vcodec \
libx264 -pix_fmt yuv420p [your other parameters go here] -movflags +faststart \
OutputAC_1080p.mp4
You could put all the inputs together:
ffmpeg -i VideoA -i AudioB -i AudioC -i AudioD
and accordingly map each for every language:
-map [0:v] -map [1:a]
-map [0:v] -map [2:a]
-map [0:v] -map [3:a]
etc.
But I feel such long commands that will result make it difficult to read, maintain and correct.

ffmpeg youtube livestream stops after a while

I'll update this question
ffmpeg -version
ffmpeg -version
ffmpeg version 4.3.1-4ubuntu1 Copyright (c) 2000-2020 the FFmpeg developers
built with gcc 10 (Ubuntu 10.2.0-9ubuntu2)
I run this command to use ffmpeg to stream to youtube ;
ffmpeg -y -threads 12 \
-loop 1 -framerate 30 -re \
-i ./1280x720.jpg \
-i ./audio.mp3 \
-video_size 1280x720 \
-vcodec libx264 -pix_fmt yuv420p \
-b:v 4500k -maxrate 5500k -bufsize 22000k \
-preset ultrafast -crf 23 -tune stillimage \
-b:a 128k -ar 44100 -ac 2 -acodec aac \
-filter_complex "dynaudnorm=f=150:g=15" \
-r 30 -g 60 \
-f flv rtmp://a.rtmp.youtube.com/live2/xxxx 2>&1 | tee _LOG
The stream is excellent for 45-53 minutes then i'll get an error like this from ffmpeg:
[flv # 0x56077027cd80] Delay between the first packet and last packet in the muxing queue is 10034000 > 10000000: forcing output
then youtube starts to say, no data being received and the stream will end, which it does.
This is the full log: http://0x0.st/-zUH.txt
Your MP3 duration is 00:49:57.42 so the stream messes up after it ends. Loop the audio with -stream_loop -1 and add -re for real-time reading of the input:
ffmpeg -y \
-loop 1 -framerate 30 -re -i ./1280x720.jpg \
-re -stream_loop -1 -i ./audio.mp3 \
-c:v libx264 -pix_fmt yuv420p \
-b:v 4500k -maxrate 5500k -bufsize 22000k \
-preset ultrafast -tune stillimage \
-b:a 128k -ar 44100 -ac 2 -c:a aac \
-filter_complex "dynaudnorm=f=150:g=15" \
-g 60 -f flv rtmp://a.rtmp.youtube.com/live2/xxxx
Alternatively, remove -re -stream_loop -1 and add the output option -shortest if you want the stream to end when the audio ends.
Unrelated changes:
No need to set -threads. Let ffmpeg auto choose.
-video_size 1280x720 is an input option for certain demuxers and does nothing in your command. Removed. Your input is already 1280x720 anyway: otherwise, see Resizing videos with ffmpeg to fit a specific size.
-b:v and -crf are mutually exclusive. In your case -b:v is being ignored. For streaming you probably want to use -b:v. Removed -crf.
You already set the frame rate with -framerate 30 so -r 30 is not needed. Removed.
Recommend using the slowest -preset that still encodes fast enough.

FFmpeg Live Stream - Loop Video?

I am trying to stream a video loop to justin.tv using FFmpeg? I have managed to loop an image sequence and combine it with line in audio:
ffmpeg -loop 1 -i imageSequence%04d.jpg -f alsa -ac 2 -ar 22050 -ab 64k \
-i pulse -acodec adpcm_swf -r 10 -vcodec flv \
-f flv rtmp://live.justin.tv/app/<yourStreamKeyHere>
Is it possible to do this with a video file?
Definitely possible. In the recent versions of ffmpeg they have added a -stream_loop flag that allows you to loop the input as many times as required.
The gotcha is that if you don't regenerate the pts from the source, ffmpeg will drop frames after the first loop (as the timestamp will suddenly go back in time). To avoid this, you need to tell ffmpeg to generate the pts so you get an increasing timestamp between loops. This is done with the +genpts call (it has to be before the -i arg).
Here's an example ffmpeg call (replace $F with your input file). This example generates two output streams and the -stream_loop -1 argument tells ffmpeg to continuously loop the input. The output in this case is for a similar stream broadcast ingest (MetaCDN), adjust accordingly to your requirements.
ffmpeg -threads 2 -re -fflags +genpts -stream_loop -1 -i $F \
-s 640x360 -ac 2 -f flv -vcodec libx264 -profile:v baseline -b:v 600k -maxrate 600k -bufsize 600k -r 24 -ar 44100 -g 48 -c:a libfdk_aac -b:a 64k "rtmp://publish.live.metacdn.com/2050C7/dfsdfsd/lowquality_664?hello&adbe-live-event=lowquality_" \
-s 1920x1080 -ac 2 -f flv -vcodec libx264 -profile:v baseline -b:v 2000k -maxrate 2000k -bufsize 2000k -r 24 -ar 44100 -g 48 -c:a libfdk_aac -b:a 64k "rtmp://publish.live.metacdn.com/2050C7/dfsdfsd/highquality_2064?mate&adbe-live-event=highquality_"
Sinclair Media has found a solution by using the lavfi filter and appending :loop=0 to the file name :
This is untested:
ffmpeg -f lavfi -re -i movie=StreamTest.avi:loop=0 \
-acodec libfaac -b:a 64k -pix_fmt yuv420p -vcodec libx264 \
-x264opts level=41 -r 25 -profile:v baseline -b:v 1500k \
-maxrate 2000k -force_key_frames 50 -s 640×360 -map 0 -flags \
-global_header -f segment -segment_list index_1500.m3u8 \
-segment_time 10 -segment_format mpeg_ts \
-segment_list_type m3u8 segmented.ts
But it should create a local "index_1500.m3u8" file that streams the video in "StreamTest.avi".
I just reuse the Rob's answers with a few of modifications in order to provide a file to live streaming
ffmpeg -threads 2 -re -fflags +genpts -stream_loop -1 -i gvf.mp4 -c copy -f mpegts -mpegts_service_id 102 -metadata service_name=My_channel -metadata service_provider=My_Self -max_interleave_delta 0 -use_wallclock_as_timestamps 1 -flush_packets 1 "udp://233.0.0.1:1001?localaddr=10.60.4.237&pkt_size=188"

Resources