FFMPEG reducing Generation Loss when inserting many videos into another video - audio

I am trying to insert many miniclips.mp4 into a main.mp4 video - Although I have been able to do this using this solution, I seem to suffer from Generation Loss
The command I am using (within a python script, in a loop at many different intervals) is:
ffmpeg -i main.mp4 -i miniclipX.mp4 -filter_complex "[0:v]drawbox=t=fill:enable='between(t,5,6.4)'[bg];[1:v]setpts=PTS+5/TB[fg];[bg][fg]overlay=x=(W-w)/2:y=(H-h)/2:eof_action=pass;[1:a]adelay=5s:all=1[a1];[0:a][a1]amix" output.mp4
(Then renaming output.mp4 to main.mp4 within a loop)
Would there be anyway to either:
A) Reduce generation loss by implementing certain flags
or
B) Include many different input files and many different -filter_complex's in a singular command to achieve what I am after?

Because you did not provide the ffmpeg log (and therefore there is no info about your ffmpeg or your inputs), for this answer I'll assume all videos are the same width and height.
Example to show miniclip1.mp4 at 5 seconds and miniclip2.mp4 at 10 seconds:
ffmpeg -i main.mp4 -i miniclip1.mp4 -i miniclip2.mp4 -filter_complex
"[1:v]setpts=PTS+5/TB[offset1];[0:v][offset1]overlay=x=(W-w)/2:y=(H-h)/2:eof_action=pass[bg];
[2:v]setpts=PTS+10/TB[offset2];[bg][offset2]overlay=x=(W-w)/2:y=(H-h)/2:eof_action=pass;
[1:a]adelay=5s:all=1[a1];
[2:a]adelay=10s:all=1[a2];
[0:a][a1][a2]amix=inputs=3"
output.mp4
Command was broken into multiple lines so it is easier to read. Make it one line when executing.

Related

Beeping out portions of an audio file using ffmpeg

I'm trying to use ffmpeg to beep out sections of an audio file (say 10-15 and 20-30). However only the first portion(10-20) gets beeped, whilst the next portion gets muted.
ffmpeg -i input.mp3 -filter_complex "[0]volume=0:enable='between(t,10,15)+between(t,20,30)'[main];sine=d=5:f=800,adelay=10s,pan=stereo|FL=c0|FR=c0[beep];[main][beep]amix=inputs=2" output.wav
Using this as my reference, but not able to make much progress.
Edit : Well, sine=d=5 clearly mentions the duration as 5 (my bad). Seems like this command can be used to add beeping to only one specific portion, how can I possibly change it to add beeps to different sections with varying durations.
ffmpeg -i input.mp3 -af "volume=enable='between(t,5,10)':volume=0[main];sine=d=5:f=800,adelay=5s,pan=stereo|FL=c0|FR=c0[beep];[main][beep]amix=inputs=2,
volume=enable='between(t,15,20)':volume=0[main];sine=d=5:f=800,adelay=15s,pan=stereo|FL=c0|FR=c0[beep];[main][beep]amix=inputs=2, volume=enable='between(t,40,50)':volume=0[main];sine=d=10:f=800,adelay=40s,pan=stereo|FL=c0|FR=c0[beep];[main][beep]amix=inputs=2" output.wav
The above code beeps 5-10, 15-20 and 40-50
This seems to work. Separating the different beeping settings with a ,(comma) and making changes at all 3 places: between, sine=d=x where x seems to be the duration and adelay=ys where y is the delay, meaning when the beeping starts. So between would be (t, y, y+x).
References : Mute specified sections of an audio file using ffmpeg and FFMPEG:Adding beep sound to another audio file in specific time portions
Would love to know a more easier/convenient way of doing this. So I'm not marking this as an answer.

Mixing various audio and video sources into a single video

