ref: 02ac617541ca1a7bf82b1615fb5a58235469b5d3
dir: /appl/wm/mpeg/mpeg.b/
implement WmMpeg;
include "sys.m";
sys: Sys;
include "draw.m";
draw: Draw;
Point, Rect, Display, Image: import draw;
include "tk.m";
tk: Tk;
Toplevel: import tk;
include "tkclient.m";
tkclient: Tkclient;
ctxt: ref Draw->Context;
include "dialog.m";
dialog: Dialog;
include "selectfile.m";
selectfile: Selectfile;
include "mpegio.m";
include "arg.m";
mio: Mpegio;
decode: Mpegd;
remap: Remap;
Mpegi: import mio;
WmMpeg: module
{
init: fn(ctxt: ref Draw->Context, argv: list of string);
};
Stopped, Playing, Stepping, Paused: con iota;
state := Stopped;
depth := -1;
sdepth: int;
cvt: ref Image;
pixelrec: Draw->Rect;
decoders := array[] of {
1=> Mpegd->PATH4,
2=> Mpegd->PATH4,
4=> Mpegd->PATH4,
8 or 16 or 24 or 32 => Mpegd->PATH,
};
remappers := array[] of {
1=> Remap->PATH1,
2=> Remap->PATH2,
4=> Remap->PATH4,
8 or 16 or 24 or 32 => Remap->PATH,
};
task_cfg := array[] of {
"canvas .c",
"frame .b",
"button .b.File -text File -command {send cmd file}",
"button .b.Stop -text Stop -command {send cmd stop}",
"button .b.Pause -text Pause -command {send cmd pause}",
"button .b.Step -text Step -command {send cmd step}",
"button .b.Play -text Play -command {send cmd play}",
"frame .f",
"label .f.file -text {File:}",
"label .f.name",
"pack .f.file .f.name -side left",
"pack .b.File .b.Stop .b.Pause .b.Step .b.Play -side left",
"pack .f -fill x",
"pack .b -anchor w",
"pack .c -side bottom -fill both -expand 1",
"pack propagate . 0",
};
init(xctxt: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
draw = load Draw Draw->PATH;
tk = load Tk Tk->PATH;
tkclient= load Tkclient Tkclient->PATH;
dialog = load Dialog Dialog->PATH;
selectfile= load Selectfile Selectfile->PATH;
ctxt = xctxt;
tkclient->init();
dialog->init();
selectfile->init();
darg, tkarg: string;
arg := load Arg Arg->PATH;
arg->init(argv);
while((c := arg->opt()) != 0)
case c {
'x' =>
tkarg = arg->arg();
'd' =>
darg = arg->arg();
}
args := arg->argv();
arg = nil;
if(darg != nil)
depth = int darg;
sdepth = ctxt.display.image.depth;
if (depth < 0 || depth > sdepth)
depth = sdepth;
(t, menubut) := tkclient->toplevel(ctxt, tkarg, "MPEG Player", 0);
cmd := chan of string;
tk->namechan(t, cmd, "cmd");
for(i:=0; i<len task_cfg; i++)
tk->cmd(t, task_cfg[i]);
tk->cmd(t, "bind . <Configure> {send cmd resize}");
tk->cmd(t, "update");
tkclient->onscreen(t, nil);
tkclient->startinput(t, "kbd"::"ptr"::nil);
mio = load Mpegio Mpegio->PATH;
decode = load Mpegd decoders[depth];
remap = load Remap remappers[depth];
if(mio == nil || decode == nil || remap == nil) {
dialog->prompt(ctxt, t.image, "error -fg red", "Loading Interfaces",
"Failed to load the MPEG\ninterface: "+sys->sprint("%r"),
0, "Exit"::nil);
return;
}
mio->init();
fname := "";
ctl := chan of string;
state = Stopped;
for(;;) alt {
s := <-t.ctxt.kbd =>
tk->keyboard(t, s);
s := <-t.ctxt.ptr =>
tk->pointer(t, *s);
s := <-t.ctxt.ctl or
s = <-t.wreq =>
tkclient->wmctl(t, s);
s := <-menubut =>
if(s == "exit"){
state = Stopped;
return;
}
tkclient->wmctl(t, s);
press := <-cmd =>
case press {
"file" =>
state = Stopped;
patterns := list of {
"*.mpg (MPEG movie files)",
"* (All Files)"
};
fname = selectfile->filename(ctxt, t.image, "Locate MPEG files",
patterns, nil);
if(fname != nil) {
tk->cmd(t, ".f.name configure -text {"+fname+"}");
tk->cmd(t, "update");
}
"play" =>
if (state != Stopped) {
state = Playing;
continue;
}
if(fname != nil) {
state = Playing;
spawn play(t, fname);
}
"step" =>
if (state != Stopped) {
state = Stepping;
continue;
}
if(fname != nil) {
state = Stepping;
spawn play(t, fname);
}
"pause" =>
if(state == Playing)
state = Paused;
"stop" =>
state = Stopped;
}
}
}
play(t: ref Toplevel, file: string)
{
sp := list of { "Stop Play" };
fd := sys->open(file, Sys->OREAD);
if(fd == nil) {
dialog->prompt(ctxt, t.image, "error -fg red", "Open MPEG file", sys->sprint("%r"), 0, sp);
return;
}
m := mio->prepare(fd, file);
m.streaminit(Mpegio->VIDEO_STR0);
p := m.getpicture(1);
decode->init(m);
remap->init(m);
canvr := canvsize(t);
o := Point(0, 0);
dx := canvr.dx();
if(dx > m.width)
o.x = (dx - m.width)/2;
dy := canvr.dy();
if(dy > m.height)
o.y = (dy - m.height)/2;
canvr.min = canvr.min.add(o);
canvr.max = canvr.min.add(Point(m.width, m.height));
if (depth != sdepth){
chans := Draw->CMAP8;
case depth {
0 => chans = Draw->GREY1;
1 => chans = Draw->GREY2;
2 => chans = Draw->GREY4;
3 => chans = Draw->CMAP8;
4 => chans = Draw->RGB16;
5 => chans = Draw->RGB24; # ?
}
cvt = ctxt.display.newimage(Rect((0, 0), (m.width, m.height)), chans, 0, 0);
}
f, pf: ref Mpegio->YCbCr;
for(;;) {
if(state == Stopped)
break;
case p.ptype {
Mpegio->IPIC =>
f = decode->Idecode(p);
Mpegio->PPIC =>
f = decode->Pdecode(p);
Mpegio->BPIC =>
f = decode->Bdecode(p);
}
while(state == Paused)
sys->sleep(0);
if (p.ptype == Mpegio->BPIC) {
writepixels(t, canvr, remap->remap(f));
if(state == Stepping)
state = Paused;
} else {
if (pf != nil) {
writepixels(t, canvr, remap->remap(pf));
if(state == Stepping)
state = Paused;
}
pf = f;
}
if ((p = m.getpicture(1)) == nil) {
writepixels(t, canvr, remap->remap(pf));
break;
}
}
state = Stopped;
}
writepixels(t: ref Toplevel, r: Rect, b: array of byte)
{
if (cvt != nil) {
cvt.writepixels(cvt.r, b);
t.image.draw(r, cvt, nil, (0, 0));
} else
t.image.writepixels(r, b);
}
canvsize(t: ref Toplevel): Rect
{
r: Rect;
r.min.x = int tk->cmd(t, ".c cget -actx");
r.min.y = int tk->cmd(t, ".c cget -acty");
r.max.x = r.min.x + int tk->cmd(t, ".c cget -width");
r.max.y = r.min.y + int tk->cmd(t, ".c cget -height");
return r;
}