ffmpeg to calculate audio/visual difference between compressed and non-compressed video - audio

I'm trying to calculate the audio + visual difference between a harshly compressed video file and one that hasn't been.
I'm using pipes because ultimately I wish this to take src from a camera stream.
I've managed to get the video results that I'm looking for, but I'm struggling with the audio.
I've added a line to invert the phase of the compressed audio, so that when they add up in the blend they should almost cancel each other out, but that doesn't happen.
ffmpeg -i input.avi -f avi -c:v libxvid -qscale:v 30 -c:a wmav1 - | \
ffmpeg -i - -f avi -af "aeval='-val(0)':c=same" - | \
ffmpeg -i input.avi -i - -filter_complex "blend=all_mode=difference" -c:v libx264 -crf 18 -f avi - | \
ffplay -
I can still hear all the audio, when what I should be hearing are solely compression artifacts. thx

To preface, I'm not sure your method would identify audio compression 'artifacts'
Your command doesn't perform any audio comparison, it only inverts a single channel. Also, the audio and video are compressed twice and the codecs the last ffmpeg command receives are the default AVI codecs of mpeg4 and mp3.
Use
ffmpeg -i input.avi -f matroska -c:v libxvid -qscale:v 30 -c:a wmav1 - |\
ffmpeg -i input.avi -i - -filter_complex "[0][1]blend=all_mode=difference;[1]aselect=gt(n\,0),asetpts=PTS-STARTPTS[1a];[0][1a]amerge,aeval=val(0)-val(1):c=mono" -c:v rawvideo -c:a pcm_s16le -f matroska - |\
ffplay -
I assume your audio is mono. If your audio has N channels, your aeval will need N expressions where the Mth expression is val(M-1)-val(N+M-1)
I also trim out the first encoded audio frame in order to mitigate encoder delay that Paul mentioned, and it seems to work here.

There might be some delay introduced with encoded audio samples. Also your command is incorrect.

Related

How do I convert wav into an mxf file with timecode?

I'm looking for a way to convert wav(16bit, 48kHz, LPCM) into an mxf file with timecode.
Since ffmpeg supports mxf, I'm trying, but I don't know the command.
ffmpeg -i ./input.wav [hh:mm:ss.ff, name1] [hh:mm:ss.ff, name2]... ./output.mxf
I'm expecting the above command, but does anyone know?
MXF is a pain
The default MXF muxer requires video.
The -timecode option with MXF requires video.
The mxf_opatom muxer allows just audio, but only mono with 48000 MHz sample rate, so each channel will need to be in its own MXF file.
Workaround 1: Pipe
ffmpeg -i input.wav -ar 48000 -c:a pcm_s16le -timecode 01:02:03:04 -f nut - | ffmpeg -i - -c:a pcm_s16le -f mxf_opatom output.mxf
I'm assuming your audio is mono (you didn't say what it is). If your input is multichannel then output each channel into its own file.
Use 01:02:03:04 for non-drop timecode, and 01:02:03.04 or 01:02:03;04 for drop.
Workaround 2: Dummy/blank video
Just ignore the video.
Non-drop timecode:
ffmpeg -f lavfi -i color=r=25 -i input.wav -timecode 01:02:03:04 -c:a copy -shortest output.mxf
Drop timecode:
ffmpeg -f lavfi -i color=r=30000/1001 -i input.wav -timecode 01:02:03.04 -c:a copy -shortest output.mxf

How to make FFmpeg automatically inject mp3 audio tracks in the single cycled muted video?

everybody here! So basically this is what I want to achieve:
I have a muted video about 3 minutes long.
I have a list of audio tracks in mp3 format (40 songs in a folder with duration 2 to 6 mins each one)
I want this video to play cycled automatically taking songs from playlist and injecting them to the video one by one. Every time a song finishes the next one from the list should start playing at the moment. Video continues playing and doesn't care duration of tracks.
I consider it as the first step on the way to broadcast radio with a video background on youtube in 24/7 mode with ability to put additional tracks to playlist without need to stop translation.
My problem is that I'm new in FFmpeg and I would appreciate any suggestions regarding which FFMpeg topic to start investigate with in order to achieve my goal
Use the concat demuxer
You can do live updates to the playlist for the concat demuxer, but each audio file must have the same attributes, the same number of streams, and all be the same format.
Create input.txt containing:
ffconcat version 1.0
file 'audio1.mp3'
file 'audio2.mp3'
file 'audio3.mp3'
file 'audio40.mp3'
All file names must be "safe" or it will fail with Unsafe file name. Basically no special characters in file names and only use absolute paths. See concat demuxer for more info.
Run ffmpeg to stream to YouTube:
ffmpeg -re -framerate 10 -loop 1 -i image.jpg -re -f concat -i input.txt -map 0:v -map 1:a -c:v libx264 -tune stillimage -vf format=yuv420p -c:a aac -g 20 -b:v 2000k -maxrate 2000k -bufsize 8000k -f flv rtmp://youtube
When you are ready to add new songs make temp.txt containing:
ffconcat version 1.0
file 'audio41.mp3'
file 'audio42.mp3'
file 'audio43.mp3'
Replace input.txt atomically:
mv temp.txt input.txt
See FFmpeg Wiki: Concatenate for lots more info.
If your audio files are not the same
The files listed in input.txt must all have the same:
Format (AAC, MP3, etc, but not mixed)
Sample rate (48000, 44100, etc)
Number of channels (mono, stereo, etc).
If they vary then you will have to pre-process them before adding them to the playlist. Bash example conforming each audio to stereo (-ac 2) with 44100 sample rate (-ar 44100) and save as AAC format in M4A container:
mkdir conformed
for f in *.mp3; do ffmpeg -i "$f" -map 0:a -ac 2 -ar 44100 -c:a aac "conformed/${f%.*}.m4a"; done
Outputting to AAC is recommended for streaming to YouTube.
If you do this then you can avoid re-encoding the audio in the ffmpeg command to YouTube. Just change -c:a aac to -c:a copy in step #2: Run ffmpeg to stream to YouTube.

Concat mp4 videos and merge their audios to the final output