I've already read FFmpeg - Overlay one video onto another video?, How to overlay 2 videos at different time over another video in single ffmpeg command?, FFmpeg - Multiple videos with 4 areas and different play times (and many similar questions tagged [ffmpeg] about setpts), and the following code is working, but I'm sure we can simplify it, and have a more elegant solution.
I'd like to mix multiple sources (image and sound) , with different starting points:
t (seconds) 0 1 2 3 4 5 6 7 8 9 10 11 12 13
test.png [-------------------------------]
a.mp3 [-------]
without_sound.mp4 [-------------------] (overlay at x,y=200,200)
b.mp3 [---]
with_sound.mp4 [---------------------------------------] (overlay at x,y=100,100)
This works:
ffmpeg -i test.png
-t 2 -i a.mp3
-t 5 -i without_sound.mp4
-t 1 -i b.mp3
-t 10 -i with_sound.mp4
-filter_complex "
[0]setpts=PTS-STARTPTS[s0];
[1]adelay=2000^|2000[s1];
[2]setpts=PTS-STARTPTS+7/TB[s2];
[3]adelay=5000^|5000[s3];
[4]setpts=PTS-STARTPTS+3/TB[s4];
[4:a]adelay=3000^|3000[t4];
[s1][s3][t4]amix=inputs=3[outa];
[s0][s4]overlay=100:100[o2];
[o2][s2]overlay=200:200[outv]
" -map [outa] -map [outv]
out.mp4 -y
but:
is it normal that we have to use both setpts and adelay? I have tried without adelay and then the sound is not shifted. Said differently, is there a way to simplify:
[4]setpts=PTS-STARTPTS+3/TB[s4];
[4:a]adelay=3000^|3000[t4];
?
is there a way to do it with setpts and asetpts only? When I replaced adelay=5000|5000 with asetpts=PTS-STARTPTS+5/TB and also for the other one, it didn't give the expected time-shifting (see below)
in similar questions/answers I often see overlay=...:enable='between(t,...,...)', here it seems it is not needed, why?
More generally, how would you simplify this "mix multiple audio and video" ffmpeg code?
More details about the second bullet point: if we replace adelay by asetpts,
-filter_complex "
[0]setpts=PTS-STARTPTS[s0];
[1]asetpts=PTS-STARTPTS+2/TB[s1];
[2]setpts=PTS-STARTPTS+7/TB[s2];
[3]asetpts=PTS-STARTPTS+5/TB[s3];
[4]setpts=PTS-STARTPTS+3/TB[s4];
[4:a]asetpts=PTS-STARTPTS+3/TB[t4];
[s1][s3][t4]amix=inputs=3[outa];
[s0][s4]overlay=100:100[o2];
[o2][s2]overlay=200:200[outv]
it doesn't work: [3] should begin at 0'05", and [4:a] at 0'03" but they all begin at the same time than [1], i.e. at 0'02".
It seems that amix only takes the first asetpts in consideration, and discards the others; is it true?
is it normal that we have to use both setpts and adelay?
Yes, the former is for video streams; the latter, for audio. asetpts is not suitable for use with amix since the latter ignores starting time offsets. adelay fills in with silence from 0 to the desired offset.
I often see overlay=...:enable='between(t,...,...)', here it seems it is not needed, why?
Overlay syncs its main and overlay video frames by timestamps. enable is needed if one wishes to disable overlay when synced frames are available for both inputs.

How to divide my video horizontally using ffmpeg (without any other side-effects)?

