0

i have the following bash script (taken from FFmpeg)

#!/bin/bash

################################################################################
#
# Script name: MultiMedia Concat Script (mmcat)
# Author: burek (burek021@gmail.com)
# License: GNU/GPL, see http://www.gnu.org/copyleft/gpl.html
# Date: 2012-07-14
#
# This script concatenates (joins, merges) several audio/video inputs into one
# final output (just like as if all the inputs were played in a playlist, one
# after another).
#
# All input files must have at least one audio and at least one video stream.
# If not, you can easily add audio silence, using FFmpeg. Just search the
# internet for "ffmpeg add silence".
#
# The script makes use of FFmpeg tool (www.ffmpeg.org) and is free for use under
# the GPL license. The inspiration for this script came from this FAQ item:
# http://ffmpeg.org/faq.html#How-can-I-join-video-files_003f
#
# If you find any bugs, please send me an e-mail so I can fix it.
#
################################################################################
#
# General syntax: mmcat <input1> <input2> <input3> ... <output>
#
# For example: mmcat file1.flv file2.flv output.flv
# would create "output.flv" out of "file1.flv" and "file2.flv".
#
################################################################################

# change this to what you need !!!
EXTRA_OPTIONS=${@:2:1}

################################################################################
#
# NO NEED TO TOUCH ANYTHING AFTER THIS LINE!
#
################################################################################

# the version of the script
VERSION=1.3

# location of temp folder
TMP=${@:1:1}

rm -rf $TMP
mkdir $TMP

################################################################################

echo "MultiMedia Concat Script v$VERSION (mmcat) - A script to concatenate multiple multimedia files."
echo "Based on FFmpeg - www.ffmpeg.org"
echo "Don't forget to edit this script and change EXTRA_OPTIONS"
echo ""

################################################################################
# syntax check (has to have at least 3 params: infile1, infile2, outfile
################################################################################
if [ -z $3 ]; then
    echo "Syntax: $0 <input1> <input2> <input3> ... <output>"
    exit 1
fi

################################################################################
# get all the command line parameters, except for the last one, which is output
################################################################################
# $first  - first parameter
# $last   - last parameter (output file)
# $inputs - all the inputs, except the first input, because 1st input is
#           handled separately
################################################################################
first=${@:3:1}
last=${@:$#:1}
len=$(($#-4))
inputs=${@:4:$len}

# remove all previous tmp fifos (if exist)
rm -f $TMP/mcs_*

################################################################################
# decode first input differently, because the video header does not have to be
# kept for each video input, only the header from the first video is needed
################################################################################
mkfifo $TMP/mcs_a1 $TMP/mcs_v1

ffmpeg -y -i "$first" -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 $TMP/mcs_a1 2>/dev/null </dev/null &
ffmpeg -y -i "$first" -an -f yuv4mpegpipe -vcodec rawvideo $TMP/mcs_v1 2>/dev/null </dev/null &

# if you need to log the output of decoding processes (usually not necessary)
# then replace the "2>/dev/null" in 2 lines above with your log file names, like this:
#ffmpeg -y -i "$first" -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 $TMP/mcs_a1 2>$TMP/log.a.1 </dev/null &
#ffmpeg -y -i "$first" -an -f yuv4mpegpipe -vcodec rawvideo $TMP/mcs_v1 2>$TMP/log.v.1 </dev/null &

################################################################################
# decode all the other inputs, remove first line of video (header) with tail
# $all_a and $all_v are lists of all a/v fifos, to be used by "cat" later on
################################################################################
all_a=$TMP/mcs_a1
all_v=$TMP/mcs_v1
i=2
for f in $inputs
do
    mkfifo $TMP/mcs_a$i $TMP/mcs_v$i

    ffmpeg -y -i "$f" -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 $TMP/mcs_a$i 2>/dev/null </dev/null &
    { ffmpeg -y -i "$f" -an -f yuv4mpegpipe -vcodec rawvideo - 2>/dev/null </dev/null | tail -n +2 > $TMP/mcs_v$i ; } &

    # if you need to log the output of decoding processes (usually not necessary)
    # then replace the "2>/dev/null" in 2 lines above with your log file names, like this:
    #ffmpeg -y -i "$f" -vn -f u16le -acodec pcm_s16le -ac 2 -ar 44100 $TMP/mcs_a$i 2>$TMP/log.a.$i </dev/null &
    #{ ffmpeg -y -i $f -an -f yuv4mpegpipe -vcodec rawvideo - 2>$TMP/log.v.$i </dev/null | tail -n +2 > $TMP/mcs_v$i ; } &

    all_a="$all_a $TMP/mcs_a$i"
    all_v="$all_v $TMP/mcs_v$i"
    let i++
done

################################################################################
# concatenate all raw audio/video inputs into one audio/video
################################################################################
mkfifo $TMP/mcs_a_all
mkfifo $TMP/mcs_v_all
cat $all_a > $TMP/mcs_a_all &
cat $all_v > $TMP/mcs_v_all &

################################################################################
# finally, encode the raw concatenated audio/video into something useful
################################################################################
ffmpeg -y -f u16le -acodec pcm_s16le -ac 2 -ar 44100 -i $TMP/mcs_a_all \
       -y -f yuv4mpegpipe -vcodec rawvideo -i $TMP/mcs_v_all \
    $EXTRA_OPTIONS \
    $last

################################################################################
# remove all fifos
################################################################################
rm -f $TMP/mcs_*

The above scripts takes arguments like this

bash script.sh tmp_folder video1 video2 video3 video4 ... output

Its working fine, however it doesnt read correctly the arguments when they have spaces. For example if i have a video located in "/tmp/my video.avi" it will fail to read it properly and thinks its different argument.

The problem is in these lines

first=${@:3:1}
last=${@:$#:1}
len=$(($#-4))
inputs=${@:4:$len}

Please note that you will see inside the scripts that video2 video3 and video4 are being processed seperate than video1.

0

I guess the (or one if there are many) problem is this line:

inputs=${@:4:$len}

If $len is bigger than 1 then this converts an array slice into a string and there the word splitting problem arises.

possible solution

If should work if the above line is changed to

inputs=("${@:4:$len}")

and this

for f in $inputs

to

for f in "${inputs[@]}"
  • yes, but how do i fix it? – OhGodWhy Dec 24 '14 at 15:34
  • @BlackDream I have extended my answer. – Hauke Laging Dec 25 '14 at 0:04
-1

You have to set the following code before any working files in your script:

SAVEIFS=$IFS
IFS=$(echo -en "\n\b")

Then when you want to exit from your script, you have to do it:

$IFS=$SAVEIFS
  • 1
    I prefer to save IFS using quotes (SAVEIFS="$IFS") to preserve whitespace, which IFS by default is. Setting $IFS=$SAVEIFS does not do what you want, you want IFS="$SAVEIFS". $IFS="whatever" will try to set the contents of IFS, not IFS. You do not have to restore IFS when leaving the script, because it runs in its own subshell. But I would enclose all those $@ assignments in quotes: first="${@:3:1}". – lsd Dec 24 '14 at 2:04
  • 1
    @lsd No, assignments are one of the few places in shell syntax where you don't need double quotes: SAVEIFS="$IFS" is exactly equivalent to SAVEIFS=$IFS (intuitively, if the syntax calls for a single word, no variable substitution or globbing will occur). Not that setting IFS will make the script fully work (it will protect spaces but not globbing characters), and this isn't the easiest way to do it either (setting IFS to a newline would be sufficient, no need to save the value or to use echo, and as you note there's no point in saving the old value), but it's a start. – Gilles 'SO- stop being evil' Dec 24 '14 at 20:07
  • @lsd i'm working with my answer in my scripts.... – PersianGulf Dec 25 '14 at 0:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.