FFMPEG多进程转码

FFMPEG多进程转码

最近做项目,需要对linux服务器上的视频做批量转码,所以研究了下linux shell编程,通过各种途径搜寻资料,结合项目实际情况,完成了以下脚本,功能比较简单,希望对其他有相似需求的人有所帮助。

代码的主要功能为配置进程上限,并行对指定文件夹内文件进行递归,将所有非mp4格式的视频进行转码,统一转为mp4格式,同时生成缩略图


知识点归纳

  • 文件递归
  • 并发进程数量控制
  • ffmpeg命令使用
#!/bin/bash
#未解决的问题:输入的第二个参数无法获取;ok
#qsv格式视频无法转码,需要检查ffmpeg;
#转码成功的视频,放入到一个专门的文件中记录;
#转码失败的视频,放入到一个专门的文件中记录;
#转码中的视频,跳过;
function scandir() {
    local cur_dir parent_dir workdir isTransFailed
    workdir=$1
    isTransFailed=$2
    if [[ $isTransFailed = "" ]]
    then
        isTransFailed="n"
    else
        isTransFailed="y"
    fi
    cd $workdir
    if [ $workdir = "/" ]
    then
        cur_dir=""
    else
        cur_dir=$(pwd)
    fi
    for dirlist in $(ls $cur_dir)
    do
        if test -d $dirlist
        then
            cd $dirlist
            scandir $cur_dir/$dirlist $isTransFailed
            cd ..
        else    #cat /proc/sys/kernel/random/uuid
            #跳过非法格式的文件
            if [ "${dirlist##*.}" = "out" ] || [ "${dirlist##*.}" = "jpg" ] || [ "${dirlist##*.}" = "mp4" ] || [ "${dirlist##*.}" = "" ]
            then
                continue
            fi
            #如果没有对应的out文件,直接转码
            if  [ ! -f "$cur_dir/${dirlist%%.*}.mp4.out" ]
            then
                echo ${cur_dir}/${dirlist}/"开始转码》》》"
                read -u6 # 从文件描述符6中读取行(实际指向fifo管道)
                {
                    /usr/local/bin/ffmpeg -y -i ${cur_dir}/${dirlist} -vcodec libx264 -vb 450k -acodec libvo_aacenc ${cur_dir}/${dirlist%%.*}.mp4 > ${cur_dir}/${dirlist%%.*}.mp4.out 2>&1
                    echo >&6 # 再次往fifo管道文件中写入一个空行。
                } &
                echo "查看进度,请执行命令:tail -f "${cur_dir}/"\"${dirlist%%.*}.mp4.out\""
            fi
            #如果已经转过码,那么会有out文件,根据out文件判断是否需要再次转码
            local outfile="$cur_dir/${dirlist%%.*}.mp4.out"
            #转码失败,或者out文件被清空,则打印原视频文件名
            if [ $(cat $outfile|grep failed)x = "Conversion failed!"x ] || [ ! -s $outfile ]
            then
                #echo ${outfile}
                echo "文件转换失败:"$cur_dir/$dirlist
                local transErr=$(cat $outfile | awk -F ':' '/.*input.*/ {print $2}')
                echo "失败原因:"$transErr
                if [[ $isTransFailed = "y" ]]
                then
                                        echo ${cur_dir}/${dirlist}/"重新执行转码》》》"
                    read -u6 # 从文件描述符6中读取行(实际指向fifo管道)
                    {
                        /usr/local/bin/ffmpeg -y -i ${cur_dir}/${dirlist} -vcodec libx264 -vb 450k -acodec libvo_aacenc ${cur_dir}/${dirlist%%.*}.mp4 > ${cur_dir}/${dirlist%%.*}.mp4.out 2>&1
                        echo >&6 # 再次往fifo管道文件中写入一个空行。
                    } &
                                        echo "查看进进度,请执行命令:tail -f "${cur_dir}/"\"${dirlist%%.*}.mp4.out\""
                fi
            else
                #tmpt=$(cat ${cur_dir}/${dirlist} | awk -F ',' '/Input.*/ {print $3}')
                echo "文件转换成功,或者在转换中:"$cur_dir/$dirlist > /dev/null
            fi

        fi
    done
}

oldIFS=$IFS
IFS=$(echo -en "\n\b")
if test -d $1
then
    #############进程控制管道########################################################################
    SEND_THREAD_NUM=200   #设置线程数,在这里所谓的线程,其实就是几乎同时放入后台(使用&)执行的进程。
    tmp_fifofile="/tmp/$$.fifo" # 脚本运行的当前进程ID号作为文件名
    mkfifo "$tmp_fifofile" # 新建一个随机fifo管道文件
    exec 6<>"$tmp_fifofile" # 定义文件描述符6指向这个fifo管道文件
    for ((i=0;i<$SEND_THREAD_NUM;i++));do
        echo >&6 # for循环 往 fifo管道文件中写入SEND_THREAD_NUM个空行
    done 
    ###########开始执行转码
    scandir $1 $2
    ###########等待转换结束
    wait 
    rm "$tmp_fifofile"
elif test -f $1
then
    echo "you input a file but not a directory,pls reinput and try again"
    exit 1
else
    echo "the Directory isn't exist which you input,pls input a new one!!"
    exit 1
fi
IFS=$oldIFS
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值