因最近項目需求涉及計算機視覺相關內容,須要實如今Python錄製視頻,而且錄製完成後可在瀏覽器前端中進行視頻回放的功能;特寫下此篇文章以記錄總體實現過程。php
以前一直在忙別的事,沒有繼續深刻探究,這篇文章也暫時擱置了;可是最近發現以前的實現方式(錄製avi視頻後由Java調用FFmpeg轉換爲mp4)會影響到系統的性能,緣由爲調用FFmpeg轉換視頻時CPU佔用較高QAQ,因而在此前的基礎上繼續尋找解決方式。html
既然FFmpeg的CPU佔用較高,那麼咱們首先嚐試如何下降對CPU的佔用,搜索發現能夠在FFmpeg命令中添加-threads
參數來指定CPU的使用前端
這次測試均使用相同avi視頻文件,大小爲113vue
ffmpeg -i test.avi -vcodec libx264 -f mp4 test.mp4
# 轉換用時 30s~31s
# CPU佔用 950%~1000%
複製代碼
-threads 6
參數ffmpeg -i test.avi -threads 6 -vcodec libx264 -f mp4 test.mp4
# 轉換用時 45s~46s
# CPU 佔用490%~550%
複製代碼
-threads 2
參數ffmpeg -i test.avi -threads 2 -vcodec libx264 -f mp4 test.mp4
# 轉換用時 87s~88s
# CPU佔用 205%~230%
複製代碼
能夠看出,添加-threads
參數後CPU的佔用確實少了,但相應的視頻轉換耗時也增長了,顯然這不是咱們想要的效果;因此仍是逃避不了錄製H264視頻的問題java
import cv2
正常引入便可,代碼就不放了,原文和網上都有,只是改個fourcc。import cv2
複製代碼
入參傳入「0」、「1」、「2」等數字爲攝像頭索引,0爲自帶攝像頭,可按順序調用攝像頭,也可傳入視頻文件路徑python
cap = cv2.VideoCapture(0)
複製代碼
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
複製代碼
使用攝像頭幀率錄製視頻後播放存在快進狀況,暫時寫死在VideoWriter中 不知道是否與攝像頭有關,此處未進行深刻了解 fps = cap.get(cv2. CV_CAP_PROP_FPS)nginx
須要傳入fourcc(four character code)四字符編解碼代碼: fourcc參考git
encode = cv2.VideoWriter_fourcc(*'mp4v')
複製代碼
入參參考:官方文檔github
out = cv2.VideoWriter( './test.mp4', encode, 10, (width, height), True)
複製代碼
while True:
if cv2.waitKey(25) & 0xFF == ord('q'):
break
ret, frame = cap.read()
cv2.imshow('test', frame)
out.write(frame)
複製代碼
out.release()
cap.release()
cv2.destroyAllWindows()
複製代碼
此處代碼爲演示demo,僅供參考跨域
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import cv2
# 調用攝像頭
cap = cv2.VideoCapture(0)
# 獲取攝像頭寬高
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# 獲取攝像頭幀率
#fps = cap.get(cv2.CAP_PROP_FPS)
# 指定fourcc編解碼
encode = cv2.VideoWriter_fourcc(*'mp4v')
# 初始化VideoWriter
out = cv2.VideoWriter('./test.mp4', encode, 10, (width, height), True)
while True:
# 每隔25毫秒播放下一幀,若鍵入「q」跳出循環
if cv2.waitKey(25) & 0xFF == ord('q'):
break
# 從攝像頭獲取下一幀
ret, frame = cap.read()
# 新開窗口展現圖像
cv2.imshow('test', frame)
# 將當前幀寫入視頻文件
out.write(frame)
# 釋放VideoWriter
out.release()
# 釋放攝像頭
cap.release()
# 關閉窗口
cv2.destroyAllWindows()
複製代碼
python錄製視頻是否成功
前端中video的src是否正確
瀏覽器控制檯是否報錯
nginx服務是否啓動
請求路徑是否正確
是否跨域問題
格式 | IE | Firefox | Opera | Chrome | Safari |
---|---|---|---|---|---|
Ogg | - | 3.5+ | 10.5+ | 5.0+ | - |
MPEG 4 | 9.0+ | - | - | 5.0+ | 3.0+ |
WebM | - | 4.0+ | 10.6+ | 6.0+ | - |
格式 | 視頻編碼 | 音頻編碼 |
---|---|---|
Ogg | Theora | Vorbis |
MPEG 4 | H.264 | AAC |
WebM | VP8 | Vorbis |
排除代碼及網絡請求問題後,能夠將問題定位在瀏覽器,我使用的瀏覽器爲Chrome,排除版本問題,所以能夠肯定是視頻編解碼問題,在python中錄製視頻時未使用H.264編解碼:
encode = cv2.VideoWriter_fourcc(*'mp4v')
複製代碼
查看視頻簡介能夠發現該視頻也確實非H.264編解碼,所以形成該視頻能夠在視頻播放軟件中正常播放卻沒法在h5的video中播放,見下圖:
encode = cv2.VideoWriter_fourcc(*'X264')
複製代碼
貌似不支持這個編解碼QAQ,好像須要FFmpeg的庫,Ubuntu下在終端輸入:
$sudo apt-get install ffmpeg x264 libx264-dev
複製代碼
安裝完成後Ubuntu上沒法錄製(視頻文件都沒法生成),可是在我本身的電腦不影響錄製:
首先安裝FFmpeg (Ubuntu下我沒有安裝,好像是自帶的?) macOS安裝FFmpeg Ubuntu安裝FFmpeg java這邊就再也不詳述了,直接上代碼~(一樣爲演示demo,僅供參考)
// FFmpeg轉換命令
String transferCommand = "ffmpeg -i filePath/fileName.avi -vcodec libx264 -f mp4 filePath/fileName.mp4";
Process process = Runtime.getRuntime().exec("/bin/bash");
printWriter = new PrintWriter(new BufferedWriter(new
OutputStreamWriter(process.getOutputStream())), true);
printWriter.println(transferCommand);
// 這個命令必須執行,不然in流不結束。
printWriter.println("exit");
printWriter.close();
process.waitFor();
複製代碼
轉換過程須要些許時間,採起方案爲啓一條線程完成視頻轉換,不影響當前接口響應時間,在用戶無感知的狀況下完成視頻轉換。
以上內容爲本次實現過程記錄,代碼均爲演示demo,非實際應用代碼,若有須要可根據實際需求加以調整。由於時間緣由未能在錄製H.264視頻上投入過多精力,可能將來會繼續嘗試~