Credit Andrew - add additional 16x9 formats for bluray creation; add additional value...
[goodguy/cinelerra.git] / cinelerra-5.1 / db / utils / dbtv.C
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <fcntl.h>
5 #include <signal.h>
6 #include <string.h>
7 #include <malloc.h>
8 #include <errno.h>
9 #include <X11/Xlib.h>
10 #include <sys/time.h>
11
12 #include "s.C"
13
14 #define WIDTH 640
15 #define HEIGHT 480
16
17 #define SWIDTH 80
18 #define SHEIGHT 45
19
20 double the_time()
21 {
22   struct timeval tv;
23   gettimeofday(&tv,NULL);
24   return tv.tv_sec + tv.tv_usec/1000000.0;
25 }
26
27 void loadImage(int x, int y, XImage *image, unsigned char *cp, int width, int height)
28 {
29   int i, j, k, b0, bi, npixel, nline;
30   unsigned long rmask, gmask, bmask;
31   double rshft, gshft, bshft;
32   unsigned char r, g, b, *bp, *dp, *data;
33   unsigned long pix, pixel;
34
35   npixel = image->bits_per_pixel / 8;
36   /*  A, R, G, B  or A, B, G, R */
37   if( image->byte_order != MSBFirst ) {
38     bi = 1;  b0 = 0;
39   }
40   else {
41     bi = -1; b0 = npixel-1;
42   }
43
44   rmask = image->red_mask;    rshft = rmask/255.0;
45   gmask = image->green_mask;  gshft = gmask/255.0;
46   bmask = image->blue_mask;   bshft = bmask/255.0;
47   nline = image->bytes_per_line;
48   data = (unsigned char *)image->data + y*nline + x*npixel;
49
50   for( k=0; k<height; k++ ) {
51     dp = data;
52     for( j=0; j<width; ++j ) {
53       r = g = b = *cp;
54       pixel = ((int)(r*rshft + 0.5) & rmask)
55             + ((int)(g*gshft + 0.5) & gmask)
56             + ((int)(b*bshft + 0.5) & bmask);
57       bp = dp + b0;  pix = pixel;
58       for( i=npixel; --i>0; pix>>=8 ) {
59         *bp = pix;  bp += bi;
60       }
61       dp += npixel;  ++cp;
62     }
63     data += nline;
64   }
65
66 }
67
68 int done = -1;
69 theDb db;
70
71 static void
72 clientMsg(Display *dpy,Window w,Atom amsg,int fmt)
73 {
74   XClientMessageEvent ev;
75   memset(&ev,0,sizeof(ev));
76   ev.type = ClientMessage;
77   ev.window = w;
78   ev.message_type = amsg;
79   ev.format = fmt;
80    XSendEvent(dpy,w,False,0,(XEvent *)&ev);
81 }
82
83 static void
84 scale0(uint8_t *idata,int iw,int ih,uint8_t *odata,int ow,int oh)
85 {
86    int i, dx, dy;
87    double iw1 = iw-1;
88    double ow1 = ow-1;
89
90    int idx[ow];
91    for( dx=0; dx<ow; ++dx )
92       idx[dx] = ((int)((dx*iw1)/ow1));
93
94    int rsz = iw;
95    double ih1 = ih-1;
96    double oh1 = oh-1;
97    for( dy=0;  dy<oh; ++dy ) {
98       uint8_t *row = &idata[rsz * ((int)((dy*ih1)/oh1))];
99       for( dx=0; dx<ow; ++dx ) {
100          uint8_t *bp = &row[idx[dx]];
101          for( i=1; --i>=0; *odata++ = bp[i]);
102       }
103    }
104 }
105
106 #if 0
107 static void
108 scale1(uint8_t *idata,int iw,int ih,int rx,int ry,int rw,int rh,
109        uint8_t *odata,int ow,int oh,int sx,int sy,int sw,int sh)
110 {
111    //if( rw < 3 || rh < 3 || sw < 3 || sh < 3 ) return;
112    int i, dx, dy;  int ibpp = 1, obpp = 1;
113    int rsz = ibpp * iw, ssz = obpp * ow;
114    double iw2 = rw-2, ih2 = rh-2;
115    double ow1 = iw2/(sw-1), oh1 = ih2/(sh-1);
116    odata += sy*ssz + 4*sx;
117
118    for( dy=0; dy<sh; ++dy,odata+=ssz ) {
119       double fy = dy*oh1;
120       int iy = (int)fy;
121       int yf1 = fy - iy;
122       int yf0 = 1.0 - yf1;
123       int idy = rsz * (iy + ry);
124       uint8_t *row0 = &idata[idy];
125       uint8_t *row1 = &idata[idy+rsz];
126       uint8_t *bp = odata;
127
128       for( dx=0; dx<sw; ++dx ) {
129          double fx = dx*ow1;
130          int ix = (int)fx;
131          double xf1 = fx - ix;
132          double xf0 = 1.0 - xf1;
133          int idx = ibpp * (ix + rx);
134          uint8_t *cp00 = &row0[idx];
135          uint8_t *cp01 = &row0[idx+ibpp];
136          uint8_t *cp10 = &row1[idx];
137          uint8_t *cp11 = &row1[idx+ibpp];
138          double a00 = yf0 * xf0;
139          double a01 = yf0 * xf1;
140          double a10 = yf1 * xf0;
141          double a11 = yf1 * xf1;
142          for( bp[i=ibpp]=0; --i>=0; ++cp00, ++cp01, ++cp10, ++cp11 )
143             bp[i] = *cp00*a00 + *cp01*a01 + *cp10*a10 + *cp11*a11 + 0.5;
144          bp += obpp;
145       }
146    }
147 }
148
149
150 static void
151 scale2(uint8_t *idata,int iw,int ih,int rx,int ry,int rw,int rh,
152       uint8_t *odata,int ow,int oh,int sx,int sy,int sw,int sh)
153 {
154         if( rw < 3 || rh < 3 || sw < 3 || sh < 3 ) return;
155         const int ibpp=1, obpp=1;
156         int x, y, dx, dy;
157         int rsz = ibpp*iw, ssz = obpp*ow;
158         double rw0=rw, rh0=rh;
159         double ow0=sw, oh0=sh;
160         double px = rw0/ow0, py = rh0/oh0;
161         double pz = (ow0*oh0)/(rw0*rh0);
162         double ly = 0.0;
163         odata += sy*ssz + obpp*sx;
164
165         for( dy=1; dy<=sh; ++dy,odata+=ssz ) {
166                 int iy0 = (int)ly;
167                 double yf0 = ly - iy0;
168                 double ny = dy*py + 1e-99;
169                 int iy1 = (int)ny;
170                 double yf1 = ny - iy1;
171                 uint8_t *bp = odata;
172                 double lx = 0.0;
173
174                 for( dx=1; dx<=sw; ++dx ) {
175                         int ix0 = (int)lx;
176                         double xf0 = lx - ix0;
177                         double nx = dx*px + 1e-99;
178                         int ix1 = (int)nx;
179                         double xf1 = nx - ix1;
180                         double r=0.0;
181                         for( y=iy0; y<=iy1; ++y ) {
182                                 int idy = rsz * (y + ry);
183                                 uint8_t *row = &idata[idy];
184                                 double yw = pz;
185                                 if( y == iy0 ) yw *= (y==iy1 ? yf1-yf0 : 1.0-yf0);
186                                 else if( y == iy1 ) yw *= yf1;
187                                 if( yw <= 0.0 ) continue;
188                                 for( x=ix0; x<=ix1; ++x ) {
189                                         double xyw = yw;
190                                         if( x == ix0 ) xyw *= (x==ix1 ? xf1-xf0 : 1.0-xf0);
191                                         else if( x == ix1 ) xyw *= xf1;
192                                         if( xyw <= 0.0 ) continue;
193                                         int idx = ibpp*(x + rx);
194                                         uint8_t *cp = &row[idx];
195                                         r += cp[0]*xyw;
196                                 }
197                         }
198                         *bp++ = r + 0.5;
199                         xf0 = xf1;
200                         lx = nx;
201                 }
202                 yf0 = yf1;
203                 ly = ny;
204         }
205 }
206
207 void write_pbm(uint8_t *tp, int w, int h, const char *fmt, ...)
208 {
209   va_list ap;    va_start(ap, fmt);
210   char fn[256];  vsnprintf(fn, sizeof(fn), fmt, ap);
211   va_end(ap);
212   FILE *fp = !strcmp(fn,"-") ? stdout : fopen(fn,"w");
213   if( fp ) {
214     fprintf(fp,"P5\n%d %d\n255\n",w,h);
215     fwrite(tp,w,h,fp);
216     fclose(fp);
217   }
218 }
219
220 #endif
221
222 int main(int ac,char **av)
223 {
224   Window w, root;
225   Display *display;
226   GC gc;
227   XGCValues gcv;
228   XEvent xev;
229   XImage *image;
230   Visual *visual;
231   Screen *screen;
232   Atom aMsg;
233   char *pixels;
234   int n, depth, depthfactor;
235   int client_msg;
236
237   setbuf(stdout,NULL);
238   if( db.open(av[1]) ) {
239     fprintf(stderr,"cant open db: %s\n",av[1]);
240     exit(1);
241   }
242   int clip_id = atoi(av[2]);
243   if( db.clip_set.FindId(clip_id) ) {
244     printf("cant open clip %d\n",clip_id);
245     exit(1);
246   }
247   double framerate = db.clip_set.Framerate();
248   int ret = TimelineLoc::ikey_Sequences(db.timeline,clip_id,0).Locate();
249   if( ret || clip_id != (int)db.timeline.Clip_id() ) {
250     printf("cant access timeline of clip %d\n",clip_id);
251     exit(1);
252   }
253   int frame_no = 0, frame_id = -1;
254   uint8_t *dat = 0;
255
256   display = XOpenDisplay(NULL);
257   if( display == NULL ) {
258     fprintf(stderr,"cant open display\n");
259     exit(1);
260   }
261
262   root = RootWindow(display,0);
263   screen = DefaultScreenOfDisplay(display);
264   depth = DefaultDepthOfScreen(screen);
265   visual = DefaultVisualOfScreen(screen);
266   client_msg = 0;
267  
268   switch( visual->c_class ) {
269   case TrueColor:
270     depthfactor = 4;
271     break;  
272   default:
273     fprintf(stderr,"bad visual class %d\n",visual->c_class);
274     exit(1);
275   }
276
277   w = XCreateSimpleWindow(display, root, 0, 0, WIDTH, HEIGHT,
278           0, 0, WhitePixelOfScreen(screen));
279
280   pixels = (char *) malloc(HEIGHT*WIDTH*depthfactor);
281   image = XCreateImage( display,  visual, depth, ZPixmap, 0,
282                         pixels, WIDTH, HEIGHT, 8, WIDTH*depthfactor);
283  
284   XSelectInput(display, w, ExposureMask|StructureNotifyMask|ButtonPressMask);
285   XMapWindow(display, w);
286   XFlush(display);
287   aMsg = XInternAtom(display,"dbtv",False);
288   gcv.function = GXcopy;
289   gcv.foreground = BlackPixelOfScreen(DefaultScreenOfDisplay(display));
290   gcv.line_width = 1;
291   gcv.line_style = LineSolid;
292   n = GCFunction|GCForeground|GCLineWidth|GCLineStyle;
293   gc = XCreateGC(display,w,n,&gcv);
294   double start_time = the_time();
295
296   while( done < 0 ) {
297     XNextEvent(display,&xev);
298     /* printf("xev.type = %d/%08x\n",xev.type,xev.xany.window); */
299     switch( xev.type ) {
300     case ButtonPress:
301       if( xev.xbutton.window != w ) continue;
302       if( xev.xbutton.button != Button1 ) {
303         done = 1;
304         break;
305       }
306       done = 0;
307       break;
308
309     case Expose:
310       if( client_msg != 0 ) break;
311       client_msg = 1; /* fall through */
312       start_time = the_time();
313
314     case ClientMessage:
315       frame_id = db.timeline.Frame_id();
316       if( db.video_frame.FindId(frame_id) ) {
317         printf("cant access frame %d (id %d) in clip %d\n",
318           frame_no, frame_id, clip_id);  done = 1;  break;
319       }
320       dat = db.video_frame._Frame_data();
321       //write_pbm(dat, SWIDTH,SHEIGHT, "%s/f%05d.pbm",av[2], fid);
322       uint8_t img[WIDTH*HEIGHT];
323       scale0(dat,SWIDTH,SHEIGHT, img,WIDTH,HEIGHT);
324 //      scale1(dat, SWIDTH,SHEIGHT, 0,0,SWIDTH,SHEIGHT,
325 //             img, WIDTH, HEIGHT,  0,0,WIDTH, HEIGHT);
326       loadImage(0,0, image, img, WIDTH, HEIGHT);
327       while( (int)(1000 * (frame_no/framerate - (the_time()-start_time))) > 0 ) {
328         usleep(1000);
329       }
330       ++frame_no;
331       XPutImage( display, w, gc, image, 0, 0, 0, 0, WIDTH, HEIGHT);
332       XFlush(display);
333       ret = TimelineLoc::rkey_Sequences(db.timeline).Next();
334       if( ret || clip_id != (int)db.timeline.Clip_id() ) { done = 1;  break; }
335       clientMsg(display,w,aMsg,32);
336       break;
337
338     case DestroyNotify:
339       done = 0;
340       break;
341     }
342   }
343
344   XCloseDisplay(display);
345   return done;
346 }
347