
/*
**
**  $VER: classbase.c 1.4 (3.3.98)
**  mpegsystem.datatype 1.4
**
**  Library routines for a DataTypes class
**
**  Written 1997/1998 by Roland 'Gizzy' Mainz
**  Original example source from David N. Junod
**
*/


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


/****** mpegsystem.datatype/MAIN *********************************************
*
*    INTRODUCTION
*        Datatypes class for MPEG 1 System movies.
*
*    REQUIREMENTS
*        - You need at least Kick/WB 3.0.
*
*        - datatypes.library >= V45
*
*        - "datatypes/animation.datatype", >= V40.
*          "animation.datatype 40.6 (28.09.93)" requires itself some
*          libraries/boopsi classes:
*          - "realtime.library", >= V39              - for timing
*          - "gadgets/tapedeck.gadget" (any version) - for the controls
*
*        - mpegvideo.datatype >= V1.6 (V2.x preferred)
*
*        - mpegaudio.datatype >= V1.1
*
*    USAGE
*        If the datatypes descriptor file was activated, any attempt to load
*        a MPEG System stream using GMultiView, MultiView, AmigaGuide or
*        SwitchWindow will load and play the movie.
*
*    INSTALLATION
*        After unpacking this archive:
*        Because this version does not include an Installer script, you have
*        to do the installation manually through the shell:
*
*          - Unpack this archive and copy the "mpegsystem.datatype" to
*            SYS:Classes/DataTypes/:
*
*        Copy CLONE FROM "mpegsystem.datatype" TO
*         "SYS:Classes/DataTypes/mpegsystem.datatype"
*
*          - Then copy the datatypes descriptor into the DEVS:DataTypes
*            directory.
*            If the descriptor already exists, you should not replace it,
*            otherwise you may loose "toolnodes" and other settings stored in
*            the existing descriptor.
*
*     Copy CLONE FROM "MPEG System(%|.info)" TO DEVS:Datatypes/
*
*    SOURCE
*        Source is included as an example how to write a datatypes clas
*        implements a virtual filesystem and embeds other datatype objects
*        for it's work.
*
*    MODEL
*        This datatype uses a very complex model for decoding MPEG system
*        streams. The small drawing below shows the model (OK, the
*        drawing is not very good, it's incomplete and so on. If someone
*        has the time to draw a better one, send it to me).
*
*                           system stream
*                                 |
*                                 |
*                                 Y
*             +-------------------------------------------------------------+
*             |            mpeg system datatype                             |
*             +-----------------------------------------+-------------------+
*             |              demultiplexer              | ADTM_LOADFRAME    |
*             |  video 0...video n | audio 0... audio n | ADTM_UNLOADFRAME  |
*             +-----+-------+------+------+-------+-----+-------------------+
*                   |       |             |       |               ^ ^
*                   |       |             |       |               | |
*                   |       *             |       *               | |
*                   |                     |                       | |
*                   |                     |                       | |
*                   Y                     Y                       | |
*      +---------------------+   +---------------------+          | |
*      | mpeg video datatype |   | mpeg audio datatype |          | |
*      +-----------+---------+   +--------+------------+          | |
*                  |                      |                       | |
*                  |                      |                       | |
*                  |                      +-----------------------+ |
*                  +------------------------------------------------+
*
*    AUTHOR
*        If you want to blame me, report any bugs, or wants a new version
*        send your letter to:
*                        Roland Mainz
*                        Hohenstaufenstraße 8
*                        52388 Nörvenich
*                        GERMANY
*
*        Phone: (+49)(0)2426/901568
*        Fax:   (+49)(0)2426/901569
*
*        EMAIL is also available (if you want to send me attachments
*        larger than 1MB (up to 5MB, more with my permission):
*
*        GISBURN@w-specht.rhein-ruhr.de
*
*        Up to April 1998 I'm reachable using this email address, too:
*        Reinhold.A.Mainz@KBV.DE
*
*        | Please put your name and address in your mails !
*        | German mailers should add their phone numbers.
*        | See BUGS section above when submitting bug reports.
*
*        Sorry, but I can only look once a week for mails.
*        If you don't hear something from me within three weeks, please
*        send your mail again (but watch about new releases) (problems with
*        this email port are caused by reconfigurations, hackers, network
*        problems etc.).
*
*        The  entire  "mpegsystem.datatype"  package  may  be  noncommercially
*        redistributed, provided  that  the package  is always  distributed
*        in it's complete  form (including it's documentation). A small
*        copy fee  for media costs is okay but any kind of commercial
*        distribution is strictly forbidden without my permission !
*        Comments and suggestions how to improve this program are
*        generally appreciated!
*
*        Thanks to David Junod, who wrote the animation.datatype and lots of
*        the datatypes example code, Matt Dillon for his DICE,
*        Olaf 'Olsen' Barthel for his help, ideas and some text clips from
*        his documentations.
*
******************************************************************************
*
*/



