Credit Andrew R for finding the direct copy mods for exr and ppm sequences
[goodguy/cinelerra.git] / cinelerra-5.1 / libzmpeg3 / x.C
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <time.h>
8 #include <math.h>
9
10 #include <X11/X.h>
11 #include <X11/Xlib.h>
12 #include <X11/extensions/Xvlib.h>
13
14 #include <alsa/asoundlib.h>
15 #include <sys/time.h>
16 #include <sys/ipc.h>
17 #include <sys/shm.h>
18
19 #include "libzmpeg3/libzmpeg3.h"
20 #include "thr.h"
21
22 //c++ -pthread -I.. -I../db x.C ./x86_64/libzmpeg3.a ../db/x86_64/db.a -lX11 -lasound -lm
23 //c++ -g -pthread -I.. -I../db x.C ./x86_64/libzmpeg3.a ../db/x86_64/db.a -lX11 -lXext -lasound -lm
24
25 using namespace std;
26 int building = getenv("BUILDING") ? 1 : 0;
27
28 zmpeg3_t *ysrc;
29
30 const double nudge = 0.0;
31 const double ahead = 0.0;
32 static int verbose = 0;
33
34
35 //#define AUDIO
36 #define VIDEO
37 //#define DB
38 //#define LAST8M
39
40 #ifdef DB
41 #include "db.h"
42 #include "s.C"
43 #endif
44
45 #ifdef AUDIO
46 snd_pcm_t *zpcm = 0;
47 snd_pcm_uframes_t zpcm_ufrm_size = 0;
48 snd_pcm_sframes_t zpcm_sbfr_size = 0;
49 snd_pcm_sframes_t zpcm_sper_size = 0;
50 snd_pcm_sframes_t zpcm_total_samples = 0;
51 double zpcm_play_time = 0.;
52 Mutex zpcm_lock;
53 unsigned int zpcm_rate = 0;
54 static const char *zpcm_device = "plughw:0,0";
55 static unsigned int zpcm_bfr_time_us = 500000; 
56 static unsigned int zpcm_per_time_us = 200000;
57 static snd_pcm_channel_area_t *zpcm_areas = 0;
58 static int zpcm_channels = 0;
59 static short **zpcm_buffers = 0;
60 static short *zpcm_samples = 0;
61
62 void alsa_close()
63 {
64   if( zpcm_buffers != 0 ) { delete [] zpcm_buffers; zpcm_buffers = 0; }
65   if( zpcm_areas != 0 ) { delete [] zpcm_areas; zpcm_areas = 0; }
66   if( zpcm_samples != 0 ) { delete [] zpcm_samples; zpcm_samples = 0; }
67   if( zpcm != 0 ) { snd_pcm_close(zpcm);  zpcm = 0; }
68 }
69
70 void alsa_open(int chs,int rate)
71 {
72   int ich, bits, byts, dir, ret;
73   zpcm_lock.reset();
74   snd_pcm_format_t fmt = SND_PCM_FORMAT_S16;
75   snd_pcm_hw_params_t *phw;
76   snd_pcm_sw_params_t *psw;
77   snd_pcm_hw_params_alloca(&phw);
78   snd_pcm_sw_params_alloca(&psw);
79
80   zpcm = 0;
81   zpcm_total_samples = 0;
82   zpcm_play_time = 0.;
83   ret = snd_pcm_open(&zpcm, zpcm_device,
84      SND_PCM_STREAM_PLAYBACK, 0 /* + SND_PCM_NONBLOCK */);
85   if( ret >= 0 )
86     ret = snd_pcm_hw_params_any(zpcm, phw);
87   if( ret >= 0 )
88     ret = snd_pcm_hw_params_set_rate_resample(zpcm, phw, 1);
89   if( ret >= 0 )
90     ret = snd_pcm_hw_params_set_access(zpcm, phw,
91       SND_PCM_ACCESS_RW_NONINTERLEAVED);
92   if( ret >= 0 )
93     ret = snd_pcm_hw_params_set_format(zpcm, phw, fmt);
94   if( ret >= 0 ) {
95     zpcm_channels = chs;
96     ret = snd_pcm_hw_params_set_channels(zpcm, phw, chs);
97   }
98   if( ret >= 0 ) {
99     zpcm_rate = rate;
100     ret = snd_pcm_hw_params_set_rate_near(zpcm, phw, &zpcm_rate, 0);
101     if( (int)zpcm_rate != rate )
102       printf("nearest audio_rate for %d is %u\n",rate,zpcm_rate);
103   }
104   if( ret >= 0 )
105     ret = snd_pcm_hw_params_set_buffer_time_near(zpcm, phw,
106       &zpcm_bfr_time_us, &dir);
107   if( ret >= 0 )
108     ret = snd_pcm_hw_params_get_buffer_size(phw, &zpcm_ufrm_size);
109   if( ret >= 0 ) {
110     zpcm_sbfr_size = zpcm_ufrm_size;
111     ret = snd_pcm_hw_params_set_period_time_near(zpcm, phw,
112       &zpcm_per_time_us, &dir);
113   }
114   if( ret >= 0 )
115     ret = snd_pcm_hw_params_get_period_size(phw, &zpcm_ufrm_size, &dir);
116   if( ret >= 0 ) {
117     zpcm_sper_size = zpcm_ufrm_size;
118     ret = snd_pcm_hw_params(zpcm, phw);
119   }
120   if( ret >= 0 )
121     ret = snd_pcm_sw_params_current(zpcm, psw);
122   if( ret >= 0 )
123     ret = snd_pcm_sw_params_set_start_threshold(zpcm, psw,
124       (zpcm_sbfr_size / zpcm_sper_size) * zpcm_sper_size);
125   if( ret >= 0 )
126     ret = snd_pcm_sw_params_set_avail_min(zpcm, psw, zpcm_sper_size);
127   if( ret >= 0 )
128     ret = snd_pcm_sw_params(zpcm, psw);
129   /* snd_pcm_dump(zpcm, stdout); */
130
131   if( ret >= 0 ) {
132      zpcm_areas = new snd_pcm_channel_area_t[chs];
133      bits = snd_pcm_format_physical_width(fmt);
134      byts = (bits+7) / 8;
135      zpcm_samples = new short[zpcm_sper_size * chs * (byts+1)/2];
136      zpcm_buffers = new short *[chs];
137      if( zpcm_samples ) {
138        for( ich = 0; ich < chs; ++ich ) {
139          zpcm_areas[ich].addr = zpcm_samples;
140          zpcm_areas[ich].first = ich * zpcm_sper_size * bits;
141          zpcm_areas[ich].step = bits;
142          zpcm_buffers[ich] = zpcm_samples + ich*zpcm_sper_size;
143        }
144      }
145      else {
146        fprintf(stderr,"alsa sample buffer allocation failure.\n");
147        ret = -999;
148      }
149   }
150   if( ret < 0 ) {
151     if( ret > -999 )
152       printf("audio error: %s\n", snd_strerror(ret));
153     alsa_close();
154   }
155 }
156
157 short *alsa_bfr(int ch) { return zpcm_buffers[ch]; }
158 int alsa_bfrsz() { return zpcm_sper_size; }
159
160 int alsa_recovery(int ret)
161 {
162   printf("alsa recovery\n");
163   switch( ret ) {
164   case -ESTRPIPE:
165     /* wait until the suspend flag is released, then fall through */
166     while( (ret=snd_pcm_resume(zpcm)) == -EAGAIN ) usleep(100000);
167   case -EPIPE:
168     ret = snd_pcm_prepare(zpcm);
169     if( ret < 0 )
170       printf("underrun, prepare failed: %s\n", snd_strerror(ret));
171     break;
172   default:
173     printf("unhandled error: %s\n",snd_strerror(ret));
174     break;
175   }
176   return ret;
177 }
178
179 int alsa_write(int length)
180 {
181   struct timeval tv;
182   int i, ret, count, retry;
183   snd_pcm_sframes_t sample_delay;
184   double play_time, time;
185   short *bfrs[zpcm_channels];
186   retry = 3;
187   ret = count = 0;
188   for( i=0; i<zpcm_channels; ++i ) bfrs[i] = zpcm_buffers[i];
189
190   while( count < length ) {
191     ret = snd_pcm_writen(zpcm,(void **)bfrs, length-count);
192     if( ret == -EAGAIN ) continue;
193     if ( ret < 0 ) {
194       if( --retry < 0 ) return ret;
195       alsa_recovery(ret);
196       ret = 0;
197       continue;
198     }
199     for( i=0; i<zpcm_channels; ++i ) bfrs[i] += ret;
200     count += ret;
201   }
202   zpcm_lock.lock();
203   zpcm_total_samples += count;
204   snd_pcm_delay(zpcm,&sample_delay);
205   if( sample_delay > zpcm_total_samples )
206     sample_delay = zpcm_total_samples;
207   gettimeofday(&tv,NULL);
208   time = tv.tv_sec + tv.tv_usec/1000000.0;
209   play_time = (zpcm_total_samples - sample_delay) / (double)zpcm_rate;
210   zpcm_play_time = time - play_time;
211   zpcm_lock.unlock();
212   return ret < 0 ? ret : 0;
213 }
214
215 double alsa_time()
216 {
217   double time, play_time;
218   struct timeval tv;
219   zpcm_lock.lock();
220   gettimeofday(&tv,NULL);
221   time = tv.tv_sec + tv.tv_usec/1000000.0;
222   play_time = time - zpcm_play_time;
223   zpcm_lock.unlock();
224   return play_time;
225 }
226
227 #else
228
229 double alsa_time()
230 {
231   double time, play_time;
232   struct timeval tv;
233   gettimeofday(&tv,NULL);
234   time = tv.tv_sec + tv.tv_usec/1000000.0;
235   return time;
236 }
237
238 #endif
239
240
241 double tstart;
242
243 double the_time()
244 {
245   double time;
246   struct timeval tv;
247   gettimeofday(&tv,NULL);
248   time = tv.tv_sec + tv.tv_usec/1000000.0;
249   if( tstart < 0. ) tstart = time;
250   return time - tstart;
251 }
252
253
254 void mpeg3_stats(zmpeg3_t *zsrc)
255 {
256   int astream, vstream;
257   int has_audio, total_astreams, audio_channels, sample_rate;
258   int has_video, total_vstreams, width, height, colormodel;
259   long audio_samples, video_frames;
260   float frame_rate;
261
262   has_audio = mpeg3_has_audio(zsrc);
263   printf(" has_audio = %d\n", has_audio);
264   total_astreams = mpeg3_total_astreams(zsrc);
265   printf(" total_astreams = %d\n", total_astreams);
266   for( astream=0; astream<total_astreams; ++astream ) {
267     audio_channels = zsrc->audio_channels(astream);
268     printf("   audio_channels = %d\n", audio_channels);
269     sample_rate = zsrc->sample_rate(astream);
270     printf("   sample_rate = %d\n", sample_rate);
271     audio_samples = zsrc->audio_samples(astream);
272     printf("   audio_samples = %ld\n", audio_samples);
273   }
274   printf("\n");
275   has_video = mpeg3_has_video(zsrc);
276   printf(" has_video = %d\n", has_video);
277   total_vstreams = mpeg3_total_vstreams(zsrc);
278   printf(" total_vstreams = %d\n", total_vstreams);
279   for( vstream=0; vstream<total_vstreams; ++vstream ) {
280     width = zsrc->video_width(vstream);
281     printf("   video_width = %d\n", width);
282     height = zsrc->video_height(vstream);
283     printf("   video_height = %d\n", height);
284     frame_rate = zsrc->frame_rate(vstream);
285     printf("   frame_rate = %f\n", frame_rate);
286     video_frames = zsrc->video_frames(vstream);
287     printf("   video_frames = %ld\n", video_frames);
288     colormodel = zsrc->colormodel(vstream);
289     printf("   colormodel = %d\n", colormodel);
290   }
291 }
292
293 #ifdef DB
294
295 class mdb_q : public Condition {
296   class pkt_q;
297   class pkt_t;
298
299   class pkt_t {
300     pkt_t *next;
301   public:
302     friend class pkt_q;
303     friend class mdb_q;
304
305     long framenum;
306     int len;
307     uint8_t *bfr;
308
309     uint8_t *dat() { return bfr; }
310     pkt_t(int sz) { bfr = new uint8_t[sz]; }
311     ~pkt_t() { delete [] bfr; }
312   };
313
314   class pkt_q : Mutex {
315     pkt_t *list;
316   public:
317     friend class mdb_q;
318     pkt_t *get();
319     void put(pkt_t *p);
320
321     pkt_q() : list(0) {}
322     ~pkt_q() { for( pkt_t *p=list; p!=0; ) { list=p->next; delete p; } }
323   } avail, packets;
324
325 public: 
326   typedef pkt_t pkt;
327   typedef pkt_q pktq;
328
329   void init(int qsize, int bsize);
330   pkt *avl_get() { return avail.get(); }
331   void avl_put(pkt *p) { avail.put(p); }
332   pkt *pkt_get() { return packets.get(); }
333   void pkt_put(pkt *p) { packets.put(p); }
334
335   mdb_q() {}
336   ~mdb_q() {}
337 };
338
339 typedef mdb_q::pkt mdb_pkt;
340 typedef mdb_q::pktq mdb_pktq;
341
342
343 mdb_pkt *mdb_pktq::get()
344 {
345   pkt_t *p = 0;
346   lock();
347   if( list ) {
348     p = list->next;
349     if( p == list ) list = 0;
350     else list->next = p->next;
351   }
352   unlock();
353   return p;
354 }
355
356 void mdb_pktq::put(mdb_pkt *p)
357 {
358   lock();
359   if( !list ) list = p;
360   else p->next = list->next;
361   list->next = p;
362   list = p;
363   unlock();
364 }
365
366 void mdb_q::init(int qsize, int bsize)
367 {
368   pkt_t **qp = &avail.list;
369   while( --qsize >= 0 ) {
370     pkt_t *p = new pkt_t(bsize);
371     *qp = p;  qp = &p->next;
372   }
373   *qp = avail.list;
374 }
375
376
377 class Media : public Thread {
378 public:
379   theDb db;
380   mdb_q q;
381
382   void run();
383   void newDb(const char *dfn);
384   void openDb(const char *dfn);
385   void closeDb();
386   void add_key(uint8_t *dat, int sz, int id, double tm);
387   void get_key(uint8_t *dat, int sz, int &id, double &tm);
388
389   Media() { q.init(32,9600); }
390   ~Media() {}
391 } *the_db;
392
393 void Media::newDb(const char *dfn)
394 {
395   if( db.create(dfn) ) {
396     fprintf(stderr,"Media::db.create failed\n");
397     exit(1);
398   }
399 }
400
401 void Media::openDb(const char *dfn)
402 {
403   if( db.open(dfn) ) {
404     fprintf(stderr,"Media::db.open failed\n");
405     exit(1);
406   }
407 }
408
409 void Media::closeDb()
410 {
411   db.close();
412 }
413
414 void Media::add_key(uint8_t *dat, int sz, int id, double tm)
415 {
416 printf("add %d\n",id);
417   db.prefix.Allocate();
418   db.prefix.Clip_id(id);
419   db.prefix.Time_offset(tm);
420   int ksz = Db::mediaKey::byte_size(sz, 8);
421   uint8_t *key = db.prefix._Key_data(ksz);
422   Db::mediaKey::build(key, dat, 8, sz);
423   db.prefix.Construct();
424   db.commit();
425 }
426
427 void Media::get_key(uint8_t *dat, int sz, int &id, double &tm)
428 {
429   int ksz = Db::mediaKey::byte_size(sz, 8);
430   uint8_t key[ksz];
431   Db::mediaKey::build(key, dat, 8, sz);
432   int ret = PrefixLoc::ikey_Prefix_key_data(db.prefix,
433       PrefixObj::t_Key_data(key, ksz)).Find();
434   if( ret != 0 ) {
435 printf(" not found, ret = %d\n",ret);
436     return;
437   }
438
439   id = db.prefix.Clip_id();
440   tm = db.prefix.Time_offset();
441 printf("found id = %d\n",id);
442 }
443
444
445 void Media::run()
446 {
447   if( building ) newDb("/tmp/dat/media.db");
448   openDb("/tmp/dat/media.db");
449   q.lock();
450
451   while( !q.lock() && running() ) {
452     mdb_pkt *p;
453     while( (p=q.pkt_get()) != 0 ) {
454       if( building ) {
455         double tm = 0.0;  int id = p->framenum;
456         add_key(p->dat(), p->len, id, tm);
457       }
458       else {
459         double tm = 0.0;  int id = -1;
460         get_key(p->dat(), p->len, id, tm);
461       }
462       q.avl_put(p);
463     }
464   }
465   closeDb();
466 }
467
468 #endif
469
470 #ifdef VIDEO
471
472 class Video : public Thread {
473   zmpeg3_t *zsrc;
474   double vstart;
475   double last_vtime;
476   double video_time(int stream);
477
478 public:
479   void run();
480
481   Video(zmpeg3_t *z) : zsrc(z) {}
482   ~Video() {}
483 } *the_video;
484
485
486 double Video::video_time(int stream)
487 {
488   double vtime = zsrc->get_video_time(stream);
489   double vnow = vtime;
490   if( vstart == 0. ) vstart = vnow;
491   if( vtime < last_vtime )
492     vstart -= last_vtime;
493   last_vtime = vtime;
494   return vnow - vstart + nudge;
495 }
496
497 void Video::run()
498 {
499   Window w, root;
500   Display *display;
501   GC gc;
502   XGCValues gcv;
503   XEvent xev;
504   XImage *image0, *image1, *image;
505   Visual *visual;
506   Screen *screen;
507   XShmSegmentInfo info0, info1;
508   int done;
509   double delay;
510   float frame_rate, frame_delay;
511   uint8_t **rows, **row0, **row1, *cap, *cap0, *cap1;
512   int ret, row, frame, dropped, more_data;
513   int width, height, depth, owidth, oheight;
514   const int frame_drop = 0;
515   const int shared_memory = 1;
516
517   display = XOpenDisplay(NULL);
518   if( display == NULL ) {
519     fprintf(stderr,"cant open display\n");
520     exit(1);
521   }
522
523   root = RootWindow(display,0);
524   screen = DefaultScreenOfDisplay(display);
525   depth = DefaultDepthOfScreen(screen);
526   visual = DefaultVisualOfScreen(screen);
527   if( visual->c_class != TrueColor ) {
528     printf("visual class not truecolor\n");
529     exit(1);
530   }
531   int image_bpp = 4;
532  
533   frame_rate = zsrc->frame_rate(0);
534   frame_delay = 2.0 / frame_rate;
535   height = zsrc->video_height(0);
536   width = zsrc->video_width(0);
537
538   //oheight = 2*height / 3;
539   //owidth = 2*width / 3;
540   //oheight = 1050-96;
541   //owidth = 1680-64;
542   //oheight = height;
543   //owidth = width;
544   oheight = 720;
545   owidth = 1280;
546
547   w = XCreateSimpleWindow(display, root, 0, 0, owidth, oheight,
548           0, 0, WhitePixelOfScreen(screen));
549   XSelectInput(display, w, ExposureMask|StructureNotifyMask|ButtonPressMask);
550
551   if( !shared_memory ) {
552     int sz0 = oheight*owidth*image_bpp + 4;
553     cap0 = new uint8_t[sz0];
554     image0 = XCreateImage(display, visual, depth, ZPixmap, 0,
555                (char*)cap0, owidth, oheight, 8, owidth*4);
556     int sz1 = oheight*owidth*image_bpp + 4;
557     cap1 = new uint8_t[sz1];
558     image1 = XCreateImage(display, visual, depth, ZPixmap, 0,
559                (char*)cap1, owidth, oheight, 8, owidth*4);
560   }
561   else {
562     image0 = XShmCreateImage(display, visual, depth, ZPixmap, 0,
563                &info0, owidth, oheight);
564     int sz0 = oheight*image0->bytes_per_line+image_bpp;
565     info0.shmid = shmget(IPC_PRIVATE, sz0, IPC_CREAT | 0777);
566     if( info0.shmid < 0) { perror("shmget"); exit(1); }
567     cap0 = (uint8_t *)shmat(info0.shmid, NULL, 0);
568     shmctl(info0.shmid, IPC_RMID, 0);
569     image0->data = info0.shmaddr = (char *)cap0;
570     info0.readOnly = 0;
571     XShmAttach(display,&info0);
572     image1 = XShmCreateImage(display, visual, depth, ZPixmap, 0,
573                &info1, owidth, oheight);
574     int sz1 = oheight*image1->bytes_per_line+image_bpp;
575     info1.shmid = shmget(IPC_PRIVATE, sz1, IPC_CREAT | 0777);
576     if( info1.shmid < 0) { perror("shmget"); exit(1); }
577     cap1 = (uint8_t *)shmat(info1.shmid, NULL, 0);
578     shmctl(info1.shmid, IPC_RMID, 0);
579     image1->data = info1.shmaddr = (char *)cap1;
580     info1.readOnly = 0;
581     XShmAttach(display,&info1);
582   }
583
584   row0 = new uint8_t *[oheight];
585   row1 = new uint8_t *[oheight];
586   for( row=0; row<oheight; ++row ) {
587     row0[row] = cap0 + row*owidth*image_bpp;
588     row1[row] = cap1 + row*owidth*image_bpp;
589   }
590
591   cap = cap0;
592   rows = row0;
593   image = image0;
594   if( image->bits_per_pixel != 32 ) {
595     printf("image bits_per_pixel=%d\n",image->bits_per_pixel);
596     exit(1);
597   }
598   int cmdl = -1;
599   unsigned int rmsk = image->red_mask;
600   unsigned int gmsk = image->green_mask;
601   unsigned int bmsk = image->blue_mask;
602   switch( image_bpp ) {
603   case 4:
604     if( bmsk==0xff0000 && gmsk==0x00ff00 && rmsk==0x0000ff )
605       cmdl = zmpeg3_t::cmdl_RGBA8888;
606     else if( bmsk==0x0000ff && gmsk==0x00ff00 && rmsk==0xff0000 )
607       cmdl = zmpeg3_t::cmdl_BGRA8888;
608     break;
609   case 3:
610     if( bmsk==0xff0000 && gmsk==0x00ff00 && rmsk==0x0000ff )
611       cmdl = zmpeg3_t::cmdl_RGB888;
612     else if( bmsk==0x0000ff && gmsk==0x00ff00 && rmsk==0xff0000 )
613       cmdl = zmpeg3_t::cmdl_BGR888;
614     break;
615   case 2:
616     if( bmsk==0x00f800 && gmsk==0x0007e0 && rmsk==0x00001f )
617       cmdl = zmpeg3_t::cmdl_RGB565;
618     break;
619   }
620   if( cmdl < 0 ) {
621     printf("unknown color model, bpp=%d, ",image_bpp);
622     printf(" rmsk=%08x,gmsk=%08x,bmsk=%08x\n", rmsk, gmsk, bmsk);
623     exit(1);
624   }
625
626   XMapWindow(display, w);
627   XFlush(display);
628   gcv.function = GXcopy;
629   gcv.foreground = BlackPixelOfScreen(DefaultScreenOfDisplay(display));
630   gcv.line_width = 1;
631   gcv.line_style = LineSolid;
632   int m = GCFunction|GCForeground|GCLineWidth|GCLineStyle;
633   gc = XCreateGC(display,w,m,&gcv);
634
635   frame = dropped = 0;
636   vstart = last_vtime = 0.;
637   more_data = 1;
638   done = 0;
639
640   while( !done && running() && more_data ) {
641     if( !XPending(display) ) {
642       more_data = 0;
643       delay = (frame+dropped)/frame_rate - alsa_time();
644 //      delay = the_time() - video_time(zsrc,0);
645       if( frame_drop ) {
646         if( -delay >= frame_delay ) {
647           int nframes = (long)ceil(-delay/frame_rate);
648           if( nframes > 2 ) nframes = 2;
649           zsrc->drop_frames(nframes,0);
650           dropped += nframes;
651         }
652       }
653       //printf("delay %f\n",delay*1000.);
654       if( delay > 0 )
655         usleep((int)(delay*1000000.0));
656       ret = zsrc->read_frame(rows, 0, 0, width, height,
657                owidth, oheight, cmdl, 0);
658       //printf("%d %ld\n",frame,zsrc->vtrack[0]->demuxer->titles[0]->fs->current_byte);
659       if( verbose )
660         printf("read_video(stream=%d, frame=%d) = %d, %f sec\n", 0, frame, ret, the_time());
661       ++frame;
662
663       if( !shared_memory )
664         XPutImage(display, w, gc, image, 0, 0, 0, 0, owidth, oheight);
665       else
666         XShmPutImage(display, w, gc, image, 0, 0, 0, 0, owidth, oheight, False);
667
668 #ifdef DB
669       mdb_pkt *p = the_db->q.avl_get();
670       if( p ) {
671         uint8_t *bp;  int w, h, frn;
672         zsrc->get_thumbnail(0,frn,bp,w,h);
673         p->framenum = frn;
674 printf("put %d\n",frame);
675         uint8_t *bfr = p->dat();
676         memcpy(bfr,bp,p->len=w*h);
677         the_db->q.pkt_put(p);
678         the_db->q.unlock();
679       }
680 #endif
681
682       cap = cap==cap0 ?
683         (rows=row1, image=image1, cap1) :
684         (rows=row0, image=image0, cap0) ;
685       //printf(" %d/%d  %f  %f  %f\n",frame,dropped,(frame+dropped)/frame_rate,
686       //  video_time(zsrc,0),zsrc->get_video_time(0));
687       more_data |= !zsrc->end_of_video(0);
688     }
689     else {
690       XNextEvent(display,&xev);
691       /* printf("xev.type = %d/%08x\n",xev.type,xev.xany.window); */
692       switch( xev.type ) {
693       case ButtonPress:
694         if( xev.xbutton.window != w ) continue;
695         if( xev.xbutton.button != Button1 )
696           done = 1;
697         break;
698       case Expose:
699         break;
700       case DestroyNotify:
701         done = 1;
702         break;
703       }
704     }
705   }
706
707   XCloseDisplay(display);
708   delete [] row0; row0 = 0;
709   delete [] row1; row1 = 0;
710 }
711
712 #endif
713
714 #ifdef AUDIO
715
716 class Audio : public Thread {
717   zmpeg3_t *zsrc;
718   double astart;
719   double audio_time(int stream);
720
721 public:
722   void run();
723
724   Audio(zmpeg3_t *z) : zsrc(z) {}
725   ~Audio() {}
726 } *the_audio;
727
728
729 double Audio::audio_time(int stream)
730 {
731   double anow = zsrc->get_audio_time(stream);
732   if( astart < 0. ) astart = anow;
733   return anow - astart;
734 }
735
736 void Audio::run()
737 {
738   double delay;
739   int audio_channels, sample_rate, more_data;
740   int stream = 0;
741
742   audio_channels = zsrc->audio_channels(stream);
743   sample_rate = zsrc->sample_rate(stream);
744   alsa_open(audio_channels,sample_rate);
745   astart = -1.;
746   more_data = 1;
747
748   while( running() && more_data ) {
749     more_data = 0;
750     int ich;
751     int n = alsa_bfrsz();
752     for( ich=0; ich<audio_channels; ++ich) {
753       short *bfr = alsa_bfr(ich);
754       int ret = ich == 0 ?
755         zsrc->read_audio(bfr, ich, n, stream) :
756         zsrc->reread_audio(bfr, ich, n, stream);
757       if( verbose )
758         printf("read_audio(stream=%d,channel=%d) = %d\n", stream, ich, ret);
759     }
760
761     alsa_write(n);
762     delay = audio_time(stream) - the_time();
763     if( (delay-=ahead) > 0. ) {
764       usleep((int)(delay*1000000.0/2.));
765     }
766     more_data |= !zsrc->end_of_audio(0);
767   }
768
769   alsa_close();
770 }
771
772 #endif
773
774 void sigint(int n)
775 {
776 #ifdef VIDEO
777   the_video->cancel();
778 #endif
779 #ifdef AUDIO
780   the_audio->cancel();
781 #endif
782 #ifdef DB
783   the_db->cancel();
784 #endif
785 }
786
787
788 int main(int ac, char **av)
789 {
790   int ret;
791   long pos;
792 #ifdef LAST8M
793   struct stat st_buf;
794 #endif
795   setbuf(stdout,NULL);
796   tstart = -1.;
797
798 #ifdef VIDEO
799   XInitThreads();
800 #endif
801
802   zmpeg3_t* zsrc = new zmpeg3_t(av[1],ret);
803   ysrc = zsrc;
804   printf(" ret = %d\n",ret);
805   if( ret != 0 ) exit(1);
806   mpeg3_stats(zsrc);
807
808   zsrc->set_cpus(8);
809   pos = 0;
810 #ifdef LAST8M
811   if( stat(zsrc->fs->path, &st_buf) >= 0 ) {
812     if( (pos = (st_buf.st_size & ~0x7ffl) - 0x800000l) < 0 )
813       pos = 0;
814   }
815 #endif
816   zsrc->seek_byte(pos);
817 //  zsrc->show_subtitle(0);
818   signal(SIGINT,sigint);
819
820 #ifdef DB
821   the_db = new Media();
822 #endif
823 #ifdef AUDIO
824   the_audio = new Audio(zsrc);
825 #endif
826 #ifdef VIDEO
827   the_video = new Video(zsrc);
828 #endif
829 #ifdef DB
830   the_db->start();
831 #endif
832 #ifdef AUDIO
833   the_audio->start();
834 #endif
835 #ifdef VIDEO
836   the_video->start();
837 #endif
838 #ifdef VIDEO
839   the_video->join();
840 #endif
841 #ifdef AUDIO
842   the_audio->join();
843 #endif
844 #ifdef DB
845   the_db->join();
846 #endif
847
848   delete zsrc;
849   return 0;
850 }
851