X-Git-Url: http://git.cinelerra-gg.org/git/?p=goodguy%2Fhistory.git;a=blobdiff_plain;f=cinelerra-5.1%2Fcinelerra%2Fydiff.C;h=ebf1e75533bdeb895c10db342cb7f5fd133fe855;hp=c0322c3949e679bc041b263a52bd87bf84de7112;hb=2e48b660e37eb5c661264d601211e16cb6cd6e89;hpb=b9c7bc3ce26b8e6df4b6ad64d7b2d328525f7198 diff --git a/cinelerra-5.1/cinelerra/ydiff.C b/cinelerra-5.1/cinelerra/ydiff.C index c0322c39..ebf1e755 100644 --- a/cinelerra-5.1/cinelerra/ydiff.C +++ b/cinelerra-5.1/cinelerra/ydiff.C @@ -2,8 +2,19 @@ #include #include #include +#include +#include +#include +#include #include #include +#include +#include + +#include +#include +#include +#include extern "C" { #include "libavfilter/buffersrc.h" @@ -20,110 +31,200 @@ extern "C" { #include "libswscale/swscale.h" } -#include -#include - int done = 0; +int64_t tm = 0, tn = 0; void sigint(int n) { done = 1; } +class gg_window +{ +public: + gg_window(Display *display, int x, int y, int w, int h); + ~gg_window(); + Display *display; + Window win; + GC gc; + int x, y, w, h; + void show(); + void hide(); +}; + +gg_window::gg_window(Display *display, int x, int y, int w, int h) +{ + this->display = display; + this->x = x; this->y = y; + this->w = w; this->h = h; + + Window root = DefaultRootWindow(display); + Screen *screen = DefaultScreenOfDisplay(display); + Visual *visual = DefaultVisualOfScreen(screen); + int depth = DefaultDepthOfScreen(screen); + int border = 0; + unsigned long gcmask = GCGraphicsExposures; + XGCValues gcvalues; + gcvalues.graphics_exposures = 0; + gc = XCreateGC(display, root, gcmask, &gcvalues); + + XSetWindowAttributes attributes; + attributes.background_pixel = BlackPixel(display, DefaultScreen(display)); + attributes.border_pixel = WhitePixel(display, DefaultScreen(display)); + attributes.event_mask = + EnterWindowMask | LeaveWindowMask | + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | FocusChangeMask; + int valueMask = CWBackPixel | CWBorderPixel | CWEventMask; + this->win = XCreateWindow(display, root, x, y, w, h, border, depth, + InputOutput, visual, valueMask, &attributes); +} + +gg_window::~gg_window() +{ + XFreeGC(display, gc); + XDestroyWindow(display, win); +} -void dst_exit(GtkWidget *widget, gpointer data) +void gg_window::show() { - exit(0); + XMapWindow(display,win); + XFlush(display); +} +void gg_window::hide() +{ + XUnmapWindow(display,win); + XFlush(display); } -class gtk_window { +class gg_ximage +{ public: - gtk_window(int width, int height); - ~gtk_window(); - - GdkVisual *visual; - GtkWidget *window; - GtkWidget *image; - GtkWidget *panel_hbox; - GdkImage *img0, *img1; - GdkPixbuf *pbuf0, *pbuf1; - unsigned char *bfr, *bfrs, *bfr0, *bfr1; - unsigned char **rows, **row0, **row1; - uint64_t flip_bfrs, flip_rows; - int width, height, linesize; - int done; + Display *display; + XShmSegmentInfo shm_info; + XImage *ximage; + int w, h; + unsigned char *data; + int shm, sz; + uint32_t lsb[3]; + gg_ximage(Display *display, int w, int h, int shm); + ~gg_ximage(); + + void put_image(gg_window &gw); +}; + +gg_ximage::gg_ximage(Display *display, int w, int h, int shm) +{ + this->display = display; + this->w = w; this->h = h; + this->shm = shm; + + ximage = 0; sz = 0; data = 0; + Screen *screen = DefaultScreenOfDisplay(display); + Visual *visual = DefaultVisualOfScreen(screen); + int depth = DefaultDepthOfScreen(screen); + + if( shm ) { + ximage = XShmCreateImage(display, visual, depth, ZPixmap, (char*)NULL, &shm_info, w, h); +// Create shared memory + sz = h * ximage->bytes_per_line; + shm_info.shmid = shmget(IPC_PRIVATE, sz + 8, IPC_CREAT | 0777); + if(shm_info.shmid < 0) perror("shmget"); + data = (unsigned char *)shmat(shm_info.shmid, NULL, 0); +// This causes it to automatically delete when the program exits. + shmctl(shm_info.shmid, IPC_RMID, 0); + ximage->data = shm_info.shmaddr = (char*)data; + shm_info.readOnly = 0; +// Get the real parameters + if(!XShmAttach(display, &shm_info)) perror("XShmAttach"); + } + else { + ximage = XCreateImage(display, visual, depth, ZPixmap, 0, (char*)data, w, h, 8, 0); + sz = h * ximage->bytes_per_line; + data = new unsigned char[sz+8]; + } + memset(data, 0, sz); + ximage->data = (char*) data; + lsb[0] = ximage->red_mask & ~(ximage->red_mask<<1); + lsb[1] = ximage->green_mask & ~(ximage->green_mask<<1); + lsb[2] = ximage->blue_mask & ~(ximage->blue_mask<<1); +} + +gg_ximage::~gg_ximage() +{ + if( shm ) { + data = 0; + ximage->data = 0; + XDestroyImage(ximage); + XShmDetach(display, &shm_info); + XFlush(display); + shmdt(shm_info.shmaddr); + } + else { + delete [] data; + data = 0; + ximage->data = 0; + XDestroyImage(ximage); + } +} + +void gg_ximage::put_image(gg_window &gw) +{ + Display *display = gw.display; + Window win = gw.win; + GC gc = gw.gc; + if( shm ) + XShmPutImage(display, win, gc, ximage, 0,0, 0,0,w,h, 0); + else + XPutImage(display, win, gc, ximage, 0,0, 0,0,w,h); + XFlush(display); +} +class gg_thread +{ +public: pthread_t tid; + gg_window &gw; + gg_ximage *imgs[2], *img; + int active, done; + gg_thread(gg_window &gw, int shm) ; + ~gg_thread(); + static void *entry(void *t); void start(); void *run(); - uint8_t *next_bfr(); - void post(); + void join(); + void post(gg_ximage *ip); + gg_ximage *next_img(); pthread_mutex_t draw; void draw_lock() { pthread_mutex_lock(&draw); } void draw_unlock() { pthread_mutex_unlock(&draw); } }; -gtk_window::gtk_window(int width, int height) +gg_thread::gg_thread(gg_window &gw, int shm) + : gw(gw) { - this->width = width; - this->height = height; - this->linesize = width*3; - visual = gdk_visual_get_system(); - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_signal_connect(GTK_OBJECT(window),"destroy", - GTK_SIGNAL_FUNC(dst_exit),NULL); - gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_NONE); - /* try for shared image bfr, only seems to work with gtk_rgb */ - img0 = gdk_image_new(GDK_IMAGE_SHARED, visual, width, height); - pbuf0 = gdk_pixbuf_new_from_data((const guchar *)img0->mem, - GDK_COLORSPACE_RGB,FALSE,8,width,height,linesize,NULL,NULL); - bfr0 = gdk_pixbuf_get_pixels(pbuf0); - memset(bfr0,0,height*linesize); - image = gtk_image_new_from_pixbuf(pbuf0); - /* double buffered */ - img1 = gdk_image_new(GDK_IMAGE_SHARED, visual, width, height); - pbuf1 = gdk_pixbuf_new_from_data((const guchar *)img1->mem, - GDK_COLORSPACE_RGB,FALSE,8,width,height,linesize,NULL,NULL); - bfr1 = gdk_pixbuf_get_pixels(pbuf1); - memset(bfr1,0,height*linesize); - - row0 = new unsigned char *[height]; - row1 = new unsigned char *[height]; - - for( int i=0; irun(); + return ((gg_thread*)t)->run(); } -void gtk_window::start() +void gg_thread::start() { pthread_attr_t attr; pthread_attr_init(&attr); @@ -132,37 +233,46 @@ void gtk_window::start() pthread_create(&tid, &attr, &entry, this); pthread_attr_destroy(&attr); } +void gg_thread::join() +{ + done = 1; + pthread_join(tid, 0); +} -void *gtk_window::run() +void *gg_thread::run() { while( !done ) { - if( !gtk_events_pending() ) { - if( !bfr ) { usleep(10000); continue; } - GdkGC *blk = image->style->black_gc; - gdk_draw_rgb_image(image->window,blk, 0,0,width,height, - GDK_RGB_DITHER_NONE,bfr,linesize); - gdk_flush(); - unsigned long *fbfrs = (unsigned long *)&bfrs; *fbfrs ^= flip_bfrs; - unsigned long *frows = (unsigned long *)&rows; *frows ^= flip_rows; - bfr = 0; - draw_unlock(); + if( XPending(gw.display) ) { + XEvent xev; + XNextEvent(gw.display, &xev); + switch( xev.type ) { + case KeyPress: + case KeyRelease: + case ButtonPress: + case Expose: + break; + } + continue; } - else - gtk_main_iteration(); - } + if( !img ) { usleep(10000); continue; } + img->put_image(gw); + img = 0; + draw_unlock(); + } return (void*)0; } -uint8_t *gtk_window::next_bfr() +gg_ximage *gg_thread::next_img() { - return bfrs; + gg_ximage *ip = imgs[active]; + active ^= 1; + return ip; } -void gtk_window::post() +void gg_thread::post(gg_ximage *ip) { - draw_lock(); - bfr = bfrs; + this->img = ip; } @@ -178,6 +288,7 @@ public: AVPixelFormat pix_fmt; double frame_rate; int width, height; + int need_packet, eof; int open_decoder(const char *filename, int vid_no); void close_decoder(); AVFrame *read_frame(); @@ -191,6 +302,8 @@ ffcmpr::ffcmpr() this->st = 0; this->ctx = 0 ; this->frame_rate = 0; + this->need_packet = 0; + this->eof = 0; this->pix_fmt = AV_PIX_FMT_NONE; width = height = 0; } @@ -199,6 +312,7 @@ void ffcmpr::close_decoder() { av_packet_unref(&ipkt); if( !fmt_ctx ) return; + if( ctx ) avcodec_free_context(&ctx); avformat_close_input(&fmt_ctx); av_frame_free(&ipic); } @@ -235,28 +349,31 @@ int ffcmpr::open_decoder(const char *filename, int vid_no) this->st = 0; for( int i=0; !this->st && ret>=0 && i<(int)fmt_ctx->nb_streams; ++i ) { AVStream *fst = fmt_ctx->streams[i]; - AVMediaType type = fst->codec->codec_type; + AVMediaType type = fst->codecpar->codec_type; if( type != AVMEDIA_TYPE_VIDEO ) continue; if( --vid_no < 0 ) this->st = fst; } - AVCodecID codec_id = st->codec->codec_id; + AVCodecID codec_id = st->codecpar->codec_id; AVDictionary *copts = 0; //av_dict_copy(&copts, opts, 0); AVCodec *decoder = avcodec_find_decoder(codec_id); - if( avcodec_open2(st->codec, decoder, &copts) < 0 ) { + ctx = avcodec_alloc_context3(decoder); + avcodec_parameters_to_context(ctx, st->codecpar); + if( avcodec_open2(ctx, decoder, &copts) < 0 ) { fprintf(stderr,"codec open failed: %s\n", filename); return -1; } av_dict_free(&copts); ipic = av_frame_alloc(); + eof = 0; + need_packet = 1; AVRational framerate = av_guess_frame_rate(fmt_ctx, st, 0); this->frame_rate = !framerate.den ? 0 : (double)framerate.num / framerate.den; - this->ctx = st->codec; - this->pix_fmt = ctx->pix_fmt; - this->width = ctx->width; - this->height = ctx->height; + this->pix_fmt = (AVPixelFormat)st->codecpar->format; + this->width = st->codecpar->width; + this->height = st->codecpar->height; return 0; } @@ -265,46 +382,69 @@ AVFrame *ffcmpr::read_frame() av_frame_unref(ipic); for( int retrys=1000; --retrys>=0; ) { - av_packet_unref(&ipkt); - int ret = av_read_frame(fmt_ctx, &ipkt); - if( ret == AVERROR_EOF ) break; - if( ret != 0 ) continue; - if( !ipkt.data ) continue; - if( ipkt.stream_index != st->index ) continue; - while( ipkt.size > 0 ) { - int got_frame = 0; - ret = avcodec_decode_video2(st->codec, ipic, &got_frame, &ipkt); - if( ret <= 0 ) break; - if( got_frame ) - return ipic; - ipkt.data += ret; - ipkt.size -= ret; + if( need_packet ) { + if( eof ) return 0; + AVPacket *pkt = &ipkt; + av_packet_unref(pkt); + int ret = av_read_frame(fmt_ctx, pkt); + if( ret < 0 ) { + if( ret != AVERROR_EOF ) return 0; + ret = 0; eof = 1; pkt = 0; + } + if( pkt ) { + if( pkt->stream_index != st->index ) continue; + if( !pkt->data || !pkt->size ) continue; + } + avcodec_send_packet(ctx, pkt); + need_packet = 0; } + int ret = avcodec_receive_frame(ctx, ipic); + if( ret >= 0 ) return ipic; + if( ret != AVERROR(EAGAIN) ) { + eof = 1; need_packet = 0; + break; + } + need_packet = 1; } return 0; } -static int diff_frame(AVFrame *afrm, AVFrame *bfrm, uint8_t *fp, int w, int h) +static int diff_frame(AVFrame *afrm, AVFrame *bfrm, gg_ximage *ximg, int w, int h) { int n = 0, m = 0; uint8_t *arow = afrm->data[0]; uint8_t *brow = bfrm->data[0]; + uint8_t *frow = ximg->data; int asz = afrm->linesize[0], bsz = afrm->linesize[0]; - int rsz = w * 3; - for( int y=h; --y>=0; arow+=asz, brow+=bsz ) { - uint8_t *ap = arow, *bp = brow; - for( int x=rsz; --x>=0; ++ap,++bp ) { - int d = *ap - *bp, v = d + 128; - if( v > 255 ) v = 255; - else if( v < 0 ) v = 0; - *fp++ = v; - m += d; - if( d < 0 ) d = -d; - n += d; + XImage *ximage = ximg->ximage; + int fsz = ximage->bytes_per_line; + int rsz = w, bpp = (ximage->bits_per_pixel+7)/8; + uint32_t *lsb = ximg->lsb; + + for( int y=h; --y>=0; arow+=asz, brow+=bsz, frow+=fsz ) { + uint8_t *ap = arow, *bp = brow, *fp = frow; + for( int x=rsz; --x>=0; ) { + uint32_t rgb = 0; uint8_t *rp = fp; + for( int i=0; i<3; ++i ) { + int d = *ap++ - *bp++; + int v = d + 128; + if( v > 255 ) v = 255; + else if( v < 0 ) v = 0; + rgb |= v * lsb[i]; + m += d; + if( d < 0 ) d = -d; + n += d; + } + if( ximage->byte_order == MSBFirst ) + for( int i=3; --i>=0; ) *rp++ = rgb>>(8*i); + else + for( int i=0; i<3; ++i ) *rp++ = rgb>>(8*i); + fp += bpp; } } int sz = h*rsz; printf("%d %d %d %f", sz, m, n, (double)n/sz); + tm += m; tn += n; return n; } @@ -312,9 +452,12 @@ int main(int ac, char **av) { int ret; setbuf(stdout,NULL); - - gtk_set_locale(); - gtk_init(&ac, &av); + XInitThreads(); + Display *display = XOpenDisplay(getenv("DISPLAY")); + if( !display ) { + fprintf(stderr,"Unable to open display\n"); + exit(1); + } ffcmpr a, b; if( a.open_decoder(av[1],0) ) return 1; @@ -339,7 +482,7 @@ int main(int ac, char **av) // if( a.ctx->codec_id != b.ctx->codec_id ) { printf("codec mismatch\n"); return 1;} if( a.width != b.width ) { printf("width mismatch\n"); return 1;} if( a.height != b.height ) { printf("height mismatch\n"); return 1;} - if( a.frame_rate != b.frame_rate ) { printf("framerate mismatch\n"); return 1;} +// if( a.frame_rate != b.frame_rate ) { printf("framerate mismatch\n"); return 1;} // if( a.pix_fmt != b.pix_fmt ) { printf("format mismatch\n"); return 1;} signal(SIGINT,sigint); @@ -360,9 +503,10 @@ int main(int ac, char **av) AVFrame *bfrm = av_frame_alloc(); av_image_alloc(bfrm->data, bfrm->linesize, b.width, b.height, AV_PIX_FMT_RGB24, 1); - - gtk_window gw(a.width, a.height); - gw.start(); +{ gg_window gw(display, 10,10, a.width,a.height); + gw.show(); + gg_thread thr(gw, 1); + thr.start(); int64_t err = 0; int frm_no = 0; @@ -381,18 +525,26 @@ int main(int ac, char **av) afrm->data, afrm->linesize); sws_scale(b_cvt, bp->data, bp->linesize, 0, bp->height, bfrm->data, bfrm->linesize); - uint8_t *fbfr = gw.next_bfr(); - ret = diff_frame(afrm, bfrm, fbfr, ap->width, ap->height); + thr.draw_lock(); + gg_ximage *fimg = thr.next_img(); + ret = diff_frame(afrm, bfrm, fimg, ap->width, ap->height); + thr.post(fimg); err += ret; ++frm_no; printf(" %d\n",frm_no); - gw.post(); } + av_freep(&afrm->data); av_frame_free(&afrm); + av_freep(&bfrm->data); av_frame_free(&bfrm); b.close_decoder(); a.close_decoder(); + + thr.join(); + gw.hide(); } + XCloseDisplay(display); + printf("\n%jd %jd\n", tm, tn); return 0; }