影像處理的範圍過於龐大, 包含ffmpeg, opencv, 作業系統, 安裝方式, 操作方式, 及Python的支援方式. 所以才獨立此項目分別說明.
FFmpeg簡介
FFmpeg是一套可以用來記錄, 轉換音頻視頻, 並能將其轉化為stream的開源程式. 採用LGPL/GPL授權模式. 提供了錄制, 轉換及流化音視頻的完整解決方案.
FFmepg是在Linux平台上開發出來的. 但經過重新編譯後, 在Windows及Mac OS X也可以使用. 早期由Fabrice Bellard發起, 後來由Michael Niedermayer負責維護. 裏面的成員都來自於MPlayer這個專案. FF 表示 Fast Forward 的意思
FFmepg組成
ffmpeg由三個部份組成. 第一個為完成品工具, 第二為 SDK, 第三為完整代碼
完成品工具
共有四個工具
ffmpeg : 音視頻轉碼
ffplay : 簡易音視頻播放器
ffserver : stream媒体服務器
ffprobe : 分析器
SDK
可供自行撰寫程式碼調用的函數庫, 常見的有如下
libavcode : 編碼器及解碼器
libavutil : 常用工具, 如隨機亂數生成器, 數據結構, 數學函數
libavformat : 多媒体容器格式的封裝, 解封裝
libavfilter : 瀘鏡功能
libavdevice : 音視頻數據採集和渲染等功能的相關設備
libswscale : 圖像網放及其他轉換功能
libswresample : 音訊頻重新採樣和格式轉換
Linux安裝
sudo apt-get install ffmpeg
Windows安裝
進入 http://ffmpeg.org/download.html , 然後選取 shared的版本, 解開後即可使用, 請記得設定系統環境變數 path
簡易操作
ffmpeg -h : 相關命令查詢
ffmpeg -i test.mp4 : 查詢影片的編碼方式及相關資訊
參數格式
ffmpeg [options] [[infile options] -i infile] {[outfile options] outfile}
optoins : 針對 ffmpeg的設定選項
infile option : 針對輸入影像的設定選項
outfile option :針對輸出影像的設定選項
常用查詢
ffmpeg -f v4l2 -list_formats all -i /dev/video0 #查詢解析度
ffprobe -v quiet -print_format json -show_format -show_streams -i /dev/video0 #查webcam參數
v4l2-ctl --list-formats-ext
轉檔
在Windows下,直接使用ffmpeg轉檔指令如下
ffmpeg -hwaccel cuvid -c:v h264_cuvid -i 魔鬼終結者6.黑暗宿命.Terminator.Dark.Fate.2019.2160p.mkv -b:v 6000k -c:v h264_nvenc out.mp4
使用此方法轉檔,比格式化工廠更快,畫質更好。
ffmpeg 推播
推播電影
ffmpeg -i Videos/snake.mkv \ -b:v 4000k -r 24 -c:a aac -ac 1 -strict -2 -b:a 128k -ar 44100 -c:v h264_omx -f flv rtmp://mahaljsp.asuscomm.com/live/movie \ -b:v 4000k -r 24 -c:a aac -ac 1 -strict -2 -b:a 128k -ar 44100 -c:v h264_omx -f segment -segment_time 00:20:00 -reset_timestamps 1 output%03d.mp4
上述指令中, 使用硬体編碼 h264_omx, 一邊推播, 一邊儲存在樹莓派的sdcard上. 其cpu的資源耗損只有 200%(全速是 400%), 而且每秒幀輻可達24fps. 所以對樹莓派而言, 簡直是輕而易舉.
將轉檔結果儲存成檔案. 若要依一段時間就切割檔案, 使用如下參數
-segment_time 00:20:00 -f segment -reset_timestamps 1 output%03d.mp4
推播WebCam
底下為二路編碼輸入二路, 速度很慢
nohup ffmpeg -video_size 1920x1080 -input_format mjpeg -i /dev/video0 \
-vf drawtext='fontfile=fonts/FreeSerif.ttf:text=%{localtime}:x=5:y=20:fontcolor=white:fontsize=36:box=1:boxcolor=0x000000@0.5' \
-b:v 4000k -r 24 -c:a aac -ac 1 -strict -2 -b:a 128k -ar 44100 -c:v h264_omx -f flv rtmp://mahaljsp.asuscomm.com/live/car \
-vf drawtext='fontfile=fonts/FreeSerif.ttf:text=%{localtime}:x=5:y=20:fontcolor=white:fontsize=36:box=1:boxcolor=0x000000@0.5' \
-b:v 4000k -r 24 -c:a aac -ac 1 -strict -2 -b:a 128k -ar 44100 -c:v h264_omx -f segment -segment_time 00:20:00 -reset_timestamps 1 output%03d.mp4
推播並儲存
以下使用usb webcam可以達到22fps, cpu只佔用 86%
單一編碼分二路, 一定要加 -flags global_header, 否則無法執行
#!/bin/bash
while ! ping -q -c 1 -W 1 google.com
do
sleep 1
done
ffmpeg -input_format mjpeg -video_size 1600x896 -i /dev/video0 \
-f alsa -i hw:1,0 \
-flags global_header \
-vf drawtext='fontfile=fonts/FreeSerif.ttf:text=%{localtime}:x=5:y=20:fontcolor=white:fontsize=36:box=1:boxcolor=0x000000@0.5' \
-b:v 4000k -vcodec h264_omx \
-c:a aac -b:a 64k \
-profile:v baseline -preset veryfast -pix_fmt yuv420p \
-f tee -map 0:v -map 1:a \
"[f=segment:segment_atclocktime=1:segment_time=1800:strftime=1]/home/pi/records/car_%Y%m%d-%H%M%S.mp4|\
[f=flv:onfail=ignore]rtmp://mahaljsp.asuscomm.com/live/car"
av
Windows : pip install av
Linux : sudo pip3 install av
av 調用ffmpeg 的sdk來執行的, 可以作更精細的動作. 只可惜的是, 並不支援硬体編碼. 而且官方也說了, 硬体編碼不在此專案的計畫當中, 看來只能死心了.
存成圖片
底下代碼, 可以把影片裏的frame一幅一幅的存成 jpg圖片檔
ffmpeg指令 : ffmpeg -i ../snake.mkv -r 1 img-%5d.jpg
-r 1 : 每秒取一張. 數字可以自已變更
#!/usr/bin/python3 import av container = av.open("../snake.mkv") stream = container.streams.video[0] stream.codec_context.skip_frame = 'NONKEY' for frame in container.decode(stream): frame.to_image().save('f-%04d.jpg' % frame.pts)
轉換格式
import av import av.datasets input_ = av.open(path_to_video) output = av.open('remuxed.mkv', 'w') in_stream = input_.streams.video[0] out_stream = output.add_stream(template=in_stream) for packet in input_.demux(in_stream): if packet.dts is None: continue packet.stream = out_stream output.mux(packet) output.close()
推播到rtmp
下面代碼, 可以自web cam取得影像, 解碼成 image後, 處理image, 然後再推播到rtmp. 只可惜 output_的編碼器若使用 h264_omx, 則整個會當掉. 此為PyAv的bug, 目前尚無解
所以只能用軟体編碼 “h264”, fps 只剩下 5fps. 所以目前放棄使用 PyAv
#!/usr/bin/python3
import av
import cv2
from datetime import datetime
input_ = av.open("/dev/video0")
in_stream=input_.streams.video[0]
in_stream.options={"input_format":"mjpeg", "video_size":"1920x1080"}
#in_stream.width=1920
#in_stream.height=1080
output_=av.open('rtmp://mahaljsp.asuscomm.com/live/car',mode='w', format='flv')
output_stream = output_.add_stream(codec_name="h264",rate=24)
output_stream.options = {"b":"4000k", "vcodec":"libx264", "video_size":"1920x1080"}
t1=datetime.now()
t2=t1
index=0
for frame in input_.decode(in_stream):
for packet in output_stream.encode(frame):
output_.mux(packet)
t2=datetime.now()
if (t2-t1).seconds>0:
print(index)
index=0
t1=t2
else:
index+=1
cv2.waitKey(5)
output_.close()
轉換成image再推播
此方式因要處理圖片, 所以要先 sudo pip3 install Pillow ttf-wqy-zenhei
#!/usr/bin/python3
import av
import time
import cv2
from PIL import ImageDraw
from PIL import ImageFont
from datetime import datetime
infile = av.open("/dev/video0")
instream=infile.streams.video[0]
instream.options={"input_format":"mjpeg", "video_size":"1920x1080"}
outfile=av.open('rtmp://mahaljsp.asuscomm.com/live/car',mode='w', format='flv')
outstream = outfile.add_stream(codec_name="h264",rate=24)
outstream.options = {"b":"4000k", "vcodec":"h264_omx", "video_size":"1920x1080", "threads":"16"}
t1=round(time.time() * 1000)
t2=t1
index=0
for packet in infile.demux():
frame=packet.decode()[0]
img = frame.to_image()
datetime_dt = datetime.today() # 獲得當地時間
datetime_str = datetime_dt.strftime("%Y/%m/%d %H:%M:%S") # 格式化日期
draw = ImageDraw.Draw(img)
draw.text((10,30), datetime_str, font=ImageFont.truetype("/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc",36), fill=(0, 255, 255, 255))
#底下這最編碼, 在樹莓派若採軟体編碼, 非常的慢, 頂多 2fps而以
out_packet = outstream.encode(av.VideoFrame.from_image(img))
outfile.mux(out_packet)
t2=round(time.time() * 1000)
if (t2-t1)>=1000:
print(index)
index=0
t1=round(time.time() * 1000)
else:
index+=1
Windows 版
#!/usr/bin/python3 import av import time import cv2 from PIL import ImageDraw from PIL import ImageFont from datetime import datetime #infile = av.open("/dev/video0") infile = av.open("c922 Pro Stream Webcam", mode='r', format='vfwcap') instream=infile.streams.video[0] instream.options={"input_format":"mjpeg", "video_size":"1920x1080"} outfile=av.open('rtmp://mahaljsp.asuscomm.com/live/car',mode='w', format='flv') outstream = outfile.add_stream(codec_name="h264_nvenc",rate=24) outstream.options = {"b":"4000k", "video_size":"1920x1080", "threads":"16"} t1=round(time.time() * 1000) t2=t1 index=0 for packet in infile.demux(): frame=packet.decode()[0] img = frame.to_image() datetime_dt = datetime.today() # 獲得當地時間 datetime_str = datetime_dt.strftime("%Y/%m/%d %H:%M:%S") # 格式化日期 draw = ImageDraw.Draw(img) #draw.text((10,30), datetime_str, font=ImageFont.truetype("/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc",36), fill=(0, 255, 255, 255)) draw.text((10, 30), datetime_str, font=ImageFont.truetype("arial.ttf", 36),fill=(0, 255, 255, 255)) #底下這最編碼, 在樹莓派若採軟体編碼, 非常的慢, 頂多 2fps而以 out_packet = outstream.encode(av.VideoFrame.from_image(img)) outfile.mux(out_packet) t2=round(time.time() * 1000) if (t2-t1)>=1000: print(index) index=0 t1=round(time.time() * 1000) else: index+=1
ffmpy3
Windows : pip install ffmpy3
Linux : sudo pip3 install ffmpy3
ffmpy3好像是去執行ffmpeg這支程式的, 還不確定, 測試中
ffmpy3是在Python裏調用ffmpeg這支程式, 進行音視訊的操作, 記得將 ffmpeg這支程式放在專案裏
blog.csdn.net/qq_40962368/article/details/91355429
ffmpeg with C++
組合語言是現今CPU 的語言, 而c or c++是人類與CPU之間最直接的溝通橋樑, 無人可匹敵.
C/C++ 有如文言文, 讓很多人卻步, 轉而學習其他語言, 如Java, Python. 是的, 的確是如此, 但這只是短視近利的商人眼中才會有如此想法跟作法.
使用 c++調用 ffmpeg的 sdk, 其實是有必要性的. 客製化自已想要的功能, 再加上Python薄弱的支援, 運行速度的關係, 都顯示了在樹莓派使用C++撰寫程式碼的需求.
安裝套件
底下是安裝 ffmpeg 的 library
sudo apt-get install libavcodec-dev libavformat-dev libavfilter-dev libavdevice-dev
Hello world
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <stdlib.h>
#include <stdio.h>
int main(){
printf("%d", 10);
}
makefile
PROG= main
CFLAGS+= -Wall -std=c99 -g
LDFLAGS+= -lavcodec -lavformat -lavutil -lm
all: ${PROG}
$(PROG):$(PROG).cpp
cc $(CFLAGS) $(PROG).cpp $(LDFLAGS) -o $(PROG)
clean:
rm -f $(PROG}
編譯
make