Skip to content

Instantly share code, notes, and snippets.

@henkman
Created May 29, 2018 15:12
Show Gist options
  • Save henkman/dc8ddcdc644ff0d5e8f21caccf3711e9 to your computer and use it in GitHub Desktop.
Save henkman/dc8ddcdc644ff0d5e8f21caccf3711e9 to your computer and use it in GitHub Desktop.
single header C api for webcam frame capture
/*
// 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