/*
 * aagrab.c: Acquisisce dalla webcam e renderizza il video in ascii.
 * TODO: da sistemare, non del tutto funzionante!
 *
 * Copyright (c) 2003, eazy <eazy@ondaquadra.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * *  Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <aalib.h>
#include <unistd.h>
#include <linux/videodev.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

#define FILENAME_LEN 30
#define aa_getpalette(r,g,b) (((r)*30+(g)*59+(b)*11)>>8)

void
err_quit(void)
{
	perror("error");
	exit(-1);
}

int
main(int argc, char **argv)
{
	aa_context     *context;
	struct aa_renderparams *render_param;

	struct video_window video_win;
	struct video_capability video_cap;
	struct video_picture video_pic;
	struct video_mbuf video_buf;
	struct video_mmap *video_map;
	char           *device = "/dev/video0";
	int             i, x, y, dev, index;
	char            *map;

	/*
	if (!aa_parseoptions(NULL, NULL, &argc, argv) || argc != 1) {
		printf("%s", aa_help);
		exit(1);
	}
	*/

	context = aa_autoinit(&aa_defparams);
	if (context == NULL) {
		printf("Failed to initialize aalib\n");
		exit(1);
	}
	
	render_param = aa_getrenderparams();

	render_param->bright = 50;
	render_param->contrast = 80;
	//render_param->gamma = 10;

	if ((dev = open(device, O_RDWR)) == -1)
		err_quit();

	if (ioctl(dev, VIDIOCGCAP, &video_cap) == -1)
		err_quit();

	if (!(video_cap.type & VID_TYPE_CAPTURE)) {
		fprintf(stderr, "Device %s can't capture frame\n", device);
		exit(-1);
	}
	if (video_cap.type & VID_TYPE_SCALES) {

		memset(&video_win, 0, sizeof(struct video_window));
		video_win.width = aa_imgwidth(context);
		video_win.height = aa_imgheight(context);

		if (ioctl(dev, VIDIOCSWIN, &video_win) == -1)
			err_quit();
	}
	if (ioctl(dev, VIDIOCGWIN, &video_win) == -1)
		err_quit();

	/*
	if (video_win.width != aa_imgwidth(context) || video_win.height != aa_imgheight(context)) {
		fprintf(stderr, "Resolution not supported\n");
		exit(-1);
	}
	*/
	printf("%dx%d\n", video_win.width, video_win.height);
	sleep(1);

	if (ioctl(dev, VIDIOCGPICT, &video_pic) == -1)
		err_quit();

	video_pic.depth = 24;
	video_pic.palette = VIDEO_PALETTE_RGB24;
	video_pic.brightness = 65000;
	video_pic.contrast = 65000;

	if (ioctl(dev, VIDIOCSPICT, &video_pic) == -1)
		err_quit();

	if (ioctl(dev, VIDIOCGPICT, &video_pic) == -1)
		err_quit();

	if ((video_pic.depth != 24) || (video_pic.palette != VIDEO_PALETTE_RGB24)) {
		fprintf(stderr, "Capture format not supported\n");
		exit(-1);
	}
	if (ioctl(dev, VIDIOCGMBUF, &video_buf) == -1)
		err_quit();

	if ((int) (map = mmap(0, video_buf.size, PROT_READ | PROT_WRITE, MAP_SHARED, dev, 0)) == -1)
		err_quit();

	if ((video_map = calloc(video_buf.frames, sizeof(struct video_mmap))) == NULL)
		err_quit();

	index = 0;
	for (;;) {

		if (index == video_buf.frames)
			index = 0;

		video_map[index].frame = index;
		video_map[index].height = video_win.height;
		video_map[index].width = video_win.width;
		video_map[index].format = video_pic.palette;

		if (ioctl(dev, VIDIOCMCAPTURE, &video_map[index]) == -1)
			err_quit();

		if (ioctl(dev, VIDIOCSYNC, &video_map[index]) == -1)
			err_quit();

		i = 0;
		for (y = 0; y < aa_imgheight(context); y++) {
			for (x = 0; x < aa_imgwidth(context); x++) {


				aa_putpixel(context, x, y, aa_getpalette((map + video_buf.offsets[index])[i * 3 + 0],
				(map + video_buf.offsets[index])[i * 3 + 1],
									 (map + video_buf.offsets[index])[i * 3 + 2]));

				/*
				 printf("r: %d, g: %d, b: %d\n", (map + video_buf.offsets[index])[i * 3 + 2],
				 (map + video_buf.offsets[index])[i * 3 + 1], (map + video_buf.offsets[index])[i * 3 + 0]);
				*/
				i++;
			}
			i += video_win.width - aa_imgwidth(context);
		}

		/*
		  Esegue il rendering dell'immagine
		 */
		aa_render(context, render_param, 0, 0, aa_scrwidth(context), aa_scrheight(context));

		/*
		  Visualizza l'immagine sul terminale
		 */
		aa_flush(context);

		index++;

	}

	munmap(map, video_buf.size);
	free(video_map);
	aa_close(context);
	close(dev);

}
