ffmpeg dts_delta_threshold and aresample=async=1 - ffmpeg

I am using ffmpeg to encode livestreams for use in a tvheadend server. ffmpeg and hls discontinuities dont work, but ive fixed that using streamlink to read the hls stream then pipe that into ffmpeg.
Sometimes the audio has gaps in the live stream and the audio goes out of sync from that point on, I have managed to fix this using aresample=async=1. ffmpeg inserts silence for the gaps and audio stays synced.
Tvheadend doesnt like dts discontinuities and the stream will freeze whenever one is encountered. I have also fixed this with dts_delta_threshold 1. With this option the stream plays seamlessly without any freezes
Here is where my problem comes in when using dts_delta_threshold 1 the aresample command no longer works, I assume because there are no more gaps so it cant insert the silence. Ive tried various combinations and ordering of options.
Is there any way to apply the aresample=async=1 and also the dts_delta_threshold 1 command after.
This is my current command
streamlink -l warning --ringbuffer-size 64M --hls-timeout 100000000 --hls-live-restart hls://192.168.10.1/play/$1.$2.m3u8 best -O | \
ffmpeg -loglevel fatal -err_detect ignore_err \
-f mpegts -i - \
-filter_complex "eq=contrast=${3:-1.0}" \
-c:v libx264 -crf 18 -preset superfast -tune zerolatency -pix_fmt yuv420p -force_key_frames "expr:gte(t,n_forced*2)" \
-c:a aac -b:a 256k -ac 2 -af aresample=async=1 \
-metadata service_provider=$1 -metadata service_name="$1.$2" -f mpegts pipe:1
Ive tried putting the dts_delta_threshold before and after input, same thing audio goes out of sync if there is a gap in audio. Ive tried putting async 1 before input but that doesnt work either

Related

FFMPEG vsync drop and regeneration

According to the ffmpeg documentation
-vsync parameter
Video sync method. For compatibility reasons old values can be specified as numbers. Newly added values will have to be
specified as strings always.
drop
As passthrough but destroys all timestamps, making the muxer
generate fresh timestamps based on frame-rate.
It appears that the mpegts mux does not regenerate the timestamps correctly (PTS/DTS); however, piping the output after vsync drop to a second process as raw h264 does force mpegts to regenerate the PTS.
Generate test stream
ffmpeg -f lavfi -i testsrc=duration=20:size=1280x720:rate=50 -pix_fmt yuv420p -c:v libx264 -b:v 4000000 -x264-params ref=1:bframes=0:vbv-maxrate=4500:vbv-bufsize=4000:nal-hrd=cbr:aud=1:bframes=0:intra-refresh=1:keyint=30:min-keyint=30:scenecut=0 -f mpegts -muxrate 5985920 -pcr_period 20 video.ts -y
Generate output ts that has correctly spaced PTS values
ffmpeg -i video.ts -vsync drop -c:v copy -bsf:v h264_mp4toannexb -f h264 - | ffmpeg -fflags +igndts -fflags +nofillin -fflags +genpts -r 50 -i - -c:v copy -f mpegts -muxrate 5985920 video_all_pts_ok.ts -y
Generate output ts where all PTS are zero
ffmpeg -i video.ts -vsync drop -c:v copy -bsf:v h264_mp4toannexb -f mpegts - | ffmpeg -fflags +igndts -fflags +nofillin -fflags +genpts -r 50 -i - -c:v copy -f mpegts -muxrate 5985920 video_all_pts_zero.ts -y
It appears that vsync drop does destroy them but the mpegts doesn't regenerate them? Any ideas on what needs adding to get it to work as a single ffmpeg command?
Tested on both Linux and Windows with the same result
Try recoding the video just using -vsync 1, without -fflags +genpts. I found some good information here. This guy talking about streaming video. So highest quality isn't his objective. But there is useful info.
https://videoblerg.wordpress.com/2017/11/10/ffmpeg-and-how-to-use-it-wrong/
Section one – Constant frame rate
"-r is used to specify the output frame rate. This must be the same as the input frame rate to eliminate judder. This is used in conjunction with the -vsync parameter using the 1 option which will retime the PTS/DTS timestamps accordingly"
Section six – Audio [Has some good advice too]
"-af "aresample=async=1:min_hard_comp=0.100000:first_pts=0" helps to keep your audio lined up with the beginning of your video. It is common for a container to have the beginning of the video and the beginning of the audio start at different points. By using this your container should have little to no audio drift or offset as it will pad the audio with silence or trim audio with negative PTS timestamps if the audio does not actually start at the beginning of the video."
I haven't tried this yet, no videos with sync problems at the moment.

