Skip to content

Instantly share code, notes, and snippets.

@Hermann-SW
Last active February 6, 2020 11:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Hermann-SW/ec6a2070935f69d999ad9b860d6b140f to your computer and use it in GitHub Desktop.
Save Hermann-SW/ec6a2070935f69d999ad9b860d6b140f to your computer and use it in GitHub Desktop.
High framerate drawing stream of RGB frames on Raspberry framebuffer (https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=264109)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
int align_up(int x, int y) { return ((x-1)|((1<<y)-1))+1; }
#include <time.h>
long prev_us = 0, delta_us = 0, base_sec = 0;
#define _ {long a=prev_us;struct timespec t;clock_gettime(CLOCK_REALTIME,&t);\
if (!base_sec) { base_sec = t.tv_sec; }\
prev_us=1000000*(t.tv_sec-base_sec)+t.tv_nsec/1000; delta_us = prev_us - a;}
#define __ _ fprintf(stderr, "%ld\n", delta_us);
#define ___(n, blk) for(int i=0; i<n; ++i) { blk }
void FillArea32(char *buf, unsigned nStride3, unsigned *fbp, unsigned lStride,
int xres, int yres, int x1, int y1, int x2, int y2, int cmask)
{
fbp += (y1 * lStride + x1);
for(int y = y1; y < y2; y++, fbp += lStride, buf += nStride3 - 3 * (x2 - x1))
{
if (y < 0) { buf += nStride3; continue; }
if (y >= yres) { break; }
char *p = (char*)fbp;
for(int x = x1; x < x2; x++, p+=4)
{
if ((x < 0) || (x >= xres)) { buf += 3; continue; }
p[2] = cmask & 0x04 ? *buf++ : (buf++,0);
p[1] = cmask & 0x02 ? *buf++ : (buf++,0);
p[0] = cmask & 0x01 ? *buf++ : (buf++,0);
p[3] = 0;
}
}
}
int main(int argc, char *argv[])
{
unsigned width, height, nStride, nSliceHeight, nLen, cmask;
char *buf;
int fbfd = 0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
unsigned *fbp = NULL;
assert((argc+1)/2==2 || !"Format: rgb2fb width height [dmask]");
// memory mapped framebuffer
assert(-1 != (fbfd = open("/dev/fb0", O_RDWR)));
assert(ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) != -1);
assert(ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) != -1);
assert(vinfo.xoffset == 0);
assert(vinfo.yoffset == 0);
assert(vinfo.bits_per_pixel == 32);
fbp = mmap(0, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
assert(fbp != (void*)-1);
for(volatile unsigned *p = fbp; p < fbp + finfo.smem_len/4; ++p)
*p = *p;
msync(fbp, finfo.smem_len, MS_SYNC);
// init rgb stdin related variables
width = atoi(argv[1]); nStride = align_up(width, 5);
height = atoi(argv[2]); nSliceHeight = align_up(height, 4);
nLen = nStride * nSliceHeight * 3;
assert( (buf = malloc(nLen)) );
cmask = (argc == 3) ? 'F' : argv[3][0];
cmask -= (cmask > '9') ? '7' : '0';
// take rgb frames from stdin and display on framebuffer
//
fread(buf, nLen, 1, stdin);
_ // do not profile 1st fread
while (!feof(stdin))
{
__ int colmask[4] = {0x07, 0x01, 0x02, 0x04};
_ for(int i=3; i>=0; --i)
if (cmask & (1<<i))
{
int x = vinfo.xres / 2 - (1 - i%2) * width;
int y = vinfo.yres / 2 - (1 - i/2) * height;
FillArea32(buf, nStride * 3, fbp, finfo.line_length/4,
vinfo.xres, vinfo.yres, x, y, x + width, y + height, colmask[i]);
}
if (cmask == 0)
{
int x = (vinfo.xres - width) / 2;
int y = (vinfo.yres - height) / 2;
FillArea32(buf, nStride * 3, fbp, finfo.line_length/4,
vinfo.xres, vinfo.yres, x, y, x + width, y + height, 0x07);
}
__
msync(fbp, finfo.smem_len, MS_SYNC);
_
int ret = fread(buf, nLen, 1, stdin);
assert(feof(stdin) || (1 == ret));
}
free(buf);
munmap(fbp, finfo.smem_len);
close(fbfd);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment