/*
 *  tcextract.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 "xio.h"
#include "ioaux.h"
#include "tc.h"


#define EXE "tcextract"

#define MAX_BUF 1024

int verbose=TC_INFO;

void import_exit(int code) 
{
  if(verbose & TC_DEBUG) { fprintf (stderr, "[%s] (pid=%d) exit ", EXE, (int) getpid()); 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 name           input file name [stdin]\n");
  fprintf(stderr,"\t -t magic          file type [autodetect]\n");
  fprintf(stderr,"\t -a track          track number [0]\n");
  fprintf(stderr,"\t -x codec          source codec\n");
  fprintf(stderr,"\t -d mode           verbosity mode\n");
  fprintf(stderr,"\t -C s-e            process only (video frame/audio byte) range [all]\n");
  fprintf(stderr,"\t -f seekfile       seek/index file [off]\n");
  fprintf(stderr,"\t -v                print version\n");

  exit(status);
  
}


/* ------------------------------------------------------------ 
 *
 * universal extract thread frontend 
 *
 * ------------------------------------------------------------*/

void extract_lzo(info_t *ipipe);

int main(int argc, char *argv[])
{

    info_t ipipe;

    int user=0;

    long 
	stream_stype = TC_STYPE_UNKNOWN, 
	stream_magic = TC_MAGIC_UNKNOWN, 
	stream_codec = TC_CODEC_UNKNOWN;

    int ch, done=0, track=0;
    char *magic=NULL, *codec=NULL, *name=NULL;

	tc_memcpy_init(verbose & TC_INFO, -1);

    //proper initialization
    memset(&ipipe, 0, sizeof(info_t));
    ipipe.frame_limit[0]=0;
    ipipe.frame_limit[1]=LONG_MAX;

    
    while ((ch = getopt(argc, argv, "d:x:i:f:a:vt:C:?h")) != -1) {
	
	switch (ch) {
	    
	case 'i': 
	    
	  if(optarg[0]=='-') usage(EXIT_FAILURE);
	  name = optarg;

	  break;

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

	case 'x': 
	  
	  if(optarg[0]=='-') usage(EXIT_FAILURE);
	  codec = optarg;
	  break;
	  
	case 'f': 
	  
	  if(optarg[0]=='-') usage(EXIT_FAILURE);
	  ipipe.nav_seek_file = optarg;

	  break;

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

	  break;
	  
	case 'a': 
	    
	  if(optarg[0]=='-') usage(EXIT_FAILURE);
	  track = strtol(optarg, NULL, 0);
	  break;
	  
        case 'C':

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

	case 'v': 
	  version(EXE);
	  exit(0);
	  break;
	  
	case 'h':
	  usage(EXIT_SUCCESS);
	default:
	  usage(EXIT_FAILURE);
	}
    }

    /* ------------------------------------------------------------ 
     *
     * fill out defaults for info structure
     *
     * ------------------------------------------------------------*/
    
    // assume defaults
    if(name==NULL) stream_stype=TC_STYPE_STDIN;
    
    // no autodetection yet
    if(codec==NULL && magic==NULL) {
      fprintf(stderr, "error: invalid codec %s\n", codec);
      usage(EXIT_FAILURE);
    }

    if(codec==NULL) codec="";

    // do not try to mess with the stream
    if(stream_stype!=TC_STYPE_STDIN) {
      
      if(file_check(name)) exit(1);
      
      if((ipipe.fd_in = xio_open(name, O_RDONLY))<0) {
	perror("file open");
	return(-1);
      }
      
      stream_magic = fileinfo(ipipe.fd_in, 0);
      
      if(verbose & TC_DEBUG) fprintf(stderr, "[%s] (pid=%d) %s\n", EXE, getpid(), filetype(stream_magic));
      
    } else ipipe.fd_in = STDIN_FILENO;

    if(verbose & TC_DEBUG) 
	fprintf(stderr, "[%s] (pid=%d) starting, doing %s\n", EXE, getpid(), codec);
    
    // fill out defaults for info structure
    ipipe.fd_out = STDOUT_FILENO;
    
    ipipe.magic   = stream_magic;
    ipipe.stype   = stream_stype;
    ipipe.codec   = stream_codec;
    ipipe.track   = track;
    ipipe.select  = TC_VIDEO;

    ipipe.verbose = verbose;

    ipipe.name = name;
    
    /* ------------------------------------------------------------ 
     *
     * codec specific section
     *
     * note: user provided magic values overwrite autodetection!
     *
     * ------------------------------------------------------------*/

    if(magic==NULL) magic="";
    
    // OGM

    if (ipipe.magic == TC_MAGIC_OGG) {

	// dummy for video
	if(strcmp(codec, "raw")==0) ipipe.codec = TC_CODEC_RGB;
	if((strcmp(codec, "vorbis")==0) || (strcmp(codec, "ogg")==0)) {
	    ipipe.codec = TC_CODEC_VORBIS;
	    ipipe.select = TC_AUDIO;
	}
	if(strcmp(codec, "mp3")==0) {
	    ipipe.codec = TC_CODEC_MP3;
	    ipipe.select = TC_AUDIO;
	}
	if(strcmp(codec, "pcm")==0) {
	    ipipe.codec = TC_CODEC_PCM;
	    ipipe.select = TC_AUDIO;
	}

	extract_ogm(&ipipe);
	done = 1;
    }

    // MPEG2
    if(strcmp(codec,"mpeg2")==0) { 
      
      ipipe.codec = TC_CODEC_MPEG2;
      
      if(strcmp(magic, "vob")==0) ipipe.magic = TC_MAGIC_VOB;
      if(strcmp(magic, "m2v")==0) ipipe.magic = TC_MAGIC_M2V;
      if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
      
      extract_mpeg2(&ipipe);
      done = 1;
    }
    
    // PCM
    if(strcmp(codec,"pcm")==0) { 
      
	ipipe.codec = TC_CODEC_PCM;
	ipipe.select = TC_AUDIO;

	if(strcmp(magic, "vob")==0) ipipe.magic = TC_MAGIC_VOB;
	if(strcmp(magic, "avi")==0) ipipe.magic = TC_MAGIC_AVI;
	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
	if(strcmp(magic, "wav")==0) ipipe.magic = TC_MAGIC_WAV;

	extract_pcm(&ipipe);
	done = 1;
    }

    // SUBTITLE (private_stream_1)
    if(strcmp(codec,"ps1")==0) { 
      
	ipipe.codec = TC_CODEC_PS1;
	ipipe.select = TC_AUDIO;

	if(strcmp(magic, "vob")==0) ipipe.magic = TC_MAGIC_VOB;
	if(strcmp(magic, "vdr")==0) ipipe.magic = TC_MAGIC_VDR;

	extract_ac3(&ipipe);
	done = 1;
    }


    // DV
    if(strcmp(codec,"dv")==0) { 
	
	ipipe.codec = TC_CODEC_DV;

	if(strcmp(magic, "avi")==0) ipipe.magic = TC_MAGIC_AVI;
	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;

	extract_dv(&ipipe);
	done = 1;
    }


    // RGB
    if(strcmp(codec,"rgb")==0) { 
	
	ipipe.codec = TC_CODEC_RGB;
	
	if(strcmp(magic, "avi")==0) ipipe.magic = TC_MAGIC_AVI;
	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
	if(strcmp(magic, "wav")==0) ipipe.magic = TC_MAGIC_WAV;

	extract_rgb(&ipipe);
	done = 1;
    }
    
    
    // DTS
    if(strcmp(codec,"dts")==0) {
	
	ipipe.codec = TC_CODEC_DTS;
	ipipe.select = TC_AUDIO;

	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
	if(strcmp(magic, "vob")==0) ipipe.magic = TC_MAGIC_VOB;

	extract_ac3(&ipipe);
	done = 1;
    }

    // AC3
    if(strcmp(codec,"ac3")==0) {
	
	ipipe.codec = TC_CODEC_AC3;
	ipipe.select = TC_AUDIO;

	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
	if(strcmp(magic, "vob")==0) ipipe.magic = TC_MAGIC_VOB;

	extract_ac3(&ipipe);
	done = 1;
    }

    // A52
    if(strcmp(codec,"a52")==0) {
	
	ipipe.codec = TC_CODEC_A52;
	ipipe.select = TC_AUDIO;

	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
	if(strcmp(magic, "vob")==0) ipipe.magic = TC_MAGIC_VOB;

	// handled by ac3
	extract_ac3(&ipipe);
	done = 1;
    }

    // MP3
    if(strcmp(codec,"mp3")==0 || strcmp(codec,"mp2")==0) {
	
	ipipe.codec = TC_CODEC_MP3;
	ipipe.select = TC_AUDIO;

	if(strcmp(magic, "avi")==0) ipipe.magic = TC_MAGIC_AVI;
	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
	if(strcmp(magic, "vob")==0) ipipe.magic = TC_MAGIC_VOB;

	extract_mp3(&ipipe);
	done = 1;
    }

    // YV12
    if(strcmp(codec,"yv12")==0) { 
	
	ipipe.codec = TC_CODEC_YV12;

	if(strcmp(magic, "avi")==0) ipipe.magic = TC_MAGIC_AVI;
	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
	if(strcmp(magic, "yuv4mpeg")==0) ipipe.magic = TC_MAGIC_YUV4MPEG;
	
	extract_yuv(&ipipe);
	done = 1;
    }

    // YV12
    if(strcmp(codec,"uyvy")==0) { 
	
	ipipe.codec = TC_CODEC_YV12;

	if(strcmp(magic, "avi")==0) ipipe.magic = TC_MAGIC_AVI;
	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
	
	extract_yuv(&ipipe);
	done = 1;
    }
   
   
    // LZO
    if(strcmp(codec,"lzo")==0) { 
	
	ipipe.codec = TC_CODEC_YV12;

	if(strcmp(magic, "avi")==0) ipipe.magic = TC_MAGIC_AVI;
	if(strcmp(magic, "raw")==0) ipipe.magic = TC_MAGIC_RAW;
	
	extract_lzo(&ipipe);
	done = 1;
    }


    // AVI extraction

    //need to check if there isn't a codec from the input option (if we have a file with TC_MAGIC_AVI and we specify -x pcm we have pcm and rgb output)
    if ((strcmp(magic, "avi")==0 || ipipe.magic==TC_MAGIC_AVI)&& (codec == NULL)) {
	
	ipipe.magic=TC_MAGIC_AVI;
	extract_avi(&ipipe);
	done = 1;
    }

    if (strcmp(codec, "raw")==0 || strcmp(codec, "video")==0) {
	ipipe.select=TC_VIDEO-1;
	ipipe.magic=TC_MAGIC_AVI;
	extract_avi(&ipipe);
	done = 1;
    }
    

    if(!done) {
	fprintf(stderr, "[%s] (pid=%d) unable to handle codec %s\n", EXE, getpid(), codec);
	exit(1);
    }    
    
    if(ipipe.fd_in != STDIN_FILENO) xio_close(ipipe.fd_in);
    
    return(0);
}

#include "libxio/static_xio.h"