ffmpeg live stream transcoding. A/V sync issues on fast camera movement

I create a webrtc peer connection with my server(only stun)
Using pion webrtc for the server
I write the received RTP packets as VP8 and opus streams, as described here, to two pipes (the writers; created with os.Pipe() in golang)
The read ends of these two pipes are received by ffmpeg as inputs (via exec.Command.ExtraFiles) for transcoding using libx264 and aac into a single stream. The command:
ffmpeg -re -i pipe:3 -re -r pipe:4 -c:a aac -af aresample=48000 -c:v libx264 -x264-params keyint=48:min-keyint=24 -profile:v main -preset ultrafast -tune zerolatency -crf 20 -fflags genpts -avoid_negative_ts make_zero -vsync vfr -map 0:0,0:0 -map 1:0,0:0 -f matroska -strict -2 pipe:5
The above command outputs to a pipe(:5) the read end of which is being taken as input by the following:
ffmpeg -hide_banner -y -re -i pipe:3 -sn -vf scale=-1:'min(ih,360)' -c:v libx264 -pix_fmt yuv420p -ca aac -b:a 128k -b:v 1400k -maxrate 1498k -bufsize 2100k -hls_time 1 -hls_playlist_type event -hls_base_url /workdir/streamID/360p -hls_segment_filename /workdir/streamID/360p/360_%%03d.ts -f hls /workdir/streamID/360p.m3u8
This works fine as long as there are no movements of my webcam. The moment that happens the video speed suddenly increases for a split second and audio delay gets introduced. This delay keeps increasing each time I shake my webcam.
The first command in point 4 above - if written to a file separately will be absolutely fine, in terms of a/v sync, even with vigorous camera shaking. The weird audio delay is only when transcoding for hls output irrespective of whether I'm actually viewing it live or playing it back later.
This is my first time working with ffmpeg/hls/webrtc - would be really helpful if I could be pointed in the correct direction at least to be able to debug this or even know why this happens. Any and all help is greatly appreciated

FFMPEG: How to avoid audio/video desync in output of crossfaded clips when input is variable frame rate video

