How to script this, so output is used as input? - linux

I would like to script this command
ffmpeg -i concat:file1.mp3\|file2.mp3 -acodec copy output.mp3
which merges file1.mp3 and file2.mp3 to become output.mp3.
The problem is that I have a lot more than 2 files that I would like to merge.
Example
ffmpeg -i concat:file1.mp3\|file2.mp3 -acodec copy output1.mp3
ffmpeg -i concat:output1.mp3\|file3.mp3 -acodec copy output2.mp3
ffmpeg -i concat:output2.mp3\|file4.mp3 -acodec copy output3.mp3
ffmpeg -i concat:output3.mp3\|file5.mp3 -acodec copy output4.mp3
output4.mp3 is the result I am looking for.
The files are not actually nicely called "file" adn then a number, but ls lists them in the order they should be merged in.
Question
How can this be scripted, so I can execute it in a directory with either an even or odd number of files?

if ffmpeg supports more then two files and no file contains |, and there are not too many, you can do:
ffmpeg -i concat:"$(ls|tr '\n' '|')" -acodec copy out.mp3
if not:
for cfile in *.mp3; do
ffmpeg -i concat:myout.mp3tmp1\|$cfile -acodec copy myout.mp3tmp2
mv myout.mp3tmp2 myout.mp3tmp1
done
mv myout.mp3tmp1 <your final file name>

If you can just concatenate all files in one wash, that'd be best. But a generic answer for your Bash question:
ffmpeg -i concat:file1.mp3\|file2.mp3 -acodec copy output1.mp3
for i in $(seq 1 10); do
ffmpeg -i concat:output${i}.mp3\|file$((i + 2)).mp3 -acodec copy output$((i + 1)).mp3
done
Here 10 is two less than your total number of input files.

Related

ffmpeg split | merge video voice not sync

there are what i done:
download a full mp4 file.
due to it's watermark(0s-10s), i split the full video into 2 parts from 10second. the first part with watermark.
use ffmpeg delogo the first part.
merge the two video into a full again.
wget -O download.mp4
ffmpeg -i download.mp4 -vcodec copy -acodec copy -t 00:00:10 tmp1.mp4
ffmpeg -i download.mp4 -vcodec copy -acodec copy -ss 00:00:10 tmp2.mp4
ffmpeg -i tmp1.mp4 -vf "delogo=x=432:y=44:w=1060:h=108" -c:a copy tmp3.mp4
echo file tmp3.mp4 > mergelist.txt && echo file tmp2.mp4 >> mergelist.txt
ffmpeg -f concat -i mergelist.txt -c copy output.mp4
problem i faced:
in the last merged video, only one tmp part is fine, the other's video and voice not sync and play time more faster than before.
why i divide it, delogo(although only the first 10 seconds shows) full video more than 1h, re-encode takes much time, 10s part fine to me.
Have you tried this?
ffmpeg -i download.mp4 -vf "delogo=enable='lte(t,10)':x=432:y=44:w=1060:h=108" -c:a copy output.mp4
I'm assuming delogo filter is timeline editing enabled.

Generate new video from selected seconds of a longer video

I try to generate a shorter version of a 10min original videofile.mp4 that includes only four 10s subclips of the original file (i.e. from seconds 10 to 20;197 to 207;393 to 403;570 to 580). So far I could only generate 4 new files copying both video and audio:
ffmpeg -i videofile.mp4 -vcodec copy -acodec copy -ss 10 -to 20 videofile1.mp4 -vcodec copy -acodec copy -ss 197 -to 207 videofile2.mp4 -vcodec copy -acodec copy -ss 393 -to 403 videofile3.mp4 -vcodec copy -acodec copy -ss 570 -to 580 videofile4.mp4
However, I am having deep trouble in concatenating those 4 subclips to generate the desired 40seconds out_videofile.mp4. I found this alternative approach using the "select" command in ffmpeg which saves me of my "failed" concatenation process. So far I have:
ffmpeg -i videofile.mp4 -vf "select='between(t,10,20)+between(t,197,207)+between(t,393,403)+between(t,570,580)',setpts=N/FRAME_RATE/TB" -af "aselect='between(t,10,20)+between(t,197,207)+between(t,393,403)+between(t,570,580)" out_videofile.mp4
I guess this last code should give me the 40s out_videofile.mp4 I want. However, it gives me a "SyntaxError: invalid syntax". Any idea where I go wrong?
Thanks for your time anyways.
You're missing a closing quote, but also a filter for smoothing the audio timestamps.
Use
ffmpeg -i videofile.mp4 -vf "select='between(t,10,20)+between(t,197,207)+between(t,393,403)+between(t,570,580)',setpts=N/FRAME_RATE/TB" -af "aselect='between(t,10,20)+between(t,197,207)+between(t,393,403)+between(t,570,580)',asetpts=N/SR/TB" out_videofile.mp4

Passing spaces conteined string to script

I use such small script to convert videos from my SAT receiver to h264/mp3 format.
[maciek#piotr Pobrane]$ cat ./conv_sat_to_clean_ts
#!/bin/bash
ffmpeg -i $1.ts -movflags +faststart -vcodec h264 -acodec mp3 -f mpegts $1-new.ts
The problem is that when I call that script in such way:
./conv_sat_to_clean_ts ./Operacja\ Dunaj.ts
it shows me an error:
./Operacja: No such file or directory
So that means that spaces included in call parameters are ignored and filename is not interpreted correctly.
Is any way to resolve that problem?
Give $1 in double quotes since filename has space.
ffmpeg -i "$1".ts -movflags +faststart -vcodec h264 -acodec mp3 -f mpegts "$1"-new.ts
and run the script without .ts
./conv_sat_to_clean_ts ./Operacja\ Dunaj
or
./conv_sat_to_clean_ts "Operacja Dunaj"
Yes. RBH was right. Now my script looks like this and work properly.
#!/bin/bash
ffmpeg -i "$1" -movflags +faststart -vcodec h264 -acodec mp3 -f mpegts NEW-"$1"
And spaces in filenames (as script call parameter) are interpreted correctly

How to tell ffmpeg to loop through all files in directory in order

ffmpeg has concat option for this but all streams start working really bad and breaking sound after a day of streaming.
I tried looking at loops but i couldnt figure out how to execute a loop with ffmpeg command so it transcodes all files in 1 directory
/lely/ffmpeg -y -re -i /home/ftp/kid1.mp4 -vcodec copy -acodec copy -dts_delta_threshold 1000 -ar 44100 -ab 32k -f flv rtmp://10.0.0.17:1935/live/kid
In folder /home/ftp/ there are files kid1, kid2, kid3 - all *.mp4 files
So basically i would like a loop to change the input to next file every time previous ends.
Maybe you could use find and xargs to help you feed the files for ffmpeg:
find /home/ftp -name "*.mp4" | xargs -I $ /lely/ffmpeg -y -re -i $ -vcodec copy -acodec copy -dts_delta_threshold 1000 -ar 44100 -ab 32k -f flv rtmp://10.0.0.17:1935/live/kid
Here you first ask find to look for all mp3 files in /home/ftp.
Then you feed the results to xargs. For xargs you tell it to replace input it receives with token $ in your ffmpeg string.
You can concatenate the video files to a "named pipe" and use the pipe as a source for ffmpeg.
For example:
mkfifo pipeFile # create a FIFO file (named pipe)
cat $(find /home/ftp -name "*.mp4") > pipeFile & # concatenate video files do the pipe (do not forget the "&" for running in background)
/lely/ffmpeg -y -re -i pipeFile -vcodec copy -acodec copy -dts_delta_threshold 1000 -ar 44100 -ab 32k -f flv rtmp://10.0.0.17:1935/live/kid # run ffmpeg with the pipe as the input
Notes:
The order of files in the input will be that the find generates. You can add a "sort" command after the find to produce files in a sorted manner.
I have not tested this, since a I do not have ffmpeg installed. However, it should work :-)

ffmpeg correct audio streams when appending

I am appending 2 mp4 files together using the following routine:
ffmpeg -y -i one.mp4 -vcodec copy -vbsf h264_mp4toannexb -acodec copy one.ts
ffmpeg -y -i two.mp4 -vcodec copy -vbsf h264_mp4toannexb -acodec copy two.ts
cat one.ts two.ts >> joined.ts
ffmpeg -y -i joined.ts -vcodec copy -acodec copy -absf aac_adtstoasc joined.mp4
This works fine, however when one.mp4 has no audio stream (the file is created using ffmpeg from a single jpeg, so no sound), the routine appends the files but the audio of two.mp4 starts at the beginning of the video. how should I solve this problem? Should I add switches to my append routine so that the audio in two.mp4 starts playing where it should, or should I add something to the ffmpeg command which creates the video from jpg?
here is the command I use to create one.mp4 which contains no sound:
ffmpeg -y -loop 1 -i blah.jpg -t 3 -vcodec libx264 one.mp4

Resources