12 #include <X11/extensions/Xvlib.h>
14 #include <alsa/asoundlib.h>
19 #include "libzmpeg3/libzmpeg3.h"
24 c++ -g -pthread -I../.. -I ../guicast xtv.C \
25 ../../cinelerra/x86_64/mediadb.o ../../cinelerra/x86_64/filexml.o \
26 ../../libzmpeg/x86_64/libzmpeg3.a ../../db/x86_64/db.a \
27 -lX11 -lXext -lasound -lm
31 int building = getenv("BUILDING") ? 1 : 0;
35 const double nudge = 0.0;
36 const double ahead = 0.0;
37 static int verbose = 0;
39 typedef int (*skim_fn)(void *vp, int track);
50 snd_pcm_uframes_t zpcm_ufrm_size = 0;
51 snd_pcm_sframes_t zpcm_sbfr_size = 0;
52 snd_pcm_sframes_t zpcm_sper_size = 0;
53 snd_pcm_sframes_t zpcm_total_samples = 0;
54 double zpcm_play_time = 0.;
56 unsigned int zpcm_rate = 0;
57 static const char *zpcm_device = "plughw:0,0";
58 static unsigned int zpcm_bfr_time_us = 500000;
59 static unsigned int zpcm_per_time_us = 200000;
60 static snd_pcm_channel_area_t *zpcm_areas = 0;
61 static int zpcm_channels = 0;
62 static short **zpcm_buffers = 0;
63 static short *zpcm_samples = 0;
64 static short *zpcm_silence = 0;
65 static int alsa_mute = 0;
69 if( zpcm_buffers != 0 ) { delete [] zpcm_buffers; zpcm_buffers = 0; }
70 if( zpcm_areas != 0 ) { delete [] zpcm_areas; zpcm_areas = 0; }
71 if( zpcm_silence != 0 ) { delete [] zpcm_silence; zpcm_silence = 0; }
72 if( zpcm_samples != 0 ) { delete [] zpcm_samples; zpcm_samples = 0; }
73 if( zpcm != 0 ) { snd_pcm_close(zpcm); zpcm = 0; }
76 void alsa_open(int chs,int rate)
78 int ich, bits, dir, ret;
80 snd_pcm_format_t fmt = SND_PCM_FORMAT_S16;
81 snd_pcm_hw_params_t *phw;
82 snd_pcm_sw_params_t *psw;
83 snd_pcm_hw_params_alloca(&phw);
84 snd_pcm_sw_params_alloca(&psw);
87 zpcm_total_samples = 0;
89 ret = snd_pcm_open(&zpcm, zpcm_device,
90 SND_PCM_STREAM_PLAYBACK, 0 /* + SND_PCM_NONBLOCK */);
92 ret = snd_pcm_hw_params_any(zpcm, phw);
94 ret = snd_pcm_hw_params_set_rate_resample(zpcm, phw, 1);
96 ret = snd_pcm_hw_params_set_access(zpcm, phw,
97 SND_PCM_ACCESS_RW_NONINTERLEAVED);
99 ret = snd_pcm_hw_params_set_format(zpcm, phw, fmt);
102 ret = snd_pcm_hw_params_set_channels(zpcm, phw, chs);
106 ret = snd_pcm_hw_params_set_rate_near(zpcm, phw, &zpcm_rate, 0);
107 if( (int)zpcm_rate != rate )
108 printf("nearest audio_rate for %d is %u\n",rate,zpcm_rate);
111 ret = snd_pcm_hw_params_set_buffer_time_near(zpcm, phw,
112 &zpcm_bfr_time_us, &dir);
114 ret = snd_pcm_hw_params_get_buffer_size(phw, &zpcm_ufrm_size);
116 zpcm_sbfr_size = zpcm_ufrm_size;
117 ret = snd_pcm_hw_params_set_period_time_near(zpcm, phw,
118 &zpcm_per_time_us, &dir);
121 ret = snd_pcm_hw_params_get_period_size(phw, &zpcm_ufrm_size, &dir);
123 zpcm_sper_size = zpcm_ufrm_size;
124 ret = snd_pcm_hw_params(zpcm, phw);
127 ret = snd_pcm_sw_params_current(zpcm, psw);
129 ret = snd_pcm_sw_params_set_start_threshold(zpcm, psw,
130 (zpcm_sbfr_size / zpcm_sper_size) * zpcm_sper_size);
132 ret = snd_pcm_sw_params_set_avail_min(zpcm, psw, zpcm_sper_size);
134 ret = snd_pcm_sw_params(zpcm, psw);
135 /* snd_pcm_dump(zpcm, stdout); */
138 zpcm_areas = new snd_pcm_channel_area_t[chs];
139 bits = snd_pcm_format_physical_width(fmt);
140 zpcm_silence = new short[zpcm_sper_size];
141 memset(zpcm_silence,0,zpcm_sper_size*sizeof(zpcm_silence[0]));
142 zpcm_samples = new short[zpcm_sper_size * chs];
143 zpcm_buffers = new short *[chs];
145 for( ich = 0; ich < chs; ++ich ) {
146 zpcm_areas[ich].addr = zpcm_samples;
147 zpcm_areas[ich].first = ich * zpcm_sper_size * bits;
148 zpcm_areas[ich].step = bits;
149 zpcm_buffers[ich] = zpcm_samples + ich*zpcm_sper_size;
153 fprintf(stderr,"alsa sample buffer allocation failure.\n");
159 printf("audio error: %s\n", snd_strerror(ret));
164 short *alsa_bfr(int ch) { return zpcm_buffers[ch]; }
165 int alsa_bfrsz() { return zpcm_sper_size; }
167 int alsa_recovery(int ret)
169 printf("alsa recovery\n");
172 /* wait until the suspend flag is released, then fall through */
173 while( (ret=snd_pcm_resume(zpcm)) == -EAGAIN ) usleep(100000);
175 ret = snd_pcm_prepare(zpcm);
177 printf("underrun, prepare failed: %s\n", snd_strerror(ret));
180 printf("unhandled error: %s\n",snd_strerror(ret));
186 int alsa_write(int length)
189 int i, ret, count, retry;
190 snd_pcm_sframes_t sample_delay;
191 double play_time, time;
192 short *bfrs[zpcm_channels];
195 for( i=0; i<zpcm_channels; ++i ) bfrs[i] = alsa_mute ? zpcm_silence : zpcm_buffers[i];
197 while( count < length ) {
198 ret = snd_pcm_writen(zpcm,(void **)bfrs, length-count);
199 if( ret == -EAGAIN ) continue;
201 if( --retry < 0 ) return ret;
206 for( i=0; i<zpcm_channels; ++i ) bfrs[i] += ret;
210 zpcm_total_samples += count;
211 snd_pcm_delay(zpcm,&sample_delay);
212 if( sample_delay > zpcm_total_samples )
213 sample_delay = zpcm_total_samples;
214 gettimeofday(&tv,NULL);
215 time = tv.tv_sec + tv.tv_usec/1000000.0;
216 play_time = (zpcm_total_samples - sample_delay) / (double)zpcm_rate;
217 zpcm_play_time = time - play_time;
219 return ret < 0 ? ret : 0;
224 double time, play_time;
227 gettimeofday(&tv,NULL);
228 time = tv.tv_sec + tv.tv_usec/1000000.0;
229 play_time = time - zpcm_play_time;
240 gettimeofday(&tv,NULL);
241 time = tv.tv_sec + tv.tv_usec/1000000.0;
254 gettimeofday(&tv,NULL);
255 time = tv.tv_sec + tv.tv_usec/1000000.0;
256 if( tstart < 0. ) tstart = time;
257 return time - tstart;
261 void mpeg3_stats(zmpeg3_t *zsrc)
263 int astream, vstream;
264 int has_audio, total_astreams, audio_channels, sample_rate;
265 int has_video, total_vstreams, width, height, colormodel;
266 long audio_samples, video_frames;
269 has_audio = mpeg3_has_audio(zsrc);
270 printf(" has_audio = %d\n", has_audio);
271 total_astreams = mpeg3_total_astreams(zsrc);
272 printf(" total_astreams = %d\n", total_astreams);
273 for( astream=0; astream<total_astreams; ++astream ) {
274 audio_channels = zsrc->audio_channels(astream);
275 printf(" audio_channels = %d\n", audio_channels);
276 sample_rate = zsrc->sample_rate(astream);
277 printf(" sample_rate = %d\n", sample_rate);
278 audio_samples = zsrc->audio_samples(astream);
279 printf(" audio_samples = %ld\n", audio_samples);
282 has_video = mpeg3_has_video(zsrc);
283 printf(" has_video = %d\n", has_video);
284 total_vstreams = mpeg3_total_vstreams(zsrc);
285 printf(" total_vstreams = %d\n", total_vstreams);
286 for( vstream=0; vstream<total_vstreams; ++vstream ) {
287 width = zsrc->video_width(vstream);
288 printf(" video_width = %d\n", width);
289 height = zsrc->video_height(vstream);
290 printf(" video_height = %d\n", height);
291 frame_rate = zsrc->frame_rate(vstream);
292 printf(" frame_rate = %f\n", frame_rate);
293 video_frames = zsrc->video_frames(vstream);
294 printf(" video_frames = %ld\n", video_frames);
295 colormodel = zsrc->colormodel(vstream);
296 printf(" colormodel = %d\n", colormodel);
302 #include "guicast/linklist.h"
303 #include "guicast/arraylist.h"
304 #include "cinelerra/mediadb.h"
307 class SdbPacketQueue;
313 class SdbPacket : public ListItem<SdbPacket>
316 enum sdb_packet_type { sdb_none, sdb_skim_frame, } type;
317 SkimDbThread *thread;
319 virtual void run() = 0;
321 SdbPacket(sdb_packet_type ty, SkimDbThread *tp) : type(ty), thread(tp) {}
325 class SdbPacketQueue : public List<SdbPacket>, public Mutex
328 SdbPacket *get_packet();
329 void put_packet(SdbPacket *p);
332 void SdbPacketQueue::
333 put_packet(SdbPacket *p)
340 SdbPacket *SdbPacketQueue::
344 SdbPacket *p = first;
351 class SdbSkimFrame : public SdbPacket
357 uint8_t dat[SWIDTH*SHEIGHT];
359 void load(int pid, int64_t framenum, double position,
360 uint8_t *idata,int mw,int mh,int iw,int ih);
363 SdbSkimFrame(SkimDbThread *t) : SdbPacket(sdb_skim_frame, t) {}
372 int set_skimming(int track, int skim, skim_fn fn, void *vp);
373 int get_video_info(int track, int &pid,
374 double &framerate, int &width, int &height, char *title);
375 static int skimming(void *vp, int track);
376 int skimming(int track);
377 void start_skimming();
378 void stop_skimming();
380 Media() { skimming_active = 0; }
384 int Media::set_skimming(int track, int skim, skim_fn fn, void *vp)
386 return !fn ? ysrc->set_thumbnail_callback(track, 0, 0, 0, 0) :
387 ysrc->set_thumbnail_callback(track, skim, 1, fn, vp);
390 int Media::get_video_info(int track, int &pid,
391 double &framerate, int &width, int &height, char *title)
393 pid = ysrc->video_pid(track);
394 framerate = ysrc->frame_rate(track);
395 width = ysrc->video_width(track);
396 height = ysrc->video_height(track);
397 if( !title ) return 0;
400 int elements = ysrc->dvb.channel_count();
401 for( int n=0; n<elements; ++n ) {
402 int major, minor, total_vstreams, vstream, vidx;
403 if( ysrc->dvb.get_channel(n, major, minor) ||
404 ysrc->dvb.total_vstreams(n, total_vstreams) ) continue;
405 for( vidx=0; vidx<total_vstreams; ++vidx ) {
406 if( ysrc->dvb.vstream_number(n, vidx, vstream) ) continue;
407 if( vstream < 0 ) continue;
408 if( vstream == track ) {
409 sprintf(title, "%3d.%-3d", major, minor);
417 int Media::skimming(void *vp, int track)
419 return ((Media*)vp)->skimming(track);
423 class SkimDbThread : public Thread, public Media, public MediaDb
425 SdbPacketQueue active_packets;
426 Condition *input_lock;
427 friend class SdbSkimFrame;
431 double framerate_ratio;
433 SdbPacketQueue skim_frames;
439 void put_packet(SdbPacket *p);
440 int skim(int pid,int64_t framenum,double framerate,
441 uint8_t *idata,int mw,int mh,int iw,int ih);
442 int skim_frame(Snips *snips, uint8_t *tdat, double position);
443 double abs_err(Snip *snip, double *ap, int j, int len, double iframerate);
444 double frame_weight(uint8_t *tdat, int rowsz, int width, int height);
445 int verify_snip(Snip *snip, double weight, double position);
451 int Media::skimming(int track)
453 int64_t framenum; uint8_t *tdat; int mw, mh;
454 if( ysrc->get_thumbnail(track, framenum, tdat, mw, mh) ) return 1;
455 int pid, width, height; double framerate;
456 if( get_video_info(track, pid, framerate, width, height, 0) ) return 1;
457 if( !framerate ) return 1;
458 //printf("Media::skimming framenum %ld, framerate %f\n",framenum,framerate);
459 return the_db->skim(pid,framenum,framerate, tdat,mw,mh,width,height);
462 void Media::start_skimming()
464 if( !skimming_active ) {
467 set_skimming(0, 0, skimming, this);
471 void Media::stop_skimming()
473 if( skimming_active ) {
475 set_skimming(0, 0, 0, 0);
485 input_lock = new Condition(0); // "SkimDbThread::input_lock");
486 sfrm_sz = SWIDTH*SHEIGHT;
487 for( int i=32; --i>=0; ) skim_frames.append(new SdbSkimFrame(this));
505 if( openDb() ) return;
506 if( detachDb() ) return;
516 input_lock->unlock();
524 skim(int pid,int64_t framenum,double framerate,
525 uint8_t *idata,int mw,int mh,int iw,int ih)
527 SdbSkimFrame *sf = (SdbSkimFrame *)skim_frames.get_packet();
528 if( !sf ) printf("SkimDbThread::skim no packet\n");
530 sf->load(pid,framenum,framerate, idata,mw,mh,iw,ih);
536 void SdbPacket::start()
538 thread->put_packet(this);
542 put_packet(SdbPacket *p)
544 active_packets.put_packet(p);
545 input_lock->unlock();
552 input_lock->lock(); //"SkimDbThread::run");
554 SdbPacket *p = active_packets.get_packet();
564 load(int pid,int64_t framenum, double framerate, uint8_t *idata,int mw,int mh,int iw,int ih)
566 int sw=SWIDTH, sh=SHEIGHT;
568 this->framenum = framenum;
569 this->framerate = framerate;
570 //write_pbm(idata, mw, mh, "/tmp/data/f%05d.pbm",framenum);
571 Scale(idata,0,mw,mh,0,0,iw/8,ih/8).scale(dat,sw,sh,0,0,sw,sh);
572 //write_pbm(dat, SWIDTH, SHEIGHT, "/tmp/data/s%05d.pbm",framenum);
578 //write_pbm(dat, SWIDTH, SHEIGHT, "/tmp/data/h%05d.pbm",framenum);
579 double position = framenum / framerate;
580 thread->skim_frame(thread->snips, dat, position);
581 thread->skim_frames.put_packet(this);
585 double SkimDbThread::
586 frame_weight(uint8_t *tdat, int rowsz, int width, int height)
589 for( int y=height; --y>=0; tdat+=rowsz ) {
591 for( int x=width; --x>=0; ++bp ) weight += *bp;
593 return (double)weight / (width*height);
597 skim_frame(Snips *snips, uint8_t *tdat, double position)
599 int fid, result = get_frame_key(tdat, fid, snips, position, 1);
600 double weight = frame_weight(tdat, SWIDTH, SWIDTH, SHEIGHT);
601 for( Clip *next=0,*clip=snips->first; clip; clip=next ) {
603 result = verify_snip((Snip*)clip,weight,position);
605 if( clip->votes >= 2 || position-clip->start > 2 ) {
606 if( !(clip->groups & 4) ) {
610 printf("*** MUTE AUDIO clip %d\n", clip->clip_id);
615 else if( result < 0 || --clip->votes < 0 ) {
616 printf("delete clip %d, snips %d\n", clip->clip_id, snips->count-1);
617 delete clip; --snips->count;
618 if( !snips->first && alsa_mute ) {
620 printf("*** UNMUTE AUDIO clip %d\n", clip->clip_id);
624 if( snips->count > 0 ) { printf("snips %d = ", snips->count);
625 for( Clip *cp=snips->first; cp; cp=cp->next ) printf(" %d/%d",cp->clip_id,cp->votes);
630 double SkimDbThread::
631 abs_err(Snip *snip, double *ap, int j, int len, double iframerate)
634 int i, k, sz = snip->weights.size(), n = 0;
635 for( i=0; i<sz; ++i ) {
636 k = j + (snip->positions[i] - snip->start) * iframerate + 0.5;
637 if( k < 0 ) continue;
638 if( k >= len ) break;
639 double a = ap[k], b = snip->weights[i];
640 double dv = fabs(a - b);
644 return !n ? MEDIA_WEIGHT_ERRLMT : vv / n;
648 verify_snip(Snip *snip, double weight, double position)
650 int cid = snip->clip_id;
651 if( clip_id(cid) ) return -1;
652 double iframerate = clip_framerate();
653 int iframes = clip_frames();
654 double pos = position - snip->start;
655 int iframe_no = pos * iframerate + 0.5;
656 if( iframe_no >= iframes ) return -1;
657 snip->weights.append(weight);
658 snip->positions.append(position);
659 printf("%f %d ",weight,iframe_no);
660 double *iweights = clip_weights();
661 double errlmt = MEDIA_WEIGHT_ERRLMT;
662 double err = errlmt, kerr = err;
664 int tmargin = TRANSITION_MARGIN * iframerate + 0.5;
665 for( int j=-tmargin; j<=tmargin; ++j ) {
666 err = abs_err(snip, iweights, j, iframes, iframerate);
667 //printf(" err %f, j=%d\n", err, j);
668 if( err < kerr ) { kerr = err; k = j; }
670 printf("kerr %f, k=%d ", kerr, k);
671 if( kerr >= errlmt ) return 1;
672 if( iframe_no + k >= iframes ) return -1;
681 class Video : public Thread {
685 double video_time(int stream);
690 Video(zmpeg3_t *z) : zsrc(z) {}
695 double Video::video_time(int stream)
697 double vtime = zsrc->get_video_time(stream);
699 if( vstart == 0. ) vstart = vnow;
700 if( vtime < last_vtime )
701 vstart -= last_vtime;
703 return vnow - vstart + nudge;
713 XImage *image0, *image1, *image;
716 XShmSegmentInfo info0, info1;
719 float frame_rate, frame_delay;
720 uint8_t **rows, **row0, **row1, *cap, *cap0, *cap1;
721 int ret, row, frame, dropped, more_data;
722 int width, height, depth, owidth, oheight;
723 const int frame_drop = 0;
724 const int shared_memory = 1;
726 display = XOpenDisplay(NULL);
727 if( display == NULL ) {
728 fprintf(stderr,"cant open display\n");
732 root = RootWindow(display,0);
733 screen = DefaultScreenOfDisplay(display);
734 depth = DefaultDepthOfScreen(screen);
735 visual = DefaultVisualOfScreen(screen);
736 if( visual->c_class != TrueColor ) {
737 printf("visual class not truecolor\n");
742 frame_rate = zsrc->frame_rate(0);
743 frame_delay = 2.0 / frame_rate;
744 height = zsrc->video_height(0);
745 width = zsrc->video_width(0);
747 //oheight = 2*height / 3;
748 //owidth = 2*width / 3;
756 w = XCreateSimpleWindow(display, root, 0, 0, owidth, oheight,
757 0, 0, WhitePixelOfScreen(screen));
758 XSelectInput(display, w, ExposureMask|StructureNotifyMask|ButtonPressMask);
760 if( !shared_memory ) {
761 int sz0 = oheight*owidth*image_bpp + 4;
762 cap0 = new uint8_t[sz0];
763 image0 = XCreateImage(display, visual, depth, ZPixmap, 0,
764 (char*)cap0, owidth, oheight, 8, owidth*4);
765 int sz1 = oheight*owidth*image_bpp + 4;
766 cap1 = new uint8_t[sz1];
767 image1 = XCreateImage(display, visual, depth, ZPixmap, 0,
768 (char*)cap1, owidth, oheight, 8, owidth*4);
771 image0 = XShmCreateImage(display, visual, depth, ZPixmap, 0,
772 &info0, owidth, oheight);
773 int sz0 = oheight*image0->bytes_per_line+image_bpp;
774 info0.shmid = shmget(IPC_PRIVATE, sz0, IPC_CREAT | 0777);
775 if( info0.shmid < 0) { perror("shmget"); exit(1); }
776 cap0 = (uint8_t *)shmat(info0.shmid, NULL, 0);
777 shmctl(info0.shmid, IPC_RMID, 0);
778 image0->data = info0.shmaddr = (char *)cap0;
780 XShmAttach(display,&info0);
781 image1 = XShmCreateImage(display, visual, depth, ZPixmap, 0,
782 &info1, owidth, oheight);
783 int sz1 = oheight*image1->bytes_per_line+image_bpp;
784 info1.shmid = shmget(IPC_PRIVATE, sz1, IPC_CREAT | 0777);
785 if( info1.shmid < 0) { perror("shmget"); exit(1); }
786 cap1 = (uint8_t *)shmat(info1.shmid, NULL, 0);
787 shmctl(info1.shmid, IPC_RMID, 0);
788 image1->data = info1.shmaddr = (char *)cap1;
790 XShmAttach(display,&info1);
793 row0 = new uint8_t *[oheight];
794 row1 = new uint8_t *[oheight];
795 for( row=0; row<oheight; ++row ) {
796 row0[row] = cap0 + row*owidth*image_bpp;
797 row1[row] = cap1 + row*owidth*image_bpp;
803 if( image->bits_per_pixel != 32 ) {
804 printf("image bits_per_pixel=%d\n",image->bits_per_pixel);
808 unsigned int rmsk = image->red_mask;
809 unsigned int gmsk = image->green_mask;
810 unsigned int bmsk = image->blue_mask;
811 switch( image_bpp ) {
813 if( bmsk==0xff0000 && gmsk==0x00ff00 && rmsk==0x0000ff )
814 cmdl = zmpeg3_t::cmdl_RGBA8888;
815 else if( bmsk==0x0000ff && gmsk==0x00ff00 && rmsk==0xff0000 )
816 cmdl = zmpeg3_t::cmdl_BGRA8888;
819 if( bmsk==0xff0000 && gmsk==0x00ff00 && rmsk==0x0000ff )
820 cmdl = zmpeg3_t::cmdl_RGB888;
821 else if( bmsk==0x0000ff && gmsk==0x00ff00 && rmsk==0xff0000 )
822 cmdl = zmpeg3_t::cmdl_BGR888;
825 if( bmsk==0x00f800 && gmsk==0x0007e0 && rmsk==0x00001f )
826 cmdl = zmpeg3_t::cmdl_RGB565;
830 printf("unknown color model, bpp=%d, ",image_bpp);
831 printf(" rmsk=%08x,gmsk=%08x,bmsk=%08x\n", rmsk, gmsk, bmsk);
835 XMapWindow(display, w);
837 gcv.function = GXcopy;
838 gcv.foreground = BlackPixelOfScreen(DefaultScreenOfDisplay(display));
840 gcv.line_style = LineSolid;
841 int m = GCFunction|GCForeground|GCLineWidth|GCLineStyle;
842 gc = XCreateGC(display,w,m,&gcv);
845 vstart = last_vtime = 0.;
849 while( !done && running() && more_data ) {
850 if( !XPending(display) ) {
852 delay = (frame+dropped)/frame_rate - alsa_time();
853 // delay = the_time() - video_time(zsrc,0);
855 if( -delay >= frame_delay ) {
856 int nframes = (long)ceil(-delay/frame_rate);
857 if( nframes > 2 ) nframes = 2;
858 zsrc->drop_frames(nframes,0);
862 //printf("delay %f\n",delay*1000.);
864 usleep((int)(delay*1000000.0));
865 ret = zsrc->read_frame(rows, 0, 0, width, height,
866 owidth, oheight, cmdl, 0);
867 //printf("%d %ld\n",frame,zsrc->vtrack[0]->demuxer->titles[0]->fs->current_byte);
869 printf("read_video(stream=%d, frame=%d) = %d, %f sec\n", 0, frame, ret, the_time());
873 XPutImage(display, w, gc, image, 0, 0, 0, 0, owidth, oheight);
875 XShmPutImage(display, w, gc, image, 0, 0, 0, 0, owidth, oheight, False);
878 (rows=row1, image=image1, cap1) :
879 (rows=row0, image=image0, cap0) ;
880 //printf(" %d/%d %f %f %f\n",frame,dropped,(frame+dropped)/frame_rate,
881 // video_time(zsrc,0),zsrc->get_video_time(0));
882 more_data |= !zsrc->end_of_video(0);
885 XNextEvent(display,&xev);
886 /* printf("xev.type = %d/%08x\n",xev.type,xev.xany.window); */
889 if( xev.xbutton.window != w ) continue;
890 if( xev.xbutton.button != Button1 )
902 XCloseDisplay(display);
903 delete [] row0; row0 = 0;
904 delete [] row1; row1 = 0;
911 class Audio : public Thread {
914 double audio_time(int stream);
919 Audio(zmpeg3_t *z) : zsrc(z) {}
924 double Audio::audio_time(int stream)
926 double anow = zsrc->get_audio_time(stream);
927 if( astart < 0. ) astart = anow;
928 return anow - astart;
934 int audio_channels, sample_rate, more_data;
937 audio_channels = zsrc->audio_channels(stream);
938 sample_rate = zsrc->sample_rate(stream);
939 alsa_open(audio_channels,sample_rate);
943 while( running() && more_data ) {
946 int n = alsa_bfrsz();
947 for( ich=0; ich<audio_channels; ++ich) {
948 short *bfr = alsa_bfr(ich);
950 zsrc->read_audio(bfr, ich, n, stream) :
951 zsrc->reread_audio(bfr, ich, n, stream);
953 printf("read_audio(stream=%d,channel=%d) = %d\n", stream, ich, ret);
957 delay = audio_time(stream) - the_time();
958 if( (delay-=ahead) > 0. ) {
959 usleep((int)(delay*1000000.0/2.));
961 more_data |= !zsrc->end_of_audio(0);
978 the_db->stop_skimming();
983 int main(int ac, char **av)
997 zmpeg3_t* zsrc = new zmpeg3_t(av[1],ret);
999 printf(" ret = %d\n",ret);
1000 if( ret != 0 ) exit(1);
1006 if( stat(zsrc->fs->path, &st_buf) >= 0 ) {
1007 if( (pos = (st_buf.st_size & ~0x7ffl) - 0x800000l) < 0 )
1011 zsrc->seek_byte(pos);
1012 // zsrc->show_subtitle(0);
1013 signal(SIGINT,sigint);
1016 the_db = new SkimDbThread();
1019 the_audio = new Audio(zsrc);
1022 the_video = new Video(zsrc);
1025 the_db->start_skimming();
1040 the_db->stop_skimming();