no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / ydiff.C
1 /*
2  * CINELERRA
3  * Copyright (C) 2016-2020 William Morrow
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published
7  * by the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  */
20
21 #include <stdio.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <math.h>
25 #include <pthread.h>
26 #include <signal.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/stat.h>
30 #include <sys/time.h>
31 #include <sys/ipc.h>
32 #include <sys/shm.h>
33
34 #include <X11/Xatom.h>
35 #include <X11/Xlib.h>
36 #include <X11/Xutil.h>
37 #include <X11/extensions/XShm.h>
38
39 extern "C" {
40 #include "libavfilter/buffersrc.h"
41 #include "libavfilter/buffersink.h"
42 #include "libavformat/avformat.h"
43 #include "libavformat/avio.h"
44 #include "libavcodec/avcodec.h"
45 #include "libavfilter/avfilter.h"
46 #include "libavutil/avutil.h"
47 #include "libavutil/imgutils.h"
48 #include "libavutil/opt.h"
49 #include "libavutil/pixdesc.h"
50 #include "libswresample/swresample.h"
51 #include "libswscale/swscale.h"
52 }
53
54 #ifdef FFMPEG3
55 #define url filename
56 #else
57 #define av_register_all(s)
58 #define avfilter_register_all(s)
59 #endif
60
61 int done = 0;
62 int64_t tm = 0, tn = 0;
63
64 void sigint(int n)
65 {
66   done = 1;
67 }
68
69 class gg_window
70 {
71 public:
72   gg_window(Display *display, int x, int y, int w, int h);
73   ~gg_window();
74   Display *display;
75   Window win;
76   GC gc;
77   int x, y, w, h;
78   void show();
79   void hide();
80 };
81
82 gg_window::gg_window(Display *display, int x, int y, int w, int h)
83 {
84   this->display = display;
85   this->x = x;  this->y = y;
86   this->w = w;  this->h = h;
87
88   Window root = DefaultRootWindow(display);
89   Screen *screen = DefaultScreenOfDisplay(display);
90   Visual *visual = DefaultVisualOfScreen(screen);
91   int depth = DefaultDepthOfScreen(screen);
92   int border = 0;
93   unsigned long gcmask = GCGraphicsExposures;
94   XGCValues gcvalues;
95   gcvalues.graphics_exposures = 0;
96   gc = XCreateGC(display, root, gcmask, &gcvalues);
97
98   XSetWindowAttributes attributes;
99   attributes.background_pixel = BlackPixel(display, DefaultScreen(display));
100   attributes.border_pixel = WhitePixel(display, DefaultScreen(display));
101   attributes.event_mask =
102     EnterWindowMask | LeaveWindowMask |
103     ButtonPressMask | ButtonReleaseMask |
104     PointerMotionMask | FocusChangeMask;
105   int valueMask = CWBackPixel | CWBorderPixel | CWEventMask;
106   this->win = XCreateWindow(display, root, x, y, w, h, border, depth,
107       InputOutput, visual, valueMask, &attributes);
108 }
109
110 gg_window::~gg_window()
111 {
112   XFreeGC(display, gc);
113   XDestroyWindow(display, win);
114 }
115
116 void gg_window::show()
117 {
118   XMapWindow(display,win);
119   XFlush(display);
120 }
121 void gg_window::hide()
122 {
123   XUnmapWindow(display,win);
124   XFlush(display);
125 }
126
127 class gg_ximage
128 {
129 public:
130   Display *display;
131   XShmSegmentInfo shm_info;
132   XImage *ximage;
133   int w, h;
134   unsigned char *data;
135   int shm, sz;
136   uint32_t lsb[3];
137   gg_ximage(Display *display, int w, int h, int shm);
138   ~gg_ximage();
139
140   void put_image(gg_window &gw);
141 };
142
143 gg_ximage::gg_ximage(Display *display, int w, int h, int shm)
144 {
145   this->display = display;
146   this->w = w;  this->h = h;
147   this->shm = shm;
148
149   ximage = 0;  sz = 0;  data = 0;
150   Screen *screen = DefaultScreenOfDisplay(display);
151   Visual *visual = DefaultVisualOfScreen(screen);
152   int depth = DefaultDepthOfScreen(screen);
153
154   if( shm ) {
155     ximage = XShmCreateImage(display, visual, depth, ZPixmap, (char*)NULL, &shm_info, w, h);
156 // Create shared memory
157     sz = h * ximage->bytes_per_line;
158     shm_info.shmid = shmget(IPC_PRIVATE, sz + 8, IPC_CREAT | 0777);
159     if(shm_info.shmid < 0) perror("shmget");
160     data = (unsigned char *)shmat(shm_info.shmid, NULL, 0);
161 // This causes it to automatically delete when the program exits.
162     shmctl(shm_info.shmid, IPC_RMID, 0);
163     ximage->data = shm_info.shmaddr = (char*)data;
164     shm_info.readOnly = 0;
165 // Get the real parameters
166     if(!XShmAttach(display, &shm_info)) perror("XShmAttach");
167   }
168   else {
169       ximage = XCreateImage(display, visual, depth, ZPixmap, 0, (char*)data, w, h, 8, 0);
170       sz = h * ximage->bytes_per_line;
171       data = new unsigned char[sz+8];
172   }
173   memset(data, 0, sz);
174   ximage->data = (char*) data;
175   lsb[0] = ximage->red_mask & ~(ximage->red_mask<<1);
176   lsb[1] = ximage->green_mask & ~(ximage->green_mask<<1);
177   lsb[2] = ximage->blue_mask & ~(ximage->blue_mask<<1);
178 }
179
180 gg_ximage::~gg_ximage()
181 {
182   if( shm ) {
183     data = 0;
184     ximage->data = 0;
185     XDestroyImage(ximage);
186     XShmDetach(display, &shm_info);
187     XFlush(display);
188     shmdt(shm_info.shmaddr);
189   }
190   else {
191     delete [] data;
192     data = 0;
193     ximage->data = 0;
194     XDestroyImage(ximage);
195   }
196 }
197
198 void gg_ximage::put_image(gg_window &gw)
199 {
200   Display *display = gw.display;
201   Window win = gw.win;
202   GC gc = gw.gc;
203   if( shm )
204     XShmPutImage(display, win, gc, ximage, 0,0, 0,0,w,h, 0);
205   else
206     XPutImage(display, win, gc, ximage, 0,0, 0,0,w,h); 
207   XFlush(display);
208 }
209
210 class gg_thread
211 {
212 public:
213   pthread_t tid;
214   gg_window &gw;
215   gg_ximage *imgs[2], *img;
216   int active, done;
217   gg_thread(gg_window &gw, int shm) ;
218   ~gg_thread();
219
220   static void *entry(void *t);
221   void start();
222   void *run();
223   void join();
224   void post(gg_ximage *ip);
225   gg_ximage *next_img();
226
227   pthread_mutex_t draw;
228   void draw_lock() { pthread_mutex_lock(&draw); }
229   void draw_unlock() { pthread_mutex_unlock(&draw); }
230 };
231
232 gg_thread::gg_thread(gg_window &gw, int shm)
233  : gw(gw)
234 {
235   imgs[0] = new gg_ximage(gw.display, gw.w, gw.h, shm);
236   imgs[1] = new gg_ximage(gw.display, gw.w, gw.h, shm);
237   done = -1;
238   img = 0;  active = 0;
239   pthread_mutex_init(&draw, 0);
240 }
241
242 gg_thread::~gg_thread()
243 {
244   delete imgs[0];
245   delete imgs[1];
246   pthread_mutex_destroy(&draw);
247 }
248
249 void *gg_thread::entry(void *t)
250 {
251   return ((gg_thread*)t)->run();
252 }
253
254 void gg_thread::start()
255 {
256   pthread_attr_t attr;
257   pthread_attr_init(&attr);
258   pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
259   done = 0;
260   pthread_create(&tid, &attr, &entry, this);
261   pthread_attr_destroy(&attr);
262 }
263 void gg_thread::join()
264 {
265   done = 1;
266   pthread_join(tid, 0);
267 }
268
269 void *gg_thread::run()
270 {
271   while( !done ) {
272     if( XPending(gw.display) ) {
273       XEvent xev;
274       XNextEvent(gw.display, &xev);
275       switch( xev.type ) {
276       case KeyPress:
277       case KeyRelease:
278       case ButtonPress:
279       case Expose:
280         break;
281       }
282       continue;
283     }
284
285     if( !img ) { usleep(10000);  continue; }
286     img->put_image(gw);
287     img = 0;
288     draw_unlock();
289   }
290   return (void*)0;
291 }
292
293 gg_ximage *gg_thread::next_img()
294 {
295   gg_ximage *ip = imgs[active];
296   active ^= 1;
297   return ip;
298 }
299
300 void gg_thread::post(gg_ximage *ip)
301 {
302   this->img = ip;
303 }
304
305
306 class ffcmpr {
307 public:
308   ffcmpr();
309   ~ffcmpr();
310   AVPacket ipkt;
311   AVFormatContext *fmt_ctx;
312   AVFrame *ipic;
313   AVStream *st;
314   AVCodecContext *ctx;
315   AVPixelFormat pix_fmt;
316   double frame_rate;
317   int width, height;
318   int need_packet, eof;
319   int open_decoder(const char *filename, int vid_no);
320   void close_decoder();
321   AVFrame *read_frame();
322 };
323
324 ffcmpr::ffcmpr()
325 {
326   av_init_packet(&this->ipkt);
327   this->fmt_ctx = 0;
328   this->ipic = 0;
329   this->st = 0;
330   this->ctx = 0 ;
331   this->frame_rate = 0;
332   this->need_packet = 0;
333   this->eof = 0;
334   this->pix_fmt = AV_PIX_FMT_NONE;
335   width = height = 0;
336 }
337
338 void ffcmpr::close_decoder()
339 {
340   av_packet_unref(&ipkt);
341   if( !fmt_ctx ) return;
342   if( ctx ) avcodec_free_context(&ctx);
343   avformat_close_input(&fmt_ctx);
344   av_frame_free(&ipic);
345 }
346
347 ffcmpr::~ffcmpr()
348 {
349   close_decoder();
350 }
351
352 int ffcmpr::open_decoder(const char *filename, int vid_no)
353 {
354   struct stat fst;
355   if( stat(filename, &fst) ) return 1;
356   fmt_ctx = 0;
357   AVDictionary *fopts = 0;
358   av_register_all();
359   av_dict_set(&fopts, "formatprobesize", "5000000", 0);
360   av_dict_set(&fopts, "scan_all_pmts", "1", 0);
361   av_dict_set(&fopts, "threads", "auto", 0);
362   int ret = avformat_open_input(&fmt_ctx, filename, NULL, &fopts);
363   av_dict_free(&fopts);
364   if( ret < 0 ) {
365     fprintf(stderr,"file open failed: %s\n", filename);
366     return ret;
367   }
368   ret = avformat_find_stream_info(fmt_ctx, NULL);
369   if( ret < 0 ) {
370     fprintf(stderr,"file probe failed: %s\n", filename);
371     return ret;
372   }
373
374   this->st = 0;
375   for( int i=0; !this->st && ret>=0 && i<(int)fmt_ctx->nb_streams; ++i ) {
376     AVStream *fst = fmt_ctx->streams[i];
377     AVMediaType type = fst->codecpar->codec_type;
378     if( type != AVMEDIA_TYPE_VIDEO ) continue;
379     if( --vid_no < 0 ) this->st = fst;
380   }
381
382   AVCodecID codec_id = st->codecpar->codec_id;
383   AVDictionary *copts = 0;
384   //av_dict_copy(&copts, opts, 0);
385   AVCodec *decoder = avcodec_find_decoder(codec_id);
386   ctx = avcodec_alloc_context3(decoder);
387   avcodec_parameters_to_context(ctx, st->codecpar);
388   if( avcodec_open2(ctx, decoder, &copts) < 0 ) {
389     fprintf(stderr,"codec open failed: %s\n", filename);
390     return -1;
391   }
392   av_dict_free(&copts);
393   ipic = av_frame_alloc();
394   eof = 0;
395   need_packet = 1;
396
397   AVRational framerate = av_guess_frame_rate(fmt_ctx, st, 0);
398   this->frame_rate = !framerate.den ? 0 : (double)framerate.num / framerate.den;
399   this->pix_fmt = (AVPixelFormat)st->codecpar->format;
400   this->width  = st->codecpar->width;
401   this->height = st->codecpar->height;
402   return 0;
403 }
404
405 AVFrame *ffcmpr::read_frame()
406 {
407   av_frame_unref(ipic);
408
409   for( int retrys=1000; --retrys>=0; ) {
410     if( need_packet ) {
411       if( eof ) return 0;
412       AVPacket *pkt = &ipkt;
413       av_packet_unref(pkt);
414       int ret = av_read_frame(fmt_ctx, pkt);
415       if( ret < 0 ) {
416         if( ret != AVERROR_EOF ) return 0;
417         ret = 0;  eof = 1;  pkt = 0;
418       }
419       if( pkt ) {
420         if( pkt->stream_index != st->index ) continue;
421         if( !pkt->data || !pkt->size ) continue;
422       }
423       avcodec_send_packet(ctx, pkt);
424       need_packet = 0;
425     }
426     int ret = avcodec_receive_frame(ctx, ipic);
427     if( ret >= 0 ) return ipic;
428     if( ret != AVERROR(EAGAIN) ) {
429       eof = 1; need_packet = 0;
430       break;
431     }
432     need_packet = 1;
433   }
434   return 0;
435 }
436
437 static inline int get_depth(AVPixelFormat pix_fmt)
438 {
439   int depth = 0;
440   const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
441   if( desc ) {
442     for( int i=desc->nb_components; --i>=0; ) {
443       int bits = desc->comp[i].depth;
444       if( depth < bits ) depth = bits;
445     }
446   }
447   return depth;
448 }
449
450 static int diff_frame(AVFrame *afrm, AVFrame *bfrm,
451     gg_ximage *ximg, int w, int h, int s, int a1)
452 {
453   int n = 0, m = 0;
454   uint8_t *arow = afrm->data[0];
455   uint8_t *brow = bfrm->data[0];
456   uint8_t *frow = ximg->data;
457   int asz = afrm->linesize[0], bsz = afrm->linesize[0];
458   XImage *ximage = ximg->ximage;
459   int fsz = ximage->bytes_per_line;
460   int rsz = w, bpp = (ximage->bits_per_pixel+7)/8;
461   uint32_t *lsb = ximg->lsb;
462
463   for( int y=h; --y>=0; arow+=asz, brow+=bsz, frow+=fsz ) {
464     uint16_t *ap = (uint16_t*)arow + a1;
465     uint16_t *bp = (uint16_t*)brow + a1;
466     uint8_t *fp = frow;
467     for( int x=rsz; --x>=0; ) {
468       uint32_t rgb = 0;  uint8_t *rp = fp;
469       for( int i=0; i<3; ++i ) {
470         int d = *ap++ - *bp++;
471         if( s > 0 ) d >>= s;
472         else if( s < 0 ) d <<= -s;
473         int v = d + 128;
474         if( v > 255 ) v = 255;
475         else if( v < 0 ) v = 0;
476         rgb |= v * lsb[i];
477         m += d;
478         if( d < 0 ) d = -d;
479         n += d;
480       }
481       if( ximage->byte_order == MSBFirst )
482         for( int i=3; --i>=0; ) *rp++ = rgb>>(8*i);
483       else
484         for( int i=0; i<3; ++i ) *rp++ = rgb>>(8*i);
485       ++ap;  ++bp;  fp += bpp;
486     }
487   }
488   int sz = h*rsz;
489   printf("%d %d %d %f", sz, m, n, (double)n/sz);
490   tm += m;  tn += n;
491   return n;
492 }
493
494 int main(int ac, char **av)
495 {
496   setbuf(stdout,NULL);
497   XInitThreads();
498   Display *display = XOpenDisplay(getenv("DISPLAY"));
499   if( !display ) {
500     fprintf(stderr,"Unable to open display\n");
501     exit(1);
502   }
503   if( ac < 3 ) {
504     printf("usage: %s a.fmt b.fmt <frm0> <s>\n"
505         "  a = src media, b = src media, frm0 = a/b skew\n"
506         "  s = shift <0:lt, =0:none(dft), >0:rt\n"
507         "  env var GG_LOG_LEVEL=q/f/e/v/d/<nbr>\n", av[0]);
508     exit(1);
509   }
510   const char *cp = getenv("GG_LOG_LEVEL");
511   if( cp ) {
512     int lvl = -1;
513     switch( *cp ) {
514     case 'q':  lvl = AV_LOG_QUIET;    break;
515     case 'f':  lvl = AV_LOG_FATAL;    break;
516     case 'e':  lvl = AV_LOG_ERROR;    break;
517     case 'v':  lvl = AV_LOG_VERBOSE;  break;
518     case 'd':  lvl = AV_LOG_DEBUG;    break;
519     case '0'...'9': lvl = atoi(cp);   break;
520     }
521     if( lvl >= 0 )
522       av_log_set_level(lvl);
523   }
524
525   ffcmpr a, b;
526   if( a.open_decoder(av[1],0) ) return 1;
527   if( b.open_decoder(av[2],0) ) return 1;
528
529   int64_t err = 0;
530   int frm_no = 0;
531   int frm0 = ac>3 ? atoi(av[3]) : 0;
532   int s = ac>4 ? atoi(av[4]) : 0;
533
534   printf("file a:%s\n", av[1]);
535   printf("  id 0x%06x:", a.ctx->codec_id);
536   const AVCodecDescriptor *adesc = avcodec_descriptor_get(a.ctx->codec_id);
537   printf("  video %s\n", adesc ? adesc->name : " (unkn)");
538   printf(" %dx%d %5.2f", a.width, a.height, a.frame_rate);
539   const char *apix = av_get_pix_fmt_name(a.pix_fmt);
540   int ad = get_depth(a.pix_fmt);
541   printf(" pix %s, depth=%d\n", apix ? apix : "(unkn)", ad);
542
543   printf("file b:%s\n", av[2]);
544   printf("  id 0x%06x:", b.ctx->codec_id);
545   const AVCodecDescriptor *bdesc = avcodec_descriptor_get(b.ctx->codec_id);
546   printf("  video %s\n", bdesc ? bdesc->name : " (unkn)");
547   printf(" %dx%d %5.2f", b.width, b.height, b.frame_rate);
548   const char *bpix = av_get_pix_fmt_name(b.pix_fmt);
549   int bd = get_depth(b.pix_fmt);
550   printf(" pix %s, depth=%d\n", bpix ? bpix : "(unkn)", bd);
551   int d = ad>bd ? ad : bd;
552   s = 16-d + s;
553   int lsb = s, msb = lsb + 7;
554   if( lsb < 0 ) lsb = 0;
555   if( msb > 15 ) msb = 15;
556   printf("shift: %d, msb..lsb: %d..%d of uint16\n", s, msb, lsb);
557
558 //  if( a.ctx->codec_id != b.ctx->codec_id ) { printf("codec mismatch\n"); return 1;}
559   if( a.width != b.width ) { printf("width mismatch\n"); return 1;}
560   if( a.height != b.height ) { printf("height mismatch\n"); return 1;}
561 //  if( a.frame_rate != b.frame_rate ) { printf("framerate mismatch\n"); return 1;}
562 //  if( a.pix_fmt != b.pix_fmt ) { printf("format mismatch\n"); return 1;}
563
564   signal(SIGINT,sigint);
565   const AVPixFmtDescriptor *afmt = av_pix_fmt_desc_get(a.pix_fmt);
566   AVPixelFormat a_pix_fmt = afmt->flags & AV_PIX_FMT_FLAG_RGB ?
567       AV_PIX_FMT_RGBA64LE : AV_PIX_FMT_AYUV64LE ;
568   const AVPixFmtDescriptor *bfmt = av_pix_fmt_desc_get(b.pix_fmt);
569   AVPixelFormat b_pix_fmt = bfmt->flags & AV_PIX_FMT_FLAG_RGB ?
570       AV_PIX_FMT_RGBA64LE : AV_PIX_FMT_AYUV64LE ;
571   if( a_pix_fmt != b_pix_fmt ) {
572     printf(" a/b yuv/rgb mismatched, using a = %s\n", apix);
573     b_pix_fmt = a_pix_fmt;
574   }
575   int a1 = a_pix_fmt == AV_PIX_FMT_AYUV64LE ? 1 : 0; // alpha 1st chan
576
577   struct SwsContext *a_cvt = sws_getCachedContext(0, a.width, a.height, a.pix_fmt,
578                 a.width, a.height, a_pix_fmt, SWS_POINT, 0, 0, 0);
579   struct SwsContext *b_cvt = sws_getCachedContext(0, b.width, b.height, b.pix_fmt,
580                 b.width, b.height, b_pix_fmt, SWS_POINT, 0, 0, 0);
581   if( !a_cvt || !b_cvt ) {
582     printf("sws_getCachedContext() failed\n");
583     exit(1);
584   }
585
586   AVFrame *afrm = av_frame_alloc();
587   av_image_alloc(afrm->data, afrm->linesize,
588      a.width, a.height, a_pix_fmt, 1);
589
590   AVFrame *bfrm = av_frame_alloc();
591   av_image_alloc(bfrm->data, bfrm->linesize,
592      b.width, b.height, b_pix_fmt, 1);
593 { gg_window gw(display, 10,10, a.width,a.height);
594   gw.show();
595   gg_thread thr(gw, 1);
596   thr.start();
597
598   while( frm0 > 0 ) { a.read_frame(); --frm0; }
599   while( frm0 < 0 ) { b.read_frame(); ++frm0; }
600
601   while( !done ) {
602     AVFrame *ap = a.read_frame();
603     if( !ap ) break;
604     AVFrame *bp = b.read_frame();
605     if( !bp ) break;
606     sws_scale(a_cvt, ap->data, ap->linesize, 0, ap->height,
607        afrm->data, afrm->linesize);
608     sws_scale(b_cvt, bp->data, bp->linesize, 0, bp->height,
609        bfrm->data, bfrm->linesize);
610     thr.draw_lock();
611     gg_ximage *fimg = thr.next_img();
612     int ret = diff_frame(afrm, bfrm, fimg, ap->width, ap->height, s, a1);
613     thr.post(fimg);
614     err += ret;  ++frm_no;
615     printf("  %d\n",frm_no);
616   }
617
618   av_freep(&afrm->data);
619   av_frame_free(&afrm);
620   av_freep(&bfrm->data);
621   av_frame_free(&bfrm);
622   
623   b.close_decoder();
624   a.close_decoder();
625
626   thr.join();
627   gw.hide(); }
628   XCloseDisplay(display);
629   printf("\n%jd %jd\n", tm, tn);
630   return 0;
631 }
632