1/*
2 * getjpeg.c, sample tool for grabbing images from video devices
3 *
4 * Copyright (c) 2003 Joerg Heckenbach <joerg@heckenbach-aw.de>
5 *
6 *    This program is free software; you can redistribute it and/or modify
7 *    it under the terms of the GNU General Public License as published by
8 *    the Free Software Foundation; either version 2 of the License, or
9 *    (at your option) any later version.
10 *
11 *    This program is distributed in the hope that it will be useful,
12 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *    GNU General Public License for more details.
15 *
16 *    You should have received a copy of the GNU General Public License
17 *    along with this program; if not, write to the Free Software
18 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <fcntl.h>
28#include <unistd.h>
29#include <linux/types.h>
30#include <linux/videodev.h>
31#include <sys/ioctl.h>
32#include <sys/mman.h>
33#include <libgen.h>
34
35#define GETJPEG_MMAP
36#define DEF_WIDTH 640
37#define DEF_HEIGHT 480
38
39void
40usage (char *pname)
41{
42	fprintf (stderr,
43	"Usage: %s <options>\n"
44	" -d <device>          video device (default: /dev/video)\n"
45	" -o <file>            write output to file instead of stdout\n"
46	" -s NxN               define size of the output image (default:"
47		" %dx%d)\n"
48	" -n <num>             number of frames to grab\n"
49	"Example: %s -d /dev/video0 -o imagefile -s 640x480 -n 10\n",
50	(char*)basename(pname), DEF_WIDTH, DEF_HEIGHT, (char*)basename(pname));
51	exit (1);
52}
53
54int main(int argc, char **argv)
55{
56	FILE *ofid;
57	int ifid;
58	ssize_t count;
59	int num_frames=1, frame=0;
60#ifndef GETJPEG_MMAP
61	unsigned char buffer[524288];
62#endif
63	char default_dev[] = "/dev/video";
64	char *device = default_dev;
65	char default_file_templ[] = "image";
66	char *file_templ = default_file_templ;
67	char filename[255];
68
69	char *vmbuffer = NULL;
70	unsigned short *vmpointer = NULL;
71	struct video_mbuf vmbuf;
72	struct video_mmap vmmap;
73	int c;
74	int width = DEF_WIDTH, height = DEF_HEIGHT;
75
76	while ((c = getopt (argc, argv, "d:o:s:n:")) != EOF) {
77		switch (c) {
78			case 'd': /* change default device */
79				device = optarg;
80				break;
81			case 'o':
82				file_templ = optarg;
83				break;
84			case 'n':
85				sscanf (optarg, "%d", &num_frames);
86				break;
87			case 's':
88				sscanf (optarg, "%dx%d", &width, &height);
89				break;
90			default:
91				usage (argv[0]);
92				break;
93		}
94	}
95
96//	if ((ifid = open(device, O_RDWR)) < 0) {
97//		printf("Could not open device %s\n", device);
98//		return -1;
99//	}
100//	sleep(1);
101//	count = read(ifid, buffer, sizeof(buffer));
102//	close(ifid);
103//sleep(1);
104
105	if ((ifid = open(device, O_RDWR)) < 0) {
106		printf("Could not open device %s\n", device);
107		return -1;
108	}
109
110#ifdef GETJPEG_MMAP
111	/* setup everything */
112	ioctl(ifid, VIDIOCGMBUF, &vmbuf);
113	//printf("VMBUF: size=%d, frames=%d, offset[0]=%d, offset[1]=%d\n",
114	//		vmbuf.size, vmbuf.frames, vmbuf.offsets[0], vmbuf.offsets[1]);
115
116	vmbuffer = mmap(0, vmbuf.size, PROT_READ, MAP_SHARED, ifid, 0);
117	if (!(vmbuffer))
118		perror("mmap failed");
119
120	vmmap.format = VIDEO_PALETTE_RGB24;
121	vmmap.frame = 0;
122	vmmap.width = width;
123	vmmap.height = height;
124
125	if (ioctl (ifid, VIDIOCMCAPTURE, &vmmap) == -1) {
126		perror ("VIDIOCMCAPTURE(0)");
127	}
128	vmmap.frame = 1;
129
130	for (frame = 0; frame < num_frames; frame++) {
131
132		if (ioctl (ifid, VIDIOCMCAPTURE, &vmmap) == -1) {
133			perror ("VIDIOCMCAPTURE()");
134		}
135		vmmap.frame = (vmmap.frame + 1) % vmbuf.frames;
136		if (ioctl (ifid, VIDIOCSYNC, &vmmap.frame) == -1) {
137			perror ("VIDIOCSYNC()");
138		}
139
140		/* process frame while the hardware captures next frame */
141		sprintf(filename, "%s-%02d.jpg", file_templ, frame);
142
143		if ((ofid = fopen(filename, "wb")) == NULL) {
144			printf("Could not open file %s for writing\n", filename);
145			return -1;
146		}
147		// The length / 8 of the JPEG is stored in the first 2 bytes of vmbuffer
148		vmpointer = (unsigned short *)(vmbuffer+vmbuf.offsets[vmmap.frame]);
149		count = (ssize_t)((unsigned int)(vmpointer[0])<<3);
150
151		if (fwrite(vmbuffer+vmbuf.offsets[vmmap.frame] + 2, sizeof(unsigned char), (size_t)count, ofid) == count) {
152			printf("Frame %d, %d bytes... success\n", frame, (int)count);
153		}
154		fclose(ofid);
155
156	}
157
158	munmap (vmbuffer, vmbuf.size);
159
160#else // v4l_read
161
162	for (frame = 0; frame < num_frames; frame++) {
163		count = read(ifid, buffer, sizeof(buffer)) - 2; // Delete the 2 bytes of length information
164
165		sprintf(filename, "%s-%02d.jpg", file_templ, frame);
166
167		if ((ofid = fopen(filename, "wb")) == NULL) {
168			printf("Could not open file %s for writing\n", filename);
169			return -1;
170		}
171		if (fwrite(buffer + 2, sizeof(unsigned char), (size_t)count, ofid) == count) {
172			printf("Frame %d, %d bytes... success\n", frame, (int)count);
173		}
174		fclose(ofid);
175	}
176
177#endif
178	close(ifid);
179
180	return 0;
181}
182