FFmepg 推播

      在〈FFmepg 推播〉中尚無留言

影像處理的範圍過於龐大, 包含ffmpeg, opencv, 作業系統, 安裝方式, 操作方式, 及Python的支援方式. 所以才獨立此項目分別說明.

FFmpeg簡介

FFmpeg是一套可以用來記錄, 轉換音頻視頻, 並能將其轉化為stream的開源程式. 採用LGPL/GPL授權模式. 提供了錄制, 轉換及流化音視頻的完整解決方案.

FFmepg是在Linux平台上開發出來的. 但經過重新編譯後, 在Windows及Mac OS X也可以使用. 早期由Fabrice Bellard發起, 後來由Michael Niedermayer負責維護. 裏面的成員都來自於MPlayer這個專案. FF 表示 Fast Forward 的意思

官網:https://www.ffmpeg.org/

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 推播

底下的說明, 為將影片輸出到多個目的地(rtmp:flv 及 儲存檔案:h264)

 

推播電影

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

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *