视频截取和队列处理的shell实现
[
![]() 经过一次不痛快的和他人合作之后,我写了这段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 #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< 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 |
|
来自: Ralf_Jones > 《其它》