
/*
**
**  $VER: descriptor.c 2.3 (29.8.98)
**  mpegsystem.datatype 1.6
**  mpegvideo.datatype  2.6
**  mpegaudio.datatype  2.3
**
**  DataTypes custom comparision routine for MPEG streams
**
**  Written 1997/1998 by Roland 'Gizzy' Mainz
**  Original example source from David N. Junod
**
*/

/* amiga includes */
#include <exec/types.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/stdio.h>
#include <datatypes/datatypes.h>

/* amiga prototypes */
#include <clib/macros.h>
#include <clib/exec_protos.h>
#include <clib/utility_protos.h>
#include <clib/dos_protos.h>
#include <clib/datatypes_protos.h>

/* amiga pragmas */
#include <pragmas/exec_pragmas.h>
#include <pragmas/utility_pragmas.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/datatypes_pragmas.h>
#include <pragmas/dtclass_pragmas.h>
#include <pragmas/alib_pragmas.h> /* amiga.lib stubs (tagcall pragmas) */

/* ANSI includes */
#include <string.h>

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

/* SASC specific defines */
#define DISPATCHERFLAGS __saveds __asm
#define ASM             __asm
#define REGD0 register __d0
/* ... */
#define REGA0 register __a0
#define REGA1 register __a1
#define REGA2 register __a2
/* ... */
#define REGA6 register __a6

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

/* we don't have any library base yet, therefore we use the resources from the given DTHookContext */
#define SysBase     (dthc -> dthc_SysBase)
#define UtilityBase (dthc -> dthc_UtilityBase)
#define DOSBase     (dthc -> dthc_DOSBase)

/*****************************************************************************/
/* debugging */
void kprintf( STRPTR, ... );

#if 0
#define D( x ) x
#else
#define D( x )
#endif

/*****************************************************************************/
/* MPEG start codes
 * system: 0001BA    with leading 00's
 * video:  0001B3    with leading 00's
 * audio:  FFFD/FFFB with leading FFs
 */
/*
 * The following defines set the type of mpeg file to be recognized (see makefile)
#define MATCH_SYSTEM 1
#define MATCH_VIDEO 1
#define MATCH_AUDIO 1
*/

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

/* input types for MatchMPEG */
enum dtsource { dts_buffer, dts_file };

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

/* local prototypes */
static BOOL MatchMPEG( struct DTHookContext *, enum dtsource );

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

/* This custom comparisation code scans for a valid MPEG system/video/audio start code.
 * It does NOT check the syntax/compression/invalid format/invalid contents, this
 * is the job of the class library !!
 */
DISPATCHERFLAGS
BOOL DTHook( REGA0 struct DTHookContext *dthc )
{
    /* Make sure we have a buffer to work with... */
    if( (dthc -> dthc_Buffer) && (dthc -> dthc_BufferLength) )
    {
      if( MatchMPEG( dthc, dts_buffer ) )
      {
        return( TRUE );
      }
    }

    /* Make sure we have a file handle ! */
    if( dthc -> dthc_FileHandle )
    {
      return( MatchMPEG( dthc, dts_file ) );
    }

    return( FALSE );
}


enum scanner_state { nothing_found, introducer_found, start_code_byte_one };

static
BOOL MatchMPEG( struct DTHookContext *dthc, enum dtsource whichsource )
{
    enum  scanner_state state = nothing_found; /* start code scanner state */
    ULONG i                   = 0UL;           /* buffer index ("dts_buffer" mode only) */
    LONG  ch                  = 0L;            /* current byte to work with... */

    for( ;; )
    {
      /* Get byte... */
      switch( whichsource )
      {
        case dts_buffer:
        {
            if( i >= (dthc -> dthc_BufferLength) )
              return( FALSE );

            ch = dthc -> dthc_Buffer[ i++ ];
        }
            break;

        case dts_file:
        {
            ch = FGetC( (dthc -> dthc_FileHandle) );

            if( ch == ENDSTREAMCH )
              return( FALSE );
        }
            break;
      }

#ifdef MATCH_AUDIO
      switch( state )
      {
        case nothing_found:
        {
            if( ch == 0xFF )
            {
              state = start_code_byte_one;
            }
        }
            break;

        /* we found a valid start code introducer. Now check if the stream is of the requested type or not... */
        case start_code_byte_one:
        {
            if( (ch & 0xF0) == 0xF0 )
            {
              /* ignore 0xFF bytes, e.g. keep this state... */
              if( ch != 0xFF )
              {
                /* this seems to be an mpeg audio stream... */
                return( TRUE );
              }
            }
            else
            {
              /* found rubbish...*/
              return( FALSE );
            }
        }
            break;
      }
#else
      switch( state )
      {
        case nothing_found:
        {
            if( ch == 0x00 )
            {
              state = introducer_found;
            }
        }
            break;

        case introducer_found:
        {
            switch( ch )
            {
              case 0x00:
                  /* NOP, keep state "introducer_found" */
                  break;

              case 0x01:
                  /* next state "start_code_byte_one", please... */
                  state = start_code_byte_one;
                  break;

              default:
                  /* rubbish found, back to state "nothing_found"... */
                  state = nothing_found;
                  break;
            }
        }
            break;

        /* we found a valid start code introducer. Now check if the stream is of the requested type or not... */
        case start_code_byte_one:
        {
            /* is this a system stream ? */
#ifdef MATCH_SYSTEM
            if( ch == 0xBA )
#else
#ifdef MATCH_VIDEO
            if( ch == 0xB3 )
#else
#error neither MATCH_SYSTEM nor MATCH_VIDEO defined
#endif /* MATCH_VIDEO */
#endif /* MATCH_SYSTEM */
            {
              return( TRUE );
            }
            else
            {
              return( FALSE );
            }
        }
            break;
      }
#endif /* MATCH_AUDIO */
    }

    return( FALSE );
}



