diff options
author | pommicket <pommicket@gmail.com> | 2025-02-19 19:51:34 -0500 |
---|---|---|
committer | pommicket <pommicket@gmail.com> | 2025-02-19 19:51:34 -0500 |
commit | 21642ce76342ab990b21f15f9205963c8e505d20 (patch) | |
tree | e173ff94bfcb71bcda7a458cba37a22c2ccc8e35 | |
parent | 0ab2c540d442997360830fb1ab76284c318c28ca (diff) |
YUYV support
-rw-r--r-- | camera.c | 15 | ||||
-rw-r--r-- | main.c | 59 |
2 files changed, 61 insertions, 13 deletions
@@ -123,6 +123,7 @@ bool pix_fmt_supported(uint32_t pixfmt) { switch (pixfmt) { case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_GREY: return true; } @@ -393,6 +394,10 @@ void camera_update_gl_textures(Camera *camera, const GLuint textures[3]) { if (camera->frame_bytes_set >= frame_width * frame_height) gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RED, frame_width, frame_height, 0, GL_RED, GL_UNSIGNED_BYTE, curr_frame); break; + case V4L2_PIX_FMT_YUYV: + if (camera->frame_bytes_set >= frame_width * frame_height * 2) + gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, frame_width / 2, frame_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, curr_frame); + break; } } gl.PixelStorei(GL_UNPACK_ALIGNMENT, prev_align); @@ -452,12 +457,9 @@ bool camera_set_format(Camera *camera, PictureFormat picfmt, CameraAccessMethod format.fmt.pix.field = V4L2_FIELD_ANY; // v4l2 should be able to output rgb24 for all reasonable cameras uint32_t pixfmt = V4L2_PIX_FMT_RGB24; - switch (picfmt.pixfmt) { - // we can actually handle these pixel formats - case V4L2_PIX_FMT_BGR24: - case V4L2_PIX_FMT_GREY: + if (pix_fmt_supported(picfmt.pixfmt)) { + // we can handle this format actually pixfmt = picfmt.pixfmt; - break; } format.fmt.pix.pixelformat = pixfmt; format.fmt.pix.width = picfmt.width; @@ -466,6 +468,9 @@ bool camera_set_format(Camera *camera, PictureFormat picfmt, CameraAccessMethod perror("v4l2_ioctl VIDIOC_S_FMT"); return false; } + if (pixfmt == V4L2_PIX_FMT_YUYV) { + printf("%u\n",format.fmt.pix.ycbcr_enc); + } camera->curr_format = format; //printf("image size = %uB\n",format.fmt.pix.sizeimage); switch (camera->access_method) { @@ -391,6 +391,41 @@ void main() {\n\ case 0x47585858: // XXXGRAY (used for FPS display currently)\n\ color = vec3(texture2D(u_sampler, tex_coord).w);\n\ break;\n\ + case 0x56595559: { // YUYV (YUV 4:2:2)\n\ + ivec2 texsize = textureSize(u_sampler, 0);\n\ + vec2 tc = tex_coord * vec2(texsize);\n\ + ivec2 tc00 = ivec2(tc);\n\ + ivec2 tc10 = clamp(tc00 + ivec2(1, 0), ivec2(0), texsize - ivec2(1, 1));\n\ + ivec2 tc01 = clamp(tc00 + ivec2(0, 1), ivec2(0), texsize - ivec2(1, 1));\n\ + ivec2 tc11 = clamp(tc00 + ivec2(1, 1), ivec2(0), texsize - ivec2(1, 1));\n\ + vec2 tcfrac = tc - vec2(tc00);\n\ + vec4 t00 = texelFetch(u_sampler, tc00, 0);\n\ + vec4 t10 = texelFetch(u_sampler, tc10, 0);\n\ + vec4 t01 = texelFetch(u_sampler, tc01, 0);\n\ + vec4 t11 = texelFetch(u_sampler, tc11, 0);\n\ + vec2 cbcr0 = mix(t00.yw, t01.yw, tcfrac.y);\n\ + vec2 cbcr1 = mix(t10.yw, t11.yw, tcfrac.y);\n\ + vec2 cbcr = mix(cbcr0, cbcr1, tcfrac.x);\n\ + float y0, y1;\n\ + if (tcfrac.x < 0.5) {\n\ + y0 = mix(t00.x, t00.z, tcfrac.x * 2.0);\n\ + y1 = mix(t01.x, t01.z, tcfrac.x * 2.0);\n\ + } else {\n\ + y0 = mix(t00.z, t10.x, tcfrac.x * 2.0 - 1.0);\n\ + y1 = mix(t01.z, t11.x, tcfrac.x * 2.0 - 1.0);\n\ + }\n\ + float y = mix(y0, y1, tcfrac.y);\n\ + //y = t00.x;\n\ + //cbcr = t00.yw;\n\ + y -= 16.0 / 255.0;\n\ + float cb = cbcr.x - 128.0 / 255.0;\n\ + float cr = cbcr.y - 128.0 / 255.0;\n\ + color = vec3(y+255.0/224.0*1.402*cr,\n\ + 255.0/219.0*y-255.0/224.0*1.772*0.11/0.587*cb-255.0/224.0*1.402*0.299/0.587*cr,\n\ + 255.0/219.0*y+255.0/224.0*1.772*cb);\n\ + //color = vec3(y);\n\ + color = clamp(color, 0.0, 1.0);\n\ + } break;\n\ default:\n\ color = texture2D(u_sampler, tex_coord).xyz;\n\ break;\n\ @@ -812,8 +847,16 @@ void main() {\n\ gl.Uniform2f(u_scale, 1, 1); } } + static double last_camera_time; + if (last_camera_time == 0) last_camera_time = curr_time; + static double smoothed_camera_time; if (state->camera) { if (camera_next_frame(state->camera)) { + if (smoothed_camera_time == 0) + smoothed_camera_time = curr_time - last_camera_time; + // bias towards recent frame times + smoothed_camera_time = smoothed_camera_time * 0.9 + (curr_time - last_camera_time) * 0.1; + last_camera_time = curr_time; camera_update_gl_textures(state->camera, camera_textures); } gl.Uniform1i(u_pixel_format, camera_pixel_format(state->camera)); @@ -845,12 +888,12 @@ void main() {\n\ gl.Uniform1i(u_pixel_format, V4L2_PIX_FMT_RGB24); gl.DrawArrays(GL_TRIANGLES, 0, 6); } - static double smoothed_frame_time; - if (smoothed_frame_time == 0) - smoothed_frame_time = frame_time; - // bias towards recent frame times - smoothed_frame_time = smoothed_frame_time * 0.9 + frame_time * 0.1; if (state->show_fps) { + static double smoothed_frame_time; + if (smoothed_frame_time == 0) + smoothed_frame_time = frame_time; + // bias towards recent frame times + smoothed_frame_time = smoothed_frame_time * 0.9 + frame_time * 0.1; static double last_fps_update = -INFINITY; gl.Enable(GL_BLEND); gl.ActiveTexture(GL_TEXTURE0); @@ -859,9 +902,9 @@ void main() {\n\ if (curr_time - last_fps_update > 0.5) { last_fps_update = curr_time; static char text[32]; - snprintf(text, sizeof text, "FPS: %" PRId32, - smoothed_frame_time > 1e-9 && smoothed_frame_time < 1 ? (int32_t)(1/smoothed_frame_time) - : 0); + snprintf(text, sizeof text, "Camera FPS: %" PRId32 " Render FPS: %" PRId32, + smoothed_camera_time > 1e-9 && smoothed_camera_time < 1 ? (int32_t)(1/smoothed_camera_time) : 0, + smoothed_frame_time > 1e-9 && smoothed_frame_time < 1 ? (int32_t)(1/smoothed_frame_time) : 0); SDL_Surface *fps = TTF_RenderUTF8_Blended(font, text, (SDL_Color){255,255,255,255}); SDL_LockSurface(fps); gl.PixelStorei(GL_UNPACK_ALIGNMENT, 4); |