錄
1主界面簡介
該界面是M2000的主要操作界面,這里是命令航界面,可以看到你要操作對象站點,查詢命令,命令反饋區域及命令參數輸入區域。
注意:操作對象基站可以多個選取多個基站進行操作,所以執行命令時確認只選中你要操作的對象。
2查詢
2.1小區狀態
2.1.1顯示小區動態信息
該命令主要是查詢小區的動態參數,可以看出小區是否正常建立;如果無法建立,會顯示“沒有可用的載波資源”等提示。
2.1.2查詢小區靜態信息
該命令是顯示小區的靜態參數,就是我們實際配置的小區參數都可以在這里看到,修改PCI的時候重點關注小區的靜態參數。
UBL CELL:解閉塞小區
BLK CELL:閉塞小區
這里在介紹一下華為命令組成及作用:
動作命令+操作對象
這里動作命令常用如下表所示:
UBL
解閉塞
BLK
閉塞
DSP
查詢動態信息
LST
查詢靜態信息
ADD
添加
RMV
移除
MOD
修改
這里操作目標很多,包括:EUTRANEXTERNCELL、BRD、SFP等等,常用已經在上面給出部分操作對象。
2.2eNodeB ID
LST ENODEBFUNCTION
這里可以顯示基站的eNodeBID。在修改eNodeBID的時候,必須要執行APP操作來對基站進行復位操作,否者無法成功修改基站ID;同時,修改前必須保證已經刪除站內同頻鄰區。復位操作后,基站可以通過X2接口來更新周圍基站中關于本基站的信息,如外部小區參數,鄰區關系參數等等。
2.3光功率
DSP SFP
這條命令是顯示光模塊的收發功率的,BBU側光模塊位于柜號0,框號0,槽號3,光口號0、2、4;RRU側光模塊位于柜號0,框號60、62、64,槽號0。
3增加X2鏈路
步驟1:ADD SCTPLINK
這里命令是“添加SCTP鏈路”
這里要注意的是柜號、框號、槽號,這里機柜號一般為0,BBU框號為0,RRU框號根據基帶板在不同的插槽而不同;如果LBBP位于3號槽位,RRU框號起始為60;槽位號,LBBP單板位于0~5號槽位,UMPT單板位于6~7號單板。
SCTP鏈路是建立基站到基站,基站到核心網的邏輯鏈路。
建立SCTP鏈路只需要知道源目的IP地址及端口號就可以建立SCTP鏈路,基站與基站的SCTP鏈路是需要雙向配置,到達核心網的不需要。
步驟2:ADD CPBEARER
這里用于“添加控制端口承載”
該命令必須建立在SCTP鏈路之上。
步驟3::ADD X2INTERFACE
這里命令是“添加X2接口”
這里是真正建立X2接口,需要CP承載號,運營商索引值,執行完畢后可以使用DSP X2 INTERFACE查看X2接口的運行狀態。
4修改功率
步驟1:MOD PDSCHCFG
這里的命令是修改小區的RS參考功率,參考信號功率單位是0.1dBm,比如功率是16.4dBm,這里是164。
5灌包操作
這里的灌包是在Linux服務器上進行的灌包操作,因為Linux服務器特點在于命令行,以下是Linux系統輸入的iperf命令例句:
iperf -c xxx.xxx.xxx.xxx -u -b 150m -t 99999 -i
windows上進行灌包比較容易如下圖:
上面方框是:1.目標IP地址;2.協議類型UDP;3.上行傳輸;4.帶寬大小;5.持續時間;
然后點擊開始就可以了。
6下行沖包
下行沖包是eNodeB側到UE側的沖包,而iperf從服務器上直接灌包到UE側,作用單范圍不同,可以排查相應位置的故障的問題。操作步驟如下:
步驟1:首先獲取UE的TMSI和E-RAB ID
有兩種獲取方法可以從信令跟蹤中獲取;也可以在eNodeB上通過DSP ALLUEBASICINFO與DSP UEONLINEINFO兩條命令獲取當前存在的用戶。信令的獲取方法可以參考信令分析指導書。
在eNodeB上使用命令查詢的方法:適合實驗室或現網小區下只有1個用戶的情況。
DSP ALLUEBASICINFO:LOCALCELLID=0;
DSP UEONLINEINFO:DSPMODE=STMSI,MMECODE=22,MTMSI=3255762945;
其中的ERAB列表如下:
步驟2:啟動空口下行沖包測試
在M2000或者webLMT上執行如下MML命令:(注意藍色字體的MMECODE、TMSI和ERAB-ID需要根據實際用戶設置)
STRUUDATATST:UEIDTYPE=STMSI_TYPE,MMECODE=22,MTMSI=3255762945,ERABID=5,SRCIP="5.5.5.5",SRCPORT=55,DSTIP="6.6.6.6",DSTPORT=55,PKTSIZE=1500,RATE=150000,TIME=360;
步驟3:查詢結果:DSP UUDATATST:;
:
從吞吐量監測中可以看到達到了小區最大峰值(15M、TM1)
下面是沖50M的測試:
步驟5:停止空口下行沖包測試
:
其他:需要用隨機數來啟動的場景
UE首次Attach時,沒有TMSI,會以隨機數接入,此時DSP ALLUEBASICINFO查詢到的UE標識為隨機數,后續的命令中都要以隨機數來查詢。如下:
DSP ALLUEBASICINFO:LOCALCELLID=0;
DSP UEONLINEINFO:DSPMODE=UEID,UEID="063178DAD2";
STRUUDATATST:UEIDTYPE=UEID_TYPE,UEID="063178DAD2",ERABID=5,SRCIP="5.5.5.5",SRCPORT=55,DSTIP="6.6.6.6",DSTPORT=55,PKTSIZE=1500,RATE=150000,TIME=360;
7集中任務管理
點擊”維護“->”集中任務管理“->”創建”,加上名字,點擊下一步,選擇MML腳本,進行執行。
8信令跟蹤
8.1S1接口信令跟蹤
S1接口是eNodeB到MME/SGW上的鏈路,S1標準信令跟蹤可以跟蹤所有的eNodeB與MME/SGW之間的信令,但無法跟蹤單用戶在S1接口上的信令。X接口自建立是通過S1接口完成自建立的。
8.2X2接口信令跟蹤
菜單欄“監控”->“信令跟蹤”->”S1標準跟蹤”,選擇站點,設置時間及周期
8.3Uu接口信令跟蹤
菜單欄“監控”->”信令跟蹤管理”-“Uu接口跟蹤“
8.4RSSI統計監控
菜單欄”監控“->”信令跟蹤管理“->”RSSI指標”
8.5用戶數監控
這里可以看到小區總用戶數、非激活用戶數、保持上行同步用戶數。
這里可以看到小區RLC層的比特速率,GBR業務速率
8.6MLB監控
這里可以看到負載分擔時等效RB運用量,根據具體設置來進行負載分擔,紅框內是參與負載分擔的小區。
9導出現網數據
9.1Summary
這里的Summary表里面記錄了基站無線側所有的參數,基站開站就是導入Summary表開展。
9.2無線網絡規劃數據
這里的位置是CME->高級->全景瀏覽,可以根據列出的參數把基站數據導出。
10算法開關
10.1eNodeB算法開關
LST ENODEBALGOSWITCH
這里基站切換算法開關很多,只需要找到對應的算法開關,用MOD進行修改就可以了。
10.2小區級算法開關
LST CELLALGOSWITCH
11EUTRAN添加鄰區
11.1同頻
11.1.1基站內同頻小區建立鄰區關系
步驟1:ADD EUTRANINTRAFREQNCELL
該命令為“添加EUTRAN的鄰區關系”
移動國家碼、移動網絡碼、基站標識、小區標識皆為目標小區的基站參數,本地小區標識為本基站的服務小區標識。
11.1.2站間同頻小區建立鄰區關系
步驟1:ADD EUTRANEXTERNALCELL
該命令的為“添加EUTRAN的外部小區”
移動網絡碼、移動國家碼、基站標識、小區標識、下行頻點、物理小區標識、跟蹤區域碼都是目標小區的基站參數
步驟2:ADD EUTRANINTRAFREQNCELL
該命令為“添加EUTRAN的鄰區關系”
移動國家碼、移動網絡碼、基站標識、小區標識皆為目標小區的基站參數,本地小區標識為本基站的服務小區標識。這里需要注意,在與周圍建立鄰區關系的時候,保證鄰區的PCI不要相同,否則會產生“PCI沖突告警”。
這里的“小區偏移量”(即CellIndividualOffset)就是我們所說的CIO參數,系統默認為0dB.
11.2異頻
11.2.1站內異頻小區建立鄰區關系
步驟1:ADD EUTRANINTERNFREQ
該命令是“添加EUTRAN的異頻相鄰點信息”
下行頻點及測量帶寬都是目標小區的下行頻點及測量帶寬,這里可以設置異頻切換觸發的類型。
步驟2:ADD EUTRANINTERFREQNCELL
11.2.2站外異頻小區建立鄰區關系
步驟1:ADD EUTRANINTERNFREQ
該命令為“添加EUTRAN的鄰區關系”
移動國家碼、移動網絡碼、基站標識、小區標識皆為目標小區的基站參數,本地小區標識為本基站的服務小區標識。
這里的“小區偏移量”(即CellIndividualOffset)就是我們所說的CIO參數,系統默認為0dB.
步驟2:ADD EUTRANEXTERNALCELL
該命令的為“添加EUTRAN的外部小區”
移動網絡碼、移動國家碼、基站標識、小區標識、下行頻點、物理小區標識、跟蹤區域碼都是目標小區的基站參數
步驟3:ADD EUTRANINTERFREQNCELL
該命令為“添加EUTRAN的鄰區關系”
移動國家碼、移動網絡碼、基站標識、小區標識皆為目標小區的基站參數,本地小區標識為本基站的服務小區標識。
12KPI指標統計
步驟1:開啟測量管理
點擊“性能”->“測量管理”->點擊需要測量的指標->“選擇對象”及“測量指標”及”測量時間“->”確定”。
步驟2:查詢結果
點擊”左邊白色區域右鍵點擊新查詢“->”選擇指標、對象“->點擊”線狀圖“及”柱狀圖“來查看結果。
DeFFcode是一種跨平臺的高性能視頻幀解碼器,通過內部封裝ffmpeg,提供GPU解碼支持,幾行python代碼就能夠快速解碼視頻幀,并具有強大的錯誤處理能力。DeFFcode的APIs支持多種媒體流作為輸入源,例如IP攝像機、常規多媒體文件、屏幕錄制、圖像序列、網絡協議(例如 HTTP(s)、RTP/RSTP)等。由于FFmpeg的學習曲線非常陡峭,封裝FFmpeg后的DeFFcode提供類似OpenCV-Python編碼語法來幫助用戶,使得在Python中學習、創建和開發基于FFmpeg的應用程序變得更加容易。DeFFcode的官方代碼倉庫見:?deffcode???。DeFFcode的官方文檔見??deffcode_doc??。
DeFFcode的作者專注于音視頻流的處理,除了Deffcode,作者還開源了Python視頻處理庫??VidGear??。VidGear的具體使用見??Python視頻處理庫VidGear使用指北??。DeFFcode還處于快速發展階段,許多功能還需要完善。VidGear提供了比DeFFcode更豐富的視頻處理接口,但是DeFFcode提供了比VidGear更高效更專業的視頻解碼接口。如果想要從事音視頻流解碼相關工作,還是學習ffmpeg的C++代碼使用。
入門ffmpeg使用或者想要對音視頻處理有所了解推薦看看雷霄驊的博客。雷霄驊是視音頻技術處理的專家,也是國內音視頻領域無償分享技術最多的程序員。但是很不幸雷霄驊因過度勞累于2016年與世長辭,所以大家還是多注意身體健康。身體才是革命的本錢,少加班,該休息就得休息,沒有時間休息的人注定沒有時間生病。
對于DeFFcode,python版本需要高于3.7。DeFFcode支持以下系統:
Deffcode安裝代碼如下:
pip install -U deffcode
特別要注意的是DeFFcode必須要安裝ffmpeg執行文件。安裝ffmpeg,其它系統自行搜索安裝方法,ubuntu下直接輸入:
sudo apt install ffmpeg
視頻流解碼
DeFFcode核心功能就是利用ffmpeg進行視頻解碼。相關公開測試視頻流地址為:
from deffcode import FFdecoder
import cv2
# FFedecoder創建視頻源和視頻解碼規則,formulate在ffmpeg中執行語句
# 本地視頻
# decoder = FFdecoder("test.mp4").formulate()
# rtsp流
decoder = FFdecoder("rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4").formulate()
# 從decoder中抓取RGB圖像
for frame in decoder.generateFrame():
print(frame.shape)
# 將rgb圖像轉換為bgr圖像,送給opencv展示
frame_bgr = frame[:, :, ::-1]
cv2.imshow("Output Frame", frame_bgr)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
# 安全關閉解碼進程
decoder.terminate()
視頻流屬性識別
對于給定的輸入源,DeFFcode使用各種方法識別視頻流其中包含的文件所有屬性,比如是否包含音頻,圖像分辨率,視頻碼率。不同的視頻流返回的屬性參數不同,具體按需要探索下就行了。
from deffcode import Sourcer
# sourcer設置定位視頻流中的數據信息,probe_stream探測視頻流的輸出
sourcer = Sourcer("test.mp4").probe_stream()
# 解析為python字典數據
data = sourcer.retrieve_metadata()
# pretty_json表示解析為類似json.dump后的json字符串
print(sourcer.retrieve_metadata(pretty_json=True))
DeFFcode的FFdecoder API很容易支持多媒體視頻文件路徑作為其source參數的輸入。通過它的frame_format參數,您可以輕松解碼所有知名計算機視覺庫(例如 OpenCV)都支持的任何像素格式的視頻幀。FFdecoder API 的generateFrame()函數可用于多種方法來訪問來自給定源的RGB幀,例如生成器(推薦方法)、調用with語句和迭代器。在下面示例中,我們將使用上述訪問方法從給定的視頻文件中解碼默認的RGB24視頻幀。
生成器調用
from deffcode import FFdecoder
decoder = FFdecoder("test.mp4").formulate()
# 讀取RGB24圖像
for frame in decoder.generateFrame():
if frame is None:
break
print(frame.shape)
decoder.terminate()
with調用
調用with語句方法可用于使代碼更簡單、更清晰、更易讀。這種方法還自動處理FFdecoder API 中的formulate()和terminate()方法的管理,因此不需要顯式調用它們。
from deffcode import FFdecoder
import cv2
# 不需要調用formulate和terminate
with FFdecoder("test.mp4") as decoder:
for frame in decoder.generateFrame():
if frame is None:
break
print(frame.shape)
迭代器調用
迭代器的調用方式類似于OpenCV-Python讀取視頻的方式。
from deffcode import FFdecoder
decoder = FFdecoder("test.mp4").formulate()
while True:
# next返回迭代器的下一個項目
frame = next(decoder.generateFrame(), None)
if frame is None:
break
print(frame.shape)
decoder.terminate()
參數設置
# 設置解碼后的圖像為bgr24,可以直接給opencv使用
FFdecoder("test.mp4", frame_format="bgr24")
# 設置解碼后的圖像為灰度圖像,verbose輸出解碼的詳細統計信息
FFdecoder("test.mp4", frame_format="gray", verbose=True)
# 設置解碼后的圖像為yuv420p格式,verbose輸出解碼的詳細統計信息
FFdecoder("test.mp4", frame_format="yuv420p", verbose=True)
這部分不同平臺使用方法不同,而且涉及到很多參數的使用和軟件安裝,所以這里推薦自行閱讀??Decoding Live Feed Devices??。
與解碼視頻文件類似,DeFFcode 的 FFdecoder API直接支持具有特定協議(如RTSP/RTP、HTTP(s)、MPEG-TS 等)的網絡流作為其source參數的輸入。以下示例用的都是網絡上的公開視頻流,由于網速問題有可能連接不上。
http流解碼
from deffcode import FFdecoder
import cv2
# 獲得BGR24圖像
# decoder = FFdecoder("ttp://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear2/prog_index.m3u8", frame_format="bgr24").formulate()
decoder = FFdecoder("https://abhitronix.github.io/html/Big_Buck_Bunny_1080_10s_1MB.mp4", frame_format="bgr24").formulate()
for frame in decoder.generateFrame():
if frame is None:
break
cv2.imshow("Output", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
cv2.destroyAllWindows()
decoder.terminate()
RTSP/RTP流解碼
from deffcode import FFdecoder
import cv2
# 設置傳輸協議為tcp
ffparams = {"-rtsp_transport": "tcp"}
# 取流
decoder = FFdecoder("rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4", frame_format="bgr24", verbose=True, **ffparams).formulate()
for frame in decoder.generateFrame():
if frame is None:
break
cv2.imshow("Output", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
cv2.destroyAllWindows()
decoder.terminate()
特定命名圖像序列讀取
下面的代碼展示了如何帶有特定數字標記的圖像序列逐幀讀取圖像。您可以使用以下FFmpeg命令從視頻文件中提取時間長度為2s的圖像序列,注意圖像保存的文件夾路徑應該要預先創建。
ffmpeg -t 2 -i test.mp4 imgs/image%02d.png
from deffcode import FFdecoder
import cv2
# 設置特定數字開始讀圖,在本例為img01.png
ffparams = {"-ffprefixes":["-start_number", "1"]}
# 注意圖像數大于三張
# img%02d.png: 格式化輸出文件名,本示例中輸出img00.png,img01.png, img02.png等
# 如果是jpeg圖像序列,圖像后綴名應該為jpeg而不是jpg
decoder = FFdecoder("imgs/img%02d.png", frame_format="bgr24", verbose=True, **ffparams).formulate()
for frame in decoder.generateFrame():
if frame is None:
break
cv2.imshow("Output", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
cv2.destroyAllWindows()
decoder.terminate()
glob 模式
如果圖像是連續的,但不一定是數字順序,則通配符(*表示任意數量的任意字符)很有用,但是以下代碼無法在windows下使用。
from deffcode import FFdecoder
import cv2
# glob模式抓取圖像
# glob模式在 Windows FFmpeg 版本上不可用。
ffparams = {"-ffprefixes":["-pattern_type", "glob"]}
decoder = FFdecoder("imgs/img*.png", frame_format="bgr24", verbose=True, **ffparams).formulate()
for frame in decoder.generateFrame():
if frame is None:
break
cv2.imshow("Output", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
cv2.destroyAllWindows()
decoder.terminate()
循環讀取圖像
下面的設置展示了從單個或者多個圖像循環讀取的示例。注意jpg圖像都以jpeg后綴命名。
# `-loop 1` 表示循環讀取,loop是bool類型
ffparams = {"-ffprefixes":["-loop", "1"]}
# 設置單張圖像循環讀取
decoder = FFdecoder("imgs/img01.png", frame_format="bgr24", verbose=True, **ffparams).formulate()
# 設置多張圖像循環讀取
decoder = FFdecoder("imgs/img%02d.png", frame_format="bgr24", verbose=True, **ffparams).formulate()
通過OpenCV保存視頻
from deffcode import FFdecoder
import json, cv2
decoder = FFdecoder("test.mp4", frame_format="bgr24").formulate()
# decoder.metadata讀取視頻屬性json數據,并轉碼為字典
metadata_dict = json.loads(decoder.metadata)
FOURCC = cv2.VideoWriter_fourcc("M", "J", "P", "G")
FRAMERATE = metadata_dict["source_video_framerate"]
FRAMESIZE = tuple(metadata_dict["source_video_resolution"])
writer = cv2.VideoWriter("output.avi", FOURCC, FRAMERATE, FRAMESIZE)
for frame in decoder.generateFrame():
if frame is None:
break
writer.write(frame)
cv2.imshow("Output", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
cv2.destroyAllWindows()
decoder.terminate()
writer.release()
通過VidGear保存視頻(推薦)
使用這種方式保存視頻,視頻文件壓縮率更高,保存速度更快,但是也CPU利用率也更高。
from deffcode import FFdecoder
from vidgear.gears import WriteGear
import json
decoder = FFdecoder("test.mp4", frame_format="bgr24", verbose=True).formulate()
output_params = {
"-input_framerate": json.loads(decoder.metadata)["source_video_framerate"]
}
writer = WriteGear(output_filename="output.mp4", **output_params)
for frame in decoder.generateFrame():
if frame is None:
break
writer.write(frame)
decoder.terminate()
writer.close()
參數設置
以下是各種ffmpeg參數的設置方法,ffparams設置參數后,然后傳入FFdecoder。
# 截取前3s視頻,按倒序保存
ffparams = {
"-vf": "trim=end=7,reverse"
}
# 裁剪中央輸入區域,寬高都為輸入視頻的2/3,然后拉伸為原圖像尺寸
ffparams = {
"-vf": "crop=2/3*in_w:2/3*in_h"
}
# 逆時針旋轉圖像30度,用綠色填充旋轉圖像未覆蓋的區域
ffparams = {
"-vf": "trim=end=7,rotate=angle=-30*PI/180:fillcolor=green"
}
# 保存前7秒視頻,逆時針旋轉90度,保持縱向布局
# dir為旋轉方向,具體可以搜搜ffmpeg transpose
ffparams = {
"-vf": "trim=end=7,transpose=dir=2:passthrough=portrait"
}
# 水平翻轉,然后縮放圖像到其原始大小的一半
ffparams = {
"-vf": "hflip,scale=w=iw/2:h=ih/2"
}
# 設置參數
decoder = FFdecoder(
"test.mp4", frame_format="bgr24", verbose=True, **ffparams
).formulate()
DeFFcode的FFdecoder API使用FFmpeg參數-ss提供輕松且精確的幀搜索,使我們能夠從輸入源的特定部分保存圖像。
from deffcode import FFdecoder
from PIL import Image
# 定義FFmpeg參數以查找00:00:01.45處圖像,并獲得一幀圖像
ffparams = {"-ss": "00:00:01.45", "-frames:v": 1}
# 初始化參數
decoder = FFdecoder("test.mp4", **ffparams).formulate()
# 讀取圖像
frame = next(decoder.generateFrame(), None)
# 保存圖像
if not (frame is None):
im = Image.fromarray(frame)
im.save("test.png")
else:
raise ValueError("Something is wrong!")
decoder.terminate()
DeFFcode提供各種創建虛擬視頻流的示例,具體使用見??Decoding Live Virtual Sources??,這里只列出兩個經典的案例。
從測試源模式生成和解碼幀
testsrc圖生成一個測試視頻模式,顯示顏色模式、滾動漸變和時間戳。這對于測試目的很有用。
from deffcode import FFdecoder
import cv2
# 定義參數
ffparams = {
# 播放時間為10秒
"-ffprefixes": ["-t", "10"],
}
# 生成尺寸為1280x720,幀率30的testsrc測試圖像
decoder = FFdecoder(
"testsrc=size=1280x720:rate=30",
source_demuxer="lavfi",
frame_format="bgr24",
**ffparams
).formulate()
for frame in decoder.generateFrame():
if frame is None:
break
cv2.imshow("Output", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
cv2.destroyAllWindows()
decoder.terminate()
使用自定義文本效果從漸變生成和解碼幀
from deffcode import FFdecoder
import cv2
ffparams = {
"-ffprefixes": ["-t", "15"], # 15秒播放
"-vf": "drawtext=" # 繪制文本
+ "text='%{localtime\:%X}':" # 時間 (HH::MM::SS)
+ "fontfile='c\:\/windows\/fonts\/arial.ttf':" # 字體
+ "x=(w-text_w)/2:y=h-40*t:" # 向上滾動效果
+ "fontsize=50:" # 字體大小
+ "fontcolor=white", # 字體顏色
}
decoder = FFdecoder(
"gradients=n=3",
source_demuxer="lavfi",
frame_format="bgr24",
**ffparams
).formulate()
for frame in decoder.generateFrame():
if frame is None:
break
cv2.imshow("Output", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
cv2.destroyAllWindows()
decoder.terminate()
FFmpeg 提供對不同平臺上不同支持的專用硬件的訪問,以執行一系列與視頻相關的任務,以更快地完成或使用更少的其他資源(特別是 CPU)。使用ffmpeg -decoders終端命令列出所有 FFmpeg 支持的解碼器。可以看看具體ffmpeg支持本機哪種硬件解碼。
比如判斷ffmpeg是否可以通過依賴于gpu cuda的h264_cuvid解碼,可以輸入以下指令。如果輸出包含了h264_cuvid那么就是支持的,可以通過gpu加速解碼。
linux系統:ffmpeg -hide_banner -decoders | grep h264
windows系統:ffmpeg -hide_banner -decoders | findstr h264
如果支持h264_cuvid加速解碼,可以嘗試以下示例代碼。
from deffcode import FFdecoder
import cv2
ffparams = {
"-vcodec": "h264_cuvid", # CUVID H.264加速視頻解碼
"-ffprefixes": ["-vsync", "0"], # 視頻同步方法,一般都是自動,這里設置為0
}
decoder = FFdecoder(
"test.mp4", frame_format="bgr24", verbose=True, **ffparams
).formulate()
for frame in decoder.generateFrame():
if frame is None:
break
cv2.imshow("Output", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
cv2.destroyAllWindows()
decoder.terminate()
添加水印
以下代碼展示了如何在讀取的視頻中添加圖像,并保存視頻到本地。
from deffcode import FFdecoder
from vidgear.gears import WriteGear
import json, cv2
# 定義帶有復雜水印的視頻過濾器
ffparams = {
"-ffprefixes": ["-t", "5"], # 視頻總長度為5秒
"-clones": [
"-i",
"watermark.png",
],
"-filter_complex": "[1]format=rgba," # 設置水印圖像輸入格式
+ "colorchannelmixer=aa=0.7[logo];" # 設置水印透明度,數值越小越透明
+ "[0][logo]overlay=W-w-{pixel}:H-h-{pixel}:format=auto,".format(
pixel=5 # 設置水印圖片在距離輸入視頻右下角5個像素處
)
+ "format=bgr24", # 設置輸出格式
}
decoder = FFdecoder(
"test.mp4", frame_format="bgr24", verbose=True, **ffparams
).formulate()
output_params = {
"-input_framerate": json.loads(decoder.metadata)["source_video_framerate"],
}
# 保存視頻
writer = WriteGear(output_filename="output.mp4", **output_params)
for frame in decoder.generateFrame():
if frame is None:
break
writer.write(frame)
decoder.terminate()
writer.close()
圖像效果混合
下面的代碼展示了如何往圖像序列中混合虛擬效果。
from deffcode import FFdecoder
from vidgear.gears import WriteGear
import cv2, json
ffparams = {
"-ffprefixes": [
"-t", "10", # 視頻長度為10s
"-f", "lavfi", # 使用輸入虛擬數據
"-i", "mandelbrot=rate=25", # 視頻幀率
],
"-custom_resolution": (1280, 720), # 重新設置圖像 1280x720
"-filter_complex":"[1:v]format=yuv444p[v1];"
+ "[0:v]format=gbrp10le[v0];"
+ "[v1][v0]scale2ref[v1][v0];"
+ "[v0][v1]blend=all_mode='heat',"
+ "format=yuv422p10le[v]",
"-map": "[v]",
}
# 設置圖像序列路徑
decoder = FFdecoder(
"./imgs/image-%03d.png", frame_format="bgr24", verbose=True, **ffparams
).formulate()
output_params = {
"-input_framerate": 25,
}
writer = WriteGear(output_filename="output.mp4", **output_params)
for frame in decoder.generateFrame():
if frame is None:
break
writer.write(frame)
decoder.terminate()
writer.close()
此外Deffcode還支持添加各種藝術效果,具體方法可以閱讀??transcode-art-filtergraphs??
添加新屬性
下面代碼展示了讀取視頻后,往讀取的屬性數據中添加新的屬性,注意該操作并不更改視頻的實際屬性數據。
from deffcode import FFdecoder
import json
decoder = FFdecoder("test.mp4", verbose=True)
# 設置字典數據
data = dict(
mystring="abcd",
myint=1234,
mylist=[1, "Rohan", ["inner_list"]],
mytuple=(1, "John", ("inner_tuple")),
mydict={"anotherstring": "hello"},
myjson=json.loads('{"name": "John", "age": 30, "city": "New York"}'),
)
# 分配視頻的屬性數據
decoder.metadata = data
decoder.formulate()
print(decoder.metadata)
decoder.terminate()
修改已有視頻屬性
在視頻流解碼前,可以設置視頻流的屬性數據,那么就會以更改后的屬性解碼圖像。
from deffcode import FFdecoder
import cv2
decoder = FFdecoder("test.mp4", verbose=True)
# 替換屬性數據,會以當前屬性解碼視頻
decoder.metadata = {
"output_frames_pixfmt": "gray", # 灰度圖
"source_video_resolution": [352, 288], # 寬高更改為352,288
}
decoder.formulate()
print(decoder.metadata)
for frame in decoder.generateFrame():
if frame is None:
break
cv2.imshow("Output gray", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
cv2.destroyAllWindows()
decoder.terminate()