camcapture 0.1.0-i686-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +21 -0
- data/ext/extconf.rb +3 -0
- data/ext/ruby_camcapture.c +253 -0
- data/lib/camcapture.rb +16 -0
- data/test/test.rb +14 -0
- metadata +49 -0
data/README
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
-----Ruby/CamCapture-----
|
2
|
+
|
3
|
+
-- Description --
|
4
|
+
|
5
|
+
Ruby/CamCapture is a Ruby library that provides a class for grabbing
|
6
|
+
images from a camera, through the video4linux interface.
|
7
|
+
|
8
|
+
This library is compatible with Ruby Threads, which means that it can be used
|
9
|
+
in combination with TCPServer, sockets, serial port communication (Ruby/Serialport), etc.
|
10
|
+
|
11
|
+
-- Installation --
|
12
|
+
|
13
|
+
$ cd ext
|
14
|
+
$ ruby extconf.rb
|
15
|
+
$ make
|
16
|
+
$ sudo make install
|
17
|
+
|
18
|
+
-- Testing --
|
19
|
+
|
20
|
+
* test/test.rb
|
21
|
+
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,253 @@
|
|
1
|
+
/* CamCapture Ruby class :
|
2
|
+
* Video4Linux video capture
|
3
|
+
* compatible with Ruby Threads
|
4
|
+
*
|
5
|
+
* Copyright 2006 Bruno STEUX / Ecole des Mines de Paris
|
6
|
+
*
|
7
|
+
* Released under Ruby License
|
8
|
+
*/
|
9
|
+
|
10
|
+
#include <ruby.h> /* ruby inclusion */
|
11
|
+
#include <rubyio.h> /* ruby io inclusion */
|
12
|
+
|
13
|
+
static VALUE cCamCapture; /* camera capture class */
|
14
|
+
|
15
|
+
#include <stdlib.h>
|
16
|
+
#include <stdio.h>
|
17
|
+
#include <string.h>
|
18
|
+
#include <fcntl.h>
|
19
|
+
#include <unistd.h>
|
20
|
+
#include <errno.h> /* Error number definitions */
|
21
|
+
#include <sys/types.h>
|
22
|
+
#include <sys/stat.h>
|
23
|
+
#include <sys/ioctl.h>
|
24
|
+
#include <sys/mman.h>
|
25
|
+
#include <linux/videodev.h>
|
26
|
+
|
27
|
+
static int cam_capture_get_fd(VALUE obj)
|
28
|
+
{
|
29
|
+
OpenFile *fptr;
|
30
|
+
|
31
|
+
GetOpenFile(obj, fptr);
|
32
|
+
return (fileno(fptr->f));
|
33
|
+
}
|
34
|
+
|
35
|
+
static void put32(unsigned long value, FILE* outf)
|
36
|
+
{
|
37
|
+
fputc(value & 0xff,outf);
|
38
|
+
fputc((value >> 8) & 0xff,outf);
|
39
|
+
fputc((value >> 16) & 0xff,outf);
|
40
|
+
fputc((value >> 24) & 0xff,outf);
|
41
|
+
}
|
42
|
+
|
43
|
+
static void put16(unsigned int value, FILE* outf)
|
44
|
+
{
|
45
|
+
fputc(value & 0xff,outf);
|
46
|
+
fputc((value >> 8) & 0xff,outf);
|
47
|
+
}
|
48
|
+
|
49
|
+
static VALUE cam_capture_save_bmp(VALUE self, VALUE filename)
|
50
|
+
{
|
51
|
+
VALUE image,image2;
|
52
|
+
char *imageData=RSTRING(image)->ptr;
|
53
|
+
char *fnx=RSTRING(filename)->ptr;
|
54
|
+
int width,height;
|
55
|
+
int h,w,r,g,b;
|
56
|
+
FILE *outfile;
|
57
|
+
VALUE rwidth, rheight;
|
58
|
+
|
59
|
+
rwidth=rb_iv_get(self, "@width");
|
60
|
+
width=NUM2INT(rwidth);
|
61
|
+
rheight=rb_iv_get(self, "@height");
|
62
|
+
height=NUM2INT(rheight);
|
63
|
+
image=rb_iv_get(self, "@image");
|
64
|
+
image2=StringValue(image);
|
65
|
+
if (RSTRING(image2)->len != width*height*3) {
|
66
|
+
rb_raise(rb_eRuntimeError, "image is not correct");
|
67
|
+
}
|
68
|
+
imageData=RSTRING(image2)->ptr;
|
69
|
+
|
70
|
+
outfile = fopen(fnx, "wb");
|
71
|
+
if (outfile == NULL)
|
72
|
+
{
|
73
|
+
printf("Can't open output file.\n");
|
74
|
+
exit(0);
|
75
|
+
}
|
76
|
+
|
77
|
+
fputc('B',outfile);
|
78
|
+
fputc('M',outfile);
|
79
|
+
put32(54+width*height*3, outfile);
|
80
|
+
put32(0L, outfile);
|
81
|
+
put32(54, outfile);
|
82
|
+
|
83
|
+
put32(40L, outfile);
|
84
|
+
put32(width, outfile);
|
85
|
+
put32(height, outfile);
|
86
|
+
put16(1, outfile);
|
87
|
+
put16(24, outfile);
|
88
|
+
put32(0, outfile);
|
89
|
+
put32(width*height*3, outfile);
|
90
|
+
put32(10000, outfile);
|
91
|
+
put32(10000, outfile);
|
92
|
+
put32(0, outfile);
|
93
|
+
put32(0, outfile);
|
94
|
+
|
95
|
+
for (h=height-1; h>=0; h--)
|
96
|
+
{
|
97
|
+
for (w=0; w<width; w++)
|
98
|
+
{
|
99
|
+
b = (int)*(imageData+w*3+h*width*3);
|
100
|
+
g = (int)*(imageData+w*3+h*width*3+1);
|
101
|
+
r = (int)*(imageData+w*3+h*width*3+2);
|
102
|
+
|
103
|
+
putc(b,outfile); /* B */
|
104
|
+
putc(g,outfile); /* G */
|
105
|
+
putc(r,outfile); /* R */
|
106
|
+
}
|
107
|
+
}
|
108
|
+
fclose (outfile);
|
109
|
+
return Qnil;
|
110
|
+
}
|
111
|
+
|
112
|
+
static VALUE cam_capture_create(VALUE class, VALUE device_number, VALUE width, VALUE height, VALUE palette)
|
113
|
+
{
|
114
|
+
OpenFile *fp;
|
115
|
+
int fd;
|
116
|
+
char sdevice[]="/dev/videoX";
|
117
|
+
|
118
|
+
struct video_capability vid_cap;
|
119
|
+
struct video_window vid_win;
|
120
|
+
struct video_channel vid_chan;
|
121
|
+
struct video_picture vid_pic;
|
122
|
+
|
123
|
+
sdevice[strlen(sdevice)-1]='0'+NUM2INT(device_number);
|
124
|
+
|
125
|
+
NEWOBJ(capture, struct RFile);
|
126
|
+
rb_secure(4);
|
127
|
+
OBJSETUP(capture, class, T_FILE);
|
128
|
+
MakeOpenFile(capture, fp);
|
129
|
+
|
130
|
+
fd = open(sdevice, O_RDWR | O_NONBLOCK);
|
131
|
+
if (fd == -1)
|
132
|
+
rb_sys_fail(sdevice);
|
133
|
+
|
134
|
+
// Enable blocking read
|
135
|
+
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
|
136
|
+
|
137
|
+
fp->f = rb_fdopen(fd, "r+");
|
138
|
+
fp->mode = FMODE_READWRITE | FMODE_SYNC;
|
139
|
+
|
140
|
+
if (ioctl(fd, VIDIOCGCAP, &vid_cap) == -1) {
|
141
|
+
rb_raise(rb_eIOError, "CamCapture : VIDIOCGCAP");
|
142
|
+
return Qnil;
|
143
|
+
}
|
144
|
+
|
145
|
+
if (!(vid_cap.type & VID_TYPE_CAPTURE)) {
|
146
|
+
char s[256];
|
147
|
+
sprintf(s,"%s is not a video capture device",sdevice);
|
148
|
+
rb_raise(rb_eIOError, s);
|
149
|
+
return Qnil;
|
150
|
+
}
|
151
|
+
|
152
|
+
if (ioctl(fd, VIDIOCGWIN, &vid_win) == -1) {
|
153
|
+
rb_raise(rb_eIOError, "CamCapture : VIDIOCGWIN");
|
154
|
+
return Qnil;
|
155
|
+
}
|
156
|
+
|
157
|
+
if (NUM2INT(width)!=0) {
|
158
|
+
vid_win.width=NUM2INT(width);
|
159
|
+
}
|
160
|
+
if (NUM2INT(height)!=0) {
|
161
|
+
vid_win.height=NUM2INT(height);
|
162
|
+
}
|
163
|
+
if (ioctl(fd, VIDIOCSWIN, &vid_win) == -1) {
|
164
|
+
rb_raise(rb_eIOError, "CamCapture : VIDIOCSWIN");
|
165
|
+
return Qnil;
|
166
|
+
}
|
167
|
+
|
168
|
+
rb_iv_set((VALUE)capture,"@width",INT2FIX(vid_win.width));
|
169
|
+
rb_iv_set((VALUE)capture,"@height",INT2FIX(vid_win.height));
|
170
|
+
rb_iv_set((VALUE)capture,"@image",rb_str_new2(""));
|
171
|
+
|
172
|
+
if (ioctl(fd, VIDIOCGCHAN, &(vid_chan)) == -1) {
|
173
|
+
rb_raise(rb_eIOError, "CamCapture : VIDIOCGCHAN");
|
174
|
+
return Qnil;
|
175
|
+
}
|
176
|
+
vid_chan.channel = 0;
|
177
|
+
vid_chan.norm = VIDEO_MODE_NTSC;
|
178
|
+
if (ioctl(fd, VIDIOCSCHAN, &(vid_chan)) == -1) {
|
179
|
+
rb_raise(rb_eIOError, "CamCapture : VIDIOCSCHAN");
|
180
|
+
return Qnil;
|
181
|
+
}
|
182
|
+
|
183
|
+
if (ioctl(fd, VIDIOCGPICT, &(vid_pic)) == -1) {
|
184
|
+
rb_raise(rb_eIOError, "CamCapture : VIDIOCGPICT");
|
185
|
+
return Qnil;
|
186
|
+
}
|
187
|
+
vid_pic.palette = VIDEO_PALETTE_RGB24;
|
188
|
+
if (NUM2INT(palette)!=0) {
|
189
|
+
vid_pic.palette=NUM2INT(palette);
|
190
|
+
}
|
191
|
+
if (ioctl(fd, VIDIOCSPICT, &(vid_pic)) == -1) {
|
192
|
+
rb_raise(rb_eIOError, "CamCapture : VIDIOCSPICT");
|
193
|
+
return Qnil;
|
194
|
+
}
|
195
|
+
|
196
|
+
return (VALUE) capture;
|
197
|
+
}
|
198
|
+
|
199
|
+
void Init_camcapture() {
|
200
|
+
cCamCapture = rb_define_class("CamCapture", rb_cIO);
|
201
|
+
rb_define_singleton_method(cCamCapture, "create", cam_capture_create, 4);
|
202
|
+
rb_define_method(cCamCapture, "save_bmp", cam_capture_save_bmp, 1);
|
203
|
+
|
204
|
+
#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */
|
205
|
+
#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */
|
206
|
+
#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */
|
207
|
+
#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */
|
208
|
+
#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */
|
209
|
+
#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */
|
210
|
+
#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */
|
211
|
+
#define VIDEO_PALETTE_YUYV 8
|
212
|
+
#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */
|
213
|
+
#define VIDEO_PALETTE_YUV420 10
|
214
|
+
#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */
|
215
|
+
#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */
|
216
|
+
#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */
|
217
|
+
#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */
|
218
|
+
#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */
|
219
|
+
#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */
|
220
|
+
|
221
|
+
rb_define_const(cCamCapture, "GREY", INT2FIX(VIDEO_PALETTE_GREY));
|
222
|
+
rb_define_const(cCamCapture, "RGB24", INT2FIX(VIDEO_PALETTE_RGB24));
|
223
|
+
rb_define_const(cCamCapture, "RGB32", INT2FIX(VIDEO_PALETTE_RGB32));
|
224
|
+
rb_define_const(cCamCapture, "YUV422", INT2FIX(VIDEO_PALETTE_YUV422));
|
225
|
+
|
226
|
+
/* The following definitions are more easily carried out in Ruby */
|
227
|
+
rb_eval_string(
|
228
|
+
"class CamCapture\n"
|
229
|
+
|
230
|
+
"attr_reader :width, :height, :image\n"
|
231
|
+
|
232
|
+
"def CamCapture.new(device_number=0, w=0, h=0, palette=0)\n"
|
233
|
+
"cap = create(device_number, w, h, palette)\n"
|
234
|
+
"return cap\n"
|
235
|
+
"end\n"
|
236
|
+
|
237
|
+
"def capture\n"
|
238
|
+
"sysread(@width*@height*3,@image)\n"
|
239
|
+
"end\n"
|
240
|
+
|
241
|
+
"end\n"
|
242
|
+
);
|
243
|
+
}
|
244
|
+
|
245
|
+
/* For CamelliaLib interfacing :
|
246
|
+
*
|
247
|
+
"def capture(image)\n"
|
248
|
+
"image.alloc_bgr(@width, @height) if image.width != @width or image.height != @height or not image.allocated?\n"
|
249
|
+
"if image.widthStep != @width*3 then image=nil; return; end\n"
|
250
|
+
"image.set_pixels(sysread(@width*@height*3,@image))\n"
|
251
|
+
"end\n"
|
252
|
+
*/
|
253
|
+
|
data/lib/camcapture.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'camcapture.so'
|
2
|
+
|
3
|
+
class CamCapture
|
4
|
+
attr_reader :width, :height, :image
|
5
|
+
|
6
|
+
def CamCapture.new(device_number=0, w=0, h=0, palette=0)
|
7
|
+
cap = create(device_number, w, h, palette)
|
8
|
+
return cap
|
9
|
+
end
|
10
|
+
|
11
|
+
def capture
|
12
|
+
sysread(@width*@height*3,@image)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
data/test/test.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
begin
|
2
|
+
require 'camcapture'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems'
|
5
|
+
require_gem 'camcapture'
|
6
|
+
end
|
7
|
+
|
8
|
+
camera=CamCapture.new 0, 320, 240
|
9
|
+
puts "Image size is #{camera.width}x#{camera.height}"
|
10
|
+
for i in 1..10 do
|
11
|
+
image=camera.capture
|
12
|
+
puts "image #{i} : #{image.length} bytes grabbed"
|
13
|
+
camera.save_bmp("grab#{i}.bmp")
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.0
|
3
|
+
specification_version: 1
|
4
|
+
name: camcapture
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2006-10-06 00:00:00 +02:00
|
8
|
+
summary: Camera/Webcam capture using Video4Linux interface. Compatible with Ruby Threads.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: bruno.steux@ensmp.fr
|
12
|
+
homepage: http://camellia.rubyforge.org
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: camcapture
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: i686-linux
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Bruno STEUX
|
31
|
+
files:
|
32
|
+
- ext/ruby_camcapture.c
|
33
|
+
- ext/extconf.rb
|
34
|
+
- lib/camcapture.rb
|
35
|
+
- README
|
36
|
+
test_files:
|
37
|
+
- test/test.rb
|
38
|
+
rdoc_options: []
|
39
|
+
|
40
|
+
extra_rdoc_files:
|
41
|
+
- README
|
42
|
+
executables: []
|
43
|
+
|
44
|
+
extensions:
|
45
|
+
- ext/extconf.rb
|
46
|
+
requirements: []
|
47
|
+
|
48
|
+
dependencies: []
|
49
|
+
|