
/*
**
**  $VER: classbase.c 1.3 (23.12.96)
**  film.datatype 1.0
**
**  Library routines for a DataTypes class
**
**  Written 1996 by Roland 'Gizzy' Mainz
**  Original example source from David N. Junod
**
*/


/* main includes */
#include "classbase.h"


/****** film.datatype/--datasheed-- ******************************************
*
*   NAME
*       film.datatype -- data type for IFF FILM movies
*
*   SUPERCLASS
*       animation.datatype
*
*   DESCRIPTION
*       The film datatype, a sub-class of the animation.datatype, is
*       used load and play IFF FILM movies.
*
*   METHODS
*       OM_NEW -- Create a new animation object from a description file. The
*           source may only be a file.
*
*       OM_DISPOSE -- Dispose instance and contents (frames, colormaps,
*           sounds etc.), then pass msg to superclass
*
*       OM_UPDATE -- Perform an ICM_CHECKLOOP check, and if succesfull, the
*           method will be executed like OM_SET downstairs.
*
*       OM_SET -- Pass msg to superclass and call GM_RENDER if retval from
*           superclass was != 0UL.
*
*       GM_LAYOUT -- Collect information from superclass, set up
*           struct DTSpecialInfo and send an OM_NOTIFY containing usefull
*           attributes.
*
*       DTM_FRAMEBOX -- Set up object for a specified environment if
*           FRAMEF_SPECIFY was set in (dtf -> dtf_FrameFlags).
*
*       ADTM_LOADFRAME -- Fill in struct adtFrame with requested information
*           from internal FrameNode list like bitmap, colormap and sound.
*
*       All other methods are passed unchanged to superclass.
*
*   ATTRIBUTES
*       Following attributes are set by the object and are READ-ONLY for
*       applications:
*       DTA_ObjName       -- reserved
*       DTA_ObjAuthor     -- reserved
*       DTA_ObjAnnotation -- reserved
*       DTA_ObjCopyright  -- reserved
*       DTA_ObjVersion    -- reserved
*       DTA_NominalVert   -- same as ADTA_Width
*       DTA_NominalHoriz  -- same as ADTA_Height
*       ADTA_Width        -- Set by ILBM BitMapHeader
*       ADTA_Height       -- Set by ILBM BitMapHeader
*       ADTA_Depth        -- Set by ILBM BitMapHeader
*
*   BUGS
*       - In large videos, the frames at the end will be played slower than
*         those at the beginning of the file. This is the result of the
*         sequential search internally used (only serious with more than 25000
*         frames (mc6030/50mhz)).
*         May or may not be fixed.
*
*       - The current implementation ignores any ILBM CMAPs in the CAT CELLs.
*
*       - Currently, a prefs-file is not implemented. Therefore, the NOREMAP
*         feature is useless (for now...).
*
*       - Currently, after a full playback mainly all frames are cached
*         because animation.datatype does not flush enougth frane during
*         playback. This is not a bug of animation.datatype. I don't know that
*         return codes of the ADTM_LOADFRAME method which causes
*         animation.datatype to flush unused frames. Without information from
*         CBM, Amiga Technologies or David Junod I cannot fix this bug.
*         Comments welcome !
*
*   TODO
*       - Implement ACBM/ABIT chunks as a replacement for ILBM/BODY chunks.
*         This should speed up reading/decoding.
*
*   HISTORY
*       V1.1
*         First public release.
*
*       V1.2
*         - Implemented relative seeking, which speeds up loading.
*
*         - Moved and removed some bounds checking code in the ILBM BODY
*           loader.
*
*         - Moved, removed and new code: Small cleanup
*
*         - Now supports a prefs file.
*
*         - If a ILBM CAMG-Chunks is missing in the movie and no MODEID
*           option was set, BestModeID is used to get the best matching
*           screen mode.
*
*       V1.3
*         - Now uses interleaved bitmaps for faster loading.
*
*         - Small code cleanup.
*
*   NOTES
*
*   SEE ALSO
*       animation.datatype,
*       mpegsystem.datatype, mpegvideo.datatype,
*       picmovie.datatype,
*       cdxl.datatype. avi.datatype, quicktime.datatype,
*       directory.datatype,
*       markabletextdtclass
*
*******************************************************************************
*
*/


