snaums
/
PiPlayer
Archived
1
0
Fork 0
Simple GUI around OMXPlayer for Raspberry Pi
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.
 
 

526 lines
15 KiB

## @package ui
# contains mostly UI and Window-related functions
from fltk import *
import subprocess
import sys
import config
## TODO find a better way to get killAll-fn
import piplayer
import playlist
import re
import os
btnSize = 40;
## indicates whether the omxplayer is currently playing or if its paused
playState = True;
## indicates the duration of the media in mikroseconds
durationState = 0;
## indicates the current playback-position in mikroseconds
positionState = 0;
## loop the current video and or playlist?
loop = False;
## playlist-object
pl = playlist.playlist
## unused at the moment
dbusaddr = "org.mpris.MediaPlayer2.omxplayer"
## unused at the moment
def setDBusAddr ( addr ) :
global dbusaddr
dbusaddr = addr
## call the DBus-Interface of the omxplayer using the dbuscontrol.sh-skript
# @param param the parameters as array for the dbuscontrol.sh-skript
# @return either the stdout of dbuscontrol.sh on success or "" - both as Byte-string!
def callDBus ( param ):
try:
param.insert ( 0, config.dbusconfig );
param.insert ( 0, "bash" );
out = subprocess.check_output ( param )
return out;
except subprocess.CalledProcessError:
return b"";
## callback for play-button click - command omxplayer to pause and change label on button
# @param ptr unused, but needed for FLTK
def playCb(ptr):
callDBus ( ["pause"] );
getState( None );
global playState
global playBtn
if ( playState == True ):
playBtn.label ("@||");
else :
playBtn.label("@>");
## callback for the loop-button clck - toggle the loop-state
# @param ptr unused, but needed for FLTK
def loopBtnCb ( ptr ):
global loopBtn
global loop
if ( loop == True ) :
loop = False;
else:
loop = True;
loopBtn.value ( loop );
## callback for the playlist-button, hides or shows the playlist-widget
# @param ptr unused, but needed for FLTK
def playlistbtnCb ( ptr ):
global playlistBtn
global playlistList
global playlistState
if ( playlistState == True ):
playlistState = False;
else :
playlistState = True;
playlistBtn.value ( playlistState );
resizeWindow()
## callback for the playlist-clean-button, cleans the playlist (only leaves the currently playing item)
# @param ptr unused, but needed for FLTK
def plcleanCb ( ptr ):
val = pl.index(pl.current);
pl.clean();
pl.push ( val["name"], val["url"] );
ReinitPlaylistList();
## callback for the playlist-Up-button, moves an item up
# @param ptr unused, but needed for FLTK
def plupCb ( ptr ):
global playlistList
current = playlistList.value ()-1;
pl.move ( current, current-1);
ReinitPlaylistList();
## callback for the playlist-Up-button, moves an item down
# @param ptr unused, but needed for FLTK
def pldownCb ( ptr ):
global playlistList
current = playlistList.value ()-1;
pl.move ( current, current+1);
ReinitPlaylistList();
## decodes the output of dbuscontrol.sh (already split by "\n")
# @param split string(!) of the output of dbuscontrol.sh
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 ( "Paused: (true|false)", param[i] );
if ( m is None ) :
pass;
else :
playState = ( m.group(1) == "false");
else:
positionState = int ( m.group(1) );
else:
durationState = int ( m.group(1) );
i=i+1
## convert a mikrosecond time to a hh:mm:ss-representation string.
# @param time the mikrosecond timestamp to be converted
# @return a string hh:mm:ss
def timeOut ( time ) :
time = int(time / 1000000); # mikrosec -> sec
hours = int(time / 3600);
minutes = int((time / 60)) - hours*60;
sec = time - (minutes*60) - (hours*3600);
return ( str(hours).zfill(2) + ":" + str(minutes).zfill(2) + ":" +str(sec).zfill(2) );
## set a position for playback to the omxplayer for seeking
# @param pos the position in mikroseconds
def setPosition ( pos ):
callDBus ( ["setposition", str(pos)] );
getState ( None );
## get the status of omxplayer
# @param unused but here to make FLTK happy
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 );
## Refill the playlist-list widget with the data from the playlist-object
def ReinitPlaylistList ( ) :
global playlistList;
playlistList.clear()
i = 0
while ( i < pl.length() ):
v = pl.index( i );
playlistList.add ( str(i)+". " + v["name"], i );
i=i+1
playlistList.value ( pl.current+1 );
## callback for next-button press
def nextCb ( ptr ):
pl.next();
pl.setConst();
callDBus ( ["stop"] );
ReinitPlaylistList();
## callback for previous-button press
def prevCb ( ptr ):
pl.prev();
pl.setConst();
callDBus ( ["stop"] );
ReinitPlaylistList();
## called on resize of a window - will adjust the positions of the buttons and widgets,
# will also resize the omxplayer itself
def resizeWindow ( ):
global window;
global playBtn
global fullBtn
global statusLabel
global statusProgress
global loopBtn
global volUp
global volDown
global playlistBtn
global playlistList
global playlistCleanBtn
global playlistUpBtn
global playListDownBtn
h = window.h()
w = window.w()
prevBtn.position ( 0, h-btnSize );
playBtn.position ( btnSize, h-btnSize );
nextBtn.position ( btnSize*2, h-btnSize );
loopBtn.position ( btnSize*3, h-btnSize );
statusProgress.resize ( 170, h-30, w-470, 20 );
statusLabel.resize ( w-290, h-30, statusLabel.w(), statusLabel.h() );
volUp.position ( w-(btnSize*2)-10-40, h-30 );
volDown.position ( w-(btnSize*2)-10-20, h-30 );
fullBtn.position ( w-(btnSize*2), h-btnSize);
playlistBtn.position ( w-btnSize, h-btnSize );
if ( playlistState == True ):
playlistList.set_visible();
playlistCleanBtn.set_visible();
playlistUpBtn.set_visible();
playlistDownBtn.set_visible();
playlistList.resize ( w-200, 0, 200, h-80);
playlistCleanBtn.position ( w-180, h-80 );
playlistUpBtn.position ( w-120, h-80);
playlistDownBtn.position ( w-60, h-80 );
ReinitPlaylistList();
else:
playlistList.clear_visible();
playlistCleanBtn.clear_visible();
playlistUpBtn.clear_visible();
playlistDownBtn.clear_visible();
playBtn.redraw();
fullBtn.redraw();
loopBtn.redraw();
statusProgress.redraw();
window.redraw();
resizeOMX ();
## calculates the size of the omxplayer for resizing on window-moving or resizing
# @return (x,y,x2,y2) - topleft and bottomright point of the video-space
def sizeCalc ( ):
global window
x = window.x();
y = window.y();
w = window.w();
h = window.h();
#x=x+2;
#y=y+2;
if ( playlistState == True ):
w = w - 200;
x2 = x + w;
y2 = y + h - 40;
return (x,y,x2,y2);
## resizes the OMXplayer with input of sizeCalc
# @sa resizeOMX_inner(), sizeCalc()
def resizeOMX ():
global videoSpace
(x,y,x2,y2) = sizeCalc()
videoSpace.resize ( 0,0, x2-x, y2-y );
videoSpace.redraw();
resizeOMX_inner ( x,y,x2,y2 )
## resizes the OMXplayer with arbitrary input coordinates
# @param x x of the topleft point
# @param y y of the topleft point
# @param x2 x-position of the bottomright point of the video
# @param y2 y-position of the bottomright point
def resizeOMX_inner ( x, y, x2, y2 ):
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)]);
## called on click into the progressbar of the player.
# calculates a new videoposition based on where the user clicked
def seekCb ():
global statusProgress;
x = Fl.event_x();
x = x - statusProgress.x();
dim = x / statusProgress.w();
positionState = durationState * dim;
setPosition ( positionState );
## send a volume-up command to OMXplayer
# @param ptr unused but here for FLTK
def volUpCb ( ptr ):
callDBus ( ["volumeup"] );
## send a volume-down command to OMXplayer
# @param ptr unused but here for FLTK
def volDownCb ( ptr ):
callDBus ( ["volumedown"] );
## called when the fullscreen-button is clicked
# @param ptr unused but here for FLTK
def fullscreenCb ( ptr ):
global window
fullscreenWindow ()
## toggle the window fullscreen mode
def fullscreenWindow ():
global window
if ( window.fullscreen_active() ):
window.fullscreen_off();
else :
window.fullscreen();
## FLTK window-object for the player-window
window=""
## Button object for the play button
playBtn=""
## Button object for the fullscreen-button
fullBtn=""
## Button object for the loop-buttn
loopBtn=""
## Output object for the statusLabel-Output
statusLabel=""
## progressBar-object for the progress bar on the bottom of the player
statusProgress=""
## button object for the volume-up button
volUp=""
## button object for the volume-down button
volDown=""
## black background for the video-space in the middle of the window
videoSpace=""
playlistBtn = ""
playlistState = False
playlistList = ""
nextBtn =""
prevBtn=""
def plCb ( ptr ):
pl.setCurrent( playlistList.value()-1 );
pl.setConst();
callDBus( ["stop"] );
def style ( ptr ):
ptr.box ( FL_FLAT_BOX );
ptr.color ( 0x272828ff );
ptr.labelcolor ( FL_WHITE );
ptr.selection_color ( 0xaaaaaaff );
## sets a new title for the player window
# @param the name of the video file being played
def setTitle ( name ):
global window
window.label(name + " | PiPlayer")
## initiates the player-window
# @param the configuration-data (contains Window-position and sizes)
def init ( cfg, media ):
global window
global playBtn
global fullBtn
global statusLabel
global statusProgress
global volUp
global volDown
global loopBtn
global loop
global playlistBtn
global playlistState
global playlistList
global pl
global playlistCleanBtn
global playlistUpBtn
global playlistDownBtn
global videoSpace
global nextBtn
global prevBtn
loop = cfg.get("Loop", False );
playlistState = cfg.get("PlaylistState", False );
pl = playlist.playlist();
pl.addUrls ( media );
pl.length ();
window = Fl_Window( cfg.get("WindowX", 100) , cfg.get("WindowY", 100), cfg.get("WindowWidth", 640), cfg.get("WindowHeight", 480))
window.label("PiPlayer")
window.size_range ( 320, 240, 0, 0);
window.color ( 0x272828ff );
try:
icon = [];
sizes = [64];
i=0;
if (hasattr(sys, "frozen")):
module_path = os.path.dirname(os.path.dirname(sys.executable));
else:
module_path = os.path.dirname(os.path.dirname(__file__));
while ( i < len(sizes) ) :
ifile = open ( module_path + "/pic/logo"+str(sizes[i])+".data", "rb");
b=ifile.read();
icon.append( Fl_RGB_Image( b, sizes[i], sizes[i], 4, 0 ) )
i=i+1;
window.icon ( icon[0] );
except:
pass
print (icon);
w = window.w();
h = window.h();
videoSpace = Fl_Box ( 0,0, w, h-30 );
videoSpace.box ( FL_FLAT_BOX );
videoSpace.color ( FL_BLACK );
prevBtn = Fl_Button ( 0, h-btnSize, btnSize, btnSize )
prevBtn.labeltype(FL_SYMBOL_LABEL)
prevBtn.label("@<|");
prevBtn.callback ( prevCb );
prevBtn.tooltip ( "Previous" );
style(prevBtn);
playBtn = Fl_Button(40, h-btnSize, btnSize, btnSize)
playBtn.labeltype(FL_SYMBOL_LABEL)
playBtn.label("@||")
playBtn.callback(playCb)
playBtn.tooltip ( "Play / Pause" );
style(playBtn);
nextBtn = Fl_Button ( 80, h-btnSize, btnSize, btnSize );
nextBtn.labeltype(FL_SYMBOL_LABEL)
nextBtn.label("@|>");
nextBtn.callback ( nextCb );
nextBtn.tooltip ( "Next" );
style(nextBtn);
loopBtn = Fl_Button ( 120, h-btnSize, btnSize, btnSize );
loopBtn.labeltype(FL_SYMBOL_LABEL)
loopBtn.label ('@returnarrow');
loopBtn.callback ( loopBtnCb );
loopBtn.box ( FL_THIN_UP_BOX );
loopBtn.tooltip ( "Loop" );
if ( loop ):
loopBtn.set();
style(loopBtn);
statusProgress = Fl_Progress ( 170, h-30, w-470, 20 );
statusProgress.box( FL_FLAT_BOX );
statusProgress.minimum(0);
statusProgress.maximum(1);
statusProgress.color ( 0xffffffff );
statusProgress.selection_color( 0xaaaaaaff );
statusLabel = Fl_Output ( w-290, h-30, 150, 20 );
statusLabel.label ("");
statusLabel.box ( FL_FLAT_BOX );
statusLabel.textcolor ( FL_WHITE );
style(statusLabel);
volUp = Fl_Button ( w-(btnSize*2)-50, h-30, 20,20 );
volUp.label ( "+" );
volUp.callback ( volUpCb );
volUp.tooltip ( "Volume Up" );
style(volUp);
volDown = Fl_Button ( w-(btnSize*2)-30, h-30, 20,20 );
volDown.label ( "-" );
volDown.callback ( volDownCb );
volDown.tooltip ( "Volume Down" );
style(volDown);
fullBtn = Fl_Button ( w-(btnSize*2), h-btnSize, btnSize, btnSize );
fullBtn.labeltype(FL_SYMBOL_LABEL)
fullBtn.label("@square")
fullBtn.callback( fullscreenCb )
fullBtn.shortcut ( FL_Escape );
fullBtn.tooltip ( "Fullscreen" );
style(fullBtn);
playlistBtn = Fl_Button ( w-btnSize, h-btnSize, btnSize, btnSize );
playlistBtn.labeltype(FL_SYMBOL_LABEL)
playlistBtn.label ("@menu");
playlistBtn.callback ( playlistbtnCb );
playlistBtn.tooltip ( "Show Playlist" );
style(playlistBtn);
playlistList = Fl_Select_Browser ( 420, 0, 200, w-80 );
playlistList.box ( FL_FLAT_BOX );
#playlistList.callback ( plCb );
playlistCleanBtn = Fl_Button ( w-180, h-80, 40, 40 )
playlistCleanBtn.label("Clean");
playlistCleanBtn.callback ( plcleanCb );
playlistCleanBtn.tooltip ( "Empty Playlist");
style(playlistCleanBtn);
playlistUpBtn = Fl_Button ( w-120, h-80, 40, 40 )
playlistUpBtn.labeltype(FL_SYMBOL_LABEL)
playlistUpBtn.label("@<-");
playlistUpBtn.callback ( plupCb );
playlistUpBtn.tooltip ( "Move selected element up");
style(playlistUpBtn);
playlistDownBtn = Fl_Button ( w-60, h-80, 40, 40 )
playlistDownBtn.labeltype(FL_SYMBOL_LABEL)
playlistDownBtn.label("@->");
playlistDownBtn.callback ( pldownCb );
playlistCleanBtn.tooltip ( "Move selected element down");
style(playlistDownBtn);
resizeWindow();
window.end()
window.show(1, [sys.argv[0]])