/*
    Robot server - 2005 Jason Hunt
    
    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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    Contact: huntjas2@msu.edu
    
    Most of this code is modified from the library (libjpeg) itself.
*/


#include <stdio.h>
#include <jpeglib.h>
#include <jconfig.h>
#include <jerror.h>
#include <fcntl.h>
#include <time.h>

#include <memory.h>
#include "camera.h"

unsigned int max_buffer;        // the size of the buffer that the caller is maintaining
char *compressed_buffer;        // a pointer to the compressed buffer
unsigned int out_size;          // size of the compressed object

typedef struct {                // simple destination manager
  struct jpeg_destination_mgr pub;    
} buffer_mgr;

typedef buffer_mgr * dest_ptr;

/* called on startup */
METHODDEF(void) buffer_init_destination (j_compress_ptr cinfo)
{
    dest_ptr dest = (dest_ptr) cinfo->dest;

    // point to start of buffer
    dest->pub.next_output_byte = (JOCTET *) compressed_buffer;

    // set buffer size
    dest->pub.free_in_buffer = max_buffer;
}
/* end of buffer_init_destination */


/* write the compressed data to the buffer */
METHODDEF(boolean) buffer_empty_output_buffer (j_compress_ptr cinfo)
{
    // not needed, we are writing directly to a buffer
    return(TRUE);
}
/* end of buffer_empty_output_buffer */


/* called for cleanup */
METHODDEF(void) buffer_term_destination (j_compress_ptr cinfo)
{
    dest_ptr dest = (dest_ptr) cinfo->dest;
    out_size +=  max_buffer - dest->pub.free_in_buffer;
}
/* end of buffer_term_destination */


/* setup for buffer compress */
GLOBAL(void) jpeg_buffer_dest (j_compress_ptr cinfo, char *buffer, unsigned int max)
{
    dest_ptr dest;  // pointer to destination structure
    out_size = 0;   // reset the outsize
    
    max_buffer = max;           // set max buffer size
    compressed_buffer = buffer; // link the buffer
   
    /* create the structure */
    if (cinfo->dest == NULL) 
    {	
        cinfo->dest = (struct jpeg_destination_mgr *)
                      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(buffer_mgr));
    }

    dest = (dest_ptr) cinfo->dest;

    dest->pub.init_destination = buffer_init_destination;
    dest->pub.empty_output_buffer = buffer_empty_output_buffer;
    dest->pub.term_destination = buffer_term_destination;
}
/* end of buffer_dest */


/* use ligjpeg to compress the image */
void compress_frame(unsigned char *image, unsigned char *compressed, int max, unsigned int *the_out_size, int x_size, int y_size)
{
    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;

    JSAMPROW row_pointer[1];	/* pointer to JSAMPLE row[s] */
    int row_stride;		/* physical row width in image buffer */

    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);

    jpeg_buffer_dest(&cinfo, (char *)compressed, max);

    cinfo.image_width = x_size; 	/* image width and height, in pixels */
    cinfo.image_height = y_size;

    cinfo.input_components = 3;		/* # of color components per pixel */
    cinfo.in_color_space = JCS_RGB;		/* red/green/blue */


    jpeg_set_defaults(&cinfo);
    jpeg_set_quality(&cinfo, 85, TRUE ); // 80 percent quality

    jpeg_start_compress(&cinfo, TRUE);

    row_stride = x_size * cinfo.input_components;	/* JSAMPLEs per row in image_buffer */

    while (cinfo.next_scanline < cinfo.image_height) 
    {
        row_pointer[0] = (JSAMPLE *) &image[cinfo.next_scanline * row_stride];

        jpeg_write_scanlines(&cinfo, row_pointer, 1);
    }

    jpeg_finish_compress(&cinfo);
  
    *the_out_size = out_size;   // set the outsize
  
    jpeg_destroy_compress(&cinfo);
 }
/* end of compress_frame */