/****** mpegsystem.datatype/--datasheed-- ************************************
*
*   NAME
*       mpegsystem.datatype -- data type for MPEG System streams
*
*   SUPERCLASS
*       animation.datatype
*
*   DESCRIPTION
*       The anim datatype, a sub-class of the animation.datatype, is used to
*       load and play MPEG System 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 (embedded objects etc.
*           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.
*
*       DTM_WRITE -- Save object's contents in local (MPEG System) or
*           superclass (IFF ILBM) format.
*           NOT IMPLEMENTED YET
*
*       ADTM_LOADFRAME -- Fill in struct adtFrame with requested information
*           from embedded objects like bitmap, colormap and sample.
*
*       ADTM_UNLOADFRAME -- Free resources obtained by ADTM_UNLOADFRAME.
*           The method is passed to the embedded objects.
*
*       All other methods are passed unchanged to superclass.
*
*   ATTRIBUTES
*       Following attributes are set by the object and are READ-ONLY for
*       applications:
*
*   BUGS
*       - Support for streams with multiple video- and/or audio-streams
*         has been removed. The datatype uses currently evertimes
*         the first video- and the first audio-stream it finds.
*
*       - ADTM_START, ADT_PAUSE, ADTM_STOP and ADTM_LOCATE are not passed
*         to the embedded mpevideo.datatype object(s), which may cause
*         speed loss if this datatype does speed optimisations based on use
*         of those methods.
*
*       - The sound may be out-of-sync in the case that a stream
*         is very long (more than 60 minutes) due rounding problems.
*         (In theory it should not occur - and I did not see the bug...).
*
*   TODO
*       - Fixing the bugs above.
*
*       - Write the "--input_format--"-Autodoc section.
*
*       - Leading zeros in the beginning of the file except the "start code"
*         begin sequence causes a stream not to be recognized by
*         datatypes.library.
*         May happen if someone reads raw data from a VideoCD.
*
*       - Writing the encoder part, using mpegvideo.datatype V2's encoder
*         and mpegaudio.datatype's encoder parts.
*
*       - Implementation of ACTION_INFO in the internal filesystem that
*         (in theory) optimized reading using async I/O gets correct
*         parameters.
*
*       - Support for MPEG 2 system streams.
*
*       - QUICKSCAN option for optimized and much faster scanning of system
*         streams.
*
*   HISTORY
*       V1.1
*         First public release.
*
*       V1.2
*         - Fixed the descriptor (e.g. the file "MPEG System"). The
*           old one contains unneccesary data in the comparisation mask.
*           Now the descriptor matches the standard, except that
*           leading zero bytes (0x00) causes that the stream won't be
*           identified.
*           Thanks to Steve Cutting (stevejc@c031aone.net.au) for reporting
*           the bug.
*           Fixed.
*
*         - Implemented IGNOREERRORS switch to get Steve Cutting's
*           (stevejc@c031aone.net.au) example file
*           "http://www.utexas.edustudents/cjso/Chabad/video/chase.mpg"
*           working.
*
*         - Added missing VERBOSESYNTAX and DEBUG options to find problems
*           in the datatype without recompiling the complete source.
*
*         - Fixed a bug in the FS:
*           The internal filesystem now returns ERROR_SEEK_ERROR of someone
*           send an ACTION_SEEK with an unknown position mode
*           (e.g. if it is none of OFFSET_(BEGINNING|CURRENT|END)).
*           Fixed.
*
*         - Fixed some problems with the VERBOSE and DEBUG output (missing
*           newlines, single lines > 75 chars etc.).
*           Fixed.
*
*       V1.3
*         - Minor code cleanup
*
*         - Fixed and updated the autodoc.
*
*         - Increased the handlers process priority up to 9
*           (normal FFS tasks are running at priority 10) to get more speed
*           during scanning.
*
*       V1.4
*         - Added asyncio.library support code (but it does not work yet...).
*
*         - Implemented ACTION_COPY_DIR_FH to get DupLockFromFH working which
*           is used in the new mpegaudio.datatype V2 (currently this feature
*           is not used because of some problems with mpega.library, but...).
*
*         - Fixed a bug in OM_NEWs state machine which caused big problems
*           if an error occurs with IoErr() == 0.
*           Fixed.
*
*   SEE ALSO
*       animation.datatype,
*       anim.datatype,
*       gifanim.datatype, mpegvideo.datatype,
*       picmovie.datatype,
*       cdxl.datatype, avi.datatype, quicktime.datatype,
*       moviesetter.datatype,
*       film.datatype,
*       directory.datatype,
*       markabletextdtclass
*
*******************************************************************************
*
*/


/****** mpegsystem.datatype/--input_format-- *********************************
*
*    NAME
*        MPEG System -- MPEG System stream format
*
*    DESCRIPTION
*        <Not written yet, sorry>
*
*    SEE ALSO
*
*******************************************************************************
*
*/



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

DISPATCHERFLAGS
struct IClass *ObtainMPEGSystemEngine( 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)) );

    /* Kickstart V3.0 ? */
    if( (cb -> cb_SysBase -> LibNode . lib_Version) >= 39UL )
    {
      /* Obtain ROM libs */
      if( cb -> cb_UtilityBase = OpenLibrary( "utility.library", 39UL ) )
      {
        if( cb -> cb_DOSBase = OpenLibrary( "dos.library", 39UL ) )
        {
/* disabled due problems with asyncio.library */
#ifdef USE_ASYNCIOLIB
          cb -> cb_AsyncIOBase = OpenLibrary( "asyncio.library", 39UL );
#endif /* USE_ASYNCIOLIBT */

          if( cb -> cb_GfxBase = OpenLibrary( "graphics.library", 39UL ) )
          {
            if( cb -> cb_IntuitionBase = OpenLibrary( "intuition.library", 39UL ) )
            {
              return( (&(cb -> cb_Lib . cl_Lib)) );

#ifdef COMMENTED_OUT
              CloseLibrary( (cb -> cb_IntuitionBase) );
#endif /* COMMENTED_OUT */
            }

            CloseLibrary( (cb -> cb_GfxBase) );
          }

/* disabled due problems with asyncio.library */
#ifdef USE_ASYNCIOLIB
          CloseLibrary( (cb -> cb_AsyncIOBase) );
#endif /* USE_ASYNCIOLIB */
          CloseLibrary( (cb -> cb_DOSBase) );
        }

        CloseLibrary( (cb -> cb_UtilityBase) );
      }
    }

    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;

        /* Only datatypes.library >= V45 supports virtual handlers... */
        if( cb -> cb_DataTypesBase = OpenLibrary( "datatypes.library", 45UL ) )
        {
          /* Should require animation.datatype V41 */
          if( cb -> cb_SuperClassBase = OpenLibrary( "datatypes/animation.datatype", 39UL /*41UL*/ ) )
          {
            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;
      }
    }

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

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

    return( retval );
}

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

DISPATCHERFLAGS
LONG LibExpunge( REGA6 struct ClassBase *cb )
{
    BPTR seg;

    if( cb -> cb_Lib . cl_Lib . lib_OpenCnt )
    {
      cb -> cb_Lib . cl_Lib . lib_Flags |= LIBF_DELEXP;

      seg = NULL;
    }
    else
    {
      Remove( (&(cb -> cb_Lib . cl_Lib . lib_Node)) );

      seg = cb -> cb_SegList;

      CloseLibrary( (cb -> cb_IntuitionBase) );
      CloseLibrary( (cb -> cb_GfxBase) );
/* disabled due problems with asyncio.library */
#ifdef USE_ASYNCIOLIB
      CloseLibrary( (cb -> cb_AsyncIOBase) );
#endif /* USE_ASYNCIOLIB */
      CloseLibrary( (cb -> cb_DOSBase) );
      CloseLibrary( (cb -> cb_UtilityBase) );

      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 );
}


