/* 
    snap for Bt848 frame grabber driver

    Copyright (C) 1996,97 Marcus Metzler (mocm@thp.uni-koeln.de)

    This program 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 of the License, or
    (at your option) any later version.

    This program 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 this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
 * snap.cc 
 */

#define PNM // if the jpeg library is not installed use pnm
//#define RAW

#include "snap.h"
#include "TVscreenP.h"  /* let's do it the dirty way first */

#ifndef PNM
extern "C"{
#include <jpeglib.h>
}
#endif

#define HEX(N) hex << setw(N) << setfill(int('0')) 
#define DEC(N) dec << setw(N) << setfill(int('0')) 

void flip(unsigned char *mem, int len)
{
  int i;
  unsigned char tmp;

  for (i=0;i<len;i++) {
    tmp=mem[2];
    mem[2]=mem[0];
    mem[0]=tmp;
    mem+=3;
  }
}

void write_raw(char *filename, unsigned char *mem)
{
  ofstream os(filename);
    
  os << "P5\n" << dec << 2270 << "\n"
     << dec << 288 << "\n255\n";
  os.write(mem,288*2270);
  os.close();
}

#ifndef PNM
void write_jpg(char *filename, int w, int h, unsigned char *mem)
{
  struct jpeg_compress_struct cinfo;
  struct jpeg_error_mgr jerr;
  FILE *outfile;   //libjpeg is c-library


  flip(mem, w*h);

  if (!(outfile=fopen(filename, "wb"))){
    cerr << "Error: Can't open "<< filename << endl;
    exit(1);
  }


  cinfo.err=jpeg_std_error(&jerr);
  jpeg_create_compress(&cinfo);
  jpeg_stdio_dest(&cinfo,outfile);
  cinfo.image_width=w;
  cinfo.image_height=h;
  cinfo.input_components=3;
  cinfo.in_color_space=JCS_RGB;

  jpeg_set_defaults(&cinfo);
  jpeg_set_quality(&cinfo,80,TRUE);

  jpeg_start_compress(&cinfo,TRUE);
  
  int rs=w*3;
  JSAMPROW rp[h];
  for (int k=0; k<h; k++)
    rp[k]=&mem[rs*k];
  jpeg_write_scanlines(&cinfo,rp,h);

 /* while(cinfo.next_scanline < cinfo.image_height){
    JSAMPROW rp[1];
    rp[0]=& mem[rs*cinfo.next_scanline];
    int sl=jpeg_write_scanlines(&cinfo,rp,1);
  }
*/
  jpeg_finish_compress(&cinfo);
  jpeg_destroy_compress(&cinfo);
  fclose(outfile);
}
#else

void write_pnm(char *filename, int w, int h, unsigned char *mem)
{
  ofstream os(filename);
    
  flip(mem, w*h);
  os << "P6\n" << dec << w << "\n"
     << dec << h << "\n255\n";
  os.write(mem,w*h*3);

/*
  for (int i=0; i<w*h; i++, mem+=3) {
    os.write((mem+2),1);
    os.write((mem+1),1);
    os.write(mem,1);
  }
*/
  os.close();
}
#endif




int snapit(Widget screen, char *nam,int FULL=0)
{
  char name[80];
  static int number=0;
  unsigned char *tm;
  struct video_mmap gb;

#ifndef NOCARD

  TVscreenWidget w=(TVscreenWidget) screen;

  if (w->TVscreen.CAP_ON){
    ostrstream oname(name,80);
#ifdef PNM
    oname << nam << HEX(3) << number << ".pnm" << char(0);
#else
    oname << nam << HEX(3) << number << ".jpg" << char(0);
#endif

    tm=w->TVscreen.TargetMem;

    if (FULL){ 
      gb.width=w->TVscreen.max_width;
      gb.height=w->TVscreen.max_height;
    } else {
      gb.width=w->TVscreen.vwin.width;
      gb.height=w->TVscreen.vwin.height;
    }
#ifdef RAW
    gb.width=768;
    gb.height=576;
    gb.format=VIDEO_PALETTE_RAW;
#else
    gb.format=VIDEO_PALETTE_RGB24;
#endif
#ifdef BUZ
    gb.width=720;
    gb.height=576;
#endif
    cerr << gb.width << " " << gb.height << endl;
    gb.frame=0;
    if (ioctl(w->TVscreen.fbttv, VIDIOCMCAPTURE, &gb))
      perror("VIDIOCMCAPTURE");
    ioctl(w->TVscreen.fbttv, VIDIOCSYNC, &gb.frame);

    int width=gb.width;
    int height=gb.height;
#ifdef RAW
    write_raw(name,tm);
#else
#ifdef PNM    
    write_pnm(name,width,height,tm);
#else
    write_jpg(name,width,height,tm);
#endif
#endif
    number++;
  }
#endif
return number;
}
  


int sequence(Widget screen, char *nam, int length=DEFSEQ)
{
  char name[80];
  static int number=0;
  unsigned char *tm,*ctm;
  struct video_mmap gb;
  
  if (!(length >1 && length <= MAXSEQ)){
    cerr << "Error: Invalid Sequence Length ("<< length << ")" << endl;
    return 0;
  }  
#ifndef NOCARD
  
  TVscreenWidget w=(TVscreenWidget) screen;
  
  if (w->TVscreen.CAP_ON){
    int width=w->TVscreen.vwin.width;
    int height=w->TVscreen.vwin.height;
    int old_bpp=w->TVscreen.vbuf.depth;
    
    tm=w->TVscreen.TargetMem;
    gb.width=w->TVscreen.vwin.width;
    gb.height=w->TVscreen.vwin.height;
    gb.format=VIDEO_PALETTE_RGB24;
    
    int i=0;
    gb.frame=0;
    ioctl(w->TVscreen.fbttv, VIDIOCMCAPTURE, &gb);
    gb.frame^=1;
    for (int j=0;j< length;j++){
      ioctl(w->TVscreen.fbttv, VIDIOCMCAPTURE, &gb);
      gb.frame^=1;
      ctm=tm+w->TVscreen.mbuf.offsets[gb.frame];
      ioctl(w->TVscreen.fbttv, VIDIOCSYNC, &gb.frame);

      ostrstream oname(name,80);
      oname << nam << HEX(3) << number<< "_" << HEX(3) << j ;
#ifdef PNM
      oname << ".pnm" << char(0);
#else
      oname << ".jpg" << char(0);
#endif
      
#ifdef PNM
      write_pnm(name,width,height,ctm);
#else      
      write_jpg(name,width,height,ctm);
#endif
      
#if 0
      if (height<289) {
      j++;
      ostrstream oname2(name,80);
      oname2 << nam << HEX(3) << number<< "_" << HEX(3) << j ;
#ifdef PNM
      oname2 << ".pnm" << char(0);
#else
      oname2 << ".jpg" << char(0);
#endif
      
#ifdef PNM
      write_pnm(name,width,height,ctm+width*height*3);
#else      
      write_jpg(name,width,height,ctm+width*height*3);
#endif
    }
#endif
    }
  }
  
  number++;
  
#endif
  return number;
}
  
