#include #include #include #include #include #include #include #include #include #include #include "readloop-X.h" #include "readloop-cvt.h" extern const char *__progname; static const char *videodev = "viddev"; #define NFRAMES 64 #define MAXCMDLINE 1024 typedef enum { EVT_NONE = 1, EVT_BUF, EVT_KEY, } EVTYPE; typedef struct ievent IEVENT; struct ievent { EVTYPE t; union { unsigned char buf; unsigned char key; } ; } ; static int vfd; static unsigned char *framebuf; static unsigned int framelen; static int rpipe; static unsigned char *bnv; static int ifd; static struct termios old_tio; static struct termios new_tio; static char icmdbuf[MAXCMDLINE]; static int icmdlen; static int icmdcurs; static char icmddbuf[MAXCMDLINE]; static int icmddlen; static int icmddcurs; static char icmdobuf[MAXCMDLINE+1]; static int icmdolen; static int icmdocurs; static unsigned char icmdpref; static unsigned char twirler; static const unsigned char twirl[4] = "|/-\\"; static int twirlx; static void open_video(void) { vfd = open(videodev,O_RDWR,0); if (vfd < 0) { fprintf(stderr,"%s: %s: %s\n",__progname,videodev,strerror(errno)); exit(1); } } static void size_frame(void) { int lastlen; int goodcount; int n; framelen = 1000; lastlen = 0; framebuf = 0; while (1) { if (framelen != lastlen) { goodcount = 0; free(framebuf); framebuf = malloc(framelen+1); lastlen = framelen; } n = read(vfd,framebuf,framelen+1); if (n < 0) { fprintf(stderr,"%s: %s: read: %s\n",__progname,videodev,strerror(errno)); exit(1); } if (n == 0) { fprintf(stderr,"%s: %s: read EOF\n",__progname,videodev); exit(1); } if (n > framelen) { framelen <<= 1; } else { goodcount ++; if (goodcount > 4) break; } } framelen = n; printf("framelen %d\n",n); } static void setup_frame(void) { void *mmrv; free(framebuf); mmrv = mmap(0,(framelen*NFRAMES)+1,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)(framelen*NFRAMES),strerror(errno)); exit(1); } framebuf = mmrv; bzero(framebuf,framelen*NFRAMES); bnv = malloc(NFRAMES); } static void reader_main(void) { unsigned char bno; int nr; while (1) { nr = read(rpipe,&bno,1); if (nr < 0) { fprintf(stderr,"%s: reader pipe read: %s\n",__progname,strerror(errno)); exit(1); } if (nr == 0) exit(0); if (nr != 1) { fprintf(stderr,"%s: impossible reader pipe read (%d)\n",__progname,nr); exit(1); } nr = read(vfd,framebuf+(bno*framelen),framelen+1); if (nr == framelen) { write(rpipe,&bno,1); continue; } if (nr < 0) { fprintf(stderr,"%s: %s: read: %s\n",__progname,videodev,strerror(errno)); } else if (nr == 0) { fprintf(stderr,"%s: %s: read EOF\n",__progname,videodev); } else { // fprintf(stderr,"%s: %s: read %d, expecting %d\n",__progname,videodev,nr,framelen); continue; } exit(1); } } static void fork_reader(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); } fflush(0); pid = fork(); if (pid == 0) { close(p[0]); rpipe = p[1]; reader_main(); _exit(0); } close(p[1]); rpipe = p[0]; fcntl(rpipe,F_SETFL,fcntl(rpipe,F_GETFL,0)|O_NONBLOCK); } static void queue_buffers(void) { int i; for (i=NFRAMES-1;i>=0;i--) bnv[i] = i; write(rpipe,bnv,NFRAMES); } static IEVENT get_ievent(void) { struct pollfd pfds[2]; int n; IEVENT ev; pfds[0].fd = rpipe; pfds[0].events = POLLIN | POLLRDNORM; pfds[1].fd = ifd; pfds[1].events = POLLIN | POLLRDNORM; n = poll(&pfds[0],2,INFTIM); if (n < 0) { if (errno != EINTR) { fprintf(stderr,"%s: poll: %s\n",__progname,strerror(errno)); exit(1); } ev.t = EVT_NONE; } else if (pfds[0].revents & (POLLIN|POLLRDNORM|POLLERR|POLLHUP|POLLNVAL)) { n = read(rpipe,bnv,NFRAMES); if (n < 0) { fprintf(stderr,"%s: frame pipe read: %s\n",__progname,strerror(errno)); exit(1); } if (n == 0) { fprintf(stderr,"%s: frame pipe read EOF\n",__progname); exit(1); } if (n > 1) write(rpipe,bnv,n-1); ev.t = EVT_BUF; ev.buf = bnv[n-1]; } else if (pfds[1].revents & (POLLIN|POLLRDNORM|POLLERR|POLLHUP|POLLNVAL)) { n = read(ifd,bnv,1); if (n < 0) { fprintf(stderr,"%s: input read: %s\n",__progname,strerror(errno)); exit(1); } if (n == 0) { fprintf(stderr,"%s: input read EOF\n",__progname); exit(1); } ev.t = EVT_KEY; ev.key = bnv[0]; } return(ev); } static void return_frame(int fno) { unsigned char cfno; cfno = fno; write(rpipe,&cfno,1); } static void init_cmdline(void) { ifd = 0; if (tcgetattr(ifd,&old_tio) < 0) { fprintf(stderr,"%s: tcgetattr: %s\n",__progname,strerror(errno)); exit(1); } new_tio = old_tio; new_tio.c_cc[VMIN] = 0; new_tio.c_cc[VTIME] = 0; new_tio.c_iflag &= ~(INPCK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXOFF|IXANY); new_tio.c_oflag &= ~(OPOST|ONLCR|OCRNL|OXTABS|ONOEOT|ONOCR|ONLRET); new_tio.c_cflag |= CREAD; new_tio.c_lflag &= ~(ECHOKE|ECHOE|ECHO|ECHONL|ECHOPRT|ECHOCTL|ICANON|ALTWERASE|IEXTEN|EXTPROC); if (tcsetattr(ifd,TCSADRAIN|TCSASOFT,&new_tio) < 0) { fprintf(stderr,"%s: tcsetattr: %s\n",__progname,strerror(errno)); exit(1); } icmdlen = 0; icmdcurs = 0; icmdpref = 0; icmdolen = 0; icmdocurs = 0; twirlx = 0; twirler = twirl[0]; } static void icmd_process(void) { printf("\r\n"); icmdolen = 0; icmdocurs = 0; if (icmdlen < 1) return; if (icmdbuf[0] == '?') { printf("Kr = %g, Kb = %g, clip Y = %s, clip Cb/Cr = %s\n",cvt_Kr,cvt_Kb,cvt_clip_Y?"yes":"no",cvt_clip_CbCr?"yes":"no"); } else { printf("huh?\n"); } } static void icmd_del(int at, int n) { if ((at < 0) || (n < 0) || (at+n > icmdlen)) abort(); if (n < 1) return; if (at+n < icmdlen) bcopy(&icmdbuf[at+n],&icmdbuf[at],icmdlen-(at+n)); if (icmdcurs > at+n) { icmdcurs -= n; } else if (icmdcurs > at) { icmdcurs = at; } icmdlen -= n; } static int wordchar(unsigned char ch) { static const unsigned char test[32] = { 0x00, 0x00, 0x00, 0x00, /* C0 controls */ 0x00, 0x00, 0xff, 0x03, /* space - ? */ 0xfe, 0xff, 0xff, 0x07, /* @ - _ */ 0xfe, 0xff, 0xff, 0x07, /* ` - DEL */ 0x00, 0x00, 0x00, 0x00, /* C1 controls */ 0x00, 0x00, 0x00, 0x00, /* NBSP - ¿ */ 0xff, 0xff, 0x7f, 0xff, /* À - ß */ 0xff, 0xff, 0x7f, 0xff, /* à - ÿ */ }; return((test[ch>>3]>>(ch&7))&1); } static void icmd_back_word(void) { while ( (icmdcurs > 0) && !( !wordchar(icmdbuf[icmdcurs-1]) && wordchar(icmdbuf[icmdcurs]) ) ) icmdcurs --; } static void icmd_forw_word(void) { while ( (icmdcurs < icmdlen) && !( !wordchar(icmdbuf[icmdcurs+1]) || wordchar(icmdbuf[icmdcurs]) ) ) icmdcurs ++; } static void icmd_key(unsigned char k) { int i; switch (icmdpref) { default: abort(); break; case 0: switch (k) { case 0x01: /* ^A */ icmdcurs = 0; break; case 0x02: /* ^B */ if (icmdcurs > 0) icmdcurs --; break; case 0x04: /* ^D */ if (icmdcurs < icmdlen) icmd_del(icmdcurs,1); break; case 0x05: /* ^E */ icmdcurs = icmdlen; break; case 0x06: /* ^F */ if (icmdcurs < icmdlen) icmdcurs ++; break; case 0x08: /* ^H */ case 0x7f: /* DEL */ if (icmdcurs > 0) icmd_del(icmdcurs-1,1); break; case 0x0a: /* ^J */ case 0x0d: /* ^M */ icmd_process(); icmdlen = 0; icmdcurs = 0; break; case 0x0b: /* ^K */ icmdlen = icmdcurs; break; case 0x14: /* ^T */ if (icmdcurs >= 2) { unsigned char t; t = icmdbuf[icmdcurs-2]; icmdbuf[icmdcurs-2] = icmdbuf[icmdcurs-1]; icmdbuf[icmdcurs-1] = t; } break; case ' ' ... '~': case (unsigned char)' ' ... (unsigned char)'ÿ': if (icmdlen < MAXCMDLINE) { if (icmdcurs < icmdlen) { bcopy(&icmdbuf[icmdcurs],&icmdbuf[icmdcurs+1],icmdlen-icmdcurs); icmdbuf[icmdcurs] = k; icmdcurs ++; icmdlen ++; } } break; case 0x1b: /* ESC */ icmdpref = 0x1b; break; } break; case 0x1b: icmdpref = 0; switch (k) { case 'b': icmd_back_word(); break; case 'd': i = icmdcurs; icmd_forw_word(); icmd_del(i,icmdcurs-i); break; case 'f': icmd_forw_word(); break; case 'h': i = icmdcurs; icmd_back_word(); icmd_del(icmdcurs,i-icmdcurs); break; } break; } } static void icmd_update(void) { int i; int j; int d1; int d2; void dsave(unsigned char c) { icmddbuf[j] = c; if ((j < icmdolen) && (c != icmdobuf[j])) { if (d1 < 0) d1 = j; d2 = j; } } j = 0; d1 = -1; d2 = -1; for (i=0;i icmdolen) { if (d1 < 0) d1 = icmdolen; d2 = j; } else if (j < icmdolen) { if (d1 < 0) d1 = j; d2 = icmdolen; } i = icmdocurs; if (d2 >= 0) { for (;i>d1;i--) putc('\b',stdout); for (;iicmddcurs;i--) putc('\b',stdout); for (;i