ffmpeg concatenate with dynamic chunks - linux

The ffmpeg docs for concat lists the following way
ffmpeg -f concat -i mylist.txt -c copy output
The mylist.txt file contains file like
file '/path/to/file1'
file '/path/to/file2'
file '/path/to/file3'
What I am looking is for a way to do this concat in a persistent way where the number of files can keep increasing, for example in livestreaming
I will be sending chunks of video (mp4 files) of 10 seconds each to my server and want to concat/stitch them together to output to a RTMP stream (for livestreaming)
If concat is not the proper way to do this, please suggest alternatives.
Really interested to know how people use the above concept (I hope its how it works) to send video chunks from mobile device for livestreaming

The ffmpeg docs have an example that does exactly what you're asking: https://trac.ffmpeg.org/wiki/Concatenate
This is their example:
#!/bin/bash
fn_concat_init() {
echo "fn_concat_init"
concat_pls=`mktemp -u -p . concat.XXXXXXXXXX.txt`
concat_pls="${concat_pls#./}"
echo "concat_pls=${concat_pls:?}"
mkfifo "${concat_pls:?}"
echo
}
fn_concat_feed() {
echo "fn_concat_feed ${1:?}"
{
>&2 echo "removing ${concat_pls:?}"
rm "${concat_pls:?}"
concat_pls=
>&2 fn_concat_init
echo 'ffconcat version 1.0'
echo "file '${1:?}'"
echo "file '${concat_pls:?}'"
} >"${concat_pls:?}"
echo
}
fn_concat_end() {
echo "fn_concat_end"
{
>&2 echo "removing ${concat_pls:?}"
rm "${concat_pls:?}"
# not writing header.
} >"${concat_pls:?}"
echo
}
fn_concat_init
echo "launching ffmpeg ... all.mkv"
timeout 60s ffmpeg -y -re -loglevel warning -i "${concat_pls:?}" -pix_fmt yuv422p all.mkv &
ffplaypid=$!
echo "generating some test data..."
i=0; for c in red yellow green blue; do
ffmpeg -loglevel warning -y -f lavfi -i testsrc=s=720x576:r=12:d=4 -pix_fmt yuv422p -vf "drawbox=w=50:h=w:t=w:c=${c:?}" test$i.mkv
fn_concat_feed test$i.mkv
((i++));
echo
done
echo "done"
fn_concat_end
wait "${ffplaypid:?}"
echo "done encoding all.mkv"

I try to concatenate several webm files with command below and it works (in my case)
ffmpeg -i chunk.1.webm -i chunk.2.webm -i chunk.3.webm -i chunk.4.webm -filter_complex "[0:0] [1:0] [2:0] [3:0] concat=n=4:v=1:a=0 [v]" -map "[v]" filter.webm -y
Using ffmpeg to combine small mp4 chunks?

Related

ffmpeg - stream_loop mp3 + looping video (per track)

I'm using ffmpeg to create a livestream video playlist of a folder of mp3s and a folder of videos.
I'd like everytime a new song comes on a new video loops until the next song.
Initially I was using live-stream-radio which is perfect except how it's handled is after every track a new ffmpeg stream loop is initialized. And in a lot of clients this issues a stop command, and there's "dead space" between.
My attempt was when creating the gif playlist text file (they were gifs but I converted to mp4), I set the duration for the duration of the corresponding track. The problem is the video plays once, and then freezes on the final frame until the next track.
rm music.txt
rm gifs.txt
printf "ffconcat version 1.0\n" >> gifs.txt
printf "ffconcat version 1.0\n" >> music.txt
for i in {1..9}; do
printf "file 'mp3/00%s.mp3'\n" $i >> music.txt
done
for i in {1..9}; do
DURATION=$(ffmpeg -i mp3/00$i.mp3 2>&1 | awk '/Duration/ { print substr($2,0,length($2)-1) }')
printf "file 'gif/00%s.mp4'\nduration %s\n" $i $DURATION >> gifs.txt
done
ffmpeg \
-stream_loop -1 \
-i gifs.txt \
-i music.txt \
-vcodec libx264 \
-f flv "$URL"
Any ideas here would be great.

First character disappears when piping script with ffmpeg to bash

I often create bash scripts with bash and pipe the results to bash... When I do this:
echo -e "ffmpeg -loglevel quiet -f lavfi -i nullsrc -t 1 -f null /dev/null\necho foo"|bash
I get
bash: line 2: cho: command not found
Where did the 'e' of 'echo' go? What does ffmpeg do there? Other commands work fine.
Note also:
echo -e "ffmpeg -loglevel quiet -f lavfi -i nullsrc -t 1 -f null /dev/null\necho foo" > /tmp/foo.sh
bash /tmp/foo.sh #works
bash < /tmp/foo.sh #doesn't
ffmpeg also reads from standard input, which it inherits from its parent process, which is the bash process reading your command line. This means ffmpeg is reading the e from echo following the new line.
One fix is to redirection standard input for ffmpeg:
echo -e "ffmpeg -loglevel quiet -f lavfi -i nullsrc -t 1 -f null /dev/null < /dev/null \necho foo"|bash
However, I can't help but point out that there isn't really any reason to run a script like this. If you want it in a separate process, start a subshell:
(
ffmpeg -loglevel quiet -f lavfi -i nullsrc -t 1 -f null /dev/null
echo foo
)

ffmpeg to convert .avi, .mp4, .mp3, .flv, .mkv to mp4

I searching for a script that contains all of that attributes like the title.
I have done one simple but that is only for one attribute so far and i do not want one script for each of all attributes to not be confused.
Like this, running the script for like 10 minutes to see if there is any file that consist .flv and the automatic doing a convert for the file to a mp4 attribute.
#!/bin/bash
# Convert all flv to mp4
ext=.mp4
for file in *.flv; do
currmov=$file$ext
ffmpeg -r 15 -i $file -b 296k -s 640x320 -vcodec mpeg4 -acodec aac $currmov
done
Thanks for help!
/M
For all extensions:
for file in *.{flv,avi,mp3,mkv}; do
target="${file%.*}.mp4"
[[ -f "$target" ]] && { echo "skipping $file - $target exists" ; continue; }
echo ffmpeg -r 15 -i "$file" -b 296k -s 640x320 -vcodec mpeg4 -acodec aac "$target"
done
remove the echo before ffmpeg if satisfied
You just need a second loop
for ext in avi mp3 flv mk4; do
for file in *.$ext; do
...
done
done

Linux Script - Extension retained

I'm a newbie to linux scripting and am having an issue with a script that I got from the web and am trying to modify.
Here is the script
#!/bin/bash
if (($# ==0))
then
echo "Usage: flvto3gp [flv files] ..."
exit
fi
while (($# !=0 ))
do
ffmpeg -ss 00:00:10 -t 1 -s 400x300 -i $1 -f mjpeg /home/zavids/rawvids/thumbs/$1.jpg
shift
done
echo "Finished"
echo "\"fakap all those nonsense!\""
echo ""
So I'm grabbing a screenshot from a video and saving it as a jpeg. The problem is the extension of the video file is retained so finished file is video.flv.jpg (for example). How can I get rid of that video extension?
Change this line
ffmpeg -ss 00:00:10 -t 1 -s 400x300 -i $1 -f mjpeg /home/zavids/rawvids/thumbs/$1.jpg
to this
ffmpeg -ss 00:00:10 -t 1 -s 400x300 -i $1 -f mjpeg /home/zavids/rawvids/thumbs/${1%.*}.jpg
That strips the extension from the input file before using it to create the name of the output file, using bash parameter expansion.
You can try to use this :
${string%substring}
It deletes shortest match of $substring from back of $string.
For your case :
${1%.flv}
This code will substitute .flv from the end of your first argument.
You can have a lot of details here too : http://tldp.org/LDP/abs/html/string-manipulation.html

How do I add RIFF header to MP3 files programatically?

More information about what I want to do here; http://www.studiodust.com/riffmp3.html
I want a way so that my control panel (made with Perl and Webmin) can do this automatically. Right now I have to rely on system calls and have a binary for Linux. Is there a library that does it for Perl or some other language?
What's the best way of doing this?
I know nothing about RIFF files or their structure, uses, etc. But did you try searching CPAN? The first result looks pretty promising.
The website I reference had the answer I needed. I didn't know they made a linux variant.
I have the following script for the exact thing you asked about.
#!/bin/bash
echo "$1"
ffmpeg -y -i "$1" -f wav out.wav > /dev/null 2>&1 && \
normalize-audio -q out.wav && \
lame --silent -a -m m --cbr -b 64 -q 0 out.wav out.mp3 && \
ffmpeg -y -i out.mp3 -f wav -acodec copy "$1" > /dev/null 2>&1 && \
echo "done."
rm out.wav out.mp3
Just edit the parameters to lame or just use the ffmpeg call and you're set.

Resources