背景
現在遇到了一個這樣的問題,有兩個視頻,分辨率大小一致,需要將兩個視頻左右拼接在一起,類似直播平台打PK時的那種,左邊是一個畫面,右邊是另一個畫面的場景。面對這樣的問題,我首先的做法是看一下ffmpeg是否有現成的命令,直接在一個畫布上放置兩個視頻。但是搜索了很久沒有找到滿意的結果,加上給我的時間比較短,所以我采取了簡單但是步驟比較多的方式解決了該問題。
技術
語言:python3.6
組件:opencv、ffmpeg
思路
1、首先使用opencv將兩個視頻全部圖片幀提取出來。
2、按照圖序兩兩圖片幀進行水平拼接合並,生成新的圖組。
3、將新的圖組壓縮成視頻。
4、將兩個視頻文件的音頻提取出來,並且按照兩個音軌合並成一個音頻。
5、將新圖組壓縮的視頻和新的音頻進行合並得到最終的視頻。
下面是按照這個思路,每步制作的過程。
過程
1、提取圖片幀(opencv)
使用opencv將視頻圖片幀按照順序提取出來
# =============================================================================
# opencv生成圖片序列
# =============================================================================
import cv2
# 寫圖片
def save_image(num, image):
"""Save the images.
Args:
num: serial number
image: image resource
Returns:
None
"""
image_path = 'images/video1/{}.jpg'.format(str(num))
cv2.imwrite(image_path, image)
file_path = 'videos/demo1.mp4'
vc = cv2.VideoCapture(file_path) # import video files
# determine whether to open normally
if vc.isOpened():
ret, frame = vc.read()
else:
ret = False
count = 1 # count the number of pictures
frame_interval = 30 # video frame count interval frequency
frame_interval_count = 0
# loop read video frame
while ret:
ret, frame = vc.read()
# store operation every time f frame
# if frame_interval_count % frame_interval == 0:
save_image(count, frame)
print("num:" + str(count) + ", frame: " +
str(frame_interval_count))
count += 1
frame_interval_count += 1
# cv2.waitKey(1)
vc.release()
這樣獲取了兩個視頻的所有圖片幀,按照數字進行了編號。
2、合成新圖組(opencv)
現在需要把兩個圖組的每一個對應編號的圖進行水平拼接,代碼如下:
# =============================================================================
# 水平合成圖組
# =============================================================================
import cv2
import numpy as np
# 按照兩個圖組的最小值+1,作為循環的最大值邊界
for i in range(1,2225):
img1 = cv2.imread('images/video1/{}.jpg'.format(i))
img2 = cv2.imread('images/video2/{}.jpg'.format(i))
# img1 = cv2.resize(img1, (720, 1280))
# img2 = cv2.resize(img2, (720, 1280))
# 核心代碼
image = np.concatenate([img1, img2], axis=1)
cv2.imwrite('images/result/{}.jpg'.format(i), image)
完成這一步就已經得到了水平拼接的所有圖片。
3、壓縮新圖組變成新視頻(opencv)
現在需要把圖組壓縮成視頻,要考慮到原始視頻的幀率,保持一致。
# =============================================================================
# 壓縮圖片為視頻
# =============================================================================
import cv2
import os
fourcc = cv2.VideoWriter_fourcc(*'XVID')
videoWriter = cv2.VideoWriter('videos/new.mp4', fourcc, 30, (1440,1280))
for i in range(1, 2225): #有多少張圖片,從編號1到編號2224
image_number = i
if not os.path.exists('images/result/{}.jpg'.format(str(i))):
continue
img12 = cv2.imread('images/result/' + str(i) + '.jpg')
#cv2.imshow('img', img12)
#cv2.waitKey(1)
videoWriter.write(img12)
videoWriter.release()
執行完上面的代碼,已經獲得了一個水平拼接好的視頻,但是沒有聲音,下面來制作音頻。
4、提取音頻、合並音頻(ffmpeg)
使用ffmpeg對素材視頻音頻提取
ffmpeg -i videos/demo1.mp4 -acodec pcm_s16le -f s16le -ac 1 -ar 16000 -f wav audio/demo1.wav
ffmpeg -i videos/demo2.mp4 -acodec pcm_s16le -f s16le -ac 1 -ar 16000 -f wav audio/demo2.wav
至於ffmpeg這條命令的參數說明就不多說了,音頻幾個基本參數
下面開始合並音頻
ffmpeg -y -i audio/demo1.wav -i audio/demo2.wav -filter_complex "[0:0][1:0] amix=inputs=2:duration=longest" -c:a libmp3lame audio/new.mp3
別問為什么2個wav為啥要合並成一個mp3,這個完全看心情。
5、將新音頻壓縮至新視頻(ffmpeg)
使用ffmpeg進行壓縮
ffmpeg -i videos/new.mp4 -i audio/new.mp3 -map 0:v -map 1:a -c copy -shortest videos/final.mp4
得到最終視頻。
后記
這篇文章給的方法一定不是解決這個問題最優的方法,只是我對ffmpeg研究很淺,無法立馬寫出對應指令,如果有對ffmpeg研究很深的兄弟,可以留言提供那個最優解決方案。本篇文章,只是參考,希望給碰到相同問題的朋友提供一種解決方案。