--
--	vidgrab.occ -- video grab test for occam-pi
--	Copyright (C) 2008 Fred Barnes <frmb@kent.ac.uk>
--
--	This program is free software; you can redistribute it and/or modify
--	it under the terms of the GNU General Public License as published by
--	the Free Software Foundation; either version 2 of the License, or
--	(at your option) any later version.
--
--	This program is distributed in the hope that it will be useful,
--	but WITHOUT ANY WARRANTY; without even the implied warranty of
--	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--	GNU General Public License for more details.
--
--	You should have received a copy of the GNU General Public License
--	along with this program; if not, write to the Free Software
--	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
--

#INCLUDE "course.module"
#INCLUDE "sdlraster.module"
#INCLUDE "video.module"

VAL []BYTE DEVICE.NAME IS "/dev/video0":


PROC vidgrab.main (CT.VIDEO! dev, CHAN BYTE kyb?, scr!)
  VIDEO.IDENTITY ident:
  MOBILE []VIDEO.INPUT inputs:
  VIDEO.PICTURE pict:
  VIDEO.FRAMEINFO finf:
  BOOL ok:
  SEQ

    --{{{  device identity
    out.string ("vidgrab: getting device identity...*n", 0, scr!)

    dev[req] ! get.identity
    dev[resp] ? CASE
      identity; ident
        SEQ
          out.string ("vidgrab: device is [", 0, scr!)
          out.string ([ident[name] FOR ident[namelen]], 0, scr!)
          out.string ("]*n", 0, scr!)
      MOBILE []BYTE msg:
      error; msg
        SEQ
          out.string ("vidgrab: failed to get device identity: ", 0, scr!)
          out.string (msg, 0, scr!)
          out.string ("*n", 0, scr!)

    --}}}
    --{{{  info about available inputs
    out.string ("vidgrab: getting information about available inputs...*n", 0, scr!)

    dev[req] ! get.inputs
    dev[resp] ? CASE
      inputs; inputs
        SEQ
          out.string ("vidgrab: got information about ", 0, scr!)
          out.int (SIZE inputs, 0, scr!)
          out.string (" inputs:*n", 0, scr!)
          SEQ i = 0 FOR SIZE inputs
            SEQ
              out.int (i, 2, scr!)
              out.string ("  ", 0, scr!)
              out.int (inputs[i][id], 4, scr!)
              out.string ("  ", 0, scr!)
              out.string ([inputs[i][name] FOR inputs[i][namelen]], 0, scr!)
              out.string (" (", 0, scr!)
              out.int (inputs[i][minw], 0, scr!)
              out.string ("x", 0, scr!)
              out.int (inputs[i][minh], 0, scr!)
              out.string (") - (", 0, scr!)
              out.int (inputs[i][maxw], 0, scr!)
              out.string ("x", 0, scr!)
              out.int (inputs[i][maxh], 0, scr!)
              out.string (")*n", 0, scr!)
      MOBILE []BYTE msg:
      error; msg
        SEQ
          out.string ("vidgrab: failed to get details of inputs: ", 0, scr!)
          out.string (msg, 0, scr!)
          out.string ("*n", 0, scr!)
    --}}}
    --{{{  picture properties
    out.string ("vidgrab: getting picture properties...*n", 0, scr!)

    dev[req] ! get.picture
    dev[resp] ? CASE
      picture; pict
        SEQ
          out.string ("bright:   ", 0, scr!)
          out.int (INT pict[brightness], 0, scr!)
          out.string ("*n", 0, scr!)
          out.string ("hue:      ", 0, scr!)
          out.int (INT pict[hue], 0, scr!)
          out.string ("*n", 0, scr!)
          out.string ("colour:   ", 0, scr!)
          out.int (INT pict[colour], 0, scr!)
          out.string ("*n", 0, scr!)
          out.string ("contrast: ", 0, scr!)
          out.int (INT pict[contrast], 0, scr!)
          out.string ("*n", 0, scr!)
          out.string ("white:    ", 0, scr!)
          out.int (INT pict[whiteness], 0, scr!)
          out.string ("*n", 0, scr!)
          out.string ("depth:    ", 0, scr!)
          out.int (INT pict[hue], 0, scr!)
          out.string ("*n", 0, scr!)
      MOBILE []BYTE msg:
      error; msg
        SEQ
          out.string ("vidgrab: failed to get picture properties: ", 0, scr!)
          out.string (msg, 0, scr!)
          out.string ("*n", 0, scr!)

    --}}}
    #IF FALSE
    --{{{  set picture format to RGB24
    out.string ("vidgrab: setting picture format to RGB24...*n", 0, scr!)

    pict[palette] := VIDEO.PAL.RGB24
    dev[req] ! set.picture; pict
    dev[resp] ? CASE
      picture; pict
        SEQ
          out.string ("vidgrab: picture format now ", 0, scr!)
          out.int (INT pict[palette], 0, scr!)
          VAL INT pal IS INT pict[palette]:
          IF
            (pal >= 0) AND (pal < (SIZE VIDEO.PAL.NAMES))
              SEQ
                out.string (" ", 0, scr!)
                out.string (VIDEO.PAL.NAMES[pal], 0, scr!)
            TRUE
              SKIP
          out.string ("*n", 0, scr!)
      MOBILE []BYTE msg:
      error; msg
        SEQ
          out.string ("vidgrab: failed to set picture format: ", 0, scr!)
          out.string (msg, 0, scr!)
          out.string ("*n", 0, scr!)
    --}}}
    #ENDIF
    --{{{  frame info
    out.string ("vidgrab: getting frame info...*n", 0, scr!)

    dev[req] ! get.frameinfo
    dev[resp] ? CASE
      frameinfo; finf
        SEQ
          out.string ("vidgrab: frames are ", 0, scr!)
          out.int (finf[width], 0, scr!)
          out.string ("x", 0, scr!)
          out.int (finf[height], 0, scr!)
          out.string (", palette ", 0, scr!)
          out.int (finf[format], 0, scr!)
          VAL INT pal IS INT finf[format]:
          IF
            (pal >= 0) AND (pal < (SIZE VIDEO.PAL.NAMES))
              SEQ
                out.string (" ", 0, scr!)
                out.string (VIDEO.PAL.NAMES[pal], 0, scr!)
            TRUE
              SKIP
          out.string ("*n", 0, scr!)
      MOBILE []BYTE msg:
      error; msg
        SEQ
          out.string ("vidgrab: failed to get frame info: ", 0, scr!)
          out.string (msg, 0, scr!)
          out.string ("*n", 0, scr!)
    --}}}
    #PRAGMA DEFINED finf
    #PRAGMA DEFINED pict
    CHAN RASTER rc1, rc2:
    PAR
      --{{{  create raster
      raster.display.simple ("video grab test", finf[width], finf[height], 2, rc1?, rc2!)

      --}}}
      --{{{  loop grabbing frames from the input, put them on the screen!
      SEQ

        INITIAL BOOL redraw.menu IS TRUE:
        INITIAL INT  change.input IS -1:
        INITIAL BOOL update.pict IS FALSE:
        INITIAL BOOL update.frameno IS TRUE:
        INITIAL BOOL run IS TRUE:
        INITIAL INT frameno IS 0:
        WHILE run
          RASTER r:

          PROC do.dec (INT val)
            SEQ
              val := val MINUS #100
              update.pict, redraw.menu := TRUE, TRUE
          :
          PROC do.inc (INT val)
            SEQ
              val := val PLUS #100
              update.pict, redraw.menu := TRUE, TRUE
          :

          SEQ
            rc2 ? r

            --{{{  oki, try and get a frame of data!
            -- out.string ("vidgrab: attempting to grab a video frame..*n", 0, scr!)

            IF
              change.input >= 0
                SEQ
                  dev[req] ! set.input; change.input
                  dev[resp] ? CASE
                    ok
                      SKIP
                    MOBILE []BYTE str:
                    error; str
                      SEQ
                        out.string ("vidgrab: failed to change input: ", 0, scr!)
                        out.string (str, 0, scr!)
                        out.string ("*n", 0, scr!)
                  change.input := -1
              TRUE
                SKIP

            IF
              update.pict
                SEQ
                  dev[req] ! set.picture; pict
                  dev[resp] ? CASE
                    VIDEO.PICTURE tpict:
                    picture; tpict
                      SKIP
                    MOBILE []BYTE str:
                    error; str
                      SEQ
                        out.string ("vidgrab: failed to update picture: ", 0, scr!)
                        out.string (str, 0, scr!)
                        out.string ("*n", 0, scr!)
                  update.pict := FALSE
              TRUE
                SKIP

            IF
              redraw.menu
                SEQ
                  erase.screen (scr!)
                  cursor.x.y (1, 1, scr!)

                  out.string ("B/b   +/- brightness: ", 0, scr!)
                  out.int (INT pict[brightness], 0, scr!)
                  out.string ("*n", 0, scr!)
                  out.string ("H/h   +/- hue: ", 0, scr!)
                  out.int (INT pict[hue], 0, scr!)
                  out.string ("*n", 0, scr!)
                  out.string ("C/c   +/- colour: ", 0, scr!)
                  out.int (INT pict[colour], 0, scr!)
                  out.string ("*n", 0, scr!)
                  out.string ("O/o   +/- contrast: ", 0, scr!)
                  out.int (INT pict[contrast], 0, scr!)
                  out.string ("*n", 0, scr!)
                  out.string ("W/w   +/- whiteness: ", 0, scr!)
                  out.int (INT pict[whiteness], 0, scr!)
                  out.string ("*n", 0, scr!)

                  redraw.menu := FALSE
              TRUE
                SKIP

            IF
              update.frameno
                SEQ
                  out.string ("frame: ", 0, scr!)
                  out.int (frameno, 0, scr!)
                  out.string ("*c", 0, scr!)
                  scr ! FLUSH
                  update.frameno := FALSE
              TRUE
                SKIP

            dev[req] ! grab.frame; FALSE
            INITIAL BOOL got.frame IS FALSE:
            WHILE NOT got.frame
              PRI ALT
                BYTE ch:
                kyb ? ch
                  SEQ
                    CASE ch
                      'b'
                        do.dec (pict[brightness])
                      'B'
                        do.inc (pict[brightness])
                      'h'
                        do.dec (pict[hue])
                      'H'
                        do.inc (pict[hue])
                      'c'
                        do.dec (pict[colour])
                      'C'
                        do.inc (pict[colour])
                      'o'
                        do.dec (pict[contrast])
                      'O'
                        do.inc (pict[contrast])
                      'w'
                        do.dec (pict[whiteness])
                      'W'
                        do.inc (pict[whiteness])
                      '0'
                        change.input := 0
                      '1'
                        change.input := 1
                      '2'
                        change.input := 2
                      ELSE
                        SKIP

                dev[resp] ? CASE
                  RASTER frame:
                  raster; frame
                    INT mx, my:
                    SEQ
                      -- out.string ("vidgrab: got frame! ", 0, scr!)
                      -- out.int (SIZE frame[0], 0, scr!)
                      -- out.string ("x", 0, scr!)
                      -- out.int (SIZE frame, 0, scr!)
                      -- out.string ("*n", 0, scr!)

                      -- slap it on the raster!
                      IF
                        (SIZE frame) > (SIZE r)
                          my := SIZE r
                        TRUE
                          my := SIZE frame
                      IF
                        (SIZE frame[0]) > (SIZE r[0])
                          mx := SIZE r[0]
                        TRUE
                          mx := SIZE frame[0]

                      SEQ y = 0 FOR my
                        SEQ x = 0 FOR mx
                          r[y][x] := INT frame[y][x]

                      got.frame := TRUE

                  MOBILE []BYTE msg:
                  error; msg
                    SEQ
                      out.string ("vidgrab: failed to grab frame: ", 0, scr!)
                      out.string (msg, 0, scr!)
                      out.string ("*n", 0, scr!)
            --}}}
            frameno := frameno + 1
            update.frameno := TRUE

            rc1 ! r

      --}}}
:

PROC vidgrab (CHAN BYTE kyb?, scr!, err!)
  CT.VIDEO! vcli:
  CT.VIDEO? vsvr:
  SEQ
    out.string ("vidgrab: hello, opening [", 0, scr!)
    out.string (DEVICE.NAME, 0, scr!)
    out.string ("]*n", 0, scr!)

    vcli, vsvr := MOBILE CT.VIDEO
    PAR
      video.server (vsvr, DEVICE.NAME)

      SEQ
        vcli[req] ! get.current.input
        vcli[resp] ? CASE
          INT n:
          input.number; n
            vidgrab.main (vcli, kyb?, scr!)
          MOBILE []BYTE str:
          error; str
            SEQ
              out.string ("vidgrab: failed to start video server: ", 0, scr!)
              out.string (str, 0, scr!)
              out.string ("*n", 0, scr!)
        vcli[return] ! vcli
:


