網上最近很火的段子是各種營銷號的文案,比方說下面的段子
核桃核不能吞下去是怎么回事呢?核桃核相信大家都很熟悉,但是核桃核不能吞下去是怎么回事呢,下面就讓小編帶大家一起了解吧。核桃核不能吞下去,其實就是核桃核太大了,吞下去容易噎着,大家可能會很驚訝核桃核怎么會不能吞下去呢?但事實就是這樣,小編也感到非常驚訝。這就是關於核桃核不能吞下去的事情了,大家有什么想法呢,歡迎在評論區告訴小編一起討論哦!
其實我平時見到這些文案或者視頻都很少,因為我沒用過今日頭條、抖音之類的APP
然后我就在想,如果指定文案、BGM、視頻,給定這三個東西,能否批量生成營銷號視頻,於是就有了這個項目
項目說明我錄了個視頻放在B站了,源碼放在了Github
下面詳細說明一下代碼吧
設計思路
首先我把這個程序分為了以下幾步:
剪裁視頻→getVideo()
將台詞寫入文本→getText(file)
獲取視頻總時長→getLength(video)
給視頻添加背景音樂→add_audio(video, mp3, output='out.mp4')
給視頻添加字幕→subTitle(text_file, video_file, output='out_sub.mp4')
文本轉人聲→訊飛API
給視頻添加人聲→add_people(mp3_file, video_file)
清除中間生成的文件→clean()
1. 裁剪視頻
對於大部分營銷號視頻來說,長度都在45秒左右,我也沒有弄的太復雜,就直接將給定的mp4文件的前50秒保留了下來,其余的部分不要
def getVideo():
cmd = 'ffmpeg -y -i in.mp4 -ss 00:00:00 -t 00:00:50 -acodec copy -vcodec copy -async 1 in_sub.mp4'
subprocess.call(cmd, shell=True)
上面代碼的意思是在cmd命令行中執行cmd這句命令,這個命令的意思是將in.mp4從0秒開始,裁剪到50秒,並保存為in_sub.mp4文件
2. 將文本寫入台詞
這個其實是最簡單的,網上有很多“營銷號文案生成器”,我隨便找了個源碼借鑒了下。首先你需要在一個文本文件中設定好主體、事件、另一種說法,例如
那么他就會生成文案
核桃核不能吞下去是怎么回事呢?核桃核相信大家都很熟悉,但是核桃核不能吞下去是怎么回事呢,下面就讓小編帶大家一起了解吧。核桃核不能吞下去,其實就是核桃核太大了,吞下去容易噎着,大家可能會很驚訝核桃核怎么會不能吞下去呢?但事實就是這樣,小編也感到非常驚訝。這就是關於核桃核不能吞下去的事情了,大家有什么想法呢,歡迎在評論區告訴小編一起討論哦!
其實非常簡單,就是一個字符串替換
def getText(file): # 組裝台詞 with open(file) as f: body = f.readline().strip() thing = f.readline().strip() other_word = f.readline().strip() # 主題框架 txt = '''{}{}是怎么回事呢?:4:0 {}相信大家都很熟悉,但是{}{}是怎么回事呢?:7:4 下面就讓小編帶大家一起了解吧:3:11 {}{},其實就是{}:8:15 大家可能會很驚訝{}怎么會{}呢?:6:23 但事實就是這樣,小編也感到非常驚訝:5:29 這就是關於{}{}的事情了,大家有什么想法呢?:6:34 歡迎在評論區告訴小編一起討論哦!:5:40'''.format(body, thing, body, body, thing, body, thing, other_word, body, thing, body, thing) # 台詞寫入 with open('text.txt', mode='w') as f: f.write(txt)
文本后面的數字代表意思分別是字幕的持續時間、開始出現的時間。比方說下面就讓小編帶大家一起了解吧這句話就會從第11秒開始出現,持續顯示3秒
3. 獲取視頻總時長
做這一步主要是考慮到BGM和視頻應該差不多時長,假如BGM有60秒,視頻只有50秒,那就會出現這樣一個現象,整個視頻的時長是60秒,但是當視頻播放到第50秒之后,畫面就不變化了,而BGM還在播放
所以這里獲取的視頻時長,是為了后面剪裁BGM使用的
但是又有人可能會覺得,你一開始不是設定了50秒,那這里為啥還要動態獲取時長,而不寫50秒呢?因為我考慮到后面的可擴展性,如果有用戶想要修改視頻時長,比方說改為60秒,那代碼就有很多地方也要修改。但是如果我用一個變量來代替,用戶就只需要修改第一步里的視頻時長即可
————————————————
def getLength(video): # 獲取視頻時長 cmd = 'ffprobe -v quiet -select_streams v -show_entries stream=duration -of csv="p=0" {video}'.format(video=video) seconds = os.popen(cmd, 'r') seconds = math.ceil(float(seconds.read())) m, s = divmod(seconds, 60) h, m = divmod(m, 60) return "%02d:%02d:%02d" % (h, m, s)
由於ffmpeg這個庫對時間的格式有要求,必須是00:00:00這種格式,所以我稍微做了一些處理
4. 給視頻添加背景音樂
這一步里面又分三小步
裁剪BGM
降低BGM音量
給視頻添加BGM
為什么要降低BGM音量,是因為我在后續測試的過程中發現BGM聲音有點太大了,掩蓋住了人聲
————————————————
def add_audio(video, mp3, output='out.mp4'): # 將背景音樂添加到視頻中 BGM = 'ffmpeg -i {mp3} -ss 00:00:00.0 -t {time} -acodec copy BGM.mp3'.format(mp3=mp3, time=total_time) subprocess.call(BGM, shell=True) volume = 'ffmpeg -i BGM.mp3 -vcodec copy -af "volume=-20dB" BGM_volume.mp3' subprocess.call(volume, shell=True) command = "ffmpeg -i {mp3} -i {video} -y {output}".format(video=video, mp3='BGM_volume.mp3', output=output) subprocess.call(command, shell=True)
給視頻添加字幕
添加字幕我用的是moviepy
這個庫,它里面有一個TextClip
方法,參數有很多,可以非常方便的添加字幕對象,然后將這些對象和視頻對象一起進行整合,就可以了
def subTitle(text_file, video_file, output='out_sub.mp4'): video1 = VideoFileClip(video_file) sentences = [] # 台詞列表 with open(text_file) as f: text_tmp = f.readlines() for i in text_tmp: sentences.append(i.strip().split(':')) print(sentences) txts = [] # 所有字幕剪輯 with open('args.txt') as f: color = f.readlines()[4].strip() for sentence, span, start in sentences: txt = (TextClip(sentence, fontsize=50, align='center', color=color, font='SimHei') .set_position(("center","bottom")).set_duration(int(span)).set_start(int(start))) txts.append(txt) video2 = CompositeVideoClip([video1, *txts]) video2.write_videofile(output)
6. 文本轉人聲 所有的步驟都可以自己完成,唯獨文本轉人聲不行,只能調用第三方接口,百度、騰訊、訊飛都可以,這里我用的訊飛的接口 [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2LYUgs3u-1587353056943)(https://s1.ax1x.com/2020/04/20/JQAm8J.png#shadow)] 代碼也是使用的訊飛提供的demo(python3),由於太多了,就不在這放出來了 實現的時候有一個細節要提一下,就是如何做到字幕和人聲同步 從上面的添加字幕可以看出,字幕的各種時間都是設定死的,那么能操作的也就是有人聲了。具體操作我是這樣做的,每一個字幕,生成一個人聲,一共有8段字幕,所以我有8個mp3文件,由於人聲是無法設置持續時間的,只能設置什么時間開始發聲,即只能設置開始時間,所以我把每一個mp3文件的開始時間都設置成每個字幕的開始時間相同。這樣做就會出現一個現象,假設某一段文本非常短,很快就讀完了,字幕也消失了,但是下一段字幕以及對應的人聲不會立即出現,而是單純的只有BGM,只有等這段字幕和人聲到點了,它們才會出現。不過我測試了實際效果並不突兀
7. 給視頻添加人聲
def addPeople(mp3_file, video_file): my_clip = VideoFileClip(video_file) audio_background = AudioFileClip(mp3_file) final_audio = CompositeAudioClip([my_clip.audio, audio_background]) final_clip = my_clip.set_audio(final_audio) final_clip.write_videofile('final.mp4')
8. 清除中間生成的文件
這步也非常簡單,因為使用ffmpeg
庫的時候,中間有一些臨時保存的mp3、mp4文件,在最后的時候刪除掉就行了
def addPeople(mp3_file, video_file): my_clip = VideoFileClip(video_file) audio_background = AudioFileClip(mp3_file) final_audio = CompositeAudioClip([my_clip.audio, audio_background]) final_clip = my_clip.set_audio(final_audio) final_clip.write_videofile('final.mp4')
————————————————
版權聲明:本文為CSDN博主「數學家是我理想」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_37236745/article/details/105619051