I'm doing screen recordings of gameplay (Dota2) using my NVIDIA graphics card GeForce experience hardware recording (NVEC Encoder). This creates a variable frame rate output video. My NVIDIA settings are 60 fps 15000 kbps. I have paid a guy to make a program that generates scripts that given start/stop timepoints can extract clips from the video and merge them with crossfade. See example code below. The script works for many input recordings but fails often: The audio and video are desynchronized (usually audio delay) in many of the clips, ca 0.5 seconds. I think it fails more when frame rate dropped more during recording. He does not know how to fix the problem, and I wonder if anyone could point out if anything could be fixed in the script (example below)?
Processing speed is quite important (now making a 10 min 'highlight' video takes ca 7-10 min). Solutions increasing that amount very much more is not of too big interest, unfortunately. His approach has been to work separately with audio and video and merge in the end. He already has a program to make ffmpeg code for working with different scenarios (also adding overlays, adding music, intro/outro) so it would be preferable with some easy fixes to his code and not dramatic redesigning of the logic. But if nothing else can fix the problem, a redesign in logic is ok. Using other tools than ffmpeg is also ok, but should be automatable (scripts/cli) and not increase processing times too much.
Running the program "mediainfo" on the input video shows that framerate dropped quite low for this input video:
Frame rate mode: Variable
Frame rate : 60.000 FPS
Minimum frame rate: 3.059 FPS
Maximum frame rate: 63.739 FPS
Full report here: https://pastebin.com/TX061Wih
The input video can be downloaded from dropbox here (6 GB):
https://www.dropbox.com/s/ftwdgapazbi62pr/fullgame.mp4?dl=0
Here the example of a script when asked to extract two clips from input video at 9:57 (41 sec length) and 15:45 (28 sec length) and crossfade merge them with a 0.5 crossfade time. There might be some code-remnants from options that are not used in this example (overlays, music, intro/outro). Using the input video above, this creates audio/video desync.
6 commands excecuted in sequence:
ffmpeg.exe -loglevel warning -ss 00:09:57 -i fullgame.mp4 -t 00:00:41 -filter_complex "[0:a]afade=t=out:st=40.5:d=0.5[a1]" -map "[a1]" -y out_temp_00.mp4.wav
ffmpeg.exe -loglevel warning -i fullgame.mp4 -ss 00:09:57 -t 00:00:41 -an -vcodec copy -f mpegts -avoid_negative_ts make_zero -y out_temp_00.mp4.ts
ffmpeg.exe -loglevel warning -ss 00:15:45 -i fullgame.mp4 -t 00:00:28 -filter_complex "[0:a]afade=t=in:st=0:d=0.5[a1]" -map "[a1]" -y out_temp_01.mp4.wav
ffmpeg.exe -loglevel warning -i fullgame.mp4 -ss 00:15:45 -t 00:00:28 -an -vcodec copy -f mpegts -avoid_negative_ts make_zero -y out_temp_01.mp4.ts
ffmpeg.exe -loglevel warning -i out_temp_00.mp4.wav -i out_temp_01.mp4.wav -y -filter_complex "[0:a]adelay=0|0[a0];[1:a]adelay=40500|40500[a1];[a0][a1]amix=inputs=2:dropout_transition=68.5,atrim=duration=68.5[outa0];[outa0]loudnorm[outa]" -map "[outa]" -ar 48000 -acodec aac -strict -2 fullgame_Output.mp4.aac
ffmpeg.exe -loglevel warning -i out_temp_00.mp4.ts -i out_temp_01.mp4.ts -y -i fullgame_Output.mp4.aac -filter_complex "[0:v]trim=start=0.5,setpts=PTS-STARTPTS[0c];[1:v]trim=start=0.5,setpts=PTS-STARTPTS[1c];[0:v]trim=40.5:41,setpts=PTS-STARTPTS[fo];[1:v]trim=0:0.5[fi];[fi]format=pix_fmts=yuva420p,fade=t=in:st=0:d=0.5:alpha=1[z];[fo]format=pix_fmts=yuva420p,fade=t=out:st=0:d=0.5:alpha=1[x];[z]fifo[w];[x]fifo[q];[q][w]overlay[r];[0c][r][1c]concat=n=3[outv]" -map "[outv]" -map 2:a -shortest -acodec copy -vcodec libx264 -preset ultrafast -b 15000k -aspect 1920:1080 fullgame_Output.mp4
P.S.
I already asked for help at an ffmpeg chat room. One guy said he knew what the problem was, but didnt know how to fix it(?):
[00:10] <kepstin> oh, wait, you're using -vcodec copy
[00:10] <kepstin> that explains everything.
[00:10] <kepstin> when you're using -vcodec copy, the start time (set with -ss) is rounded to the nearest keyframe
[00:10] <kepstin> it's not exact
[00:11] <kepstin> depending on the keyframe interval, this will result in possibly quite large shifts
[00:11] <kepstin> (also, your commands are applying audio filters on commands with -an, which is confusing/contradictory)
[00:12] <birdboy88> so the problem is that the audio temporary clips are not being extracted from the same excat timepoints?
[00:13] <kepstin> birdboy88: yeah, your audio is being re-encoded to wav so it's being cut sample-accurate, but the video's not being precisely cut.
[00:16] <birdboy88> kepstin: so I need to use slow seek (?) to extract video accurately? Or somehow extract audio only where there are video keyframes?
[00:17] <kepstin> birdboy88: i don't know how to extract audio starting at video keyframes with ffmpeg cli. You're already doing slow seek, which doesn't help (you should move the -ss option to before the -i option to speed it up)
[00:17] <kepstin> if you want accurate video cutting when saving to a file, you have to re-encode the video
[00:18] <kepstin> (doing this in a single ffmpeg command means you don't have to save to a file, so you can avoid the issue)
[00:18] * kepstin is off for a bit now
EDIT:
Everything is done with the latest ffmpeg version.
I was unable to get Gyan's code to work. It always loses some audio (audio is either 40.5 or 27.5, so only one audio is used). This is the only one working for me (changes were adelay=40500|40500 and amix=inputs=2[a0];[a0]loudnorm):
ffmpeg -i fullgame.mp4 -filter_complex "[0]split=2[vpre][vpost];
[0]asplit=2[apre][apost];
[vpre]trim=start='00:09:57':duration='00:00:41',setpts=PTS-STARTPTS[vpre-t];
[apre]atrim=start='00:09:57':duration='00:00:41',asetpts=PTS-STARTPTS,afade=t=out:st=40.5:d=0.5[apre-t];
[vpost]trim=start='00:15:45':duration='00:00:28',setpts=PTS-STARTPTS,format=yuva420p,fade=t=in:st=0:d=0.5:alpha=1,setpts=PTS+40.5/TB[vpost-t];
[apost]atrim=start='00:15:45':duration='00:00:28',asetpts=PTS-STARTPTS,afade=t=in:st=0:d=0.5,adelay=40500|40500[apost-t];
[vpre-t][vpost-t]overlay[v];
[apre-t][apost-t]amix=inputs=2[a0];[a0]loudnorm[a]" -map "[v]" -map "[a]" -y -c:v libx264 -preset ultrafast -b:v 15000k -aspect 1920:1080 -c:a aac fullgame_Output.mp4
Then I tried using a similar setup but with 3 clips, but on one machine I got error: "Error while filtering: Cannot allocate memory". And my 16 GB memory machine the processing speed is 0.02x! Any way to avoid this? This is the code I tried:
ffmpeg -i fullgame.mp4 -filter_complex "[0]split=3[vpre][vpost][v3];
[0]asplit=3[apre][apost][a3];
[vpre]trim=start=357:duration=41,setpts=PTS-STARTPTS[vpre-t];
[apre]atrim=start=357:duration=41,asetpts=PTS-STARTPTS,afade=t=out:st=40.5:d=0.5[apre-t];
[vpost]trim=start=795:duration=28,setpts=PTS-STARTPTS,format=yuva420p,fade=t=in:st=0:d=0.5:alpha=1,fade=t=out:st=40.5:d=0.5:alpha=1,setpts=PTS+40.5/TB[vpost-t];
[apost]atrim=start=795:duration=28,asetpts=PTS-STARTPTS,afade=t=in:st=0:d=0.5,afade=t=out:st=27.5:d=0.5,adelay=40500|40500[apost-t];
[v3]trim=start=95:duration=30,setpts=PTS-STARTPTS,format=yuva420p,fade=t=in:st=0:d=0.5,setpts=PTS+41+28-0.5/TB[v3-t];
[a3]atrim=start=95:duration=30,asetpts=PTS-STARTPTS,afade=t=in:st=0:d=0.5,adelay=68500|68500[a3-t];
[vpre-t][vpost-t]overlay[v1];
[v1][v3-t]overlay[v];
[apre-t][apost-t][a3-t]amix=inputs=3[a0];
[a0]loudnorm[a]" -map "[v]" -map "[a]" -y -c:v libx264 -preset ultrafast -b:v 15000k -aspect 1920:1080 -c:a aac fullgame_Output.mp4
Just do it in one command.
Besides the keyframe seek issue, which is true, your present sequence has an error in the last command. You have [0:v]trim=start=0.5...[0c] which trims out the first 0.5 seconds and will cause a desync of its own. Since this is the first clip, it should be [0:v]trim=0:40.5.
The full single command should be
ffmpeg -i fullgame.mp4 -filter_complex
"[0]split=2[vpre][vpost];[0]asplit=2[apre][apost];
[vpre]trim=start='00:09:57':duration='00:00:41',setpts=PTS-STARTPTS[vpre-t];
[apre]atrim=start='00:09:57':duration='00:00:41',asetpts=PTS-STARTPTS,afade=t=out:st=40.5:d=0.5[apre-t];
[vpost]trim=start='00:15:45':duration='00:00:28',setpts=PTS-STARTPTS,format=yuva420p,fade=t=in:st=0:d=0.5:alpha=1,setpts=PTS+40.5/TB[vpost-t];
[apost]atrim=start='00:15:45':duration='00:00:28',asetpts=PTS-STARTPTS,afade=t=in:st=0:d=0.5[apost-t];
[vpre-t][vpost-t]overlay[v];
[apre-t][apost-t]acrossfade=d=0.5,loudnorm,aresample=48000[a]"
-map "[v]" -map "[a]" -c:v libx264 -preset ultrafast -b:v 15000k -aspect 1920:1080 -c:a aac fullgame_Output.mp4
Your original sequence had -strict -2 for audio AAC encoding. That hasn't been needed since Dec 2015. You have a very old version of ffmpeg if your ffmpeg throws an error without it. Upgrade first.
I did not test the above with your file, as it will take too long to filter 16 min of Full HD 60 fps video, but I tested the below faster command and it works fine with the latest git build of ffmpeg:
ffmpeg -ss 00:09:57 -t 00:00:41 -i fullgame.mp4 -ss 00:15:45 -t 00:00:28 -i fullgame.mp4 -filter_complex
"[0]afade=t=out:st=40.5:d=0.5[apre-t];
[1]format=yuva420p,fade=t=in:st=0:d=0.5:alpha=1,setpts=PTS+40.5/TB[vpost-t];
[1]afade=t=in:st=0:d=0.5[apost-t];
[0][vpost-t]overlay[v];
[apre-t][apost-t]acrossfade=d=0.5,loudnorm,aresample=48000:ocl=stereo[a]"
-map "[v]" -map "[a]" -c:v libx264 -preset ultrafast -b:v 15000k -aspect 1920:1080 -c:a aac fullgame_Output.mp4

Sending BlackMagic DeckLink Studio 4K over RTMP streams with FFmpeg

I'm trying to send a stream of video that's coming into a BlackMagic DeckLink Studio 4K capture card over a few different RTMP streams at once with FFmpeg. The command that I am doing it with is this:
ffmpeg -re -format_code Hi59 -f decklink -i 'DeckLink Studio 4K' -map 0 -flags +global_header -vcodec libx264 -crf 25 -preset medium -pix_fmt yuv422p -acodec aac -f tee "[f=flv]rtmp://ip1/live/test|[f=flv]rtmp://ip2/live/test.
However, whenever I send this video out, I just get color bars when looking at the stream. I tried using a different video source (the testsrc supplied by FFmpeg), and that sends out fine over RTMP to multiple stream destinations.
Is there something weird with how tee and the decklink stuff work in FFmpeg? Or is there an issue with my command?
If you see colors bars, that means that ffmpeg is connecting to the card and streaming fine but the card is giving the bars. Your command says that ffmpeg is expecting 1920X1080#29.97 interlaced, make sure that is the format into the Decklink. You can also try explicitly setting the connection type, example:
ffmpeg -re -format_code Hi59 -video_input sdi -f decklink -i 'DeckLink Studio 4K' -map 0 -flags +global_header -vcodec libx264 -crf 25 -preset medium -pix_fmt yuv422p -acodec aac -f tee "[f=flv]rtmp://ip1/live/test|[f=flv]rtmp://ip2/live/test
If you are still running into issues, make sure that the BlackMagic software can see the video signal, and it's the format you expect.
One last thing to check, if its an HDMI input make sure it is not HDCP; it's not supported.

Transcoding FLV to MP4 with ffmpeg very slow

I am trying to support the recording of webcam video on our website, which I then need to transcode to MP4 and WebM to support HTML5 playback. I have ffmpeg 1.2 installed on our server, and have the whole process running fairly well.
The one problem I do have though is transcoding FLV to MP4. it is unacceptably slow, e.g. an 8 second FLV takes about 2.5 mins to transcode!
The ffmpeg command I am using is:
ffmpeg -y -i webcam.flv -c:a libfaac -ac 2 -b:a 64k -ar 44100 -c:v libx264 \
-b:v 350k webcam.mp4
There are so many ffmpeg params, I am a bit lost as to the best way forward with this issue. You can download a test flv from here:
dropbox.com/s/hhd6uhdiuhk800w/webcam.flv
By comparison, transcoding to WebM takes about 5 seconds:
ffmpeg -y -i webcam.flv -c:a libvorbis -ac 2 -b:a 64k -ar 44100 -c:v libvpx \
-b:v 350k -metadata:s:v:0 rotate=0 webcam.webm
ok i found the answer. i had a closer look at the ffmpeg output, and noticed:
[mp4 # 0xa0060c0] Frame rate very high for a muxer not efficiently supporting it.
Please consider specifying a lower framerate, a different muxer or -vsync 2
doh. so i added "-vsync 2" as the last parameter before the output file and it worked a charm, took transcoding time down to about 10 secs! very happy.
working out "generalised" ffmpeg settings for all types of a/v input still seems like black magic to me...

Resources