I use ffmpeg to merge mp4 and png, I use two way:
use command
String cmd = "-y -i " + in.mp4 + " -i " + in.png + " -filter_complex [0:v][1:v]overlay=0:0[out] -preset veryfast -map [out] -map 1:0 -map 0:0 -codec:a copy " + out.mp4;
output file missing audio:
use command:
String cmd = "-y -i " + in.mp4 + " -i " + in.png + " -filter_complex [0:v][1:v]overlay=0:0[out] -preset veryfast -map [out] -map 0:a -codec:a copy " + out.mp4;
=> There is audio but some mp4 file cannot merge with png file
Log: Stream map '0:a' matches no streams.
What is my command missing here ?
The first, you need use ffmpeg to check mp4 info. Then you will select command with 0:a or not
ffmpeg.execute(("-i " + filepath).split(" "), new ExecuteBinaryResponseHandler() {
boolean hasAudio = false;
#Override
public void onProgress(String s) {
if (s.matches("^\\s+Stream.+Audio.+")) {
hasAudio = true;
}
}
#Override
public void onFinish() {
}
});
You can do this with one command:
String cmd = "-y -i " + in.mp4 + " -i " + in.png + " \
-filter_complex [0:v][1:v]overlay=0:0[out] -preset veryfast \
-map [out] -map 0:a? -codec:a copy " + out.mp4;
The ? teels ffmpeg to only map the stream if it exists.
Related
I have a standard mp4 (audio + video)
I am trying to merge a 1.4 second mini mp4 clip into this track, replacing the video for the length of the mini clip but merging the audios together at a specific time
Would anyone know how to do this using ffmpeg?
I've tried quite a few different filters, however can't seem to get what I want
V <------->
miniclip.mp4 A <=======>
V <-----------> ↓ + ↓ <--->
standard.mp4 A <=========================>
Example to show miniclip.mp4 (1.4 seconds long) at timestamp 5.
ffmpeg -i main.mp4 -i miniclip.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
drawbox covers the main video with black. Only needed if miniclip.mp4 has a smaller width or height than main.mp4. You can omit it if miniclip.mp4 width and height is ≥ than main.mp4. Alternatively you could use the scale2ref filter to make miniclip.mp4 have the same width and height as main.mp4.
setpts add a 5 second offset to miniclip.mp4 video.
overlay overlays miniclip.mp4 video over main.mp4 video.
adelay adds a 5 second delay to miniclip.mp4 audio.
amix mixes miniclip.mp4 and main.mp4 audio.
More info
See FFmpeg Filter Documentation for info on each filter.
How to get video duration
Edited (now I understood the question):
First Get 1.4 seconds of standard.mp4 and audio1.mp3
-ss is the start for get the small video that will be 1.4 seconds of length (with -t option you can specify the duration, in this case 1.4 seconds) summary: cut video from min 5, 1.4 seconds
-an is for audio none copy, because you want to add a new audio1.mp3
video_only.mp4
ffmpeg -ss 00:05:00 -i standard.mp4 -t 1.4 -map 0:v -c copy -an small_only_video.mp4
audio_only.mp4
ffmpeg -ss 00:05:00 -i audio1.mp3 -t 1.4 -c copy small_only_audio.mp3
now you can to create a small_clip_audiovideo.mp4
ffmpeg -i small_only_video.mp4 -c:a mp3 -i small_only_audio.mp3 -c copy -map 0:v -map 1:a:0 -disposition:a:0 default -disposition:a:1 default -strict -2 -sn -dn -map_metadata -1 -map_chapters -1 -movflags faststart small_clip_audiovideo.mp4
V <------->
miniclip.mp4 A <=======>
V <-----------> ↓ + ↓ <------->
standard.mp4 A <=============================>
|--|--|--|--|--|--|--|--|--|--|
0 1 2 3 4 5 6 7 8 9 10
standard.mp4 have 10 seconds (aprox) of duration, have audio and video
miniclip.mp4 have 03 seconds (aprox) of duration, have video and audio
ffmpeg -i standard.mp4 |
} have same codes of video and audio?*
ffmpeg -i miniclip.mp4 |
if are not a same audio code or video code of files standard.mp4 and miniclip.mp4, you will be to recode for continue, if you want a good work.
ffmpeg -ss 00:00:00 -i standard.mp4 -t 4 -c copy 01.part_project.mp4
and 7 to 10, in 03.part_project.mp4
ffmpeg -ss 00:00:04.000 -i standard.mp4 -t 3.0000 -c copy 03.part_project.mp4
changue name or create a copy of miniclip.mp4 to 02.part_project.mp4
cp miniclip.mp4 02.part_project.mp4
(the part of 4 second to 7 seconds, of standard.mp4 will be used if you choice the OPTION 2 copy only the audio, santadard_part2_audio.mp4)
NOW THE OPTION N 1: IS TO CONTACT (UNITED) the 3 video parts
make a folder "option1" and copy 01.part_project.mp4 02.part_project.mp4 03.part_project.mp4
mkdir option1 && cp 01.part_project.mp4 02.part_project.mp4 03.part_project.mp4 ./option1 && cd ./option1
now you concat 01.part_project.mp4 + 02.part_project.mp4 + 03.part_project.mp4 into a unique file fin_option1.mp4
ffmpeg -f concat -safe 0 -i <(for f in ./*.mp4; do echo "file '$PWD/$f'"; done) -c copy fin_option1.mp4
V <------->
miniclip.mp4 A <=======>
V <-----------> ↓ + ↓ <------->
standard.mp4 A <============XXXXXXXXX========>
|--|--|--|--|--|--|--|--|--|--|
0 1 2 3 4 5 6 7 8 9 10
THE SECOND OPTION IS TO CONTACT (UNITED) the 3 video parts, BUT MIX
THE AUDIO OF miniclip.mp4 with santadard_part2_audio.mp4
get the audio stream from santadard_part2_audio.mp4 and get the audio
file only from miniclip.mp4
ffmpeg -i santadard_part2_audio.mp4 -map 0:a -c copy -vn -strict -2 mix_audio_santadad.mp4
ffmpeg -i miniclip.mp4 -map 0:a -c copy -vn -strict -2 mix_audio_miniclip.mp4
MIX ALL AUDIOS** IN ONE AND PUT THE VIDEO FROM miniclip.mp4
ffmpeg -i mix_audio_miniclip.mp4 -i mix_audio_santadad.mp4 -filter_complex amix=inputs=2:duration=longest -strict -2 audio_mixed_miniclip.mp4
get only video from miniclip.mp4
ffmpeg -i miniclip.mp4 -c copy -an miniclip_video.mp4
and get miniclip but with mixed audios, I think that it is the solution that you are looking for
ffmpeg -i miniclip_video.mp4 -i audio_mixed_miniclip.mp4 -c copy -map 0:v -map 1:a:0 -disposition:a:0 default -disposition:a:1 default -strict -2 -sn -dn -map_metadata -1 -map_chapters -1 -movflags faststart 02.part_project_OPTION2.mp4
santadard_part2_audio.mp4
+
audio_miniclip.mp4
V <------->
miniclip.mp4 A <MMMMMMMM> (audio miniclip mixed with standard.mp4)
V <-----------> ↓ + ↓ <------->
standard.mp4 A <============ ========>
|--|--|--|--|--|--|--|--|--|--|
0 1 2 3 4 5 6 7 8 9 10
make a folder "option2" and copy 01.part_project.mp4 02.part_project_OPTION2.mp4 03.part_project.mp4
mkdir option2 && cp 01.part_project.mp4 02.part_project_OPTION2.mp4 03.part_project.mp4 ./option2 && cd ./option2
ffmpeg -f concat -safe 0 -i <(for f in ./*.mp4; do echo "file '$PWD/$f'"; done) -c copy fin_option2.mp4
NOTES
** YOU CAN USE A LOT OF AUDIO MANIPULATIONS https://trac.ffmpeg.org/wiki/AudioChannelManipulation
I have five videos and want to combine them into one big "strip" with all five videos next to each other.
My code so far (following this example):
ffmpeg
-i s-0-h-0.mp4 -i s-1-h-0.mp4 -i s-2-h-0.mp4 -i s-3-h-0.mp4 -i s-4-h-0.mp4
-filter_complex "
nullsrc=size=4240x478 [base];
[0:v] setpts=PTS-STARTPTS, scale=848x478 [vid1];
[1:v] setpts=PTS-STARTPTS, scale=848x478 [vid2];
[2:v] setpts=PTS-STARTPTS, scale=848x478 [vid3];
[3:v] setpts=PTS-STARTPTS, scale=848x478 [vid4];
[4:v] setpts=PTS-STARTPTS, scale=848x478 [vid5];
[base][vid1] overlay=shortest=1 [tmp1];
[tmp1][vid2] overlay=shortest=1:x=848 [tmp2];
[tmp2][vid3] overlay=shortest=1:x=1696 [tmp3];
[tmp3][vid4] overlay=shortest=1:x=2544 [tmp4];
[tmp4][vid5] overlay=shortest=1:x=3392
"
-c:v libx264 output.mkv
However, this only includes the audio from input 1.
How do I keep the audio of all five input videos?
Add [0:a][1:a][2:a][3:a][4:a]amix=5
Refer Here for more context to my question: https://gamedev.stackexchange.com/questions/136817/how-to-get-sdl2-to-play-32bit-wav-files
I have a 24bit WAV file that has an Audio Format PCM of 1, refer here: http://soundfile.sapp.org/doc/WaveFormat/ to AudioFormat
When converting my WAV file (24bit) to 16 bit using: ffmpeg -i input.wav -ar 48000 -ac 2 -acodec pcm_s16le output.wav it retains the Audio Format PCM = 0x001.
When using ffmpeg -i input.wav -ar 48000 -ac 2 -acodec pcm_s32le output.wav the Audio Format PCM = 0xfffe.
SDL2 (as seen in the parent question) only allows files to play with Linear PCM Audio Format (1), and I am unsure how using sox or ffmpeg how to convert my 24bit WAV files upwards to 32bit (as SDL2 only plays 32bit and 16bit).
Is what I'm asking possible? Some more information on WAV files and why ffmpeg changes the header number would be greatly appreciated.
FFmpeg uses the following code to set the codec tag
...
waveformatextensible = (par->channels > 2 && par->channel_layout) ||
par->channels == 1 && par->channel_layout && par->channel_layout != AV_CH_LAYOUT_MONO ||
par->channels == 2 && par->channel_layout && par->channel_layout != AV_CH_LAYOUT_STEREO ||
par->sample_rate > 48000 ||
par->codec_id == AV_CODEC_ID_EAC3 ||
av_get_bits_per_sample(par->codec_id) > 16;
if (waveformatextensible)
avio_wl16(pb, 0xfffe);
...
A crude attempt would be to just replace the 2 bytes at 0x20 with 01 00 and try. If that doesn't work and this behaviour is out-of-spec then file a bug report.
for encoding a video in ffmpeg and stream to a server, i need to use the pipe "|" command to copy the video before re-encoding it and sending it to the server.
This command works perfectly in the shell :
./ffmpeg -f x11grab -s 640x480 -framerate 25 -i :0.0 -vcodec libx264 -framerate 25 -rtbufsize 2500k -s 640x480 -preset veryfast -pix_fmt yuv420p -crf 26 -force_key_frames 'expr:gte(t,n_forced*2) -minrate 850k -maxrate 850k -b:v 900k -bufsize 280k -f flv -
| ./ffmpeg -f flv -i - -c copy -f flv "rtmp://SERVER_ADRESS.twitch.tv/app/STREAM_KEY"
In the shell, i see the normal output of ffmpeg, wich contains multiple lines like this:
frame= 218 fps=0.0 q=-1.0 Lsize= 1860kB time=00:00:09.08 bitrate=1677.5kbits/s dup=1 drop=7 speed=11.2x
frame= 219 fps=0.0 q=-1.0 Lsize= 1860kB time=00:00:10.08 bitrate=1677.5kbits/s dup=1 drop=7 speed=11.2x
...
Now how to translate it to NODEJS with spawn ? If i do something like this :
var arguments = [
'-f', 'xgrab',
'-s', '640x480',
'-framerate', '25',
'-i', ':0.0',
'-vcodec', 'libx264',
'-framerate', '25'
'-rtbufsize', '2500k',
'-framerate', framerate,
'-s', '640x4',50
'-preset', 'veryfast',
'-pix_fmt', 'yuv420p',
'-crf', '26',
'-force_key_frames', 'expr:gte(t,n_forced*2)',
'-minrate', 850 +'k',
'-maxrate',850+'k',
'-b:v', 900+'k',
'-bufsize', 280+'k',
'-f', 'flv',
'-', '|',
'./ffmpeg', '-f','flv', '-i', '-',
'-c', 'copy',
'-f', 'flv', 'rtmp://SERVER_ADRESS.twitch.tv/app/STREAM_KEY'
]);
var childProcess = spawn(cmd, arguments);
childProcess.stdout.on('data', function(data){
console.log('stream: '+data.toString());
});
childProcess.stderr.on('data', function(data){
console.log('stream: '+data.toString());
});
I only get the output from the first part of the command, before the "|"
and the 2nd part never runs.
Also, i think something disastrous is happening in background because i get multiple instances of ffmpeg on my computer when i check the running processes.
The pipe is a shell construct, so you'll have to do something like:
spawn('/bin/sh', '-c', cmd_plus_arguments_and_pipes);
I have a video and an audio file. I'm trying joining them and slice a piece of video and it's working:
ffmpeg -ss 0:0:1.950 -i "video.avi" -ss 0:0:1.950 -i "audio.mp3" -target pal-dvd -bufsize 9175040 -muxrate 50400000 -acodec ac3 -ac 2 -ab 128k -ar 44100 -t 0:0:5.997 -y "output.mpg"
The problem is when I try resize the video using the -vf filter, example:
ffmpeg -ss 0:0:1.950 -i "video.avi" -ss 0:0:1.950 -i "audio.mp3" -vf scale="1024:420" -target pal-dvd -bufsize 9175040 -muxrate 50400000 -acodec ac3 -ac 2 -ab 128k -ar 44100 -t 0:0:5.997 -y "output.mpg"
It doesn't work because of the argument: -target pal-dvd. If I remove this argument, the video resize but doesn't keep the quality I want.
-target pal-dvd is equal to -c:v mpeg2video -c:a ac3 -f dvd -s 720x576 -r 25 -pix_fmt yuv420p -g 15 -b:v 6000000 -maxrate:v 9000000 -minrate:v 0 -bufsize:v 1835008 -packetsize 2048 -muxrate 10080000 -b:a 448000 -ar 48000. Your other options override these defaults, so you can simply use these options directly and remove the -s 720x576 and use your own size instead.
I'm not sure why you want to resize to 1024x420 and then use -target pal-dvd, but this option implies additional options. From ffmpeg_opt.c:
} else if (!strcmp(arg, "dvd")) {
opt_video_codec(o, "c:v", "mpeg2video");
opt_audio_codec(o, "c:a", "ac3");
parse_option(o, "f", "dvd", options);
parse_option(o, "s", norm == PAL ? "720x576" : "720x480", options);
parse_option(o, "r", frame_rates[norm], options);
parse_option(o, "pix_fmt", "yuv420p", options);
opt_default(NULL, "g", norm == PAL ? "15" : "18");
opt_default(NULL, "b:v", "6000000");
opt_default(NULL, "maxrate:v", "9000000");
opt_default(NULL, "minrate:v", "0"); // 1500000;
opt_default(NULL, "bufsize:v", "1835008"); // 224*1024*8;
opt_default(NULL, "packetsize", "2048"); // from www.mpucoder.com: DVD sectors contain 2048 bytes of data, this is also the size of one pack.
opt_default(NULL, "muxrate", "10080000"); // from mplex project: data_rate = 1260000. mux_rate = data_rate * 8
opt_default(NULL, "b:a", "448000");
parse_option(o, "ar", "48000", options);
Also, option placement matters. If you want to resize and use -target then place the filtering after -target. Note that this will probably resize twice.
Or omit -target and manually declare each option and modify them to your desired specifications.