I am processing my video(640 X 1280 dimensions). I want to divide my video horizontally into 2 separate videos(each video will now be 640 X 640 in dimensions),then combine them horizontally (video dimension will be now 1280 X 640)in a single video. I did the research on the internet and my issue was solved and not solved at the same time
I made a batch file and add these commands in it:-
ffmpeg -i input.mp4 -filter_complex "[0]crop=iw:ih/2:0:0[top];[0]crop=iw:ih/2:0:oh[bottom]" -map "[top]" top.mp4 -map "[bottom]" bottom.mp4
ffmpeg -i top.mp4 -i bottom.mp4 -filter_complex hstack output.mp4
Yes,my task got solved but many other issues also came out of it:-
1.) My output video has NO audio in it. No idea why there is no audio in the end results
2.) My main video file (on which I am doing all this) is 258 MB in size. But the result was only 38 MB in size. No idea what is happening? And even worse,I closely looked at the video,results were pretty same (only animation were not as smooth in output file as compared to input file)
3.) It is taking too much time(I know that computing takes some time but maybe there may be some way/sacrifice to make the process much quicker)
Thanks in advance for helping me
Combine your two commands
ffmpeg -i input.mp4 -filter_complex "[0]crop=iw:ih/2:0:0[top];[0]crop=iw:ih/2:0:oh[bottom];[top][bottom]hstack" -preset fast -c:a copy output.mp4
If you need it to encode faster then use a faster -preset as shown in FFmpeg Wiki: H.264.
x264 is a better encoder than your phone so it is not surprising that the file size is smaller.
Or use your player to do it
No need to wait for encoding. Just have your player do everything upon playback. This does not output a file, but only plays the re-arranged video. Example using mpv:
mpv --lavfi-complex="[vid1]split[v0][v1];[v0]crop=iw:ih/2:0:0[c0];[v1]crop=iw:ih/2:0:oh[c1];[c0][c1]hstack[vo]" input.mp4

Using "volume" argument in ffmpeg volume audio filter

I wish to "silence" the background noise in an audio, without removing the silence entirely - so as to keep the length of the audio constant. I am trying to use volume filter in ffmpeg like
ffmpeg -i input.flac -filter:a "volume='if(lt(volume,-8dB),0,1)':eval=frame" output.flac
but this seems to output the same file as input. I checked this by seeing the volumedetect output and it is identical for input.flac and output.flac.
I am new to ffmpeg so sorry if this is preliminary; quick help or pointers to relevant examples appreciated. Thanks!

demultiplexing UDP/RTP multi program transport streams

I'm dealing with UDP/RTP multi program transport streams with Directshow.
I wish to decode in a single graph the audio channels brought by different programs.
How can I configure the Demultiplexer in order to achieve this?
Using GraphEdit, the basic graph composed by:
Network receiver ---> MS Demultiplexer ---> PSI parser
allows me to see the program list and audio/video channels associated to each program.
If I select program, audio and video PIDs in PSI parser properties, the contents are rendered.
Now, how can I render multiple channels from different programs at the same time, in the same graph?
I tried:
1) via PSI parser properties dialog. The 1st configured is OK, but as I configure the 2nd audio/video/program, the old content rendering is replaced by the new configuration. Building a graph via API with this approach brings the same result: only the 1st configuration works. If I add other pins, I can render contents only if the configuration is the same as the 1st pin. If the audio/video PID belongs to a different program, it is not rendered.
2) cascading two (or more) Demuxes, configuring the 1st to forward packets belonging to the specific program and the 2nd to extract audio and video from the stream received. For this configuration, output pin media type = "transport stream", mapped to "Transport packet (complete)"; the PID is the program PID identified by PSI parser.
Result: the graph runs, but I got a black window and no audio.
Can you help, please?
How about adding a tee filter after the demux and then adding multiple parsers to the output pins from the tee? I think that might work.
The way I do it now is I use ffmpeg and generate multiple outputs. Then use separate FFmpeg instances to encode those streams separately. The only possible issue is that I use Linux and this may not be ideal for other operating systems.
Here is the master FFmpeg command:
/usr/bin/ffmpeg -f mpegts -i "udp://#server_ip:8080?overrun_nonfatal=1&reuse=1" \
-map 0:p:1 -copyinkf -vcodec copy -acodec copy -f mpegts "udp://server_ip:8001" \
-map 0:p:2 -copyinkf -vcodec copy -acodec copy -f mpegts "udp://server_ip:8002" \
...
-map 0:p:10 -copyinkf -vcodec copy -acodec copy -f mpegts "udp://server_ip:8010"
Then you can have single FFmpeg instances running something like this:
/usr/bin/ffmpeg -i "udp://#server_ip:8001" -vcodec libx264 -acodec libmp3lame -f mpegts rtmp://other_server:port
Hope this helps put someone in the right direction. I wish it were this simply explained when I needed help.

Resources