Created
May 29, 2018 15:12
-
-
Save henkman/dc8ddcdc644ff0d5e8f21caccf3711e9 to your computer and use it in GitHub Desktop.
single header C api for webcam frame capture
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
// gcc -s -O3 -std=c99 -Wall -o cam cam.c -lvfw32 | |
#include <stdio.h> | |
#define STB_IMAGE_WRITE_IMPLEMENTATION | |
#include "stb_image_write.h" | |
#include "cam.h" | |
int main(void) | |
{ | |
long w = 1280; | |
long h = 720; | |
unsigned char *rgb = malloc(w * h * 3); | |
Cam c = {0}; | |
cam_init(&c, w, h, rgb); | |
cam_on(&c); | |
{ | |
cam_cap(&c); | |
stbi_write_jpg("tmp1.jpg", w, h, 3, rgb, 90); | |
cam_cap(&c); | |
stbi_write_jpg("tmp2.jpg", w, h, 3, rgb, 90); | |
} | |
cam_off(&c); | |
cam_on(&c); | |
{ | |
cam_cap(&c); | |
stbi_write_jpg("tmp3.jpg", w, h, 3, rgb, 90); | |
} | |
cam_off(&c); | |
cam_destroy(&c); | |
free(rgb); | |
return 0; | |
} | |
*/ | |
#ifdef _WIN32 | |
#define WIN32_LEAN_AND_MEAN | |
#include <windows.h> | |
#include <vfw.h> | |
#define FOURCC(a, b, c, d) ((DWORD)(((d) << 24) | ((c) << 16) | ((b) << 8) | (a))) | |
static unsigned char clip(int i) | |
{ | |
if (i <= 0) | |
return 0; | |
if (i >= 255) | |
return 255; | |
return (unsigned char)i; | |
} | |
static void YUV444toRGB888(unsigned char y, unsigned char u, unsigned char v, unsigned char *dst) | |
{ | |
int C = y - 16; | |
int D = u - 128; | |
int E = v - 128; | |
*dst++ = clip((298 * C + 409 * E + 128) >> 8); | |
*dst++ = clip((298 * C - 100 * D - 208 * E + 128) >> 8); | |
*dst++ = clip((298 * C + 516 * D + 128) >> 8); | |
} | |
static void YUYVToRGB24(int w, int h, unsigned char *src, unsigned char *dst) | |
{ | |
int i; | |
unsigned char u, y1, v, y2; | |
for (i = 0; i < w * h; i += 2) | |
{ | |
y1 = *src++; | |
u = *src++; | |
y2 = *src++; | |
v = *src++; | |
YUV444toRGB888(y1, u, v, dst); | |
dst += 3; | |
YUV444toRGB888(y2, u, v, dst); | |
dst += 3; | |
} | |
} | |
typedef struct | |
{ | |
HWND hwnd; | |
long w, h; | |
BITMAPINFO bmi; | |
void *rgb; | |
} Cam; | |
LRESULT CALLBACK capVideoStreamCallback(HWND hwnd, LPVIDEOHDR vhdr) | |
{ | |
Cam *c = (Cam *)capGetUserData(hwnd); | |
if (c->bmi.bmiHeader.biCompression == FOURCC('Y', 'U', 'Y', '2')) | |
YUYVToRGB24(c->w, c->h, vhdr->lpData, c->rgb); | |
return 0; | |
} | |
static void cam_init(Cam *c, long w, long h, void *rgb) | |
{ | |
c->hwnd = capCreateCaptureWindow(0, 0, 0, 0, 0, 0, 0, 0); | |
c->w = w; | |
c->h = h; | |
c->rgb = rgb; | |
} | |
static void cam_on(Cam *c) | |
{ | |
capSetUserData(c->hwnd, c); | |
capDriverConnect(c->hwnd, 0); | |
capGetVideoFormat(c->hwnd, &c->bmi, sizeof(c->bmi)); | |
c->bmi.bmiHeader.biWidth = c->w; | |
c->bmi.bmiHeader.biHeight = c->h; | |
c->bmi.bmiHeader.biSizeImage = 0; | |
capSetVideoFormat(c->hwnd, &c->bmi, sizeof(c->bmi)); | |
capSetCallbackOnFrame(c->hwnd, capVideoStreamCallback); | |
} | |
static void cam_cap(Cam *c) | |
{ | |
capGrabFrameNoStop(c->hwnd); | |
} | |
static void cam_off(Cam *c) | |
{ | |
capDriverDisconnect(c->hwnd); | |
} | |
static void cam_destroy(Cam *c) | |
{ | |
DestroyWindow(c->hwnd); | |
} | |
#else | |
#error "not supported" | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment