#include #include #include #include #include #include #include #include #include #include #include "vidfile.h" #include "display-X.h" #include "ycbcr-rgb-cvt.h" extern const char *__progname; static int ignore_times = 0; static int slow_X = 0; static VFR_HANDLE *vfh; static int have_timestamps; static unsigned long long int timestamp; static int framesize; static unsigned char *framebuf; static int dpipe; static int framex; static int framey; static DX_FMT framefmt; #define wrt(fd,buf,len) wrt_(#fd "," #buf "," #len,(fd),(buf),len) static void wrt_(const char *s, int fd, const void *buf, int len) { int n; n = write(fd,buf,len); if (n < 0) { fprintf(stderr,"write(%s): %s\n",s,strerror(errno)); exit(1); } if (n != len) { fprintf(stderr,"write(%s): wrote %d not %d\n",s,n,len); exit(1); } } static void setup_frame(void) { void *mmrv; mmrv = mmap(0,framesize*2,PROT_READ|PROT_WRITE,MAP_ANON|MAP_SHARED,-1,0); if (mmrv == MAP_FAILED) { fprintf(stderr,"%s: buffer mmap (%u): %s\n",__progname,(unsigned int)(framesize*2),strerror(errno)); exit(1); } framebuf = mmrv; bzero(framebuf,framesize*2); } static void displayer_main(void) { unsigned char c; CVTPARAMS p; void dpr(void *buf, int len) { int nr; nr = recv(dpipe,buf,len,MSG_WAITALL); if (nr == len) { return; } else if (nr < 0) { fprintf(stderr,"%s: displayer pipe read: %s\n",__progname,strerror(errno)); } else if (nr == 0) { fprintf(stderr,"%s: displayer pipe read EOF\n",__progname); } else if (nr < len) { fprintf(stderr,"%s: displayer pipe short read (%d, wanted %d)\n",__progname,nr,len); } else { fprintf(stderr,"%s: impossible displayer pipe read: %d\n",__progname,nr); } exit(1); } setup_X(framex,framey,framefmt,slow_X?DXF_SLOW_AND_SAFE:0); p.Kr = .299; p.Kb = .114; p.minY = 0; p.maxY = 255; p.maxCC = 127; reset_cvt(&p); while (1) { dpr(&c,1); display_frame(framebuf+(c?framesize:0)); wrt(dpipe,&c,1); } } static void fork_displayer(void) { int p[2]; int pid; if (socketpair(AF_LOCAL,SOCK_STREAM,0,&p[0]) < 0) { fprintf(stderr,"%s: socketpair: %s\n",__progname,strerror(errno)); exit(1); } wrt(p[1],"\0\1",2); fflush(0); pid = fork(); if (pid == 0) { close(p[0]); dpipe = p[1]; displayer_main(); _exit(0); } close(p[1]); dpipe = p[0]; // fcntl(dpipe,F_SETFL,fcntl(dpipe,F_GETFL,0)|O_NONBLOCK); } static int rd(int fd, void *data, int len) { int r; unsigned char *dp; int l; dp = data; l = len; while (l > 0) { r = read(fd,dp,l); if (r < 0) { fprintf(stderr,"%s: read: %s\n",__progname,strerror(errno)); exit(1); } if (r == 0) return(0); if (r > l) abort(); dp += r; l -= r; } return(1); } static void handleargs(int ac, char **av) { int skip; int errs; skip = 0; errs = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**av != '-') { fprintf(stderr,"%s: extra argument `%s'\n",__progname,*av); errs = 1; continue; } if (!strcmp(*av,"-ignore-times")) { ignore_times = 1; continue; } if (!strcmp(*av,"-slow")) { slow_X = 1; continue; } fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs = 1; } if (errs) exit(1); } static void vidfile_err(void *cookie __attribute__((__unused__)), const char *msg) { fprintf(stderr,"%s: error in input: %s\n",__progname,msg); exit(1); } static int vidfile_read(void *cookie __attribute__((__unused__)), void *buf, int len) { return(fread(buf,1,len,stdin)); } static void read_header(void) { int w; int h; VF_VIDFMT fmt; void feature(void *cookie __attribute__((__unused__)), unsigned int bit, ...) { switch (bit) { case VFF_TIMESTAMPS: have_timestamps = 1; break; default: fprintf(stderr,"%s: don't understand feature bit %#x\n",__progname,bit); exit(1); break; } } have_timestamps = 0; vfh = open_vidfile_read(&vidfile_err,0,&vidfile_read,0,&w,&h,&fmt,&feature,0); switch (fmt) { case VF_FMT_RGB888_RGB: framefmt = DX_FMT_RGB888; framesize = w * h * 3; break; case VF_FMT_YCbCr422_YCbYCr_0_255: framefmt = DX_FMT_YCbCr422; framesize = w * h * 2; break; default: fprintf(stderr,"%s: don't understand format %d\n",__progname,(int)fmt); exit(1); break; } framex = w; framey = h; } static void read_packet(int bno) { if (have_timestamps) { read_vidfile_frame(vfh,&framebuf[bno?framesize:0],×tamp); } else { read_vidfile_frame(vfh,&framebuf[bno?framesize:0]); } } int main(int, char **); int main(int ac, char **av) { unsigned char bno; handleargs(ac,av); read_header(); setup_frame(); fork_displayer(); while (1) { if (! rd(dpipe,&bno,1)) { fprintf(stderr,"%s: displayer pipe EOF\n",__progname); exit(1); } read_packet(bno); if (have_timestamps && !ignore_times) { static unsigned long long int begin = 0; static unsigned long long int firststamp; struct timeval nowtv; unsigned long long int now; gettimeofday(&nowtv,0); now = nowtv.tv_usec + (nowtv.tv_sec * 1000000ULL); if (begin == 0) { begin = now; firststamp = timestamp; } now -= begin; timestamp -= firststamp; if (timestamp > now) { int delay; delay = (timestamp - now) / 1000; if (delay < 1) delay = 1; poll(0,0,delay); } } wrt(dpipe,&bno,1); } return(0); }