/*
 *	splitjag.c
 *
 * 	-------------------------------------------------------------------------
 *
 *	Utility for splitting a Jaguar Movie into a video and audio data stream
 *	for the purpose of compressing the audio data.
 *
 * 	-------------------------------------------------------------------------
 *
 *	Version: 1.0
 *	Date:	 2/16/96
 *	Prg.:	 Hans-Martin Krober
 *
 *	Copyright 1996 ATARI Corp.
 *	All rights reserved.
 *	This material is secret & confidential.
 *
 * 	------------------------------------------------------------------------- 
 *
 *	100	02/16/96 hmk	Initial Version.
 *
 */

 /*
  * ---	Include Files -----------------------------------------------------------
  */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "jagfilm.h"

 /*
  * ---	Prototypes --------------------------------------------------------------
  */
long endian_swap_long( long );

 /*
  * ---	Data --------------------------------------------------------------------
  */    

char	*version = "Version 1.0";

char	*name;			/* Program's name			*/

char	*iname;			/* Input file name			*/
FILE	*ifp;			/* Input file handle			*/

char	aname[256];		/* Audio file name			*/
FILE	*afp;			/* Audio file handle 			*/

char	vname[256];		/* Video file name			*/
FILE	*vfp;			/* Video file handle 			*/

FILM	film;			/* Jaguar Film Header 			*/

 /*
  * ---	Functions ---------------------------------------------------------------
  */    


/*
 *	:main()
 */

	void
main(argc, argv)
	int	argc;
	char	**argv;
{
	/*
	 * Get program's name
	 */
	name = argv[0];

	/*
	 * Check arguments
	 */
	if (argc != 2) {
		usage();
		exit(0);
	}
	/*
	 *	Open Jaguar Movie File
	 */
	iname = argv[1];
	if ((ifp = fopen(iname, "rb")) == NULL) {
		perror(iname);
		exit(-1);
	}
	/*
	 *	Read Film Header
	 */
	if (fread(&film, sizeof(FILM), 1, ifp) != 1) {
		perror(iname);
		exit(-1);
	}
	if (endian_swap_long(film.frameHeader.id) != FILM_ID) {
		printf("%s: %s is not a jaguar movie.\n", name, iname);
		exit(-2);
	}
	if (endian_swap_long(film.audioDescriptionAtom.id) != ADSC_ID) {
		printf("%s: %s has not audio description atom.\n", name, iname);
		exit(-2);
	}
	/*
	 * Do the actual file splitting...
	 */
	SplitJag();

	fclose(ifp);
	
	exit(0);
}

/*
 *	Split a Jaguar movie into two file: one containg the audio data (.aud) and
 *                                          one conating the video data (.vid)
 *	The one containg the video data will be preceeded by a 'VIDX' tag while
 *	the audio one will be precedded by a 'AUDX' tag. Follewed by that is a copy
 *	of the original FILM data structure with the number of samples in the Sample
 *	Table Atom being patched to either the number of video samples or audio
 * 	samples. The following Sample Table Array contains only video xor audio
 *	entries. Then follows the actual audio/video data (samples).
 */
 
	void
SplitJag()
{
	long	i, n;
	long	n_video, n_audio;
	long	audio_offset, audio_size;
	long	video_offset, video_size;	
	long	orgEndSampleTableArray;
	long	size;
	long 	count;
	STAR	*p, *a, *v;
	STAR	*orgSampleTableArray, *audSampleTableArray, *vidSampleTableArray;
	char	*s, *bufp;
	
	/*
	 * Get size in bytes of Sample Table Array and allocate memory for it
	 */
	size = endian_swap_long(film.sampleTableAtom.count) * sizeof(STAR);
	if ((orgSampleTableArray = (STAR *) malloc(size)) == NULL) {
		fprintf(stderr, "%s: Out of memory (1).\n", name);
		exit(-3);
	}

	/*
	 * Read Sample Table Array into buffer
	 */
	if (fread(orgSampleTableArray, size, 1, ifp) != 1) {
			perror(iname);
			exit(-3);
	}
	/*
	 * Get file position of end of Sample Table Array.
	 * This will be used as offset, since all entries in the array are based
	 * on the end of the array.
	 */
	orgEndSampleTableArray = ftell(ifp);

	/*
	 * Find out how many audio/video samples we have and then build new array tables
	 */
	count = endian_swap_long(film.sampleTableAtom.count);
	p = orgSampleTableArray;
	n_audio = 0;
	for (i = 0; i < count; i++, p++) {
		if ((endian_swap_long(p->start) & 0x7fffffffL) == 0x7fffffffL) {
			n_audio++;
		}
	}
	if (n_audio == 0) {
		printf("%s: No audio sections found.\n", name);
		return;
	}
	n_video = count - n_audio;

	if ((audSampleTableArray = malloc(n_audio * sizeof(STAR))) == NULL) {
		fprintf(stderr, "%s: Out of memory (2).\n", name);
		exit(-3);
	}
	if ((vidSampleTableArray = malloc(n_video * sizeof(STAR))) == NULL) {
		fprintf(stderr, "%s: Out of memory (3).\n", name);
		exit(-3);
	}
	p = orgSampleTableArray;
	v = vidSampleTableArray;
	a = audSampleTableArray;
	audio_offset = 0L; 
	video_offset = 0L; 
	audio_size = 0L;
	video_size = 0L;
	for (i = 0; i < count; i++, p++) {
		if ((endian_swap_long(p->start) & 0x7fffffffL) == 0x7fffffffL) {
			/*
			 * Build audio sample table array
			 */
			a->offset   = endian_swap_long(audio_offset + audio_size); /* patch start */
			a->size     = p->size;
			a->start    = p->start;
			a->duration = p->duration; 
			audio_size += endian_swap_long(p->size);
			a++;
		} else {
			/*
			 * Build video sample table array
			 */			
			v->offset   = endian_swap_long(video_offset + video_size); /* patch start */
			v->size     = p->size;
			v->start    = p->start;
			v->duration = p->duration; 
			video_size += endian_swap_long(p->size);
			v++;
		}
	}
		
	/*
	 * Build output names and open files for binary writing
	 */
	strcpy(vname, iname);
	strcpy(aname, iname);

	if ((s = strrchr(vname, '.')) != NULL)
		*s = '\0';
	if ((s = strrchr(aname, '.')) != NULL)
		*s = '\0';
	strcat(vname, ".vid");		
	strcat(aname, ".aud");

	if ((vfp = fopen(vname, "wb")) == NULL) {
		perror(vname);
		exit(-3);
	}
	if ((afp = fopen(aname, "wb")) == NULL) {
		perror(aname);
		exit(-3);
	}	

	/*
	 * Write tags first
	 */
	if (fwrite("VIDX", 4, 1, vfp) != 1) {
		perror(vname);
		exit(-3);
	}
	if (fwrite("AUDX", 4, 1, afp) != 1) {
		perror(aname);
		exit(-3);
	}	

	/*
	 * Now write all data structures from the original
	 * plus the new video/audio sample table arrays
	 */
	 
	n = film.sampleTableAtom.count;	      /* Backup original number */
	film.sampleTableAtom.count = endian_swap_long(n_video); /* HACK: patch in number of video samples */
	film.sampleTableAtom.size = endian_swap_long(sizeof(STAB) + n_video * sizeof(STAR)); 	
	film.frameHeader.size =
	 endian_swap_long(sizeof(FRAME) + sizeof(FDSC) + sizeof(ADSC) +
		sizeof(STAB) + n_video * sizeof(STAR));

	if (fwrite(&film, sizeof(FILM), 1, vfp) != 1) {
		perror(vname);
		exit(-3);
	}

	
	film.sampleTableAtom.count = endian_swap_long(n_audio); /* HACK: patch in number of audio samples */	
	film.sampleTableAtom.size  = endian_swap_long(sizeof(STAB) + n_audio * sizeof(STAR)); 	
	film.frameHeader.size =
	 endian_swap_long(sizeof(FRAME) + sizeof(FDSC) + sizeof(ADSC) +
		sizeof(STAB) + n_audio * sizeof(STAR));
	if (fwrite(&film, sizeof(FILM), 1, afp) != 1) {
		perror(aname);
		exit(-3);
	}
	film.sampleTableAtom.count = n; /* Restore original number */

	
	if (fwrite(vidSampleTableArray, sizeof(STAR), n_video, vfp) != n_video) {
			perror(vname);
			exit(-3);
	}
	if (fwrite(audSampleTableArray, sizeof(STAR), n_audio, afp) != n_audio) {
			perror(aname);
			exit(-3);
	}

	free(vidSampleTableArray);	
	free(audSampleTableArray);
	/*
	 * Do the actual job, read the video/audio sections and
	 * write them to seperate files
	 */

	p = orgSampleTableArray;
	for (i = 0; i < count; i++, p++) {
		size = endian_swap_long(p->size);
		if ((bufp = malloc(size)) == NULL) {
			fprintf(stderr, "%s: Out of memory (4).\n", name);
			exit(-3);
		}
		/*
		 * Go to the right spot
		 */
		fseek(ifp, orgEndSampleTableArray + endian_swap_long(p->offset), 0);

		/*
		 * Read data
		 */
		if (fread(bufp, size, 1, ifp) != 1) {
			perror(iname);
			exit(-3);
		}
		
		/*
		 * Audio or Video?
		 */
		if ((endian_swap_long(p->start) & 0x7fffffffL) == 0x7fffffffL) {
			/*
			 * Audio Data
			 */
/*
 * FOR DEBUGGING ONLY!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 */
 			printf("audio data...\n");
			if (i == 4) {
				FILE *fp;
				printf("Debug code is still in here...\n");
				fp = fopen("btst.raw", "wb");
				fwrite(bufp, size, 1, fp);
				fclose(fp);
			}
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 */
			if (fwrite(bufp, size, 1, afp) != 1) {
				perror(aname);
				exit(-3);
			}
		} else {
 			printf("video data...\n");			
			/*
			 * Video Data
			 */
			if (fwrite(bufp, size, 1, vfp) != 1) {
				perror(vname);
				exit(-3);
			}

		}
		free(bufp);	
	}
	free(orgSampleTableArray);			
	fclose(afp);
	fclose(vfp);
}

	void
usage()
{
	printf("Usage: %s JaguarMovieFileName\n", name);
	printf("\t%s\n", version);
	printf("\tSplits a Jaguar movie into an audio and a video section.\n");
	printf("\tThe output will be a \'.AUD\' and a \'.VID\' file.\n");
}


long endian_swap_long( long l )
{
unsigned long a, b, c, d;

/* 'abcd' becomes 'dcba' pr vice versa */

	a = (l >> 24L) & 0x000000ffL;
	b = (l >> 8L) & 0x0000ff00L;
	c = (l << 8L) & 0x00ff0000L;
	d = (l << 24L) & 0xff000000L;
	return( a | b | c | d );
}

short endian_swap_word( short i )
{
unsigned short a, b;

	a = (i >> 8) & 0x00ff;
	b = (i << 8) & 0xff00;
	return( a | b );
}

