parent
e3395131cc
commit
d0d2dce743
@ -1,2 +1,25 @@ |
||||
# PiPlayer |
||||
Simple GUI around OMXPlayer |
||||
|
||||
PiPlayer is a very simple GUI around the OMXPlayer on the Raspberry Pi. |
||||
|
||||
OMXPlayer is a quite basic player using the hardware decoding features of the Raspberry Pi for decoding HD videos. This GUI is intended to be used with other tools like smtube, which do not give you the opportunity to open a terminal for controlling OMXPlayer. You can now use PiPlayer for controlling OMXPlayer. |
||||
|
||||
The file ```dbuscontrol.sh``` is not written by me! I take no authorship in that bash-skript. I copied it from [popcornmix's repository](https://github.com/popcornmix/omxplayer) |
||||
|
||||
## Technical mumbo-jumbo |
||||
|
||||
PiPlayer quite litterely calls omxplayer and communicated to it via the DBus-interface. There are some functions not present in the GUI, which could be reached via the ```dbuscontrol.sh```-bash skript. |
||||
|
||||
The window is placed on the screen and omxplayer is called with the ```--win``` parameter to fit exactly inside the window. On resize of the window a DBus-interface is called to adjust for the new size of the window. That works well for maximizing, resizing or moving the window, but not for restoring it from maximized setting to normal. For that reason the OMXPlayer-output cannot be placed in the background, whereas the player-window can be in the background. |
||||
|
||||
## Usage |
||||
|
||||
You need the ```pyFLTK```-package for your Python-installation. Best to get it from the website (at least ArchLinux ARM) does not have the package in its repositories. For pyFLTK to work you of course need also the FLTK-package of your distribution (fltk1.3). |
||||
|
||||
Then you should be able to call it via a CPython3-interpreter (as far as I know the pypy-interpreter does not support pyFLTK): |
||||
|
||||
``` |
||||
python piplayer.py filename |
||||
``` |
||||
|
||||
You can also give parameters which will be directly handed to omxplayer on startup. |
||||
|
@ -0,0 +1,108 @@ |
||||
#!/bin/bash |
||||
|
||||
#set -x |
||||
|
||||
OMXPLAYER_DBUS_ADDR="/tmp/omxplayerdbus.${USER:-root}" |
||||
OMXPLAYER_DBUS_PID="/tmp/omxplayerdbus.${USER:-root}.pid" |
||||
export DBUS_SESSION_BUS_ADDRESS=`cat $OMXPLAYER_DBUS_ADDR` |
||||
export DBUS_SESSION_BUS_PID=`cat $OMXPLAYER_DBUS_PID` |
||||
|
||||
[ -z "$DBUS_SESSION_BUS_ADDRESS" ] && { echo "Must have DBUS_SESSION_BUS_ADDRESS" >&2; exit 1; } |
||||
|
||||
case $1 in |
||||
status) |
||||
duration=`dbus-send --print-reply=literal --session --reply-timeout=500 --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:"org.mpris.MediaPlayer2.Player" string:"Duration"` |
||||
[ $? -ne 0 ] && exit 1 |
||||
duration="$(awk '{print $2}' <<< "$duration")" |
||||
|
||||
position=`dbus-send --print-reply=literal --session --reply-timeout=500 --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:"org.mpris.MediaPlayer2.Player" string:"Position"` |
||||
[ $? -ne 0 ] && exit 1 |
||||
position="$(awk '{print $2}' <<< "$position")" |
||||
|
||||
playstatus=`dbus-send --print-reply=literal --session --reply-timeout=500 --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:"org.mpris.MediaPlayer2.Player" string:"PlaybackStatus"` |
||||
[ $? -ne 0 ] && exit 1 |
||||
playstatus="$(sed 's/^ *//;s/ *$//;' <<< "$playstatus")" |
||||
|
||||
paused="true" |
||||
[ "$playstatus" == "Playing" ] && paused="false" |
||||
echo "Duration: $duration" |
||||
echo "Position: $position" |
||||
echo "Paused: $paused" |
||||
;; |
||||
|
||||
volume) |
||||
volume=`dbus-send --print-reply=double --session --reply-timeout=500 --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Set string:"org.mpris.MediaPlayer2.Player" string:"Volume" ${2:+double:}$2` |
||||
[ $? -ne 0 ] && exit 1 |
||||
volume="$(awk '{print $2}' <<< "$volume")" |
||||
echo "Volume: $volume" |
||||
;; |
||||
|
||||
pause) |
||||
dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:16 >/dev/null |
||||
;; |
||||
|
||||
stop) |
||||
dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:15 >/dev/null |
||||
;; |
||||
|
||||
seek) |
||||
dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Seek int64:$2 >/dev/null |
||||
;; |
||||
|
||||
setposition) |
||||
dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.SetPosition objpath:/not/used int64:$2 >/dev/null |
||||
;; |
||||
|
||||
setalpha) |
||||
dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.SetAlpha objpath:/not/used int64:$2 >/dev/null |
||||
;; |
||||
|
||||
setvideopos) |
||||
dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.VideoPos objpath:/not/used string:"$2 $3 $4 $5" >/dev/null |
||||
;; |
||||
|
||||
setvideocroppos) |
||||
dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.SetVideoCropPos objpath:/not/used string:"$2 $3 $4 $5" >/dev/null |
||||
;; |
||||
|
||||
setaspectmode) |
||||
dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.SetAspectMode objpath:/not/used string:"$2" >/dev/null |
||||
;; |
||||
|
||||
hidevideo) |
||||
dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:28 >/dev/null |
||||
;; |
||||
|
||||
unhidevideo) |
||||
dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:29 >/dev/null |
||||
;; |
||||
|
||||
volumeup) |
||||
dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:18 >/dev/null |
||||
;; |
||||
|
||||
volumedown) |
||||
dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:17 >/dev/null |
||||
;; |
||||
|
||||
togglesubtitles) |
||||
dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:12 >/dev/null |
||||
;; |
||||
|
||||
hidesubtitles) |
||||
dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:30 >/dev/null |
||||
;; |
||||
|
||||
showsubtitles) |
||||
dbus-send --print-reply=literal --session --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Action int32:31 >/dev/null |
||||
;; |
||||
getsource) |
||||
source=$(dbus-send --print-reply=literal --session --reply-timeout=500 --dest=org.mpris.MediaPlayer2.omxplayer /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.GetSource) |
||||
[ $? -ne 0 ] && exit 1 |
||||
echo "$source" | sed 's/^ *//' |
||||
;; |
||||
*) |
||||
echo "usage: $0 status|pause|stop|seek|volumeup|volumedown|setposition [position in microseconds]|hidevideo|unhidevideo|togglesubtitles|hidesubtitles|showsubtitles|setvideopos [x1 y1 x2 y2]|setvideocroppos [x1 y1 x2 y2]|setaspectmode [letterbox,fill,stretch,default]|setalpha [alpha (0..255)]|getsource" >&2 |
||||
exit 1 |
||||
;; |
||||
esac |
@ -0,0 +1,269 @@ |
||||
from fltk import * |
||||
import sys |
||||
import os |
||||
import subprocess |
||||
import re |
||||
import time |
||||
import threading |
||||
|
||||
playState = True; |
||||
durationState = 0; |
||||
positionState = 0; |
||||
|
||||
class genericThread ( threading.Thread ): |
||||
def __init__ (self, threadID, name, counter): |
||||
threading.Thread.__init__(self); |
||||
self.threadID = threadID |
||||
self.name = name |
||||
self.counter = counter |
||||
self.fn = None; |
||||
self.args=[]; |
||||
def run( self ): |
||||
self.fn(self.args); |
||||
def setFn ( self, fn, args ): |
||||
self.fn = fn |
||||
self.args = args |
||||
|
||||
|
||||
def startOMX ( argv ): |
||||
global stateRun |
||||
argv=argv[0]; |
||||
argv.insert ( 0, "omxplayer" ) |
||||
argv.append ( "--win"); |
||||
(x,y,x2,y2) = sizeCalc(); |
||||
argv.append( str(x)+","+str(y)+","+str(x2)+","+str(y2) ) |
||||
argv.append ( "-o"); |
||||
argv.append("local"); |
||||
argv.append("--aspect-mode"); |
||||
argv.append("letterbox"); |
||||
subprocess.run ( argv ); |
||||
print ( "OMX finished"); |
||||
stateRun = False; |
||||
|
||||
def callDBus ( param ): |
||||
try: |
||||
param.insert ( 0, "dbuscontrol.sh" ); |
||||
param.insert ( 0, "bash" ); |
||||
out = subprocess.check_output ( param ) |
||||
return out; |
||||
except subprocess.CalledProcessError: |
||||
#print ("An Error occured while calling dbuscontrol.hs"); |
||||
return b""; |
||||
|
||||
def playCb(ptr): |
||||
callDBus ( ["pause"] ); |
||||
getState( None ); |
||||
global playState |
||||
if ( playState == True ): |
||||
playBtn.label ("@||"); |
||||
else : |
||||
playBtn.label("@|>"); |
||||
|
||||
def resizeCb (): |
||||
(x,y,x2,y2) = sizeCalc() |
||||
|
||||
status = callDBus ( ["status"] ); |
||||
times = 0; |
||||
while (status=="" and times < 5) : |
||||
status = callDBus ( ["status"] ); |
||||
time.sleep ( 0.5 ); |
||||
times = times + 1; |
||||
|
||||
if ( times < 5 ): |
||||
callDBus (["setvideopos", str(x), str(y), str(x2), str(y2)]); |
||||
|
||||
def sizeCalc ( ): |
||||
global window |
||||
x = window.x(); |
||||
y = window.y(); |
||||
w = window.w(); |
||||
h = window.h(); |
||||
|
||||
#x=x+2; |
||||
#y=y+2; |
||||
x2 = x + w; |
||||
y2 = y + h - 75; |
||||
|
||||
return (x,y,x2,y2); |
||||
|
||||
def DecodeState ( param ): |
||||
global playState; |
||||
global durationState; |
||||
global positionState; |
||||
i=0 |
||||
while (i < len(param)) : |
||||
m = re.search ( "Duration: ([0-9]+)", param[i] ); |
||||
if ( m is None ): |
||||
m = re.search ( "Position: ([0-9]+)", param[i] ); |
||||
if ( m is None ): |
||||
m = re.search ( "Pause: (\(true|false)\)", param[i] ); |
||||
if ( m is None ) : |
||||
pass; |
||||
else : |
||||
playState = ( m.group(1) == "true"); |
||||
else: |
||||
positionState = int ( m.group(1) ); |
||||
else: |
||||
durationState = int ( m.group(1) ); |
||||
i=i+1 |
||||
|
||||
def timeOut ( time ) : |
||||
time = int(time / 1000000); # mikrosec -> sec |
||||
hours = int(time / 3600); |
||||
minutes = int((time / 60)) - hours*60; |
||||
sec = time - minutes*60 - hours*360; |
||||
|
||||
return ( str(hours).zfill(2) + ":" + str(minutes).zfill(2) + ":" +str(sec).zfill(2) ); |
||||
|
||||
def setPosition ( pos ): |
||||
callDBus ( ["setposition", str(pos)] ); |
||||
getState ( None ); |
||||
|
||||
def getState ( ptr ) : |
||||
status = callDBus ( ["status"] ); |
||||
status = status.decode("utf-8").split("\n") |
||||
DecodeState ( status ); |
||||
|
||||
statusLabel.value ( timeOut ( positionState ) + " / " + timeOut ( durationState ) ); |
||||
if ( durationState == 0): |
||||
statusProgress.value(0); |
||||
else : |
||||
statusProgress.value( positionState / durationState ); |
||||
|
||||
stateRun = True; |
||||
def thread_state ( args ) : |
||||
global stateRun; |
||||
while ( stateRun == True ): |
||||
getState( None ); |
||||
time.sleep (1); |
||||
|
||||
omx = genericThread ( 1, "OMX", 1); |
||||
state = genericThread ( 2, "State", 2); |
||||
|
||||
def killAll ( ptr ): |
||||
global stateRun; |
||||
stateRun = False; |
||||
callDBus ( ["stop"] ); |
||||
state.join(); |
||||
omx.join(); |
||||
sys.exit(0); |
||||
|
||||
def FLTK_run () : |
||||
global stateRun |
||||
global window |
||||
global statusProgress |
||||
x = window.x(); |
||||
y = window.y(); |
||||
w = window.w(); |
||||
h = window.h(); |
||||
while (stateRun == True and window.shown()): |
||||
Fl.check(); |
||||
if ( x != window.x() or y != window.y() or |
||||
w != window.w() or h != window.h() ): |
||||
resizeWindow (); |
||||
if (Fl.event_button1() and Fl.event_inside ( statusProgress.x(), statusProgress.y(), statusProgress.x() + statusProgress.w(), statusProgress.y() + statusProgress.h() ) ): |
||||
seekCb (); |
||||
time.sleep(0.1); # I don't want to burn that much cpu-time |
||||
|
||||
def resizeWindow ( ): |
||||
global window; |
||||
global playBtn |
||||
global stateBtn |
||||
global killBtn |
||||
global statusLabel |
||||
global statusProgress |
||||
global volUp |
||||
global volDown |
||||
|
||||
h = window.h() |
||||
w = window.w() |
||||
|
||||
statusLabel.resize ( w-230, h-50, statusLabel.w(), statusLabel.h() ); |
||||
playBtn.position ( 20, h-60 ); |
||||
stateBtn.position ( 60, h-60); |
||||
killBtn.position ( 100, h-60 ); |
||||
|
||||
volUp.position ( w - 40, h-50 ); |
||||
volDown.position ( w - 60, h-50 ); |
||||
statusProgress.position ( 160, h-50 ); |
||||
statusProgress.size ( w - 410, 20 ); |
||||
|
||||
playBtn.redraw(); |
||||
stateBtn.redraw(); |
||||
killBtn.redraw(); |
||||
#statusLabel.redraw(); |
||||
statusProgress.redraw(); |
||||
window.redraw(); |
||||
|
||||
resizeCb (); |
||||
|
||||
def seekCb (): |
||||
global statusProgress; |
||||
x = Fl.event_x(); |
||||
x = x - statusProgress.x(); |
||||
dim = x / statusProgress.w(); |
||||
positionState = durationState * dim; |
||||
setPosition ( positionState ); |
||||
|
||||
def volUpCb ( ptr ): |
||||
callDBus ( ["volumeup"] ); |
||||
|
||||
def volDownCb ( ptr ): |
||||
callDBus ( ["volumedown"] ); |
||||
|
||||
if ( len ( sys.argv ) <= 1 ): |
||||
print ("Usage: " + sys.argv[0] + "[omxplayer-arguments] FILENAME"); |
||||
killAll(); |
||||
|
||||
omx.setFn ( startOMX, [sys.argv[1:]] ); |
||||
state.setFn ( thread_state, [] ); |
||||
|
||||
window = Fl_Window(100,100,640,480) |
||||
window.label(sys.argv[0]) |
||||
window.size_range ( 320, 240, 0, 0); |
||||
|
||||
# start omx-player |
||||
omx.start(); |
||||
|
||||
playBtn = Fl_Button(20, 420, 40, 40) |
||||
playBtn.label("@|>") |
||||
playBtn.callback(playCb) |
||||
playBtn.box ( FL_THIN_UP_BOX ); |
||||
|
||||
stateBtn = Fl_Button ( 60, 420, 40, 40 ); |
||||
stateBtn.label("?") |
||||
stateBtn.callback(getState) |
||||
stateBtn.box ( FL_THIN_UP_BOX ); |
||||
|
||||
killBtn = Fl_Button ( 100, 420, 40, 40 ); |
||||
killBtn.label ("x"); |
||||
killBtn.callback ( killAll ); |
||||
killBtn.box ( FL_THIN_UP_BOX ); |
||||
|
||||
statusLabel = Fl_Output ( 410, 430, 150, 20 ); |
||||
statusLabel.label (""); |
||||
statusLabel.box ( FL_FLAT_BOX ); |
||||
|
||||
statusProgress = Fl_Progress ( 160, 430, 230, 20 ); |
||||
statusProgress.box( FL_FLAT_BOX ); |
||||
statusProgress.minimum(0); |
||||
statusProgress.maximum(1); |
||||
statusProgress.color ( 0xffffffff ); |
||||
statusProgress.selection_color( 0x272828ff ); |
||||
|
||||
volUp = Fl_Button ( 600, 430, 20,20 ); |
||||
volUp.label ( "+" ); |
||||
volUp.box ( FL_THIN_UP_BOX ); |
||||
volUp.callback ( volUpCb ); |
||||
|
||||
volDown = Fl_Button ( 580, 430, 20,20 ); |
||||
volDown.label ( "-" ); |
||||
volDown.box ( FL_THIN_UP_BOX ); |
||||
volDown.callback ( volDownCb ); |
||||
|
||||
window.end() |
||||
window.show(len(sys.argv), sys.argv) |
||||
|
||||
state.start(); |
||||
FLTK_run (); |
||||
killAll( None ) |
Reference in new issue