ffmpeg in a bash pipe

2019-01-02 21:49发布

I have a rmvb file path list, and want to convert this files to mp4 files. So I hope to use bash pipeline to handle it. The code is

Convert() {
    ffmpeg -i "$1" -vcodec mpeg4 -sameq -acodec aac -strict experimental "$1.mp4"
}

Convert_loop(){
    while read line; do
       Convert $line
    done
}

cat list.txt | Convert_loop

However, it only handle the first file and the pipe exits.

So, does ffmpeg affect the bash pipe?

标签: bash ffmpeg
3条回答
只若初见
2楼-- · 2019-01-02 21:58

Caveat: I've never used ffmpeg, but in working with other questions concerning the program, it appears that, like ssh, ffmpeg reads from standard input without actually using it, so the first call to Convert is consuming the rest of the file list after read gets the first line. Try this

Convert() {
    ffmpeg -i "$1" -vcodec mpe4 -sameq -acodec aac \
           -strict experimental "$1.mp4" < /dev/null
}

This way, ffmpeg will not "hijack" data from standard input intended for read command.

查看更多
牵手、夕阳
3楼-- · 2019-01-02 21:59

[...]

for i in `cat list.txt`

Never use this syntax :

for i in $(command); do ...; done # or
for i in `command`; do ...; done

This syntax read the output of a command word by word and not row by row which often creates unexpected problems (like when row contain some spaces and when you want read a row like an item for example).

There always is a smarter solution :

command|while read -r; do ...; done # better general case to read command output in a loop
while read -r; do ...; done <<< "$(command)" # alternative to the previous solution
while read -r; do ...; done < <(command) # another alternative to the previous solution
for i in $DIR/*; do ...; done # instead of "for i in $(ls $DIR); do ...; done
for i in {1..10}; do ...; done # instead of "for i in $(seq 1 10); do ...; done
for (( i=1 ; i<=10 ; i++ )); do ...; done # such that the previous command
while read -r; do ...; done < file # instead of "cat file|while read -r; do ...; done"
# dealing with xargs or find -exec sometimes...
# ...

I wrote a course with more details about this subject and recurring errors, but in French, unfortunately :)

To answer the original question, you could use something like :

Convert() {
    ffmpeg -i “$1” -vcodec mpe4 -sameq -acodec aac -strict experimental “$1.mp4”
}

Convert_loop(){
   while read -r; do
       Convert $REPLY
   done < $1
}

Convert_loop list.txt
查看更多
君临天下
4楼-- · 2019-01-02 22:06

KISS ! =)

convert() {
    ffmpeg -i "$1" \
           -vcodec mpe4 \
           -sameq -acodec aac \
           -strict experimental "${1%.*}.mp4"
}

while read line; do
    convert "$line"
done < list.txt
查看更多
登录 后发表回答