Skip to content

Commit 35303d3

Browse files
add webcam for unix
1 parent e6ec079 commit 35303d3

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed

c_mpos/micropython.mk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@ endif
1111

1212
SRC_USERMOD_C += $(MOD_DIR)/src/hello_world.c
1313
SRC_USERMOD_C += $(MOD_DIR)/src/quirc_decode.c
14+
SRC_USERMOD_C += $(MOD_DIR)/src/webcam.c
1415

1516
SRC_USERMOD_C += $(MOD_DIR)/quirc/lib/identify.c
1617
SRC_USERMOD_C += $(MOD_DIR)/quirc/lib/version_db.c
1718
SRC_USERMOD_C += $(MOD_DIR)/quirc/lib/decode.c
1819
SRC_USERMOD_C += $(MOD_DIR)/quirc/lib/quirc.c
1920
#SRC_USERMOD_C += $(MOD_DIR)/quirc/openmv/collections.c
2021

22+
CFLAGS+= -I/usr/include
23+
LDFLAGS+= -lv4l2

c_mpos/src/webcam.c

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
//#include <Python.h>
2+
#include <stdio.h>
3+
#include <stdlib.h>
4+
#include <fcntl.h>
5+
#include <unistd.h>
6+
#include <sys/ioctl.h>
7+
#include <linux/videodev2.h>
8+
#include <sys/mman.h>
9+
#include <string.h>
10+
11+
#include "py/obj.h"
12+
#include "py/runtime.h"
13+
#include "py/mperrno.h"
14+
15+
// Module name
16+
#define MODULE_NAME "webcam"
17+
18+
// Default webcam device
19+
#define VIDEO_DEVICE "/dev/video0"
20+
#define WIDTH 640
21+
#define HEIGHT 480
22+
23+
// Structure to hold webcam state
24+
typedef struct {
25+
int fd; // File descriptor for the webcam
26+
void *buffer; // Memory-mapped buffer
27+
size_t buffer_length; // Length of the buffer
28+
} webcam_t;
29+
30+
// Convert YUYV to grayscale (extract Y component)
31+
static void yuyv_to_grayscale(uint8_t *src, uint8_t *dst, size_t width, size_t height) {
32+
for (size_t i = 0; i < width * height * 2; i += 2) {
33+
dst[i / 2] = src[i]; // Y component is every other byte
34+
}
35+
}
36+
37+
// Function to capture a grayscale image
38+
static mp_obj_t webcam_capture_grayscale(void) {
39+
webcam_t cam = { .fd = -1, .buffer = NULL, .buffer_length = 0 };
40+
struct v4l2_format fmt = {0};
41+
struct v4l2_buffer buf = {0};
42+
struct v4l2_requestbuffers req = {0};
43+
44+
// Open the webcam device
45+
cam.fd = open(VIDEO_DEVICE, O_RDWR);
46+
if (cam.fd < 0) {
47+
mp_raise_OSError(errno);
48+
}
49+
50+
// Set format to YUYV
51+
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
52+
fmt.fmt.pix.width = WIDTH;
53+
fmt.fmt.pix.height = HEIGHT;
54+
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
55+
fmt.fmt.pix.field = V4L2_FIELD_ANY;
56+
if (ioctl(cam.fd, VIDIOC_S_FMT, &fmt) < 0) {
57+
close(cam.fd);
58+
mp_raise_OSError(errno);
59+
}
60+
61+
// Request one buffer
62+
req.count = 1;
63+
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
64+
req.memory = V4L2_MEMORY_MMAP;
65+
if (ioctl(cam.fd, VIDIOC_REQBUFS, &req) < 0) {
66+
close(cam.fd);
67+
mp_raise_OSError(errno);
68+
}
69+
70+
// Query and map the buffer
71+
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
72+
buf.memory = V4L2_MEMORY_MMAP;
73+
buf.index = 0;
74+
if (ioctl(cam.fd, VIDIOC_QUERYBUF, &buf) < 0) {
75+
close(cam.fd);
76+
mp_raise_OSError(errno);
77+
}
78+
79+
cam.buffer_length = buf.length;
80+
cam.buffer = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, cam.fd, buf.m.offset);
81+
if (cam.buffer == MAP_FAILED) {
82+
close(cam.fd);
83+
mp_raise_OSError(errno);
84+
}
85+
86+
// Queue the buffer
87+
if (ioctl(cam.fd, VIDIOC_QBUF, &buf) < 0) {
88+
munmap(cam.buffer, cam.buffer_length);
89+
close(cam.fd);
90+
mp_raise_OSError(errno);
91+
}
92+
93+
// Start streaming
94+
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
95+
if (ioctl(cam.fd, VIDIOC_STREAMON, &type) < 0) {
96+
munmap(cam.buffer, cam.buffer_length);
97+
close(cam.fd);
98+
mp_raise_OSError(errno);
99+
}
100+
101+
// Dequeue the buffer (capture frame)
102+
if (ioctl(cam.fd, VIDIOC_DQBUF, &buf) < 0) {
103+
ioctl(cam.fd, VIDIOC_STREAMOFF, &type);
104+
munmap(cam.buffer, cam.buffer_length);
105+
close(cam.fd);
106+
mp_raise_OSError(errno);
107+
}
108+
109+
// Convert YUYV to grayscale
110+
size_t grayscale_size = WIDTH * HEIGHT;
111+
uint8_t *grayscale_buf = (uint8_t *)malloc(grayscale_size);
112+
if (!grayscale_buf) {
113+
ioctl(cam.fd, VIDIOC_STREAMOFF, &type);
114+
munmap(cam.buffer, cam.buffer_length);
115+
close(cam.fd);
116+
mp_raise_OSError(ENOMEM);
117+
}
118+
yuyv_to_grayscale((uint8_t *)cam.buffer, grayscale_buf, WIDTH, HEIGHT);
119+
120+
// Create MicroPython bytes object
121+
mp_obj_t result = mp_obj_new_bytes(grayscale_buf, grayscale_size);
122+
123+
// Clean up
124+
free(grayscale_buf);
125+
ioctl(cam.fd, VIDIOC_STREAMOFF, &type);
126+
munmap(cam.buffer, cam.buffer_length);
127+
close(cam.fd);
128+
129+
return result;
130+
}
131+
MP_DEFINE_CONST_FUN_OBJ_0(webcam_capture_grayscale_obj, webcam_capture_grayscale);
132+
133+
// Module definition
134+
static const mp_rom_map_elem_t webcam_module_globals_table[] = {
135+
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_webcam) },
136+
{ MP_ROM_QSTR(MP_QSTR_capture_grayscale), MP_ROM_PTR(&webcam_capture_grayscale_obj) },
137+
};
138+
static MP_DEFINE_CONST_DICT(webcam_module_globals, webcam_module_globals_table);
139+
140+
const mp_obj_module_t webcam_user_cmodule = {
141+
.base = { &mp_type_module },
142+
.globals = (mp_obj_dict_t *)&webcam_module_globals,
143+
};
144+
145+
// Register the module
146+
MP_REGISTER_MODULE(MP_QSTR_webcam, webcam_user_cmodule);
147+

0 commit comments

Comments
 (0)