Skip to content

Commit e35f60c

Browse files
Merge branch 'webcam-works'
2 parents 9318da9 + a47ce6c commit e35f60c

File tree

10 files changed

+478
-115
lines changed

10 files changed

+478
-115
lines changed

c_mpos/src/webcam.c

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313

1414
#define WIDTH 640
1515
#define HEIGHT 480
16-
#define NUM_BUFFERS 4
16+
#define NUM_BUFFERS 1 # more buffers doesnt seem to help so one is enough
1717
#define OUTPUT_WIDTH 240
1818
#define OUTPUT_HEIGHT 240
1919

20-
// Forward declaration of the webcam type
20+
#define WEBCAM_DEBUG_PRINT(...) mp_printf(&mp_plat_print, __VA_ARGS__)
21+
2122
static const mp_obj_type_t webcam_type;
2223

2324
typedef struct _webcam_obj_t {
@@ -26,27 +27,34 @@ typedef struct _webcam_obj_t {
2627
void *buffers[NUM_BUFFERS];
2728
size_t buffer_length;
2829
int frame_count;
29-
unsigned char *gray_buffer; // Persistent buffer for memoryview
30+
unsigned char *gray_buffer;
3031
} webcam_obj_t;
3132

3233
static void yuyv_to_grayscale_240x240(unsigned char *yuyv, unsigned char *gray, int in_width, int in_height) {
33-
float x_ratio = (float)in_width / OUTPUT_WIDTH;
34-
float y_ratio = (float)in_height / OUTPUT_HEIGHT;
34+
// Crop to 480x480 centered region
35+
int crop_size = 480;
36+
int crop_x_offset = (in_width - crop_size) / 2; // Center the crop: (640 - 480) / 2 = 80
37+
int crop_y_offset = (in_height - crop_size) / 2; // Center the crop: (480 - 480) / 2 = 0
38+
39+
// Downscale ratios from 480x480 to 240x240
40+
float x_ratio = (float)crop_size / OUTPUT_WIDTH; // 480 / 240 = 2.0
41+
float y_ratio = (float)crop_size / OUTPUT_HEIGHT; // 480 / 240 = 2.0
3542

3643
for (int y = 0; y < OUTPUT_HEIGHT; y++) {
3744
for (int x = 0; x < OUTPUT_WIDTH; x++) {
38-
int src_x = (int)(x * x_ratio);
39-
int src_y = (int)(y * y_ratio);
40-
int src_index = (src_y * in_width + src_x) * 2;
41-
gray[y * OUTPUT_WIDTH + x] = yuyv[src_index];
45+
// Map output pixel to cropped region
46+
int src_x = (int)(x * x_ratio) + crop_x_offset; // Adjust for crop offset
47+
int src_y = (int)(y * y_ratio) + crop_y_offset; // Adjust for crop offset
48+
int src_index = (src_y * in_width + src_x) * 2; // YUYV uses 2 bytes per pixel
49+
gray[y * OUTPUT_WIDTH + x] = yuyv[src_index]; // Extract Y channel
4250
}
4351
}
4452
}
4553

4654
static void save_raw(const char *filename, unsigned char *data, int width, int height) {
4755
FILE *fp = fopen(filename, "wb");
4856
if (!fp) {
49-
fprintf(stderr, "Cannot open file %s: %s\n", filename, strerror(errno));
57+
WEBCAM_DEBUG_PRINT("Cannot open file %s: %s\n", filename, strerror(errno));
5058
return;
5159
}
5260
fwrite(data, 1, width * height, fp);
@@ -56,7 +64,7 @@ static void save_raw(const char *filename, unsigned char *data, int width, int h
5664
static int init_webcam(webcam_obj_t *self, const char *device) {
5765
self->fd = open(device, O_RDWR);
5866
if (self->fd < 0) {
59-
fprintf(stderr, "Cannot open device: %s\n", strerror(errno));
67+
WEBCAM_DEBUG_PRINT("Cannot open device: %s\n", strerror(errno));
6068
return -1;
6169
}
6270

@@ -67,7 +75,7 @@ static int init_webcam(webcam_obj_t *self, const char *device) {
6775
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
6876
fmt.fmt.pix.field = V4L2_FIELD_ANY;
6977
if (ioctl(self->fd, VIDIOC_S_FMT, &fmt) < 0) {
70-
fprintf(stderr, "Cannot set format: %s\n", strerror(errno));
78+
WEBCAM_DEBUG_PRINT("Cannot set format: %s\n", strerror(errno));
7179
close(self->fd);
7280
return -1;
7381
}
@@ -77,7 +85,7 @@ static int init_webcam(webcam_obj_t *self, const char *device) {
7785
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
7886
req.memory = V4L2_MEMORY_MMAP;
7987
if (ioctl(self->fd, VIDIOC_REQBUFS, &req) < 0) {
80-
fprintf(stderr, "Cannot request buffers: %s\n", strerror(errno));
88+
WEBCAM_DEBUG_PRINT("Cannot request buffers: %s\n", strerror(errno));
8189
close(self->fd);
8290
return -1;
8391
}
@@ -88,14 +96,14 @@ static int init_webcam(webcam_obj_t *self, const char *device) {
8896
buf.memory = V4L2_MEMORY_MMAP;
8997
buf.index = i;
9098
if (ioctl(self->fd, VIDIOC_QUERYBUF, &buf) < 0) {
91-
fprintf(stderr, "Cannot query buffer: %s\n", strerror(errno));
99+
WEBCAM_DEBUG_PRINT("Cannot query buffer: %s\n", strerror(errno));
92100
close(self->fd);
93101
return -1;
94102
}
95103
self->buffer_length = buf.length;
96104
self->buffers[i] = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, self->fd, buf.m.offset);
97105
if (self->buffers[i] == MAP_FAILED) {
98-
fprintf(stderr, "Cannot map buffer: %s\n", strerror(errno));
106+
WEBCAM_DEBUG_PRINT("Cannot map buffer: %s\n", strerror(errno));
99107
close(self->fd);
100108
return -1;
101109
}
@@ -107,21 +115,21 @@ static int init_webcam(webcam_obj_t *self, const char *device) {
107115
buf.memory = V4L2_MEMORY_MMAP;
108116
buf.index = i;
109117
if (ioctl(self->fd, VIDIOC_QBUF, &buf) < 0) {
110-
fprintf(stderr, "Cannot queue buffer: %s\n", strerror(errno));
118+
WEBCAM_DEBUG_PRINT("Cannot queue buffer: %s\n", strerror(errno));
111119
return -1;
112120
}
113121
}
114122

115123
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
116124
if (ioctl(self->fd, VIDIOC_STREAMON, &type) < 0) {
117-
fprintf(stderr, "Cannot start streaming: %s\n", strerror(errno));
125+
WEBCAM_DEBUG_PRINT("Cannot start streaming: %s\n", strerror(errno));
118126
return -1;
119127
}
120128

121129
self->frame_count = 0;
122130
self->gray_buffer = (unsigned char *)malloc(OUTPUT_WIDTH * OUTPUT_HEIGHT);
123131
if (!self->gray_buffer) {
124-
fprintf(stderr, "Cannot allocate gray buffer: %s\n", strerror(errno));
132+
WEBCAM_DEBUG_PRINT("Cannot allocate gray buffer: %s\n", strerror(errno));
125133
close(self->fd);
126134
return -1;
127135
}
@@ -178,7 +186,7 @@ static mp_obj_t capture_frame(webcam_obj_t *self) {
178186
// snprintf(filename, sizeof(filename), "frame_%03d.raw", self->frame_count++);
179187
// save_raw(filename, self->gray_buffer, OUTPUT_WIDTH, OUTPUT_HEIGHT);
180188

181-
mp_obj_t result = mp_obj_new_bytes(self->gray_buffer, OUTPUT_WIDTH * OUTPUT_HEIGHT);
189+
mp_obj_t result = mp_obj_new_memoryview('b', OUTPUT_WIDTH * OUTPUT_HEIGHT, self->gray_buffer);
182190

183191
if (ioctl(self->fd, VIDIOC_QBUF, &buf) < 0) {
184192
mp_raise_OSError(MP_EIO);
@@ -189,7 +197,7 @@ static mp_obj_t capture_frame(webcam_obj_t *self) {
189197

190198
static mp_obj_t webcam_init(size_t n_args, const mp_obj_t *args) {
191199
mp_arg_check_num(n_args, 0, 0, 1, false);
192-
const char *device = "/dev/video0"; // Default device
200+
const char *device = "/dev/video0";
193201
if (n_args == 1) {
194202
device = mp_obj_str_get_str(args[0]);
195203
}

draft_code/image_tests.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
width=240
2+
height=240
3+
4+
import webcam
5+
import time
6+
7+
cam = webcam.init("/dev/video0") # Initialize webcam with device path
8+
memview = webcam.capture_frame(cam) # Returns memoryview
9+
time.sleep_ms(1000)
10+
static_bytes_obj = bytes(memview)
11+
12+
13+
image = lv.image(lv.screen_active())
14+
image.align(lv.ALIGN.LEFT_MID, 0, 0)
15+
image.set_rotation(900)
16+
# Create image descriptor once
17+
image_dsc = lv.image_dsc_t({
18+
"header": {
19+
"magic": lv.IMAGE_HEADER_MAGIC,
20+
"w": width,
21+
"h": height,
22+
"stride": width ,
23+
"cf": lv.COLOR_FORMAT.L8
24+
},
25+
'data_size': width * height,
26+
'data': static_bytes_obj # Will be updated per frame
27+
})
28+
image.set_src(image_dsc)
29+
30+
for i in range(300):
31+
print(f"iteration {i}")
32+
webcam.recapture_frame(cam) #refresh memview
33+
bytes_obj = bytes(memview)
34+
#print(f"got bytes: {len(bytes_obj)}")
35+
#image_dsc.data = static_bytes_obj
36+
image_dsc.data = bytes_obj
37+
#image.set_src(image_dsc)
38+
image.invalidate()
39+
time.sleep_ms(10) # seems to need more than 0 or 1 ms
40+
41+
print("cleanup")
42+
webcam.deinit(cam) # Deinitializes webcam

draft_code/saved_functions.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ def log_callback(level, log_str):
602602
# Convert log_str to string if it's a bytes object
603603
log_str = log_str.decode() if isinstance(log_str, bytes) else log_str
604604
# Optional: Print for debugging
605-
print(f"Level: {level}, Log: {log_str}")
605+
#print(f"Level: {level}, Log: {log_str}")
606606
# Log message format: "sysmon: 25 FPS (refr_cnt: 8 | redraw_cnt: 1), ..."
607607
if "sysmon:" in log_str and "FPS" in log_str:
608608
try:
@@ -628,14 +628,18 @@ def get_fps():
628628

629629

630630
# Main loop
631-
for _ in range(10):
632-
import time
633-
fps = get_fps()
634-
if fps > 0: # Only print when FPS is updated
635-
print("Current FPS:", fps)
636-
time.sleep(1)
637-
638-
631+
def print_fps():
632+
for _ in range(100):
633+
import time
634+
fps = get_fps()
635+
if fps > 0: # Only print when FPS is updated
636+
print("Current FPS:", fps)
637+
time.sleep(1)
638+
639+
640+
import _thread
641+
_thread.stack_size(12*1024)
642+
_thread.start_new_thread(print_fps, ())
639643

640644
# crash:
641645

0 commit comments

Comments
 (0)