I have several videos and photos and need to merge them with the cross-dissolve effect. The algorithm is next:
Create videos from images and add silent audio to them (so they will also have a sound stream):
ffmpeg -y -f lavfi -i anullsrc -loop 1 -i /tmp/media/import-2020-Aug-19-Wednesday-05-40-34/ea5c93fd-d946-4742-b8f7-ea9ae4d43441.jpg -c:v libx264 -t 10 -pix_fmt yuv420p -vf scale=750:1280 /tmp/media/import-2020-Aug-19-Wednesday-05-40-34/ea5c93fd-d946-4742-b8f7-ea9ae4d43441.mp4
Combine all the videos and audios into one using this command:
ffmpeg
-i /tmp/media/import-2020-Aug-19-Wednesday-05-40-34/temp_68d437c0-f5e2-4651-b07e-91533480b6ef.mp4
-i /tmp/media/import-2020-Aug-19-Wednesday-05-40-34/temp_48f3c111-610d-40c7-ac71-6ce2fbb16184.mp4
-i /tmp/media/import-2020-Aug-19-Wednesday-05-40-34/temp_1593b5d8-7e16-417d-9372-2267581cd504.mp4
-i /tmp/media/import-2020-Aug-19-Wednesday-05-40-34/temp_1ac7f6be-1b12-4e31-b904-1491cc9b9494.mp4
-i /tmp/media/import-2020-Aug-19-Wednesday-05-40-34/temp_ea5c93fd-d946-4742-b8f7-ea9ae4d43441.mp4
-filter_complex
"[0:v]trim=start=0:end=8.032,setpts=PTS-STARTPTS[clip0];
[1:v]trim=start=2:end=13.047,setpts=PTS-STARTPTS[clip1];
[2:v]trim=start=2:end=13.558,setpts=PTS-STARTPTS[clip2];
[3:v]trim=start=2:end=13.186,setpts=PTS-STARTPTS[clip3];
[4:v]trim=start=2,setpts=PTS-STARTPTS[clip4];
[0:v]trim=start=9.032:end=10.032,setpts=PTS-STARTPTS[out0];
[1:v]trim=start=14.047:end=15.047,setpts=PTS-STARTPTS[out1];
[2:v]trim=start=14.558:end=15.558,setpts=PTS-STARTPTS[out2];
[3:v]trim=start=14.186:end=15.186,setpts=PTS-STARTPTS[out3];
[1:v]trim=start=0:end=2,setpts=PTS-STARTPTS[in1];
[2:v]trim=start=0:end=2,setpts=PTS-STARTPTS[in2];
[3:v]trim=start=0:end=2,setpts=PTS-STARTPTS[in3];
[4:v]trim=start=0:end=2,setpts=PTS-STARTPTS[in4];
[in1]format=pix_fmts=yuva420p,fade=t=in:st=0:d=2:alpha=1[fadein1];
[in2]format=pix_fmts=yuva420p,fade=t=in:st=0:d=2:alpha=1[fadein2];
[in3]format=pix_fmts=yuva420p,fade=t=in:st=0:d=2:alpha=1[fadein3];
[in4]format=pix_fmts=yuva420p,fade=t=in:st=0:d=2:alpha=1[fadein4];
[out0]format=pix_fmts=yuva420p,fade=t=out:st=0:d=2:alpha=1[fadeout0];
[out1]format=pix_fmts=yuva420p,fade=t=out:st=0:d=2:alpha=1[fadeout1];
[out2]format=pix_fmts=yuva420p,fade=t=out:st=0:d=2:alpha=1[fadeout2];
[out3]format=pix_fmts=yuva420p,fade=t=out:st=0:d=2:alpha=1[fadeout3];
[fadein1]fifo[fadein1fifo];
[fadein2]fifo[fadein2fifo];
[fadein3]fifo[fadein3fifo];
[fadein4]fifo[fadein4fifo];
[fadeout0]fifo[fadeout0fifo];
[fadeout1]fifo[fadeout1fifo];
[fadeout2]fifo[fadeout2fifo];
[fadeout3]fifo[fadeout3fifo];
[fadeout0fifo][fadein1fifo]overlay[crossfade0];
[fadeout1fifo][fadein2fifo]overlay[crossfade1];
[fadeout2fifo][fadein3fifo]overlay[crossfade2];
[fadeout3fifo][fadein4fifo]overlay[crossfade3];
[clip0][crossfade0][clip1][crossfade1][clip2][crossfade2][clip3][crossfade3][clip4]concat=n=9[output];
[0:a][1:a]acrossfade=d=10:c1=tri:c2=tri[A1];
[A1][2:a]acrossfade=d=10:c1=tri:c2=tri[A2];
[A2][3:a]acrossfade=d=10:c1=tri:c2=tri[A3];
[A3][4:a]acrossfade=d=10:c1=tri:c2=tri[audio] "
-vsync 0 -map "[output]" -map "[audio]" /tmp/media/final/some_filename_d0d2aab0-792a-4540-b2d3-e64abe98bf5c.mp4
And all works pretty well, but if I have, for example:
picture
video
video
picture
Then the sound from the second video is mapping to the first picture and sound from the third video to second video. And the third video actually goes without sound.
It seems like it's happening because the silent sound of the first picture is pretty short. An I right?
If so, how can I increase its duration?
I would much appreciate any help with this!
Assuming 5 inputs of 10 seconds each, all with audio streams*, with ffmpeg 4.3 or newer, use the xfade and acrossfade filters.
ffmpeg
-i in1.mp4
-i in2.mp4
-i in3.mp4
-i in4.mp4
-i in5.mp4
-filter_complex
" [0][1]xfade=transition=fade:duration=2:offset=8[V01];
[V01][2]xfade=transition=fade:duration=2:offset=16[V02];
[V02][3]xfade=transition=fade:duration=2:offset=24[V03];
[V03][4]xfade=transition=fade:duration=2:offset=32[video];
[0:a][1:a]acrossfade=d=2:c1=tri:c2=tri[A01];
[A01][2:a]acrossfade=d=2:c1=tri:c2=tri[A02];
[A02][3:a]acrossfade=d=2:c1=tri:c2=tri[A03];
[A03][4:a]acrossfade=d=2:c1=tri:c2=tri[audio]"
-vsync 0 -map "[video]" -map "[audio]" out.mp4
*if there's no existing audio stream, add one using the command in step 1.
If the existing audio stream of a file isn't 10 seconds long, use these filters on it before acrossfade.
[input]aresample=async=1:first_pts=0,apad,atrim=0:10[filtered]
and then use this filtered stream as input.

How do I use ffmpeg to merge all audio streams (in a video file) into one audio channel?

I am attempting to use ffmpeg for a number of files.
The actual number of audio streams (there is usually one channel per stream) per file isn't known until I'm using ffmpeg.
The desired outcome is to somehow have ffmpeg get the count of audio channel, use the number in the command line to amerge those into one single audio channel.
The goal is to create a preview version of the original video file for use in a simple HTML5 page.
Is this possible in just one call to ffmpeg?
(Also, apologies as some parts of this problem I'm still learning about)
Edit:
Dumas stackoverflow asker here.
Yes, I've been trying multiple combinations of ffmpeg args.
To answer the other question, we have video files that have multiple streams, usually with single channels.
I'll post some cmdline examples shortly.
This cmdline example kind of does what I want; there are 8 streams, and I'm able to combine all audio into one. THe issue is having to know the number before running ffmpeg:
ffmpeg -i EXAMPLE.MOV -filter_complex "[0:v]scale=-2:720,format=yuv420p[v];[0:a]amerge=inputs=8[a]" -map "[v]" -map "[a]" -c:v libx264 -crf 23 -preset medium -c:a libmp3lame -ar 44100 -ac 2 OUTPUT.mov
You can use ffprobe to find the number of audio streams and use the output as a variable in your ffmpeg command. Bash example using wc to count the audio streams listed by ffprobe:
ffmpeg -i input.mov -filter_complex "[0:v]scale=-2:720,format=yuv420p[v];[0:a]amerge=inputs=$(ffprobe -loglevel error -select_streams a -show_entries stream=codec_type -of csv=p=0 input.mov | wc -l)[a]" -map "[v]" -map "[a]" -c:v libx264 -crf 23 -preset medium -c:a libmp3lame -ar 44100 -ac 2 output.mov
The following command should do the same thing as llogan's answer but doesn't recompress the video track and requires you to identify how many audio tracks should be merged together.
If you want to know how many audio streams are present, try:
ffprobe originalfile.mov 2>&1 | grep 'Stream #'
Once you have identified how many audio streams should be merged, use that number in the amerge=inputs=2 parameter here. This command will merge the streams into one and recompress the audio using aac compression.
ffmpeg -i originalfile.mov -c:v copy -c:a aac -b:a 160k -ac 2 -filter_complex amerge=inputs=2 output.mp4

ffmpeg - Have troubling syncing up audio and video together

I have a webcam and a separate mic. I want to record what is happening.
It almost works, however the audio seems to play quickly and parts missing while playing over the video.
This is the command I am currently using to get it partially working
ffmpeg -thread_queue_size 1024 -f alsa -ac 1 -i plughw:1,0 -f video4linux2 -thread_queue_size 1024 -re -s 1280x720 -i /dev/video0 -r 25 -f avi -q:a 2 -acodec libmp3lame -ab 96k out.mp4
I have tried other arguments, but unsure if it has to do with the formats I am using or incorrect parameter settings.
Also, the next part would be how to stream it. Everytime I try going through rtp it complains about multiple streams. I tried doing html as well, but didn't like the format. html html://localhost:50000/live_feed or rts rts://localhost:5000
edit:
I am running this on a rpi 3.

Resources