我使用 排程自動呼叫 python 播放影片
Raspberry Pi 4 有接螢幕
python 去指定API抓影片目錄並下載影片
使用OMXPlayer播放
每一兩天 就會OMXPlayer直接炸了
python沒有全壞就繼續在那裡背景執行
但影片早停了
#!/bin/sh
proc_name="SmartMiniBox.py"
for i in {1..12}
do
if [ `ps -ef | grep $proc_name | grep -v grep | wc -l` -eq 0 ]
then
#sudo pkill -f omxplayer;sudo pkill -f fbi;pkill -f SmartMiniBox.py; #預防性刪除舊的
FileName=$(date +%Y%m%d.%H%M%S.txt)
touch /home/pi/log/${FileName}
nohup python3 -u /home/pi/SmartMiniBox.py > /home/pi/AED/log/${FileName} 2>&1 &
fi
sleep 5s
done
#* * * * * root /bin/bash /home/pi/AED/run.sh > /dev/null 2>&1
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
# 需安裝 sudo apt-get install -y libdbus-1-3 libdbus-1-dev omxplayer fbi
# 需安裝 pip3 install requests schedule opencv-python screeninfo
# 需安裝 sudo python3 -m pip install omxplayer-wrapper
# sudo apt-get install automake autoconf libtool libreadline-dev libexif-dev libjpeg-dev libpng-dev libtiff-dev libgif-dev libsdl1.2-dev libaa1-dev libpoppler-dev libdjvulibre-dev libspectre-dev libarchive-dev
from omxplayer.player import OMXPlayer
import requests, json, schedule, time, syslog, os, signal, sys, uuid, subprocess, threading
#import datetime
try:
import RPi.GPIO as GPIO
except RuntimeError:
print("導入失敗")
syslog.syslog("導入失敗")
DOOR2_PIN = 17 #DOOR2 Pin腳
DOOR_PIN = 27 #DOOR Pin腳
SelfCheck = '00' #自檢時間
StationGuid = "XXXXXXXXXXXXXXXX" #機碼
DOOR2_STATUS = 0 #DOOR2 上次狀態暫存
DOOR_STATUS = 0 #DOOR 上次狀態暫存
ImageRoot = os.path.abspath(os.path.dirname(__file__)) + '/' #程式根
ImagePath = ImageRoot + 'video/' #影片資料夾
os.makedirs(ImagePath, exist_ok=True) #不存在則創建
BackgroundBlackSubprocess = {} #黑底背景進程
def setup():
global DOOR2_STATUS, DOOR_STATUS
GPIO.setwarnings(False) #忽略警告
GPIO.setmode(GPIO.BCM) #GPIO.BOARD GPIO編號 或 Port Pin編號
GPIO.setup([DOOR2_PIN,DOOR_PIN],GPIO.IN,pull_up_down=GPIO.PUD_DOWN) #GPIO 設定讀入 GPIO.PUD_UP/GPIO.PUD_DOWN
GPIO.add_event_detect(DOOR2_PIN, GPIO.BOTH, callback=DOOR2_WAIT_FUN, bouncetime=10) #GPIO 觸發事件 GPIO.RISING/GPIO.FALLING/GPIO.BOTH bouncetime=1
GPIO.add_event_detect(DOOR_PIN, GPIO.BOTH, callback=DOOR_WAIT_FUN, bouncetime=10) #GPIO 觸發事件 GPIO.RISING/GPIO.FALLING/GPIO.BOTH bouncetime=1
DOOR2_STATUS = GPIO.input(DOOR2_PIN)
DOOR_STATUS = GPIO.input(DOOR_PIN)
KillProcessing()
#os.system("fbi -a --noverbose -T 2 " + ImagePath + "black.jpg") #螢幕用黑色檔住
#BackgroundBlackSubprocess = subprocess.Popen(args=["fbi", "-a", "--noverbose", "-T", "2", ImagePath + "black.jpg"], shell = True) #螢幕用黑色檔住
#if os.environ.get('DISPLAY','') == '':
# print('no display found. Using :0.0')
# os.environ.__setitem__('DISPLAY', ':0.0')
#
# BackgroundBlackSubprocess = subprocess.Popen(args=["/usr/bin/feh","-q","-p","-Z","-F","-R","60","-Y","-D","15.0", ImagePath + "black.jpg"], shell = True) #螢幕用黑色檔住
# BackgroundBlackSubprocess = subprocess.Popen(args="DISPLAY=:0.0 XAUTHORITY=/home/pi/.Xauthority /usr/bin/feh -q -p -Z -F -R 60 -Y -D 15.0 "+ ImagePath + "black.jpg", shell = True) #螢幕用黑色檔住
#啟動程序
print("啟動完成")
syslog.syslog("啟動完成")
PostAPI([{
"EventTypeId": 11, #[Description("啟動完成")] SmartBoxInitFinish = 11,
"EventTitle": "SmartMiniBox 啟動狀況",
"EventContecnt": "",
"EventTime": time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
}])
def KillProcessing():
os.system("sudo pkill -f omxplayer;sudo pkill -f fbi;pkill -f SmartMiniBox.py;")
#os.system("sudo pkill omxplayer;sudo killall -s 9 omxplayer;sudo pkill fbi;sudo killall -s 9 fbi;")
#os.system("sudo pkill omxplayer; sudo killall -s 9 omxplayer;sudo killall -s 9 fbi;")
syslog.syslog("Run kill omxplayer and fbi")
def print_json(obj):
print(json.dumps(obj, sort_keys=True, indent=2, separators=(',', ': ')))
def get_mac_address():
mac=uuid.UUID(int = uuid.getnode()).hex[-12:].upper()
return "-".join([mac[e:e+2] for e in range(0,11,2)])
def PostAPI(data_detail):
API_URI = 'http://XXXXXXX.com/api/v1'
HEADERS = {'Content-Type':'application/json'}
data_json = {
"Details": data_detail,
"Command": "UploadEvent",
"StationMAC": get_mac_address(),
"StationGuid": StationGuid
}
#data_json['Details'].append(data_detail)
#print(data_detail['EventTitle'])
#print_json(data_json)
try:
response = requests.post(API_URI, headers=HEADERS, json=data_json)
response.raise_for_status()
#print(response.json()["Status"])
#print_json(response.json())
if response.json()['ErrorCode'] == 0:
print('Send API Success')
else:
print('Send API Error')
syslog.syslog("Send API Error")
time.sleep(1) #小停一下
except Exception as ex:
raise ex
def DOOR2_WAIT_FUN(channel):
global DOOR2_STATUS
DOOR2_NEW_STATUS = GPIO.input(DOOR2_PIN) #避免瞬間換狀態
if DOOR2_STATUS != DOOR2_NEW_STATUS: #不等於上次的狀態才動作
DOOR2_STATUS = DOOR2_NEW_STATUS
print("DOOR2狀況: " + ("DOOR2取走" if DOOR2_NEW_STATUS == 1 else "DOOR2歸位"))
syslog.syslog("DOOR2狀況: " + ("DOOR2取走" if DOOR2_NEW_STATUS == 1 else "DOOR2歸位"))
PostAPI([{
"EventTypeId": 3 if DOOR2_NEW_STATUS == 1 else 4, #[Description("DOOR2取走")] DOOR2Taked = 3, [Description("DOOR2歸位")] DOOR2Back = 4,
"EventTitle": "DOOR2狀況",
"EventContecnt": "",
"EventTime": time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
}])
def DOOR_WAIT_FUN(channel):
global DOOR_STATUS
DOOR_NEW_STATUS = GPIO.input(DOOR_PIN) #避免瞬間換狀態
if DOOR_STATUS != DOOR_NEW_STATUS: #不等於上次的狀態才動作
DOOR_STATUS = DOOR_NEW_STATUS
print("門狀況:" + ("開門" if DOOR_NEW_STATUS == 1 else "關門"))
syslog.syslog("門狀況:" + ("開門" if DOOR_NEW_STATUS == 1 else "關門"))
PostAPI([{
"EventTypeId": 1 if DOOR_NEW_STATUS == 1 else 2, #[Description("開門")] DoorOpen = 1, [Description("關門")] DoorClose = 2,
"EventTitle": "門狀況",
"EventContecnt": "",
"EventTime": time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
}])
class Cron(object):
def __init__(self):
schedule.every().hour.at(':'+SelfCheck).do(self.SelfCheckTask) #自檢排程
self.Run()
def Run(self):
while True:
schedule.run_pending()
time.sleep(1)
def SelfCheckTask(self):
threading.Thread(target=self.SelfCheck).start()
def SelfCheck(self):
DOOR2_NEW_STATUS = GPIO.input(DOOR2_PIN) #避免瞬間換狀態
DOOR_NEW_STATUS = GPIO.input(DOOR_PIN) #避免瞬間換狀態
print("自檢狀況: " + ("自檢正常" if DOOR2_NEW_STATUS == 0 and DOOR_NEW_STATUS == 0 else "自檢異常"))
syslog.syslog("自檢狀況: " + ("自檢正常" if DOOR2_NEW_STATUS == 0 and DOOR_NEW_STATUS == 0 else "自檢異常"))
PostAPI([{
"EventTypeId": 9 if DOOR2_NEW_STATUS == 0 and DOOR_NEW_STATUS == 0 else 10, #[Description("自檢正常")] SelfCheckCorrect = 9, [Description("自檢異常")] SelfCheckError = 10,
"EventTitle": "自檢狀況",
"EventContecnt": "自我檢測",
"EventTime": time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
},{
"EventTypeId": 3 if DOOR2_NEW_STATUS == 1 else 4, #[Description("DOOR2取走")] DOOR2Taked = 3, [Description("DOOR2歸位")] DOOR2Back = 4,
"EventTitle": "DOOR2狀況",
"EventContecnt": "自我檢測",
"EventTime": time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
},{
"EventTypeId": 1 if DOOR_NEW_STATUS == 1 else 2, #[Description("開門")] DoorOpen = 1, [Description("關門")] DoorClose = 2,
"EventTitle": "門狀況",
"EventContecnt": "自我檢測",
"EventTime": time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
}])
class PlayVideo(object):
def __init__(self):
self.PlayList = {}
self.Run()
def Run(self):
while True:
self.GetPlayList()
if self.PlayList['ErrorCode'] == 0:
print('Run Play Video Start: Run')
#self.BackgroundBlack()
self.PlayVideo()
print('Run Play Video End: Run')
else:
KillProcessing()
time.sleep(3)
print('Run Play Video Error: ' + self.PlayList['ErrorCode'])
print_json(self.PlayList)
syslog.syslog('Run Play Video Error: ' + self.PlayList['ErrorCode'])
syslog.syslog(json.dumps(self.PlayList, sort_keys=True, indent=2, separators=(',', ': ')))
def BackgroundBlack(self):
global BackgroundBlackSubprocess
for line in os.popen("ps ax | grep 'fbi -a' | grep -v grep | wc -l"): #檢查是否已經有黑色檔住
if(int(line)==0):
#BackgroundBlackSubprocess = subprocess.Popen(args=["fbi -a --noverbose -T 2 " + ImagePath + "black.jpg"], shell = True) #螢幕用黑色檔住
BackgroundBlackSubprocess = subprocess.Popen(args=["fbi", "-a", "--noverbose", "-T", "2", ImagePath + "black.jpg"]) #螢幕用黑色檔住
print('Background Black ID:' + BackgroundBlackSubprocess + ' path:' + ImagePath + "black.jpg")
def PlayVideo(self):
print('Play Video Start: PlayVideo')
plays = {}
TmpPlays = {}
#print(json.dumps(self.PlayList["Details"], sort_keys=True, indent=2, separators=(',', ': ')))
for k, d in enumerate(self.PlayList["Details"]):
#d["FileName"] = '202009101128550045988_1185.mp4'
if os.path.isfile(ImagePath+d["FileName"]):
try:
plays[k] = OMXPlayer(ImagePath+d["FileName"], args='--no-osd -b -o both --layer ' + str(10000-k), dbus_name="org.mpris.MediaPlayer2.omxplayer"+ str(10000-k))
print(k, plays[k].duration(),ImagePath+d["FileName"])
if k > 0: #關掉上一個播放的
plays[0].quit()
TmpPlays.quit()
TmpPlays = plays[k] #暫存影片索引
time.sleep(plays[k].duration()-0.5)
except Exception as err:
print(str(err))
plays[k].quit()
KillProcessing()
print('Playe Video Error, Run SmartMiniBox Stop')
syslog.syslog('Playe Video Error, Run SmartMiniBox Stop')
GPIO.cleanup() # cleanup all GPIO
#sys.exit("Playe Video Error, Run SmartMiniBox Stop")
os._exit(1)
else:
print('Playe Video Error: ' + ImagePath+d["FileName"] + ' Not Found')
syslog.syslog('Playe Video Error: ' + ImagePath+d["FileName"] + ' Not Found')
print('Play Video End: PlayVideo')
def GetPlayList(self):
API_URI = 'http://XXXXXXX.com/api/v1'
HEADERS = {'Content-Type':'application/json'}
data_json = {
"Command": "GetVideoFileList",
"StationMAC": get_mac_address(),
"StationGuid": StationGuid
}
#print_json(data_json)
try:
response = requests.post(API_URI, headers=HEADERS, json=data_json)
response.raise_for_status()
#print(response.json()["Status"])
#print_json(response.json())
if response.json()['ErrorCode'] == 0:
print('Get Play List Success')
for k, d in enumerate(response.json()["Details"]):
print('Download Video Start')
self.Download(d)
print('Download Video End')
else:
print('Get Play List Error: 1')
print(response.json()['Description'])
print_json(response.json())
syslog.syslog('Get Play List Error: 1')
syslog.syslog(response.json()['Description'])
syslog.syslog(json.dumps(response.json(), sort_keys=True, indent=2, separators=(',', ': ')))
self.PlayList = response.json()
return response.json()
except Exception as ex:
print('Get Play List Error: 2')
print(ex)
syslog.syslog('Get Play List Error: 2')
syslog.syslog(ex)
raise ex
def Download(self, Data):
API_URI = 'http://XXXXXXX.com/api/download'
HEADERS = {'Content-Type':'application/json'}
data_json = {
"Command": "DownLoadVideoFile",
"StationMAC": get_mac_address(),
"StationGuid": StationGuid,
"Type": "Video",
"Guid": Data["FileGuid"]
}
#print_json(data_json)
try:
if os.path.isfile(ImagePath+Data["FileName"]):
if os.path.getsize(ImagePath+Data["FileName"]) != Data["FileLength"]:
os.remove(ImagePath+Data["FileName"])
print('Video Size Error Run Remove File: '+Data["FileName"])
if not os.path.isfile(ImagePath+Data["FileName"]):
response = requests.post(API_URI, headers=HEADERS, json=data_json)
response.raise_for_status()
with open(ImagePath+Data["FileName"],'wb') as f:
f.write(response.content)
f.close()
print('Download Video Success: '+Data["FileName"])
print('Check Video Success: '+Data["FileName"])
#time.sleep(1) #小停一下
except Exception as ex:
print('Download Video Error')
print(ex)
syslog.syslog('Download Video Error')
syslog.syslog(ex)
raise ex
if __name__ == '__main__': # Program start from here
setup()
threading.Thread(target=Cron).start() #setDaemon(True)
threading.Thread(target=PlayVideo).start() #setDaemon(True)
try:
while True:
time.sleep(1)
except KeyboardInterrupt: # When Ctrl+C is pressed, the child program destroy() will be executed.
GPIO.cleanup() # cleanup all GPIO
KillProcessing()
print('SmartMiniBox Stop')
syslog.syslog('SmartMiniBox Stop')
DBus cannot connect to the OMXPlayer process
Exception in thread Thread-2:
Traceback (most recent call last):
File "/home/pi/SmartMiniBox.py", line 205, in PlayVideo
plays[k] = OMXPlayer(ImagePath+d["FileName"], args='--no-osd -b -o both --layer ' + str(10000-k), dbus_name="org.mpris.MediaPlayer2.omxplayer"+ str(10000-k))
File "/usr/local/lib/python3.7/dist-packages/omxplayer/player.py", line 154, in __init__
self.load(source, pause=pause)
File "/usr/local/lib/python3.7/dist-packages/omxplayer/player.py", line 251, in load
self._load_source(source)
File "/usr/local/lib/python3.7/dist-packages/omxplayer/player.py", line 163, in _load_source
self._connection = self._setup_dbus_connection(self._Connection, self._bus_address_finder)
File "/usr/local/lib/python3.7/dist-packages/omxplayer/player.py", line 236, in _setup_dbus_connection
raise SystemError('DBus cannot connect to the OMXPlayer process')
SystemError: DBus cannot connect to the OMXPlayer process
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.7/threading.py", line 917, in _bootstrap_inner
self.run()
File "/usr/lib/python3.7/threading.py", line 865, in run
self._target(*self._args, **self._kwargs)
File "/home/pi/SmartMiniBox.py", line 170, in __init__
self.Run()
File "/home/pi/SmartMiniBox.py", line 178, in Run
self.PlayVideo()
File "/home/pi/SmartMiniBox.py", line 214, in PlayVideo
plays[k].quit()
KeyError: 8
個人建議用ffmpeg裡的ffplay,以全螢幕播放影片...
GUI跟純CLI全適用
安裝很簡單,用 sudo apt-get install ffmpeg 即可