home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Best of Mecomp Multimedia 1
/
Mecomp-CD.iso
/
amiga
/
tools
/
opus
/
opus-tools5.x
/
amipeg
/
source
/
main.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-06-27
|
12KB
|
556 lines
/*
* This is the main part
*/
#include <intuition/screens.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include "video.h"
#include "proto.h"
#include <sys/types.h>
#include <signal.h>
#include <proto/timer.h>
#include <devices/timer.h>
#define ASIO_REGARGS
#include <clib/asyncio_protos.h>
#include "util.h"
#define HELP_TEXT "NOB\t- ignore and not display any B frames.\n\
NOP\t- ignore and not display any P frames.\n\
LOOP\t- makes the player loop back to the beginning after reaching the end.\n\
EACHSTAT- causes statistics to be displayed after each frame.\n\
\t Only valid when compiled with -DANALYSIS\n\
NODISPLAY- dithers, but does not display, usually used for\n\
\t testing and timing purposes.\n\
QUIET\t- supresses printing of frame numbers, timing information,\n\
\t and most error messages.\n\
DITHER\t- selects from a variety of dither options.\n\
\t The possible values are:\n\
\t\tcolor\n\
\t\thiresham\n\
\t\tham6\n\
\t\tcybergfx\n\
\t\tcybergfxgray\n\
\t\tgray\n\
\t\tnone\n\
PUBSCREEN- open window on selected \"deep\" public screen. Only valid\n\
\t with DITHER cybergfx or cybergfxgray. Use with \"DEFAULT\" to open\n\
\t on current default public screen.\n\
MODEID\t- select modeid for screen to open and play on.\n\
FRAMERATE- speed in frames per second. (0 - as fast as possible).\n\
BUFFER\t- size of the io buffer (default - 65536).\n\
FILE\t- filename of MPEG stream.\n"
#define TEMPLATE "NOB/S,NOP/S,LOOP/S,EACHSTAT/S,ND=NODISPLAY/S,QUIET/S,DITHER/K,PS=PUBSCREEN/K,MODEID/K,FRAMERATE=FPS/K,BUFFER=BUF/K,FILE/A"
#define OPT_NOB 0
#define OPT_NOP 1
#define OPT_LOOP 2
#define OPT_EACHSTAT 3
#define OPT_NODISPLAY 4
#define OPT_QUIET 5
#define OPT_DITHER 6
#define OPT_PUBSCREEN 7
#define OPT_MODEID 8
#define OPT_FPS 9
#define OPT_BUFFER 10
#define OPT_FILE 11
#define OPT_COUNT 12
const char *dither_names = "ham6\1color\1hiresham\1ham6\1cybergfx\1cybergfxgray\1gray\1none";
/* 01234 56789 1113151719 2123 2527293133 353739414345 474951 53
got it? :) 10 12141618 202224 26283032 34363840424446 4850 525456
*/
char animname[1024];
char pubscreen_name[MAXPUBSCREENNAME + 1];
char *pubname_ptr;
/* Declaration of global variable to hold dither info. */
int ditherType;
/* size of the io buffer */
int buf_length = 65536;
/* Global file pointer to incoming data. */
struct AsyncFile *input;
/* End of File flag. */
static int EOF_flag = 0;
/* Loop flag. */
int loopFlag = 0;
/* Quiet flag. */
int quietFlag = 0;
/* Display image on screen? */
int noDisplayFlag = 0;
/* Setjmp/Longjmp env. */
jmp_buf env;
/* HAM6 rendering / HAM hires flag */
extern int ham6, lores;
/* modeid of CyberGraphX screen */
unsigned long modeid = 0xffffffff;
/* are we going to play on the Public Screen? */
int cyber_pub = 0;
/* Framerate, -1: specified in stream (default)
0: as fast as possible
N (N>0): N frames/sec
*/
int framerate = -1;
/* these are for timer.device */
struct Library *TimerBase;
struct MsgPort *TimerMP; /* Message port pointer */
struct timerequest *TimerIO; /* I/O structure pointer */
/* Method of picture conversion */
void (*DoDitherImage)(unsigned char *l, unsigned char *Cr, unsigned char *Cb,
unsigned char *disp, int h, int w);
static char version[]="$VER: aMiPEG 0.7 (compiled on " __DATE__ ", " __TIME__ ")\n";
/*
*--------------------------------------------------------------
*
* get_more_data --
*
* Called by correct_underflow in bit parsing utilities to
* read in more data.
*
* Results:
* Input buffer updated, buffer length updated.
* Returns 1 if data read, 0 if EOF, -1 if error.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
int get_more_data(unsigned int *buf_start, int max_length, int *length_ptr, unsigned int **buf_ptr)
{
int length, num_read, request;
unsigned char *buffer, *mark;
if (EOF_flag) return 0;
length = *length_ptr;
buffer = (unsigned char *) *buf_ptr;
if (length > 0) {
memcpy((unsigned char *) buf_start, buffer, (length*4));
mark = ((unsigned char *) (buf_start + length));
}
else {
mark = (unsigned char *) buf_start;
length = 0;
}
request = (max_length-length)*4;
// num_read = fread( mark, 1, request, input);
num_read = ReadAsync(input, mark, request);
/* Paulo Villegas - 26/1/1993: Correction for 4-byte alignment */
{
int num_read_rounded;
unsigned char *index;
num_read_rounded = num_read & 0xfffffffc;
/* this can happen only if num_read<request; i.e. end of file reached */
if( num_read_rounded < num_read )
{
num_read_rounded+=4;
/* fill in with zeros */
for( index=mark+num_read; index<mark+num_read_rounded; *(index++)=0 );
/* advance to the next 4-byte boundary */
num_read = num_read_rounded;
}
}
if (num_read < 0) {
return -1;
}
else if (num_read == 0) {
*buf_ptr = buf_start;
/* Make 32 bits after end equal to 0 and 32
bits after that equal to seq end code
in order to prevent messy data from infinite
recursion.
*/
*(buf_start + length) = 0x0;
*(buf_start + length+1) = SEQ_END_CODE;
EOF_flag = 1;
return 0;
}
num_read >>= 2;
*buf_ptr = buf_start;
*length_ptr = length + num_read;
return 1;
}
/*
*--------------------------------------------------------------
*
* int_handler --
*
* Handles Cntl-C interupts..
*
* Results:
* None.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
void int_handler(int dummy)
{
if (!quietFlag) fprintf(stderr, "Interrupted!\n");
if (curVidStream) DestroyVidStream(curVidStream);
if(input)
CloseAsync(input);
exit(1);
}
/*
*--------------------------------------------------------------
*
* init_timer --
*
* Prepare timer.device and IORequest for later use
*
* Results:
* None.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
void init_timer(void)
{
/* Create port for timer device communications */
if(TimerMP = CreatePort(NULL, 0))
/* Create message block for device IO */
if(TimerIO = (struct timerequest *)CreateExtIO(TimerMP, sizeof(struct timerequest)))
/* Open the timer device with UNIT_MICROHZ */
if(!OpenDevice(TIMERNAME, UNIT_MICROHZ, (struct IORequest *)TimerIO, 0))
{
TimerBase = (struct Library *)TimerIO->tr_node.io_Device;
TimerIO->tr_node.io_Command = TR_ADDREQUEST;
return;
}
else
fprintf(stderr, "Error: Can't open Timer.device\n");
else
fprintf(stderr, "Error: Can't create IO request\n");
else
fprintf(stderr, "Error: Can't create port\n");
exit(1);
}
/*
*--------------------------------------------------------------
*
* close_timer --
*
* Close timer.device, remove IORequest and message port
*
* Results:
* None.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
void close_timer(void)
{
if(TimerBase)
CloseDevice((struct IORequest *)TimerIO); /* Close Timer device */
if(TimerIO)
DeleteExtIO((struct IORequest *)TimerIO);
if(TimerMP)
DeletePort(TimerMP);
}
/*
*--------------------------------------------------------------
*
* main --
*
* Parses command line, starts decoding and displaying.
*
* Results:
* None.
*
* Side effects:
* None.
*
*--------------------------------------------------------------
*/
void main(int argc, char **argv)
{
static VidStream *theStream;
extern int lores;
LONG opts[OPT_COUNT];
struct RDArgs *rdargs;
ditherType = FULL_COLOR_DITHER;
noDisplayFlag = 0;
memset(opts, 0, sizeof(opts));
if(rdargs = (struct RDArgs *)AllocDosObject(DOS_RDARGS, NULL))
{
rdargs->RDA_ExtHelp = HELP_TEXT;
if(rdargs = ReadArgs(TEMPLATE, opts, rdargs))
{
if(opts[OPT_NOP])
TogglePFlag();
if(opts[OPT_NOB])
ToggleBFlag();
if(opts[OPT_DITHER])
{
switch(strstr(dither_names, strlwr((char *)opts[OPT_DITHER])) - dither_names)
{
case 5: /* color */
ditherType = FULL_COLOR_DITHER;
break;
case 11: /* hiresham */
ditherType = FULL_COLOR_DITHER;
lores = FALSE;
break;
case 0: /* ham6 */
ditherType = FULL_COLOR_DITHER;
ham6 = TRUE;
break;
case 25: /* cybergfx */
ditherType = CYBERGFX_DITHER;
break;
case 34: /* cybergfxgray */
ditherType = CYBERGFXGRAY_DITHER;
break;
case 42: /* gray */
ditherType = GRAY_DITHER;
break;
case 52: /* none */
ditherType = NO_DITHER;
break;
default:
fprintf(stderr, "You should specify legal dither name after DITHER keyword.\n");
FreeArgs(rdargs);
exit(10);
}
}
if(opts[OPT_EACHSTAT])
#ifdef ANALYSIS
showEachFlag = 1;
#else
{
fprintf(stderr, "To use EACHSTAT, recompile with DEFINE ANALYSIS in CFLAGS\n");
exit(1);
}
#endif
if(opts[OPT_QUIET])
quietFlag = 1;
if(opts[OPT_LOOP])
loopFlag = 1;
if(opts[OPT_NODISPLAY])
noDisplayFlag = 1;
if(opts[OPT_PUBSCREEN])
{
if(!stricmp("default", (char *)opts[OPT_PUBSCREEN]))
pubname_ptr = NULL;
else
{
strcpy(pubscreen_name, (char *)opts[OPT_PUBSCREEN]);
pubname_ptr = pubscreen_name;
}
cyber_pub = 1;
}
if(opts[OPT_MODEID])
if(sscanf((char *)opts[OPT_MODEID], "%x", &modeid) != 1)
{
fprintf(stderr, "ModeID should be an hexadecimal value.\n");
FreeArgs(rdargs);
exit(10);
}
if(opts[OPT_FPS])
if(sscanf((char *)opts[OPT_FPS], "%d", &framerate) != 1)
{
fprintf(stderr, "You should specify a number after FRAMERATE keyword.\n");
FreeArgs(rdargs);
exit(10);
}
if(opts[OPT_BUFFER])
if(sscanf((char *)opts[OPT_BUFFER], "%d", &buf_length) != 1)
{
fprintf(stderr, "You should specify a number after BUFFER keyword.\n");
FreeArgs(rdargs);
exit(10);
}
if(opts[OPT_FILE])
{
// input = fopen((char *)opts[OPT_FILE], "r");
input = OpenAsync((char *)opts[OPT_FILE], MODE_READ, buf_length);
if(input == NULL)
{
fprintf(stderr, "Could not open file %s\n", (char *)opts[OPT_FILE]);
FreeArgs(rdargs);
exit(10);
}
strcpy(animname, (char *)opts[OPT_FILE]);
signal(SIGINT, int_handler);
init_tables();
switch (ditherType)
{
case CYBERGFX_DITHER:
InitColorDither();
modeid = InitCyberGfxDisplay(modeid);
HAM8_draw = (void (*)(void *, int, int)) DrawCyberGfxImage;
DoDitherImage = ColorDitherImage_RGB;
break;
case CYBERGFXGRAY_DITHER:
InitColorDither();
modeid = InitCyberGfxDisplay(modeid);
HAM8_draw = (void (*)(void *, int, int)) DrawCyberGfxImage;
DoDitherImage = NoDitherImage;
break;
case GRAY_DITHER:
InitColorDither();
modeid = InitGrayDisplay(modeid);
HAM8_draw = (void (*)(void *, int, int)) DrawGrayImage;
DoDitherImage = NoDitherImage;
break;
case FULL_COLOR_DITHER:
InitColorDither();
InitColorDisplay();
break;
case NO_DITHER:
HAM8_draw = (void (*)(void *, int, int)) NoDitherImage; // method casting ... argh!
DoDitherImage = NoDitherImage;
break;
}
init_timer();
/*
* The new restart handling has not been checked out very closely with changing
* (non)intra scale matrices!
*/
theStream = NewVidStream(buf_length);
if (setjmp(env) != 0)
{
mpegInitVidRsrc(); /* fix bug in static first in mpegVidRsrc */
// rewind(input);
SeekAsync(input, 0, MODE_START);
EOF_flag = 0;
theStream->bit_offset = 0;
theStream->buf_length = 0;
theStream->buffer = NULL;
totNumFrames = 0;
#ifdef ANALYSIS
init_stats();
#endif
}
realTimeStart = ReadSysClock();
while (mpegVidRsrc(0, theStream));
CloseAsync(input);
}
FreeArgs(rdargs);
}
else
{
PrintFault(IoErr(), argv[0]);
exit(10);
}
FreeDosObject(DOS_RDARGS, rdargs);
}
else
{
PrintFault(IoErr(), argv[0]);
exit(10);
}
}
/*
* Dummy display method
*
*/
void NoDitherImage(unsigned char *l, unsigned char *Cr, unsigned char *Cb,
unsigned char *disp, int h, int w)
{}