/****** film.datatype/--input format-- ****************************************
*
*    NAME
*        IFF FILM -- ILBM frames with interleaved 8SVX samples
*
*    DESCRIPTION
*        A IFF FILM stream contains uncompressed video and audio data.
*        The LIST section contains a ILBM part and a 8SVX part, which
*        must contain a ILBM BMHD (BitMapHeader), a ILBM CMAP
*        (global colormap), a ILMB CAMG (amiga view mod id) and a 8SVX VHDR
*        (VoiceHeader). Other information (like a 8SVX CHAN chunk are
*        optional).
*
*        After this "header" part, the single animation frames will follow.
*        A "frame" consists of a CAT CELL, which contains the video (FORM ILBM
*        BODY) and audio (FORM 8SVX BODY) data.
*        Each ILBM/8SVX BODY must have exactly the same size, and as a result,
*        all CELLs have the same size (usefull for continous reading).
*
*        Example (created with "sift"):
*        . LIST 736892 FILM
*        . . PROP 100 ILBM          ; shared ILBM properties
*        . . . BMHD 20 ILBM
*        . . . CAMG 4 ILBM
*        . . . CMAP 48 ILBM
*        . . PROP 44 8SVX           ; shared 8SVX properties
*        . . . VHDR 20 8SVX
*        . . . CHAN 4 8SVX
*        . . CAT  16000 CELL        ; 1st cell (frame of movie)
*        . . . FORM 14532 ILBM
*        . . . . BODY 14520 ILBM    ;   ILBM BitMap data
*        . . . FORM 1448 8SVX
*        . . . . BODY 1436 8SVX     ;   8SVX Sample data
*        . . CAT  16000 CELL        ; 2nd cell
*        . . . FORM 14532 ILBM
*        . . . . BODY 14520 ILBM    ;   ILBM BitMap data
*        . . . FORM 1448 8SVX
*        . . . . BODY 1436 8SVX     ;   8SVX Sample data
*        . . CAT  16000 CELL        ; 3rd cell
*        . . . FORM 14532 ILBM
*        . . . . BODY 14520 ILBM    ;   ILBM BitMap data
*        . . . FORM 1448 8SVX
*        . . . . BODY 1436 8SVX     ;   8SVX Sample data
*        and so on....
*
*    SEE ALSO
*        - AminetCD2:gfx/show/AGMSFilm2.LhA, which includes a much better
*          description, the history and background of the IFF FILM format.
*
*        - Aminet:gfx/conv/DumpDTAnim#?.LhA as an implementation of an 
*          IFF FILM writer
*
*        - ARKM Devices: IFF part
*
*        - iffparse.library autodocs
*
*******************************************************************************
*
*/



/*****************************************************************************/

DISPATCHERFLAGS
struct IClass *ObtainFilmEngine( REGA6 struct ClassBase *cb )
{
    return( (cb -> cb_Lib . cl_Class) );
}

/*****************************************************************************/

DISPATCHERFLAGS
struct Library *LibInit( REGD0 struct ClassBase *cb, REGA0 BPTR seglist, REGA6 struct ExecBase *sysbase )
{
    cb -> cb_SegList = seglist;
    cb -> cb_SysBase = sysbase;

    InitSemaphore( (&(cb -> cb_Lock)) );

    if( (cb -> cb_SysBase -> LibNode . lib_Version) >= 39UL )
    {
      /* Obtain ROM libs */
      if( cb -> cb_IntuitionBase = OpenLibrary( "intuition.library", 39UL ) )
      {
        if( cb -> cb_GfxBase = OpenLibrary( "graphics.library",  39UL ) )
        {
          if( cb -> cb_DOSBase = OpenLibrary( "dos.library", 39UL ) )
          {
            if( cb -> cb_IFFParseBase = OpenLibrary( "iffparse.library", 39UL ) )
            {
              if( cb -> cb_UtilityBase = OpenLibrary( "utility.library", 39UL ) )
              {
                return( (&(cb -> cb_Lib . cl_Lib)) );

#ifdef COMMENTED_OUT
                CloseLibrary( UtilityBase );
#endif /* COMMENTED_OUT */
              }

              CloseLibrary( IFFParseBase );
            }

            CloseLibrary( DOSBase );
          }

          CloseLibrary( GfxBase );
        }

        CloseLibrary( IntuitionBase );
      }
    }

    return( NULL );
}

/*****************************************************************************/

DISPATCHERFLAGS
LONG LibOpen( REGA6 struct ClassBase *cb )
{
    LONG retval = (LONG)cb;
    BOOL success = TRUE;

    ObtainSemaphore( (&(cb -> cb_Lock)) );

    /* Use an internal use counter */
    cb -> cb_Lib . cl_Lib . lib_OpenCnt++;
    cb -> cb_Lib . cl_Lib . lib_Flags &= ~LIBF_DELEXP;

    if( (cb -> cb_Lib . cl_Lib . lib_OpenCnt) == 1U )
    {
      if( (cb -> cb_Lib . cl_Class) == NULL )
      {
        success = FALSE;

        if( cb -> cb_DataTypesBase = OpenLibrary( "datatypes.library", 39UL ) )
        {
          if( cb -> cb_SuperClassBase = OpenLibrary( "datatypes/animation.datatype", 39UL ) )
          {
            if( cb -> cb_Lib . cl_Class = initClass( cb ) )
            {
              success = TRUE;
            }
          }
        }
      }
    }

    if( !success )
    {
      CloseLibrary( (cb -> cb_SuperClassBase) );
      CloseLibrary( (cb -> cb_DataTypesBase) );

      cb -> cb_DataTypesBase = cb -> cb_SuperClassBase = NULL;

      (cb -> cb_Lib . cl_Lib . lib_OpenCnt)--;

      retval = 0L;
    }

    ReleaseSemaphore( (&(cb -> cb_Lock)) );

    return( retval );
}

/*****************************************************************************/

DISPATCHERFLAGS
LONG LibClose( REGA6 struct ClassBase *cb )
{
    LONG retval = 0L;

    ObtainSemaphore( (&(cb -> cb_Lock)) );

    if( cb -> cb_Lib . cl_Lib . lib_OpenCnt )
    {
      (cb -> cb_Lib . cl_Lib . lib_OpenCnt)--;
    }

    if( ((cb -> cb_Lib . cl_Lib . lib_OpenCnt) == 0U) && (cb -> cb_Lib . cl_Class) )
    {
      if( FreeClass( (cb -> cb_Lib . cl_Class) ) )
      {
        cb -> cb_Lib . cl_Class = NULL;

        CloseLibrary( (cb -> cb_SuperClassBase) );
        CloseLibrary( (cb -> cb_DataTypesBase) );
      }
      else
      {
        cb -> cb_Lib . cl_Lib . lib_Flags |= LIBF_DELEXP;
      }
    }

    if( cb -> cb_Lib . cl_Lib . lib_Flags & LIBF_DELEXP )
    {
      retval = LibExpunge( cb );
    }

    ReleaseSemaphore( (&(cb -> cb_Lock)) );

    return( retval );
}

/*****************************************************************************/

DISPATCHERFLAGS
LONG LibExpunge( REGA6 struct ClassBase *cb )
{
    BPTR seg = cb -> cb_SegList;

    Remove( (&(cb -> cb_Lib . cl_Lib . lib_Node)) );

    CloseLibrary( (cb -> cb_UtilityBase) );
    CloseLibrary( (cb -> cb_IFFParseBase) );
    CloseLibrary( (cb -> cb_DOSBase) );
    CloseLibrary( (cb -> cb_GfxBase) );
    CloseLibrary( (cb -> cb_IntuitionBase) );

    FreeMem( (APTR)((ULONG)(cb) - (ULONG)(cb -> cb_Lib . cl_Lib . lib_NegSize)), (ULONG)((cb -> cb_Lib . cl_Lib . lib_NegSize) + (cb -> cb_Lib . cl_Lib . lib_PosSize)) );

    return( (LONG)seg );
}


