summaryrefslogtreecommitdiff
path: root/appl/wm/mpeg/mpeg.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/wm/mpeg/mpeg.b')
-rw-r--r--appl/wm/mpeg/mpeg.b285
1 files changed, 285 insertions, 0 deletions
diff --git a/appl/wm/mpeg/mpeg.b b/appl/wm/mpeg/mpeg.b
new file mode 100644
index 00000000..1ac8c276
--- /dev/null
+++ b/appl/wm/mpeg/mpeg.b
@@ -0,0 +1,285 @@
+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;
+}