Skip to content

Instantly share code, notes, and snippets.

@steveway
Last active May 7, 2019 00:09
Show Gist options
  • Select an option

  • Save steveway/9dc5897fcb6d4010d44e6a0aae0a8d96 to your computer and use it in GitHub Desktop.

Select an option

Save steveway/9dc5897fcb6d4010d44e6a0aae0a8d96 to your computer and use it in GitHub Desktop.
This should add the ability to overlay images on a gmv video.
//====================================================
// gmplay 2.1 - geekmaster's kindle video player
// Copyright (C) 2012 by geekmaster, with MIT license:
// http://www.opensource.org/licenses/mit-license.php
// Modified by Stefan Murawski ([email protected])
//----------------------------------------------------
// Tested on DX,DXG,K3,K4main,K4diags,K5main,K5diags.
//----------------------------------------------------
#include <sys/ioctl.h> // ioctl
#include <sys/mman.h> // mmap, munmap
#include <stdio.h> // printf
#include <stdlib.h> // malloc, free
#include <linux/fb.h> // screeninfo
#include <sys/time.h> // gettimeofday
#include <unistd.h> // usleep
#include <string.h> // memset, memcpy
#include <fcntl.h> // open, close, write
#include <time.h> // time
typedef unsigned long u64;
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
u32 __invalid_size_argument_for_IOC; // ioctl.h bug fix for tcc
//----- eink definitions from eink_fb.h and mxcfb.h -----
#define EU3 0x46dd
#define EU50 0x4040462e
#define EU51 0x4048462e
struct update_area_t {int x1,y1,x2,y2,which_fx;u8 *buffer;};
struct mxcfb_rect {u32 top,left,width,height;};
struct mxcfb_alt_buffer_data {u32 phys_addr,width,height;
struct mxcfb_rect alt_update_region;};
struct mxcfb_update_data {struct mxcfb_rect update_region;
u32 waveform_mode,update_mode,update_marker;int temp;uint flags;
struct mxcfb_alt_buffer_data alt_buffer_data;};
struct mxcfb_update_data51 {struct mxcfb_rect update_region;
u32 waveform_mode,update_mode,update_marker;
u32 hist_bw_waveform_mode,hist_gray_waveform_mode;
int temp;uint flags;struct mxcfb_alt_buffer_data alt_buffer_data;};
//----- function prototypes -----
void gmplay4(void);
void gmplay8(void);
int getmsec(void);
int gmlib(int);
//----- gmlib global vars -----
enum GMLIB_op {GMLIB_INIT,GMLIB_CLOSE,GMLIB_UPDATE,GMLIB_VSYNC};
u8 *fb0=NULL; // framebuffer pointer
int fdFB=0; // fb0 file descriptor
int teu=0; // eink update time
u32 fs=0; // fb0 stride
u32 MX=0; // xres (visible)
u32 MY=0; // yres (visible)
u32 VY=0; // (VY>MY): mxcfb driver
u8 ppb=0; // pixels per byte
u32 fc=0; // frame counter
time_t current_time;
struct tm * time_info;
char clockimagepath[99]; // space for "HH:MM\0"
char clockmaskpath[99]; // space for "HH:MM\0"
#define FBSIZE (600/8*800)
#define MAGICTRANSPVALUE 0
//==================================
// gmplay4 - play video on 4-bit fb0
//----------------------------------
void gmplay4(void) {
u32 i,x,y,b,p,off=(MY/2-400)*fs+MX/4-150,fbsize=FBSIZE; u8 fbt[FBSIZE];
while (fread(fbt,fbsize,1,stdin)) { teu+=130; // teu: next update time
if (getmsec()>teu+1000) continue; // drop frame if > 1 sec behind
gmlib(GMLIB_VSYNC); // wait for fb0 ready
for (y=0;y<800;y++) for (x=0;x<600;x+=8) {
b=fbt[600/8*y+x/8]; i=y*fs+x/2+off;
p=(b&1)*240; b>>=1; fb0[i]=p|(b&1)*15; b>>=1;
p=(b&1)*240; b>>=1; fb0[i+1]=p|(b&1)*15; b>>=1;
p=(b&1)*240; b>>=1; fb0[i+2]=p|(b&1)*15; b>>=1;
p=(b&1)*240; b>>=1; fb0[i+3]=p|(b&1)*15;
} fc++; gmlib(GMLIB_UPDATE);
}
}
//==================================
// gmplay4 - play video on 4-bit fb0
//----------------------------------
void gmplay4_addon(void) {
u32 i,x,y,b,p,off=(MY/2-400)*fs+MX/4-150,fbsize=FBSIZE;
u8 fbt[FBSIZE];
u32 addonimageb, addonmaskb, clockimageb, clockmaskb, addonimagep;
u8 addonmaskp, clockimagep, clockmaskp;
FILE *addonimagefp;
FILE *addonmaskfp;
u8 addonimage[FBSIZE];
u8 addonmask[FBSIZE];
FILE *clockimagefp;
FILE *clockmaskfp;
u8 clockimage[FBSIZE];
u8 clockmask[FBSIZE];
time(&current_time);
time_info = localtime(&current_time);
strftime(clockimagepath, sizeof(clockimagepath), "./clock_images/%H_%M.gmi", time_info);
strftime(clockmaskpath, sizeof(clockmaskpath), "./clock_masks/%H_%M.gmi", time_info);
addonimagefp = fopen("addonimage.gmi","rb");
while(addonimagefp == NULL){
addonimagefp = fopen("addonimage.gmi","rb");
}
addonmaskfp = fopen("addonmask.gmi","rb");
while(addonmaskfp == NULL){
addonmaskfp = fopen("addonimage.gmi","rb");
}
clockimagefp = fopen(clockimagepath,"rb");
while(clockimagefp == NULL){
clockimagefp = fopen(clockimagepath,"rb");
}
clockmaskfp = fopen(clockmaskpath,"rb");
while(clockmaskfp == NULL){
clockmaskfp = fopen(clockmaskpath,"rb");
}
while (fread(fbt,fbsize,1,stdin)) {
teu+=130; // teu: next update time
time(&current_time);
time_info = localtime(&current_time);
strftime(clockimagepath, sizeof(clockimagepath), "./clock_images/%H_%M.gmi", time_info);
strftime(clockmaskpath, sizeof(clockmaskpath), "./clock_masks/%H_%M.gmi", time_info);
if((time_info->tm_sec)==0){
fclose(addonimagefp);
fclose(addonmaskfp);
fclose(clockimagefp);
fclose(clockmaskfp);
clockimagefp = fopen(clockimagepath,"rb");
while(clockimagefp == NULL){
clockimagefp = fopen(clockimagepath,"rb");
}
clockmaskfp = fopen(clockmaskpath,"rb");
while(clockmaskfp == NULL){
clockmaskfp = fopen(clockmaskpath,"rb");
}
addonimagefp = fopen("addonimage.gmi","rb");
while(addonimagefp == NULL){
addonimagefp = fopen("addonimage.gmi","rb");
}
addonmaskfp = fopen("addonmask.gmi","rb");
while(addonmaskfp == NULL){
addonmaskfp = fopen("addonimage.gmi","rb");
}
}
else{
rewind(addonimagefp);
rewind(addonmaskfp);
rewind(clockimagefp);
rewind(clockmaskfp);
}
fread(clockimage,fbsize,1,clockimagefp);
fread(clockmask,fbsize,1,clockmaskfp);
//if(((time_info->tm_min %5) + time_info->tm_sec)==0){
//Every 5 Minutes
//system("./update_twitimage.sh");
//}
fread(addonimage,fbsize,1,addonimagefp);
fread(addonmask,fbsize,1,addonmaskfp);
if (getmsec()>teu+1000) continue; // drop frame if > 1 sec behind
gmlib(GMLIB_VSYNC); // wait for fb0 ready
for (y=0;y<800;y++) for (x=0;x<600;x+=8) {
addonimageb = addonimage[600/8*y+x/8];
addonmaskb = addonmask[600/8*y+x/8];
clockimageb = clockimage[600/8*y+x/8];
clockmaskb = clockmask[600/8*y+x/8];
b=fbt[600/8*y+x/8]; i=y*fs+x/2+off;
addonmaskp=(addonmaskb&1)*240; addonmaskb>>=1;
addonimagep=(addonimageb&1)*240; addonimageb>>=1;
clockmaskp=(clockmaskb&1)*240; clockmaskb>>=1;
clockimagep=(clockimageb&1)*240; clockimageb>>=1;
p=(b&1)*240; b>>=1;
if((addonmaskp|(addonmaskb&1)*15) != MAGICTRANSPVALUE){
fb0[i]=(addonimagep|(addonimageb&1)*15);
}
//if(1==0){
else if((clockmaskp|(clockmaskb&1)*15) != MAGICTRANSPVALUE){
fb0[i]=(clockimagep|(clockimageb&1)*15)|0xFF;
}
else{ fb0[i]=p|(b&1)*15; }
addonmaskb>>=1; addonimageb>>=1; b>>=1;
addonmaskp=(addonmaskb&1)*240; addonmaskb>>=1;
addonimagep=(addonimageb&1)*240; addonimageb>>=1;
clockmaskp=(clockmaskb&1)*240; clockmaskb>>=1;
clockimagep=(clockimageb&1)*240; clockimageb>>=1;
p=(b&1)*240; b>>=1;
if((addonmaskp|(addonmaskb&1)*15) != MAGICTRANSPVALUE){
fb0[i +1]=(addonimagep|(addonimageb&1)*15);
}
//if(1==0){
else if((clockmaskp|(clockmaskb&1)*15) != MAGICTRANSPVALUE){
fb0[i+ 1]=(clockimagep|(clockimageb&1)*15)|0xFF;
}
else{ fb0[i +1]=p|(b&1)*15; }
addonmaskb>>=1; addonimageb>>=1; b>>=1;
addonmaskp=(addonmaskb&1)*240; addonmaskb>>=1;
addonimagep=(addonimageb&1)*240; addonimageb>>=1;
clockmaskp=(clockmaskb&1)*240; clockmaskb>>=1;
clockimagep=(clockimageb&1)*240; clockimageb>>=1;
p=(b&1)*240; b>>=1;
if((addonmaskp|(addonmaskb&1)*15) != MAGICTRANSPVALUE){
fb0[i + 2]=(addonimagep|(addonimageb&1)*15);
}
//if(1==0){
else if((clockmaskp|(clockmaskb&1)*15) != MAGICTRANSPVALUE){
fb0[i + 2]=(clockimagep|(clockimageb&1)*15)|0xFF;
}
else{ fb0[i + 2]=p|(b&1)*15; }
addonmaskb>>=1; addonimageb>>=1; b>>=1;
addonmaskp=(addonmaskb&1)*240; addonmaskb>>=1;
addonimagep=(addonimageb&1)*240; addonimageb>>=1;
clockmaskp=(clockmaskb&1)*240; clockmaskb>>=1;
clockimagep=(clockimageb&1)*240; clockimageb>>=1;
p=(b&1)*240; b>>=1;
if((addonmaskp|(addonmaskb&1)*15) != MAGICTRANSPVALUE){
fb0[i + 3]=(addonimagep|(addonimageb&1)*15);
}
//if(1==0){
else if((clockmaskp|(clockmaskb&1)*15) != MAGICTRANSPVALUE){
fb0[i + 3]=(clockimagep|(clockimageb&1)*15)|0xFF;
}
else{ fb0[i + 3]=p|(b&1)*15; }
//p=(b&1)*240; b>>=1; fb0[i]=p|(b&1)*15; b>>=1;
//p=(b&1)*240; b>>=1; fb0[i+1]=p|(b&1)*15; b>>=1;
//p=(b&1)*240; b>>=1; fb0[i+2]=p|(b&1)*15; b>>=1;
//p=(b&1)*240; b>>=1; fb0[i+3]=p|(b&1)*15;
} fc++; gmlib(GMLIB_UPDATE);
}
}
//==================================
// gmplay8 - play video on 8-bit fb0
//----------------------------------
void gmplay8(void) {
u32 i,x,y,b,fbsize=FBSIZE;
u32 addonimageb, addonmaskb, clockimageb, clockmaskb;
u8 fbt[FBSIZE];
FILE *addonimagefp;
FILE *addonmaskfp;
u8 addonimage[FBSIZE];
u8 addonmask[FBSIZE];
FILE *clockimagefp;
FILE *clockmaskfp;
u8 clockimage[FBSIZE];
u8 clockmask[FBSIZE];
while (fread(fbt,fbsize,1,stdin)) {
time(&current_time);
time_info = localtime(&current_time);
strftime(clockimagepath, sizeof(clockimagepath), "./clock_images/%H_%M.gmi", time_info);
strftime(clockmaskpath, sizeof(clockmaskpath), "./clock_masks/%H_%M.gmi", time_info);
printf(clockimagepath);
clockimagefp = fopen(clockimagepath,"rb");
clockmaskfp = fopen(clockmaskpath,"rb");
fread(clockimage,fbsize,1,clockimagefp);
fread(clockmask,fbsize,1,clockmaskfp);
if(((time_info->tm_min %5) + time_info->tm_sec)==0){
//Every 5 Minutes
system("./update_twitimage.sh");
}
addonimagefp = fopen("addonimage.gmi","rb");
addonmaskfp = fopen("addonmask.gmi","rb");
fread(addonimage,fbsize,1,addonimagefp);
fread(addonmask,fbsize,1,addonmaskfp);
teu+=130; // teu: next update time
if (getmsec()>teu+1000) continue; // drop frame if > 1 sec behind
gmlib(GMLIB_VSYNC); // wait for fb0 ready
for (y=0;y<800;y++) for (x=0;x<600;x+=8) {
b=fbt[600/8*y+x/8];
addonimageb=addonimage[600/8*y+x/8];
addonmaskb=addonmask[600/8*y+x/8];
clockimageb=clockimage[600/8*y+x/8];
clockmaskb=clockmask[600/8*y+x/8];
i=y*fs+x;
if(addonmaskb != MAGICTRANSPVALUE){ fb0[i]=(addonimageb&1)*255; }
else if(clockmaskb != MAGICTRANSPVALUE){ fb0[i]=(clockimageb&1)*255;}
else{ fb0[i]=(b&1)*255; }
b>>=1; addonimageb>>=1; addonmaskb>>=1; clockimageb>>=1; clockmaskb>>=1;
if(addonmaskb != MAGICTRANSPVALUE){ fb0[i+1]=(addonimageb&1)*255; }
else if(clockmaskb != MAGICTRANSPVALUE){ fb0[i+1]=(clockimageb&1)*255;}
else{ fb0[i+1]=(b&1)*255; }
b>>=1; addonimageb>>=1; addonmaskb>>=1; clockimageb>>=1; clockmaskb>>=1;
if(addonmaskb != MAGICTRANSPVALUE){ fb0[i+2]=(addonimageb&1)*255; }
else if(clockmaskb != MAGICTRANSPVALUE){ fb0[i+2]=(clockimageb&1)*255;}
else{ fb0[i+2]=(b&1)*255; }
b>>=1; addonimageb>>=1; addonmaskb>>=1; clockimageb>>=1; clockmaskb>>=1;
if(addonmaskb != MAGICTRANSPVALUE){ fb0[i+3]=(addonimageb&1)*255; }
else if(clockmaskb != MAGICTRANSPVALUE){ fb0[i+3]=(clockimageb&1)*255;}
else{ fb0[i+3]=(b&1)*255; }
b>>=1; addonimageb>>=1; addonmaskb>>=1; clockimageb>>=1; clockmaskb>>=1;
if(addonmaskb != MAGICTRANSPVALUE){ fb0[i+4]=(addonimageb&1)*255; }
else if(clockmaskb != MAGICTRANSPVALUE){ fb0[i+4]=(clockimageb&1)*255;}
else{ fb0[i+4]=(b&1)*255; }
b>>=1; addonimageb>>=1; addonmaskb>>=1; clockimageb>>=1; clockmaskb>>=1;
if(addonmaskb != MAGICTRANSPVALUE){ fb0[i+5]=(addonimageb&1)*255; }
else if(clockmaskb != MAGICTRANSPVALUE){ fb0[i+5]=(clockimageb&1)*255;}
else{ fb0[i+5]=(b&1)*255; }
b>>=1; addonimageb>>=1; addonmaskb>>=1; clockimageb>>=1; clockmaskb>>=1;
if(addonmaskb != MAGICTRANSPVALUE){ fb0[i+6]=(addonimageb&1)*255; }
else if(clockmaskb != MAGICTRANSPVALUE){ fb0[i+6]=(clockimageb&1)*255;}
else{ fb0[i+6]=(b&1)*255; }
b>>=1; addonimageb>>=1; addonmaskb>>=1; clockimageb>>=1; clockmaskb>>=1;
if(addonmaskb != MAGICTRANSPVALUE){ fb0[i+7]=(addonimageb&1)*255; }
else if(clockmaskb != MAGICTRANSPVALUE){ fb0[i+7]=(clockimageb&1)*255;}
else{ fb0[i+7]=(b&1)*255; }
/*
fb0[i+1]=(b&1)*255; b>>=1;
fb0[i+2]=(b&1)*255; b>>=1;
fb0[i+3]=(b&1)*255; b>>=1;
fb0[i+4]=(b&1)*255; b>>=1;
fb0[i+5]=(b&1)*255; b>>=1;
fb0[i+6]=(b&1)*255; b>>=1;
fb0[i+7]=(b&1)*255;
*/
} fc++; gmlib(GMLIB_UPDATE);
fclose(addonimagefp);
fclose(addonmaskfp);
}
}
//====================================
// gmlib - geekmaster function library
// op (init, update, vsync, close)
//------------------------------------
int gmlib(int op) {
static struct update_area_t ua={0,0,600,800,21,NULL};
static struct mxcfb_update_data ur={
{0,0,600,800},257,0,1,0x1001,0,{0,0,0,{0,0,0,0}}};
static struct mxcfb_update_data51 ur51={
{0,0,600,800},257,0,1,0,0,0x1001,0,{0,0,0,{0,0,0,0}}};
static int eupcode; static void *eupdata=NULL;
struct fb_var_screeninfo screeninfo;
if (GMLIB_INIT==op) {
teu=getmsec();
fdFB=open("/dev/fb0",O_RDWR);
ioctl(fdFB,FBIOGET_VSCREENINFO,&screeninfo);
ppb=8/screeninfo.bits_per_pixel;
fs=screeninfo.xres_virtual/ppb;
VY=screeninfo.yres_virtual;
MX=screeninfo.xres;
MY=screeninfo.yres;
ua.x2=MX;
ua.y2=MY;
ur.update_region.width=MX;
ur.update_region.height=MY;
fb0=(u8 *)mmap(0,MY*fs,PROT_READ|PROT_WRITE,MAP_SHARED,fdFB,0); // map fb0
if (VY>MY) {
eupcode=EU50;
eupdata=&ur;
ur.update_mode=0;
if (ioctl(fdFB,eupcode,eupdata)<0) {
eupcode=EU51;
eupdata=&ur51;
}
} else { eupcode=EU3; eupdata=&ua; }
//system("eips -f -c;eips -c");
//sleep(1);
} else if (GMLIB_UPDATE==op) {
if (ioctl(fdFB,eupcode,eupdata)<0) {}//system("eips ''");} // 5.1.0 fallback
} else if (GMLIB_VSYNC==op) { while (teu>getmsec()) usleep(1000); // fb0 busy
} else if (GMLIB_CLOSE==op) { gmlib(GMLIB_UPDATE); //sleep(1); // last screen
//system("eips -f -c;eips -c");
munmap(fb0,MY*fs);
close(fdFB);
} else { return -1; }
return 0;
}
//====================================
// getmsec - get msec since first call
// (tick counter wraps every 12 days)
//------------------------------------
int getmsec(void) {
int tc; static int ts=0; struct timeval tv;
gettimeofday(&tv,NULL); tc=tv.tv_usec/1000+1000*(0xFFFFF&tv.tv_sec);
if (0==ts) ts=tc;
return tc-ts;
}
//==================
// main - start here
//------------------
int main(void) {
int i;
gmlib(GMLIB_INIT);
if (ppb-1) { gmplay4_addon(); } else { gmplay8(); }
i=getmsec()/100;
// printf("%d frames in %0.1f secs = %2.1f FPS\n", fc,(double)i/10.0,(double)fc*10.0/i);
gmlib(GMLIB_CLOSE);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment