/*
 *  tcdecode.c
 *
 *  Copyright (C) Thomas Östreich - June 2001
 *
 *  This file is part of transcode, a video stream processing tool
 *      
 *  transcode is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *   
 *  transcode is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *   
 *  You should have received a copy of the GNU General Public License
 *  along with GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 */

#include "transcode.h"

#include <sys/errno.h>
#include <limits.h>

#include "ioaux.h"
#include "tc.h"
#include "xio.h"

#define EXE "tcdecode"

extern long fileinfo(int fd, int skip);

int verbose=TC_QUIET;

void import_exit(int code) 
{
  if(verbose & TC_DEBUG) import_info(code, EXE);
  exit(code);
}


/* ------------------------------------------------------------ 
 *
 * print a usage/version message
 *
 * ------------------------------------------------------------*/


void usage(int status)
{
  version(EXE);

  fprintf(stderr,"\nUsage: %s [options]\n", EXE);

  fprintf(stderr,"\t -i file           input file [stdin]\n");
  fprintf(stderr,"\t -x codec          source codec (required)\n");
  fprintf(stderr,"\t -t package        codec package\n");
  fprintf(stderr,"\t -g wxh            stream frame size [autodetect]\n");
  fprintf(stderr,"\t -y format         output raw stream format [rgb]\n");
  fprintf(stderr,"\t -Q mode           decoding quality (0=fastest-5=best) [%d]\n", VQUALITY);
  fprintf(stderr,"\t -d mode           verbosity mode\n");
  fprintf(stderr,"\t -s c,f,r          audio gain for ac3 downmixing [1,1,1]\n");
  fprintf(stderr,"\t -A n              A52 decoder flag [0]\n");
  fprintf(stderr,"\t -C s,e            decode only from start to end ((V) frames/(A) bytes) [all]\n");
  fprintf(stderr,"\t -Y                use libdv YUY2 decoder mode\n");
  fprintf(stderr,"\t -z r              convert zero padding to silence\n");
  fprintf(stderr,"\t -v                print version\n");

  exit(status);
}

/* ------------------------------------------------------------ 
 *
 * universal decode thread frontend 
 *
 * ------------------------------------------------------------*/

int main(int argc, char *argv[])
{
    decode_t decode;
    int ch, done=0;
    char *codec=NULL, *format="rgb", *magic="none";

	tc_memcpy_init(verbose & TC_INFO, -1);

    memset(&decode, 0, sizeof(decode));
    decode.magic = TC_MAGIC_UNKNOWN;
    decode.stype = TC_STYPE_UNKNOWN;
    decode.quality = VQUALITY;
    decode.ac3_gain[0] = decode.ac3_gain[1] = decode.ac3_gain[2] = 1.0;
    decode.frame_limit[0]=0; 
    decode.frame_limit[1]=LONG_MAX; 

    while ((ch = getopt(argc, argv, "Q:t:d:x:i:a:g:vy:s:YC:A:z:?h")) != -1) {
	switch (ch) {
	    
	case 'i': 
	  if (optarg[0]=='-') usage(EXIT_FAILURE);
	  decode.name = optarg;
	  break;

	case 'd': 
	  if (optarg[0]=='-') usage(EXIT_FAILURE);
	  verbose = atoi(optarg);
	  break;

	case 'Q': 
	  if (optarg[0]=='-') usage(EXIT_FAILURE);
	  decode.quality = atoi(optarg);
	  break;

	case 'A': 
	  if (optarg[0]=='-') usage(EXIT_FAILURE);
	  decode.a52_mode = atoi(optarg);
	  break;
		  
	case 'x': 
	  if (optarg[0]=='-') usage(EXIT_FAILURE);
	  codec = optarg;
	  break;

	case 't': 
	  if (optarg[0]=='-') usage(EXIT_FAILURE);
	  magic = optarg;
	  break;

	case 'y': 
	  if (optarg[0]=='-') usage(EXIT_FAILURE);
	  format = optarg;
	  break;
	  
	case 'g': 
	  if (optarg[0]=='-') usage(EXIT_FAILURE);
	  if (2 != sscanf(optarg,"%dx%d", &decode.width, &decode.height)) usage(EXIT_FAILURE);
	  break;
	  
	case 'v': 
	  version(EXE);
	  exit(0);
	  break;

	case 'Y': 
	  decode.dv_yuy2_mode=1;
	  break;

	case 's': 
	  if(optarg[0]=='-') usage(EXIT_FAILURE);
	  if (3 != sscanf(optarg,"%lf,%lf,%lf", &decode.ac3_gain[0], &decode.ac3_gain[1], &decode.ac3_gain[2])) usage(EXIT_FAILURE);
	  break;
	  
	case 'C': 
	  if(optarg[0]=='-') usage(EXIT_FAILURE);
	  if (2 != sscanf(optarg,"%ld,%ld", &decode.frame_limit[0], &decode.frame_limit[1])) usage(EXIT_FAILURE);
 	  if (decode.frame_limit[0] >= decode.frame_limit[1])
	  {
  		fprintf(stderr,"Invalid -C options\n");
		usage(EXIT_FAILURE);
	  }
	  break;

	case 'z':
	  if(optarg[0]=='-') usage(EXIT_FAILURE);
	  decode.padrate = atoi(optarg);
	  break;
	  
	case 'h':
	  usage(EXIT_SUCCESS);
	default:
	  usage(EXIT_FAILURE);
	}
    }

    /* ------------------------------------------------------------ 
     *
     * fill out defaults for info structure
     *
     * ------------------------------------------------------------*/
    
    // assume defaults
    if(decode.name==NULL) decode.stype=TC_STYPE_STDIN;
    
    // no autodetection yet
    if(codec==NULL) {
	fprintf(stderr, "error: invalid codec %s\n", codec);
	usage(EXIT_FAILURE);
    }
    
    // do not try to mess with the stream
    if (decode.stype != TC_STYPE_STDIN) {
	if (file_check(decode.name)) exit(1);
	if ((decode.fd_in = xio_open(decode.name, O_RDONLY)) < 0) {
	    perror("open file");
	    exit(1);
	} 
	
	// try to find out the filetype
	decode.magic = fileinfo(decode.fd_in, 0);
	if (verbose) fprintf(stderr, "[%s] (pid=%d) %s\n", EXE, getpid(), filetype(decode.magic));
	
    } else decode.fd_in = STDIN_FILENO;
    
    decode.fd_out = STDOUT_FILENO;
    decode.codec = TC_CODEC_UNKNOWN;
    decode.verbose = verbose;
    if (decode.width < 0) decode.width = 0;
    if (decode.height < 0) decode.height = 0;

    /* ------------------------------------------------------------ 
     *
     * output raw stream format
     *
     * ------------------------------------------------------------*/

    if (!strcmp(format, "rgb")) decode.format = TC_CODEC_RGB;
    else if (!strcmp(format, "yv12")) decode.format = TC_CODEC_YV12;
    else if (!strcmp(format, "yuv2")) decode.format = TC_CODEC_YUV2;
    else if (!strcmp(format, "yuy2")) decode.format = TC_CODEC_YUY2;
    else if (!strcmp(format, "pcm")) decode.format = TC_CODEC_PCM;
    else if (!strcmp(format, "raw")) decode.format = TC_CODEC_RAW;

    /* ------------------------------------------------------------ 
     *
     * codec specific section
     *
     * note: user provided values overwrite autodetection!
     *
     * ------------------------------------------------------------*/

    // FFMPEG can decode a lot
    if(!strcmp(magic, "ffmpeg") || !strcmp(magic, "lavc")) {
	if (!strcmp(codec, "mpeg2")) decode.codec = TC_CODEC_MPEG2;
	else if (!strcmp(codec, "mpeg2video")) decode.codec = TC_CODEC_MPEG2;
	else if (!strcmp(codec, "mpeg1video")) decode.codec = TC_CODEC_MPEG1;
	else if (!strcmp(codec, "divx3")) decode.codec = TC_CODEC_DIVX3;
	else if (!strcmp(codec, "divx")) decode.codec = TC_CODEC_DIVX4;
	else if (!strcmp(codec, "divx4")) decode.codec = TC_CODEC_DIVX4;
	else if (!strcmp(codec, "mp42")) decode.codec = TC_CODEC_MP42;
	else if (!strcmp(codec, "mjpg")) decode.codec = TC_CODEC_MJPG;
	else if (!strcmp(codec, "mjpeg")) decode.codec = TC_CODEC_MJPG;
	else if (!strcmp(codec, "rv10")) decode.codec = TC_CODEC_RV10;
	else if (!strcmp(codec, "svq1")) decode.codec = TC_CODEC_SVQ1;
	else if (!strcmp(codec, "svq3")) decode.codec = TC_CODEC_SVQ3;
	else if (!strcmp(codec, "vp3")) decode.codec = TC_CODEC_VP3;
	else if (!strcmp(codec, "4xm")) decode.codec = TC_CODEC_4XM;
	else if (!strcmp(codec, "wmv1")) decode.codec = TC_CODEC_WMV1;
	else if (!strcmp(codec, "wmv2")) decode.codec = TC_CODEC_WMV2;
	else if (!strcmp(codec, "hfyu")) decode.codec = TC_CODEC_HFYU;
	else if (!strcmp(codec, "indeo3")) decode.codec = TC_CODEC_INDEO3;
	else if (!strcmp(codec, "h263p")) decode.codec = TC_CODEC_H263P;
	else if (!strcmp(codec, "h263i")) decode.codec = TC_CODEC_H263I;
	else if (!strcmp(codec, "dvvideo")) decode.codec = TC_CODEC_DV;
	else if (!strcmp(codec, "dv")) decode.codec = TC_CODEC_DV;

	decode_lavc(&decode);
    }
    
    // MPEG2
    if (!strcmp(codec, "mpeg2")) { 
	decode.codec = TC_CODEC_MPEG2;
	decode_mpeg2(&decode);
	done = 1;
    }
    
    // OGG
    if (!strcmp(codec, "ogg")) {
	decode.codec = TC_CODEC_VORBIS;
	decode_ogg(&decode);
	done = 1;
    }

    // AC3
    if (!strcmp(codec, "ac3")) {
	decode.codec = TC_CODEC_AC3;
	decode_ac3(&decode);
	done = 1;
    }

    // A52
    if (!strcmp(codec, "a52")) {
	decode.codec = TC_CODEC_A52;
	decode_a52(&decode);
	done = 1;
    }

    // MP3
    if (!strcmp(codec, "mp3")) {
	decode.codec = TC_CODEC_MP3;
	decode_mp3(&decode);
	done = 1;
    }

    // MP2
    if (!strcmp(codec, "mp2")) {
	decode.codec = TC_CODEC_MP3;
	decode_mp2(&decode);
	done = 1;
    }

    // DV
    if (!strcmp(codec, "dv")) {
	decode.codec = TC_CODEC_DV;
	decode_dv(&decode);
	done = 1;
    }

    // YV12
    if (!strcmp(codec, "yv12")) { 
	decode.codec = TC_CODEC_YV12;
	decode_yuv(&decode);
	done = 1;
    }

    // AF6 audio
    if (!strcmp(codec, "af6audio")) {
      decode.select = TC_AUDIO;
      decode_af6(&decode);
      done = 1;
    }
    
    // AF6 video
    if (!strcmp(codec, "af6video")) {
      decode.select = TC_VIDEO;
      decode_af6(&decode);
      done = 1;
    }
    
#if 0
    // DivX Video
    if (!strcmp(codec, "divx")) {
      decode.select = TC_VIDEO;
      decode_divx(&decode);
      done = 1;
    }
#endif
    
    // XviD Video
    if (!strcmp(codec, "xvid")) {
      decode.select = TC_VIDEO;
      decode_xvid(&decode);
      done = 1;
    }
    
    // MOV 
    if (!strcmp(codec, "mov")) {
      decode_mov(&decode);
      done = 1;
    }
    
    // LZO
    if (!strcmp(codec, "lzo")) {
      decode_lzo(&decode);
      done = 1;
    }
    
    if(!done) {
	fprintf(stderr, "[%s] (pid=%d) unable to handle codec %s\n", EXE, getpid(), codec);
	exit(1);
    }
    
    if (decode.fd_in != STDIN_FILENO) xio_close(decode.fd_in);
    
    return 0;
}

#include "libxio/static_xio.h"
