/*
 * grab.c: Grabber per la webcam.
 *
 *
 * 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 <unistd.h>
#include <linux/videodev.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>

#define FILENAME_LEN 30

void 
err_quit(void)
{
	perror("error");
	exit(-1);
}

int
main(int argc, char **argv)
{

	FILE           *fp;
	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, j, dev, width = 320, height = 240, index;
	char            filename[FILENAME_LEN], *map;

	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 = width;
		video_win.height = height;

		if (ioctl(dev, VIDIOCSWIN, &video_win) == -1)
			err_quit();
	}
	if (ioctl(dev, VIDIOCGWIN, &video_win) == -1)
		err_quit();

	fprintf(stderr, "Width: %d, Height: %d\n", video_win.width, video_win.height);

	if (ioctl(dev, VIDIOCGPICT, &video_pic) == -1)
		err_quit();

	video_pic.depth = 24;
	video_pic.palette = VIDEO_PALETTE_RGB24;

	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 (i = 0; i < 10; i++) {

                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();

		snprintf(filename, FILENAME_LEN - 1, "picture%d.ppm", i);
		printf("Writing out PPM file %s\n", filename);

		if ((fp = fopen(filename, "w")) == NULL)
			err_quit();

		fprintf(fp, "P6\n%d %d\n255\n", video_win.width, video_win.height);

		for (j = 0; j < video_win.width * video_win.height; j++) {
			putc((map + video_buf.offsets[index])[j * 3 + 2], fp);
			putc((map + video_buf.offsets[index])[j * 3 + 1], fp);
			putc((map + video_buf.offsets[index])[j * 3 + 0], fp);
		}

                index++;
		fclose(fp);

	}
	
	munmap(map, video_buf.size);
	free(video_map);
	close(dev);
	return 0;
}

