Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
SS_monitor_04
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ivan
SS_monitor_04
Commits
eed276bc
Commit
eed276bc
authored
Mar 02, 2020
by
ivan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add new file
parent
0f9bf0e8
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
179 additions
and
0 deletions
+179
-0
readme.md
readme.md
+179
-0
No files found.
readme.md
0 → 100644
View file @
eed276bc
# 監控系統建置教學
一開始將本專案git clone 下來,首先在 server的資料夾中包含著本次系統所需的媒體伺服器EasyDarwin,不管是回撥還是現場調閱兼會使用到他,
~~~
sudo docker build -t easydarwin .
~~~
使用上述指令便能輕鬆建置容器
建置好容器之後,再來到portainer去設定該容器的volume,根據影片檔案位置選取,ex. 點Bind 在下列位置方別填入 container> /data host > /data 並在/record 下也連結影片位置,因為easydarwin預設播放路徑必須是在/record下面,所以才這樣設定,再來點選Depoly the container ,就完成媒體伺服器設定了。
接著在回播影片前,仍必須儲存影片片段,到storage資料夾,裡面有包含各地區的程式,接著我選一個做範例,進去txg資料夾(也就是昱通台中地區),裡面有 docker-composer.yml ,Dockerfile ,storage.py,這幾個檔案分別做不同的事,docker-composer.yml 是撰寫所需容器的資訊以及ip位置,名稱等等 而Dockerfile 則是建置容器所需的環境寫在裡面, 最後就是storage.py 這是主程式,就是儲存程式的位置,而程式中重要的程式碼,便是ffmpeg儲存影片的參數,以及後半段跨天處理得主程式部分,
~~~
python
'ffmpeg -fflags nobuffer -rtsp_transport tcp -i {1} -vsync 0 -copyts -c:v copy -movflags frag_keyframe+empty_moov -an -f segment -strftime 1 -segment_list_flags live -segment_time 10 -segment_list_size 0 -segment_format mpegts -segment_list /data/{0}/{2}/index.m3u8 -segment_list_type m3u8 -segment_list_entry_prefix /record/{0}/{2}/ /data/{0}/{2}/
%
s.ts'
~~~
此指令包含-fflags nobuffer 顧名思義就是不要有buffer 在儲存時會減少伺服器的負擔,-vsync 0 為視訊同步的方法 0 為不改變畫格的時間戳記,-copyts 為不處理時間戳記,但保留他, -c:v copy為複製源影片的編碼格式,
-movflags frag_keyframe為在每個視頻關鍵幀處開始一個新片段,
empty_moov 為直接在文件的開頭寫一個初始的moov原子,而不描述其中的任何樣本,有這兩個參數的支持可以處理segment更為順利,
-strftime 1 為方便使用日期為.ts檔名,
-segment_list_flags live 為使m3u8檔可作為live使用,
-segment_time 10 為使每個片段持續10秒,
-segment_list_size 0 為m3u8 list 不受限制可無限寫下去,
-segment_list 為m3u8檔的儲存位置,
-segment_list_type m3u8 就列表格式為m3u8,
-segment_list_entry_prefix 為m3u8內部的連結.ts檔的前綴,最後則是輸出.ts檔的位置及格式。
知道原理後下
~~~
docker-composer up -d --build
~~~
儲存影片的容器就開啟了
有了儲存的片段後,接著就是回撥,這時我們會需要用到flask並包含jupyter notebook 做API功能撰寫,首先看到resources.py裡面的 class Replay2(Resource):
一開始當然是透過網頁去call API 然後 再透過flask框架 接收到所需的數值至API方法,由於回播片段想當然需要 起始時間,結束時間,再來就是回播的camera編號,以及camera所在的地區,__init__這個方法便將我們所需的的數值接收進來,在透過query語法,去搜索我們需要的片段回來重組m3u8,而下面將介紹query語法的重點。
首先為了方便撰寫將個參數方別利用三個"""包起來,可以避免"以及'互相干擾,並且將不同的參數存在不同變數中,方便修改。
fields = """timestamp,save_path,EXTINF"""
上面這個變數儲存的式所需查詢的field
measurement = """{}""".format(goup_name)
上面這個變數儲存的則是欲查詢的measurement
filters = """ WHERE time >='{0}'-8h and time <='{1}'-8h """.format(START_DATE,END_DATE)
上面這個參數則是篩選所須查詢的時間範圍,而因為時差的關係 在時間後面加上 -8h 以符合+8時區
GROUP="""GROUP BY {} """.format("ch")
而上面這個參數便是為了方便後面做篩選所需的參數,沒有這個參數,在後面做.get_points這個方法時便無法篩選到要的camera_path
query = """SELECT {} FROM {} {} {} tz('Asia/Taipei')""".format(fields, measurement, filters,GROUP)
至於上面的參數則是最終的語法,透過select並加入上述所用到的所有變數,去組成一個query語法,也為了符合時區 加上了tz('Asia/Taipei')到語法的最後。
results= influxclient.query(query)
上述語法則是將query語法送至influxdb做查詢
points = list(results.get_points(measurement=goup_name,tags={'ch':camera_path
[
i
]
}))
做完查詢後再來就是進一步篩選所需的資料,透過results.get_points將查詢回來的語法做篩選,並透過指定measurement,及在儲存時存上的tags選擇要的camera_path。
到這裡便完成了查詢的部分,將查詢及經篩選的資料,傳入read_data()方法,做到重組回撥m3u8檔案。
接著看def read_data(),由於前五行基本上都固定的參數,所以在計數時由第5行開始往下寫,而下面判斷的地方有分是否為wgs如只需判斷一個地方,沒有額外的easydarwin伺服器使用,可以擇一刪除。
~~~
with open("/wgs/replay/{0}/{1}/replay.m3u8".format(name,path), 'w') as f: #開啟目標位置的資料夾覆寫要重組的replay.m3u8,
if os.path.isdir(wgs_path): #這裡會先判斷使否在本機有此資料夾,沒有的話跳else,代表在NAS
try:
data=open("/wgs/replay/{0}/{1}/replay.m3u8".format(name,path)).read()
lines=[]
if (len(data) ==0): #判斷使否有data在replay.m3u8 沒有就寫入下面的固定參數
lines.append("#EXTM3U\n")
lines.append("#EXT-X-VERSION:3\n")
lines.append("#EXT-X-MEDIA-SEQUENCE:0\n")
lines.append("#EXT-X-ALLOW-CACHE:NO\n")
lines.append("#EXT-X-TARGETDURATION:11\n")
for l in range(start,len(points),1): #依次讀取每行
if (points[l]['EXTINF']):
a1 = int(points[l - 1]['timestamp'])
a2 = int(points[l]['timestamp'])
a3 = int(points[l]['EXTINF'].split('#EXTINF:')[1].split(',')[0].split('.')[0])
if ((a2 - a1) > a3 +1): #這裡的用意是在判斷是否有跨天,透過前一個timestamp與當前timestamp比對,a2-a1 >a3+1 就代表有跨天,所以寫入下列參數,此參數可以代表切換第二個流
lines.append("#EXT-X-DISCONTINUITY\n")
lines.append(points[l]['EXTINF'] + "\n") #這裡寫入每個ts的相關資料
lines.append("/record/"+(points[l]['save_path']+points[l]['timestamp']).split('/{}/'.format(name),1)[1]+".ts"+"\n")
finally:
lines.append("#EXT-X-ENDLIST") #在最後寫入此參數代表結束,沒有此參數會認為是直播,無法自由看所需片段
f.writelines(lines) #寫入上述的lines所存放的值
f.flush()
#f.close()
~~~
這樣便完成了回撥的功能,接下來是為了防止本機空間不足,所以寫了一個backup到NAS程式,該程式在move的資料夾裡面,都在gitlab SS_monitor_03上面。下面介紹各方法
~~~
def dir_status(): #這個方法是用於判斷目標資料夾的使用情形
line=[]
with os.scandir('/data') as entries:
for entry in entries:
dir_stat=entry.stat().st_mtime,entry.name #將資料夾修改狀態,及資料夾名稱組在一起
line.append(dir_stat) #將所有目標資料夾的子資料夾存入line裡面
line.sort() #將資料夾的修改時間依由小至大作排列
c=line.pop(0) #倒出最後一個資料夾,也就是最舊的資料夾
return(c[1]) #回傳最舊資料夾的資料夾名稱
~~~
~~~
def copytree(src='/data/{0}'.format(dir_status()), dst='/nas/{0}'.format(dir_status()), symlinks = False, ignore = None):
#這是複製整個資料樹的方法 ,src 為來源資料夾 ,dst為目的地資料夾,並將最舊資料夾的名稱傳進來做為複製的目標
if not os.path.exists(dst):
os.makedirs(dst)
shutil.copystat(src, dst)
lst = os.listdir(src)
if ignore:
excl = ignore(src, lst)
lst = [x for x in lst if x not in excl]
for item in lst:
s = os.path.join(src, item)
d = os.path.join(dst, item)
if symlinks and os.path.islink(s):
if os.path.lexists(d):
os.remove(d)
os.symlink(os.readlink(s), d)
try:
st = os.lstat(s)
mode = stat.S_IMODE(st.st_mode)
os.lchmod(d, mode)
except:
pass
elif os.path.isdir(s):
copytree(s, d, symlinks, ignore)
else:
shutil.copy2(s, d)
~~~
~~~
def disk_root(): #這個是判斷該硬碟的使用情形
s=0
disk=os.statvfs('/data')
percent=(disk.f_blocks-disk.f_bfree)*100/(disk.f_blocks-disk.f_bfree+disk.f_bavail)
if percent > 80: 百分比大於80 回傳 True 反之為False
return s==0
else:
return s==1
~~~
~~~
def restart_program(): #這個方法則是重開程式,由於copy容易占用大量的資源,程式一直啟動則速度會越來越慢
python = sys.executable
os.execl(python, python, * sys.argv)
~~~
~~~
while True: #這裡是主程式的部分
time.sleep(10)
if disk_root() == True : #判斷是否為True ,True的話開始複製至mount NAS 的資料夾
try:
copytree()
except IOError as e:
print("Unable to copy file. %s" % e)
except:
print("ERROR")
else:
old_path = r"/data/{0}".format(dir_status()) #這裡判斷需刪除的本機最舊資料夾
try:
shutil.rmtree(old_path) #移除的指令
except OSError as e:
print(e)
else:
print("The directory is deleted successfully")
print("program restart !! ")
time.sleep(3)
restart_program() #重開程式
~~~
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment