//////////////////////////////////////////////////////////////////////////////
//
//      BDVideo Class - BDTools Library
//              2001 - Brent Dubs ( bdubs@vanityshops.com )
//
//      Uses the XPPMM.PRG from Gernot Trautmann availible in
//        the ASCN section of Alaska Software's website
//        www.alaska-software.com
//
//      Version level
//              1.2 - Added methods: SetPos, SetSize, SetPosAndSize,
//                                   and Ready
//
//              1.1 - Added methods: SetVolume, Mute, SetSpeed, Rewind,
//                                   FreezeRect, SaveFrame, Quality,
//                                   Seek, GetPosition, and FrameStep
//                    Added ivars: length, frames, volume, muted
//
//              1.0 - Original version
//
//////////////////////////////////////////////////////////////////////////////

#include "Common.ch"
#include "Xbp.ch"
#include "\bestatt\aaa\prgx\Xppmm.ch"

CLASS BDVideo FROM XbpStatic
        EXPORTED
        VAR     Ret
        VAR     handle
        VAR     error           // Error value of last command
        VAR     errorString     // Text description of error
        VAR     filename        // File loaded
        VAR     opened          // Is file opened
        VAR     paused          // Is video paused
        VAR     volume          // Volume level (0-1000)
        VAR     length          // Length of video in seconds
        VAR     frames          // Number of frames in the video
        VAR     muted           // Is audio muted

        METHOD  Init
        METHOD  Create
        METHOD  Destroy
        METHOD  LoadFile        // Load the file
        METHOD  Play            // Play the video
        METHOD  Pause           // Pause the video
        METHOD  Stop            // Stop the video
        METHOD  GetErrorString  // Retreive the descripion of the error
        METHOD  Status          // Retreive the playing status of the video
        METHOD  Ready           // Retreive the ready status of the MCI device
        METHOD  SetPos          // Set the display position of the video
        METHOD  SetSize         // Set the display size of the video
        METHOD  SetPosAndSize   // Set the display position and size of the video
        METHOD  SetVolume       // Set the volume level in percentage (0-100%)
        METHOD  Mute            // Set the audio off/on
        METHOD  SetSpeed        // Increase/decrease the playing speed
        METHOD  Seek            // Seek to a spot in the video in seconds
        METHOD  FrameStep       // Seek ahead or back in Frames (+ or -)
        METHOD  GetPosition     // Return the number of seconds into the video
        METHOD  Rewind          // Play video in reverse (not always supported)
        METHOD  FreezeRect      // Freeze a frame rect (not always supported)
        METHOD  SaveFrame       // Save a frame to a JPEG file (not always supported)
        METHOD  Quality         // Return the quality of video (not always supported)
ENDCLASS

//-----------------------------------------------------------------------------

METHOD BDVideo:Init( oParent, oOwner, aPos, aSize, aPP, lVisible )
   DEFAULT aPP TO {}
   ::XbpStatic:init( oParent, oOwner, aPos, aSize, aPP, lVisible )
   ::XbpStatic:type := XBPSTATIC_TYPE_TEXT
   ::error := 0
   ::errorString := ""
   ::Ret := SPACE(50)
   ::filename := ""
   ::opened := .F.
   ::handle := ""
   ::paused := .F.
   ::volume := 1000
   ::Length := 0
   ::frames := 0
   ::muted := .F.
   ::volume := 100
RETURN self

//-----------------------------------------------------------------------------

METHOD BDVideo:Create( oParent, oOwner, aPos, aSize, aPP, lVisible )
  ::XbpStatic:Create( oParent, oOwner, aPos, aSize, aPP, lVisible )
RETURN self

//-----------------------------------------------------------------------------

METHOD BDVideo:Destroy()
  IF ::opened
    ::error := mmSendString( "close movie", @::Ret )
    ::getErrorString()
  ENDIF
  ::XbpStatic:destroy()
RETURN

//-----------------------------------------------------------------------------
// Open the specified file and prepare it for playing.

METHOD BDVideo:loadFile(cFileName)
  ::filename := cFileName
  ::handle := Transform(::XbpStatic:getHwnd(),"9999999999")
  IF ::opened  // A file is already loaded...close it.
    ::error := mmSendString( "close movie", @::Ret )
    ::getErrorString()
  ENDIF
  ::Ret := SPACE(50)

  // Open the file
  ::error := mmSendString( "open "+ '"' + cFileName + '"' + " parent "+ ;
                         ::handle +" style child alias movie" , @::Ret)
  ::getErrorString()

  // Detect the length in frames
  mmSendString( "set movie time format frames", @::Ret )
  mmSendString( "status movie length", @::Ret )
  ::frames := IF(ValType(::Ret)=="C",VAL(::Ret),0)

  // Detect the length in seconds
  mmSendString( "set movie time format milliseconds", @::Ret )
  mmSendString( "status movie length", @::Ret )
  ::length := IF(ValType(::Ret)=="C",VAL(::Ret),0)

  // Detect the volumn level
  mmSendString( "status movie volume", @::Ret )
  ::volume := INT(VAL(::Ret)/10)

  // Create the display window
  IF ::error == 0
    ::error := mmSendString( "put movie window at 0 0 " +;
                             AllTrim(STR(::XbpStatic:currentSize()[1])) + " " +;
                             AllTrim(STR(::XbpStatic:currentSize()[2])) +;
                             " wait ", @::Ret )
    ::getErrorString()
    ::opened := .T.
  ENDIF
RETURN ::error

//-----------------------------------------------------------------------------
// Set the position and size of the video display

METHOD BDVideo:setPosAndSize(aPos,aSize,lPaint)
  LOCAL lSuccess := .T.
  DEFAULT lPaint TO .T.
  lSuccess := ::XbpStatic:setPosandSize(aPos,aSize,lPaint)
  ::error := mmSendString( "put movie window at 0 0 " +;
                           AllTrim(STR(aSize[1])) + " " +;
                           AllTrim(STR(aSize[2])) +;
                           " wait ", @::Ret )
  ::getErrorString()
RETURN lSuccess

//-----------------------------------------------------------------------------
// Set the position of the video display

METHOD BDVideo:setPos(aPos,lPaint)
  LOCAL lSuccess := .T.
  DEFAULT lPaint TO .T.
  lSuccess := ::XbpStatic:setPos(aPos,lPaint)
RETURN lSuccess

//-----------------------------------------------------------------------------
// Set the size of the video display

METHOD BDVideo:setSize(aSize,lPaint)
  LOCAL lSuccess := .T.
  DEFAULT lPaint TO .T.
  lSuccess := ::XbpStatic:setSize(aSize,lPaint)
  ::error := mmSendString( "put movie window at 0 0 " +;
                           AllTrim(STR(aSize[1])) + " " +;
                           AllTrim(STR(aSize[2])) +;
                           " wait ", @::Ret )
  ::getErrorString()
RETURN lSuccess

//-----------------------------------------------------------------------------
// Make the error string availible.

METHOD BDVideo:getErrorString()
  IF ::error != 0
    ::errorString := mmGetErrString(::error)
  ELSE
    ::errorString := ""
  ENDIF
RETURN ::errorString

//-----------------------------------------------------------------------------
// Check the status of the video clip.
//   Returns "playing", "paused", "stopped", etc.

METHOD BDVideo:status()
  ::error := mmSendString( "status movie mode", @::Ret )
RETURN ALLTRIM(::Ret)

//-----------------------------------------------------------------------------
// Check the ready status of the video clip.
//   Returns .T. if MCI device is ready for another command

METHOD BDVideo:ready()
  ::error := mmSendString( "status movie ready", @::Ret )
  ::getErrorString()
  ::Ret := STRTRAN(::Ret,CHR(0))
RETURN (UPPER(AllTrim(::Ret)) == "TRUE") .OR. EMPTY(::Ret)

//-----------------------------------------------------------------------------
// Play the video clip

METHOD BDVideo:Play(lFromStart,lWait,lRepeat)
  DEFAULT lFromStart TO .F.
  DEFAULT lWait TO .F.
  DEFAULT lRepeat TO .F.
  IF lFromStart  // Play from the beginning of the clip.
    IF ::opened  // If another clip is loaded...close it,
      ::error := mmSendString( "close movie", @::Ret )
    ENDIF
    ::loadfile(::filename)
  ENDIF
  ::paused := .F.  // If paused, it no longer is.
  IF lWait  // Freeze execution until the clip is finished.
    ::error := mmSendString( "play movie wait", @::Ret )
    ::stop()
  ELSE
    IF lRepeat  // Repeat the clip in loops.
      ::error := mmSendString( "play movie repeat", @::Ret )
    ELSE
      ::error := mmSendString( "play movie     ", @::Ret )
    ENDIF
  ENDIF
  ::getErrorString()
RETURN ::error

//-----------------------------------------------------------------------------
// Pause the video clip

METHOD BDVideo:Pause(lPlayIfPaused)
  DEFAULT lPlayIfPaused TO .F.
  IF ::paused
    IF lPlayIfPaused  // If it was previously paused then un-pause it.
      ::paused := .F.
      ::error := mmSendString( "play movie", @::Ret )
    ENDIF
  ELSE
    ::error := mmSendString( "pause movie", @::Ret )
    ::paused := .T.
  ENDIF
  ::getErrorString()
RETURN ::error

//-----------------------------------------------------------------------------
// Stop the video clip from playing

METHOD BDVideo:Stop()
  IF ::opened
    ::error := mmSendString( "stop movie", @::Ret )
  ENDIF
  ::getErrorString()
RETURN ::error

//-----------------------------------------------------------------------------
// Jump to position in video clip in seconds

METHOD BDVideo:Seek(nSeconds)
  LOCAL lPlaying := ::status() == "playing"
  LOCAL nOldPosition := ::GetPosition()
  nSeconds := ROUND(nSeconds,0) * 1000
  ::error := mmSendString( "seek movie to " + ALLTRIM(STR(nSeconds)), @::Ret )
  ::getErrorString()
  IF lPlaying
    mmSendString( "play movie", @::Ret )
  ENDIF
RETURN nOldPosition

//-----------------------------------------------------------------------------
// Jump to position in video clip in frames

METHOD BDVideo:FrameStep(nFrames)
  LOCAL lPlaying := ::status() == "playing"
  ::error := mmSendString( "step movie by " + ALLTRIM(STR(nFrames)), @::Ret )
  ::getErrorString()
  IF lPlaying
    mmSendString( "play movie", @::Ret )
  ENDIF
RETURN

//-----------------------------------------------------------------------------
// Set the speed of the video clip in percentages
//      50 = 50% speed (0.5x), 100 = 100% (normal), 200 = 200% speed (2x)

METHOD BDVideo:SetSpeed(nSpeed)
  DEFAULT nSpeed TO 100  // set to the regular speed
  nSpeed := nSpeed * 10
  ::error := mmSendString( "set movie speed " + ALLTRIM(STR(INT(nSpeed))), @::Ret )
  ::getErrorString()
RETURN

//-----------------------------------------------------------------------------
// Get the current positon in seconds

METHOD BDVideo:GetPosition()
  ::error := mmSendString( "status movie position", @::Ret )
  ::getErrorString()
RETURN (VAL(::Ret)/1000)

//-----------------------------------------------------------------------------
// Turn the audio off/on

METHOD BDVideo:Mute(lOn)
  DEFAULT lOn TO .T.
  IF lOn  // Turn sound off
    ::error := mmSendString( "set movie audio all off", @::Ret )
    ::muted := .T.
  ELSE  // Turn sound on
    ::error := mmSendString( "set movie audio all on", @::Ret )
    ::muted := .F.
  ENDIF
  ::getErrorString()
RETURN

//-----------------------------------------------------------------------------
// Set the audio volume level to percentage
//      0 = 0% (No sound), 50 = 50% (half-volume), 100 = 100% (full volume)

METHOD BDVideo:SetVolume(nLevel)
  DEFAULT nLevel TO 100
  IF nLevel < 0
    nLevel := 0
  ENDIF
  IF nLevel > 100
    nLevel := 100
  ENDIF
  ::volume := nLevel
  ::error := mmSendString( "setaudio movie volume to "+ALLTRIM(STR(INT(nLevel*10))), @::Ret )
  ::getErrorString()
RETURN

//-----------------------------------------------------------------------------
// Returns the quality of the video
//    This is not supported by all MCI devices (check :errorstatus)

METHOD BDVideo:quality()
  ::error := mmSendString( "info movie video quality", @::Ret )
  ::getErrorString()
RETURN ::Ret

//-----------------------------------------------------------------------------
// Saves current frame to a JPEG file
//    This is not supported by all MCI devices (check :errorstatus)

METHOD BDVideo:SaveFrame(cFileName)
  mmSendString( "set movie file format jpeg", @::Ret )
  ::error := mmSendString( "capture movie as " + cFileName, @::Ret )
  ::getErrorString()
RETURN

//-----------------------------------------------------------------------------
// Freeze a rectagle area of the video
//    This is not supported by all MCI devices (check :errorstatus)

METHOD BDVideo:freezeRect(aPos,aSize)
  ::error := mmSendString( "freeze movie at " +;
                            ALLTRIM(STR(aPos[1])) + " " +;
                            ALLTRIM(STR(aPos[2])) + " " +;
                            ALLTRIM(STR(aSize[1])) + " " +;
                            ALLTRIM(STR(aSize[2])), @::Ret )
   ::getErrorString()
RETURN

//-----------------------------------------------------------------------------
// Play the video in reverse
//    This is not supported by all MCI devices (check :errorstatus)

METHOD BDVideo:rewind()
  ::error := mmSendString( "play movie reverse", @::Ret )
  ::getErrorString()
RETURN

//-----------------------------------------------------------------------------
