iT邦幫忙

0

請教各位大大 Raspberry Pi 4 使用 OMXPlayer 播放影片的問題

  • 分享至 

  • xImage

我使用 排程自動呼叫 python 播放影片
Raspberry Pi 4 有接螢幕

python 去指定API抓影片目錄並下載影片
使用OMXPlayer播放

每一兩天 就會OMXPlayer直接炸了
python沒有全壞就繼續在那裡背景執行
但影片早停了

定時呼叫順便當看門狗(shell)

#!/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

code

#!/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')



log檔案看到的最後報錯

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
biscuit iT邦新手 5 級 ‧ 2022-11-04 15:18:22 檢舉
更新~~我最後使用更換VLC撥放解決撥放問題~
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 個回答

1
japhenchen
iT邦超人 1 級 ‧ 2021-04-01 15:13:26

個人建議用ffmpeg裡的ffplay,以全螢幕播放影片...

GUI跟純CLI全適用

安裝很簡單,用 sudo apt-get install ffmpeg 即可

播放器的問題是地雷,踩到了要脫身還真的難,ffmpeg是我用過最順的一個

biscuit iT邦新手 5 級 ‧ 2021-04-01 16:02:01 檢舉

真的...我真新覺得 OMXPlayer 有夠難用...
我試試看~感謝大大回應

samshum iT邦新手 5 級 ‧ 2022-08-29 19:12:50 檢舉

omxplayer 很好用...
但不知為什麼,去到pi4播放得久會卡死

我要發表回答

立即登入回答