Browse Source

First version of piplayer

master
Stefan Naumann 5 years ago
parent
commit
d0d2dce743
  1. 25
      README.md
  2. 108
      dbuscontrol.sh
  3. 269
      piplayer.py

25
README.md

@ -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.

108
dbuscontrol.sh

@ -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

269
piplayer.py

@ -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 )