原理1 : -f wav -vn 作为编码参数,可转换音频
原理2: -af “afade=t=out:st=5:d=5” 作为滤镜参数,可淡出音频
原理3: gradle 调用 powershell 播放wave文件
afterEvaluate {
gradle.buildFinished{ BuildResult buildResult ->
if (buildResult.failure) {
['powershell', """(New-Object Media.SoundPlayer "D:\\Downloads\\music\\muse_SchivoNo.2.wav").PlaySync();"""].execute()
println("failed doing task")
} else {
['powershell', """(New-Object Media.SoundPlayer "D:\\Downloads\\music\\muse_SchivoNo.2.wav").PlaySync();"""].execute()
println("build finished")
}
}
}
原理4: -af “reverse” 作为滤镜参数,可反转音频(倒放)
原理5: ffmpeg 滤镜可组合使用
脚本使用:
:wav 回车
:ao 回车
输入输出路径 回车 (默认使用源路径)
将源文件拖拽至此 回车 回车
即可生成淡出音频的BGM!
进阶 ——
:ar 回车 反转音频
:vr 回车 反转视频
:ao 指令 可以指定淡出时间,默认两秒:
如 :ao5 回车 则淡出最后五秒。
配合potplayer书签:
可配合potplayer书签功能截取视频片段(一对书签截取一段视频)。需设置potplayer保存设置到ini文件并在脚本中填写ini文件路径。如果没有,则转换整个文件。
资源
#!/usr/bin/env python
# -*-coding=utf-8 -*-
from datetime import *
import os
import re
import sys
import codecs
#reload(sys)
#sys.setdefaultencoding("ascii")
os.system('title 切割视频 - 脚本工具箱')a
def main():
theta = 0;
flibf = r"D:\software\PotPlayer\PotPlayerMini64.ini"
#ffmpegexe = r'D:\Downloads\ffmpeg-4.1.3-win64-shared\bin\ffmpeg.exe'
ffmpegexe = r"D:\software\ffmpeg\ffmpeg-n4.4-latest-win64-gpl-shared-4.4\bin\ffmpeg.exe"
#ffmpegexe = r'ffmpeg.exe'
#ffmpegexe = r'D:\Downloads\ffmpeg-4.2-win64-static\bin\ffmpeg.exe'
global videoPathName
global OutputPath
lastVideoQuality=-1
lastAccuracy=False
global wave
global fadeoutMusic
global reverseVideo
global reverseAudio
fadeoutMusic = -1
wave = False
reverseVideo = False
reverseAudio = False
def receiveFunc():
global videoPathName
videoPathName = str(input("videoPathName")).replace('"', '')
return videoPathName!="";
def buildOutputPath(e):
nopath=False
if len(e)==0 or len(e)!=1 and not os.sep in e:
nopath=True
else:
if len(e)==1:
e = e+":\\harvest"
try:
if not os.path.exists(e):
os.makedirs(e)
if not os.path.exists(e):
nopath=True
except:
nopath=True
if nopath:
e=None
print("提示:路径设空")
elif e[-1]!=os.sep:
e=e+os.sep
print("提示:路径设为::"+e)
return e
OutputPath="F:\\harvest\\"
OutputPath=""
PrevSpecName = None
while True:
videoPathNames = []
Accuracy = []
OutputPaths = []
lastVideoQualitys = []
while(receiveFunc()):
isTmp = False
if videoPathName.startswith("=="):
if len(videoPathName) > 2:
PrevSpecName = videoPathName
else:
videoPathName = PrevSpecName
videoPathName = "C:\\tmp\\tmp.mp4"+videoPathName+"-";
isTmp = True
if videoPathName[0]==':':
if False:
print (0)
elif videoPathName.startswith(':wav'):
wave = videoPathName==':wav'
print("波形音频!" if wave else "不波形音频!")
elif videoPathName.startswith(':ao'):
fadeoutMusic=videoPathName[3:]
if len(fadeoutMusic)==0:
fadeoutMusic = 2
elif fadeoutMusic.isnumeric():
fadeoutMusic = int(fadeoutMusic)
else:
fadeoutMusic = -1
print(fadeoutMusic, "淡出音频!" if fadeoutMusic>=0 else "不淡出音频!")
elif videoPathName.startswith(':ar'):
reverseAudio = videoPathName==':ar'
print("反转音频!" if reverseAudio else "不反转音频!")
elif videoPathName.startswith(':vr'):
reverseVideo = videoPathName==':vr'
print("反转视频!" if reverseVideo else "不反转视频!")
elif len(videoPathName)>1:
if videoPathName.startswith(':t'):
lastAccuracy='ts'
else:
videoPathName=videoPathName[1:]
if videoPathName.isnumeric():
lastAccuracy=True
lastVideoQuality=int(videoPathName)
else:
OutputPath=buildOutputPath(videoPathName)
else:
lastAccuracy=True
else:
lastAccuracy_=lastAccuracy
lastVideoQuality_=lastVideoQuality
match=re.match('(.*)(:[0-9]?)$', videoPathName)
if match!=None:
videoPathName=match.group(1)
args=match.group(2)
lastAccuracy_=True
if len(args)>1 and args[1:].isnumeric():
lastVideoQuality_=int(args[1:])
print(videoPathName)
path_test = videoPathName;
if path_test.endswith("-") and path_test.find("==")>0:
path_test = path_test[:path_test.find("==")]
if not os.path.isfile(path_test) and videoPathName!='x' and not videoPathName.endswith(".flv") and not videoPathName.endswith(".mp4"):
OutputPath=buildOutputPath(path_test)
continue
videoPathNames.append(videoPathName)
OutputPaths.append(OutputPath)
Accuracy.append(lastAccuracy_)
lastVideoQualitys.append(lastVideoQuality_)
f = codecs.open(flibf,"r","utf-16")
flib = f.read()
f.close()
#获取文件名
bmlOff = flib.find("[BMList]")
bmlOff2 = flib.find("=\r",bmlOff)
bml = flib[bmlOff:bmlOff2]
#print bml
o=bml.find(str(theta)+"=")
findCount = 0
while(bml.find("\n",o)!=-1):
o=bml.find("\n",o)+2
findCount+=1
print ("acc = ",findCount,"\r\n")
for (index,videoPathI) in enumerate(videoPathNames):
if videoPathI=='x':
return;
keyToFind = videoPathI
hasSpecName = False
if keyToFind.endswith("-") and keyToFind.find("==")>0:
keyToFind = videoPathI[:videoPathI.find("==")]
hasSpecName = True
print("keyToFind is : ",keyToFind, hasSpecName, "\n")
accurate_recode=Accuracy[index]
for fileIdx in range(0,findCount):
ducOff = bml.find(str(0+theta+fileIdx)+"=")
ducOff2 = bml.find("\r",ducOff)
try:
videoPathName = bml[ducOff:ducOff2].split("=")[1]
except IndexError:
print ("\n\nError_log_ theta threshold is too big \n\n")
#print ("acc = ",videoPathI,videoPathName)
if(videoPathName!=keyToFind and keyToFind!='"'+videoPathName+'"'):
continue
o = 0
while(videoPathName.find("\\",o)!=-1):
o=videoPathName.find("\\",o)+1
videoName = videoPathName[o:]
if(hasSpecName):
videoName = videoPathI[videoPathI.find("==")+2:-1]+".mp4"
videoPath = videoPathName[:o]
if OutputPaths[index]!=None and len(OutputPaths[index])>0:
videoPath=OutputPaths[index]
print("videoName is : ",videoName,videoPath, hasSpecName, "\n")
#获取当前文件的书签列表
#print flib.find("[BMItem_"+str(theta+fileIdx))
itemSectionOff = flib.find("[BMItem_"+str(theta+fileIdx))
#print flib.find("=\r",itemSectionOff)
itemSectionOff2 = flib.find("=\r",itemSectionOff)
section = flib[itemSectionOff:itemSectionOff2]
bookMarkList = []
for i in section.split("\r\n"):
tmp = i.split("*")[0]
if tmp.find("=")!=-1:
bookMarkList.append(int(tmp.split("=")[1]))
#print bookMarkList
#获取当前文件的书签列表END
cc = 0
for i in range(int(len(bookMarkList)/2)):
#print "doin"
start = bookMarkList[i*2]
end = bookMarkList[i*2+1]
tm = start/1000
h=int(tm/60/60)
m=int(tm%(60*60)/60)
s=int(tm%(60*60)%60)
#print(start)
tm1 = str(time(h,m,s)) +"."+str(start%1000)
tm = end/1000
h=int(tm/60/60)
m=int(tm%(60*60)/60)
s=int(tm%(60*60)%60)
tm2 = str(time(h,m,s)) +"."+str(end%1000)
codec=" -codec copy -avoid_negative_ts 1 -strict -2 "
accurate = False
if accurate_recode=='ts':
codec=" -codec copy -copyts -avoid_negative_ts 1 -strict -2 -bsf:v h264_mp4toannexb -f mpegts "
elif accurate_recode:
accurate = True
codec=" -codec copy -c:v libx264 -avoid_negative_ts 1 -strict -2 "
if lastVideoQualitys[index]>=0:
codec+="-crf "+str(lastVideoQualitys[index])+" "
suffix = ".mp4"
suffixIdx = videoName.rfind(".")
if suffixIdx > 0:
suffix = videoName[suffixIdx:]
videoName = videoName[:suffixIdx]
if suffix==".flv":
suffix = ".mp4"
decode = codec
if wave:
suffix = ".wav"
decode = " -f wav -vn "
if reverseVideo:
decode += " -vf \"reverse\" "
if reverseAudio:
decode += " -af \"areverse\" "
new_path = videoPath+videoName+"_SchivoNo."+str(cc)+suffix
while os.path.exists(new_path):
cc+=1;
new_path = videoPath+videoName+"_SchivoNo."+str(cc)+suffix
cc+=1
new_path='"'+new_path+'"'
inputfile=" -accurate_seek "+"-i "+'"'+videoPathName+'"'
duration = 1.0*(end-start)/1000
sst=r' -ss '+ (tm1)+" -t "+str(duration)
if fadeoutMusic>=0:
# ' -af "afade=t=out:st=5:d=5" '
d = fadeoutMusic
st = duration-d
if st < 0 :
d/=2
st = duration-d
decode = f' -af "afade=t=out:st={st}:d={d}" ' + decode
offset_and_input=sst+inputfile
if accurate:
offset_and_input=inputfile+sst
#codec=" -codec copy -avoid_negative_ts 1 -strict -2 "
#offset_and_input=inputfile+sst
mingling=offset_and_input+decode+new_path
print ("\r\ncommand on queue: FFMPEG "+mingling+"\n")
mingling = ffmpegexe + mingling
os.system(mingling+" -n")
break
#os.system("pause")
if __name__ == '__main__':
main()
os._exit(0)
示例
将偶然看到的“美篇”BGM拿来,截取前两秒项目构建成功的提示音,是一种开放的感觉,open feeling,心胸开阔,开启无限可能。反转后作为构建失败的提示音,别有旋律,是一种幽然的警报声,紧张中带有诙谐感,开始无限调试。
用 FFMEPG 为Android Studio制作的提示音