分享

视频截取和队列处理的shell实现

 Ralf_Jones 2008-04-03
视频截取和队列处理的shell实现
| |
[不指定 2007/06/05 21:07 | by wirlfly ]
           经过一次不痛快的和他人合作之后,我写了这段shell脚本,主要用于视频文件的转换队列处理,和视频大文件的截取.涉及到诸如3gp,asf,wmv,avi,mp4,mpeg,mov,vob,rm,rmvb等格式的转换成flv,同时分段截取各种格式的大文件.主要采用的工具无非就是开源的ffmpeg,mencoder,MediaInfo,前两者转换和截取,后者获取视频元数据.多谢sleetdrop推荐.
           对于视频文件的元数据而言,是否都存在都柏林元数据,特征元数据是否值得信赖是一个问题,因此在脚本中做了一些信任机制的处理,脚本写的很清晰,应该不是太难懂,而且里面都做了撇脚的英文注释.已经通过功能测试,至于压力测试,正在进行中.不过对于脚本运行环境,是在ffmpeg+mencoder环境下运行的,对于怎样搭建ffmpeg+mencoder,可以参考这篇文章.
           可能会要应用于实际比较恶劣的情况中,因此还需要对代码进行改进,甚至可能要用到shc,日志功能和错误处理功能还要加强,还有就是根据不同格式和不同质量的视频文件,采用不同的方法进行转换也是在下一步策划之中.如果大家有什么更好的方法,或者对此进行了改进,请共享出来吧.
引用
#!/bin/bash
#
#file:  convert_videos.sh
#usage:
#desc:  convert many other formats of videos to flv format
#author:        Spark Zheng
#version:       V1.0
#date:  2007-05-31

declare -a video_format         #video formats
declare -a video_size           #video sizes
declare -a video_metadata       #array of the metadata geted by MediaInfo
declare -i flag                 #delay flag, wait for queue
declare -i file_size            #the video file size, we trust it!

VIDEO_IN_DIR=/home/zhengyu/video_again                                  #video queue dir
VIDEO_OUT_DIR=/home/zhengyu/flv                                         #the flv videos moved to
VIDEO_BAK_DIR=/home/zhengyu/video_bak                                   #video which has handled moved to, need?
VIDEO_FORMAT_FILE=/home/zhengyu/code/shell/convert_formats.list         #formats, just define it
VIDEO_SIZE_FILE=/home/zhengyu/code/shell/convert_sizes.list             #sizes, frame sizes, just define it
DEBUG=1                         #debug flag: 1 to debug, 0 to cancel

MediaInfo_dir=/usr/local/bin    #MediaInfo tool‘s dir
ffmpeg_dir=/usr/local/bin       #ffmpeg tool‘s dir
mencoder_dir=/usr/local/bin     #mencoder tool‘s dir
file_limit=10485760             #file size to check: 10M(10*1024*1024)
diff_time_max=600               #diff between caculate time and get time: 10 minute(600 second)
diff_time_min=-600              #same as diff_time_max
bit_rate_max=41943040           #trust when below the max bit rate: 40Mbps(40*1024*1024)
bit_rate_min=1024               #trust when over the min bit rate: 1Kbps(1*1024)
time_to_trucate=1800            #trucate the video when playtime is over: 30 minute(1800 second)

video_format=($(cat $VIDEO_FORMAT_FILE))
video_size=($(cat $VIDEO_SIZE_FILE))
flag=0                          #first init flag with 0
pid=$$

#####################functions start#############################

#function: get_metadata
#usage: fill the video_metadata array with useful arguments
#return: 0
function get_metadata()
{
#       video_metadata[0]=$(cat tmp|grep "PlayTime"|awk -F: ‘{if(NR==1) print $2}‘)
#       video_metadata[1]=$(cat tmp|grep "Bit rate"|awk -F: ‘{if(NR==1) print $2}‘)
#       video_metadata[2]=$(cat tmp|grep "File size"|awk -F: ‘{if(NR==1) print $2}‘)
#       video_metadata[3]=$(cat tmp|grep "Format"|awk -F: ‘{if(NR==1) print $2}‘)
#       video_metadata[4]=$(cat tmp|grep "Width"|awk -F: ‘{if(NR==1) print $2}‘)
#       video_metadata[5]=$(cat tmp|grep "Height"|awk -F: ‘{if(NR==1) print $2}‘)
#       video_metadata[6]=$(cat tmp|grep "Frame rate"|awk -F: ‘{if(NR==1) print $2}‘)

#you may add it like above, as an example.
       video_metadata=($(awk -F: ‘BEGIN{PT=1;pt=0;BR=1;br=0;F=1;f=0;FMT=1;fmt="";W=1;w=0;H=1;h=0;FR=1;fr=0;}
                                  {if(($0 ~ "PlayTime")&&(PT==1))
                                       {PT=0; split($2,array," "); if(array[1]~"h"){pt+=3600*int(array[1]);} else if(array[1]~"mn") {pt+=60*int(array[1]);} else if(array[1]~"s") {pt+=int(array[1]);} if(array[2]~"mn") {pt+=60*int(array[2]);} else if(array[2]~"s") {pt+=int(array[2]);} }
                                   if(($0 ~ "Bit rate")&&(BR==1))
                                       {BR=0; split($2,array," "); if(array[2]~"Mbps") {br=1024*1024*int(array[1]);} else if(array[2]~"Kbps") {br=1024*int(array[1]);} else {br=int(array[1]);}}
                                   if(($0 ~ "File size")&&(F==1))
                                       {F=0; split($2,array," "); if(array[2]~"MiB") {f=1024*1024*int(array[1]);} else if(array[2]~"KiB") {f=1024*int(array[1]);} else {f=int(array[1]);}}
                                   if(($0 ~ "Codec")&&(FMT==1))
                                       {FMT=0; split($2,array," "); fmt=array[1];}
                                   if(($0 ~ "Width")&&(W==1))
                                       {W=0; split($2,array," "); w=int(array[1]);}
                                   if(($0 ~ "Height")&&(H==1))
                                       {H=0; split($2,array," "); h=int(array[1]);}
                                   if(($0 ~ "Frame rate")&&(FR==1))
                                       {FR=0; split($2,array," "); fr=int(array[1]);}}
                                  END{print pt" "br" "f" "fmt" "w" "h" "fr;}‘ /tmp/$0.tmp))

       return 0
}

#function: check_metadata
#usage: to decide the metadata we get by get_metadata() weather were trusted
#return: >0 not trusted, =0 trusted
function check_metadata()
{

if [ $DEBUG -gt 0 ]
then
       echo ${video_metadata[0]}
       echo ${video_metadata[1]}
       echo ${video_metadata[2]}
       echo ${video_metadata[3]}
       echo ${video_metadata[4]}
       echo ${video_metadata[5]}
       echo ${video_metadata[6]}
       echo ""
fi

       #not trust bit rates
       if [ ${video_metadata[1]} -gt $bit_rate_max -o ${video_metadata[1]} -lt $bit_rate_min ]
       then
               return 15
       fi

       diff_cacul=$(expr 8 \* $file_size / ${video_metadata[1]} - ${video_metadata[0]})

       #not trust play times
       if [ $diff_cacul -gt $diff_time_max -o $diff_cacul -lt $diff_time_min  ]
       then
               [ $DEBUG -gt 0 ] && echo "\$diff_cacul is $diff_cacul"

               return 14
       fi

       #need to check the format?
       return 0
}

#function: convert_video
#usage: use ffmpeg/mencoder to convert the videos, trucate videos when necessary
#return: 0
function convert_video()
{
       if [ -z "$1" ]
       then
               return 13
       fi

       if [ -z "$2" ]
       then
               trucate_flag=0          #0 means not to trucate the video file
       else
               trucate_flag=$2
       fi

       #any other smart method to get the flv_file? another method is directly assigned with $1.flv,maybe better
#       flv_file=$(echo $1 | awk ‘{split($0,array,".");for(i in array) {;} array[i]=""; for(j in array) {if(j        flv_file=$1         #for some convenience

       #need trucate?
       case "$trucate_flag" in
       0 )
               if [ "X${video_metadata[3]}" == "XRealVideo" ]          #rv format like rm/rmvb use mencoder
               then
                       : #mencoder args, need more opts? finish it by yourself like " $mencoder_dir/mencoder $1 -o ${flv_file}.flv  ** "
                       

                       if [ $? -ne 0 ]
                       then
                               [ $DEBUG -gt 0 ] && echo "mencoder failed to convert video $1"
                       fi

                       [ $DEBUG -gt 0 ] && echo "mencoder invoked for arg2:$trucate_flag"
               else                                                    #oth format use ffmpeg for convert speed
                       : #ffmpeg args,  need to change the ffmpeg‘s args? you may finish by yourself,  like " $ffmpeg_dir/ffmpeg -y -i $1 ${flv_file}.flv ** "
                       
                       if [ $? -ne 0 ]
                       then
                               [ $DEBUG -gt 0 ] && echo "ffmpeg failed to convert video $1"
                       fi

                       [ $DEBUG -gt 0 ] && echo "ffmpeg invoked for arg2:$trucate_flag"
               fi
               ;;
       * )     #we could take care
               loop_count=$(expr $trucate_flag + 1)
               dura_time=$(expr ${video_metadata[0]} / $loop_count)

               for trucate_count in $(seq $loop_count)
               do
                       if [ "X${video_metadata[3]}" == "XRealVideo" ]  #rv format like rm/rmvb use mencoder
                       then
                               case "$trucate_count" in
                               1)
                                       : #mencoder args, need more opts? finish it by yourself, like "$mencoder_dir/mencoder $1 -o ${flv_file}.${trucate_count}.flv -ss $((($trucate_count-1)*$dura_time)) -endpos $(($dura_time+2)) ** "                                      
                                       
                                       if [ $? -ne 0 ]
                                       then
                                               [ $DEBUG -gt 0 ] && echo "mencoder failed to convert video $1"
                                       fi
                                       ;;
                               $loop_count)
                                       : #mencoder args, need more opts? finish it by yourself, like " $mencoder_dir/mencoder $1 -o ${flv_file}.${trucate_count}.flv -ss $((($trucate_count-1)*$dura_time-2)) ** "

                                       if [ $? -ne 0 ]
                                       then
                                               [ $DEBUG -gt 0 ] && echo "mencoder failed to convert video $1"
                                       fi
                                       ;;
                               *)
                                       : #mencoder args, need more opts? finish it by yourself, like " $mencoder_dir/mencoder $1 -o ${flv_file}.${trucate_count}.flv -ss $((($trucate_count-1)*$dura_time-2)) -endpos $(($dura_time+2)) **  "
                                       if [ $? -ne 0 ]
                                       then
                                               [ $DEBUG -gt 0 ] && echo "mencoder failed to convert video $1"
                                       fi
                                       ;;
                               esac

                               [ $DEBUG -gt 0 ] && echo "mencoder invoked for arg2:$trucate_flag"
                       else                                            #oth format use ffmpeg for convert speed
                               case "$trucate_count" in
                               1)
                                       : #ffmpeg args, need more opts? finish it by yourself, like "$ffmpeg_dir/ffmpeg -y -i $1 -ss $((($trucate_count-1)*$dura_time)) -t $(($dura_time+2))  ${flv_file}.${trucate_count}.flv *** "                                        

                                       if [ $? -ne 0 ]
                                       then
                                               [ $DEBUG -gt 0 ] && echo "ffmpeg failed to convert video $1"
                                       fi
                                       ;;
                               $loop_count)
                                       : #ffmpeg args, need more opts? finish it by yourself, like " $ffmpeg_dir/ffmpeg -y -i $1 -ss $((($trucate_count-1)*$dura_time-2)) ${flv_file}.${trucate_count}.flv ** "

                                       if [ $? -ne 0 ]
                                       then
                                               [ $DEBUG -gt 0 ] && echo "ffmpeg failed to convert video $1"
                                       fi
                                       ;;
                               *)
                                       : #ffmpeg args, need more opts? finish it by yourself, like " $ffmpeg_dir/ffmpeg -y -i $1 -ss $((($trucate_count-1)*$dura_time-2)) -t $(($dura_time+2))  ${flv_file}.${trucate_count}.flv ** "

                                       if [ $? -ne 0 ]
                                       then
                                               [ $DEBUG -gt 0 ] && echo "ffmpeg failed to convert video $1"
                                       fi
                                       ;;
                               esac

                               [ $DEBUG -gt 0 ] && echo "ffmpeg invoked for arg2:$trucate_flag"
                       fi
               done    #trucate times end.
               ;;
       esac            #need trucate end.

       return 0
}

#function: mv_video
#usage: mv the source video and converted videos to VIDEO_OUT_DIR for the loop needed
#return: 0
function mv_video()
{
       if [ -z "$1" ]
       then
               return 12
       fi

       flvs=$(find . -name \*.flv -type f)
       if [ -n "$flvs" ]
       then
               mv -f $flvs $VIDEO_OUT_DIR
       fi

       if [ -e "$1" ]
       then
               mv -f $1 $VIDEO_BAK_DIR
       fi

       return 0
}

#function: write_pid
#usage: write the script pid to /tmp/$0.pid
#return: 0
function write_pid()
{
       echo "$pid" > /tmp/$0.pid

       return 0
}

#function: write_log
#usage: write logs to file? to syslogd?
#return: 0
function write_log()
{
       case "$1" in
       0)
               logger -t $0 -i "$2"
               ;;
       *)
               log_time=$(date +"%F %T")
               echo "${log_time}\tlocalhost\t${0}[${pid}]:\t${2}" >> $3
               ;;
       esac

       return 0
}

#function: sig_init_kill
#usage: when in loops, we need to handle the SIGINT and SIGKILL
#return: 1(exit)
function sig_int_kill()
{
       if [ -e "/tmp/$0.pid" ]
       then
               rm -rf /tmp/$0.pid
       fi

       if [ -e "/tmp/$0.tmp" ]
       then
               rm -rf /tmp/$0.tmp
       fi

       if [ -e "/tmp/$0.sig" ]
       then
               rm -rf /tmp/$0.sig
       fi

       echo "when out:" >> /tmp/$0.sig
       echo "video_file is $video_file" >> /tmp/$0.sig
       echo "trucate_flag is $trucate_flag" >> /tmp/$0.sig
       echo "...... enjoy your finishing ......" >> /tmp/$0.sig

       exit 1
}

######################functions end##############################

write_pid

trap ‘sig_int_kill‘ SIGINT
trap ‘sig_int_kill‘ SIGKILL

pushd $VIDEO_IN_DIR

while :         #yes, the SIG is handled
do
       video_file=$(find . -type f |tail -n 1)                 #get a file? many, you complete

       [ $DEBUG -gt 0 ] && echo "\$video_file is $video_file"

       if [ -z "$video_file" ]                         #there is no file,waiting for a coming file
       then
               sleep $((1<                ((flag++))

               if [ $flag -gt 10 ]
               then
                       flag=1
               fi
       else
               flag=0
               file_size=$(ls -l $video_file |awk ‘{print $5}‘)        #we trust this file_size

               if [ $file_size -gt $file_limit ]               #too small,the vidoe doesn‘t need to trucate
               then
                       ${MediaInfo_dir}/MediaInfo $video_file >/tmp/$0.tmp 2>&1

                       get_metadata                    #get the video‘s metadata
                       check_metadata                  #check it whether it‘s trusted to

                       if [ $? -ne 0 ]                 #not trusted?
                       then
                               convert_video $video_file 0
                               mv_video $video_file

                               [ $DEBUG -gt 0 ] && echo "not trust not trucated, converted and continued"

                               continue;               #just continue; we finished the untrustable video
                       fi

                       if [ ${video_metadata[0]} -gt $time_to_trucate ]        #need trucate
                       then
                               full_time=$(expr ${video_metadata[0]} / $time_to_trucate)
                               convert_video $video_file $full_time
                               mv_video $video_file

                               [ $DEBUG -gt 0 ] && echo "trucated and converted and continued"

                               continue;               #trucated and finished
                       fi
                                                       #the video is pretty simple
                       convert_video $video_file 0
                       mv_video $video_file

                       [ $DEBUG -gt 0 ] && echo "play time not too long not trucated, converted and continued"
               else                                    #file size is too small to trucate
                       convert_video $video_file 0
                       mv_video $video_file

                       [ $DEBUG -gt 0 ] && echo "file to small not trucated, converted and continued"
               fi
       fi
done

popd

exit 0

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多