【脚本资源】巧用 FFMEPG 为Android Studio制作提示音,用音乐舒缓压力

原理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制作的提示音

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值