search fixes, preset fixes, ladspa icon logging, igor pref theme, drag btn rollover
[goodguy/history.git] / cinelerra-5.1 / cinelerra / ydiff.C
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <math.h>
5 #include <sys/stat.h>
6 #include <sys/time.h>
7
8 extern "C" {
9 #include "libavfilter/buffersrc.h"
10 #include "libavfilter/buffersink.h"
11 #include "libavformat/avformat.h"
12 #include "libavformat/avio.h"
13 #include "libavcodec/avcodec.h"
14 #include "libavfilter/avfilter.h"
15 #include "libavutil/avutil.h"
16 #include "libavutil/imgutils.h"
17 #include "libavutil/opt.h"
18 #include "libavutil/pixdesc.h"
19 #include "libswresample/swresample.h"
20 #include "libswscale/swscale.h"
21 }
22
23 #include <gtk/gtk.h>
24 #include <gdk/gdk.h>
25
26 int done = 0;
27
28 void sigint(int n)
29 {
30   done = 1;
31 }
32
33
34 void dst_exit(GtkWidget *widget, gpointer data)
35 {
36    exit(0);
37 }
38
39 class gtk_window {
40 public:
41   gtk_window(int width, int height);
42   ~gtk_window();
43
44   GdkVisual *visual;
45   GtkWidget *window;
46   GtkWidget *image;
47   GtkWidget *panel_hbox;
48   GdkImage  *img0, *img1;
49   GdkPixbuf *pbuf0, *pbuf1;
50   unsigned char *bfr, *bfrs, *bfr0, *bfr1;
51   unsigned char **rows, **row0, **row1;
52   uint64_t flip_bfrs, flip_rows;
53   int width, height, linesize;
54   int done;
55
56   pthread_t tid;
57   static void *entry(void *t);
58   void start();
59   void *run();
60   uint8_t *next_bfr();
61   void post();
62
63   pthread_mutex_t draw;
64   void draw_lock() { pthread_mutex_lock(&draw); }
65   void draw_unlock() { pthread_mutex_unlock(&draw); }
66 };
67
68 gtk_window::gtk_window(int width, int height)
69 {
70   this->width = width;
71   this->height = height;
72   this->linesize = width*3;
73   visual = gdk_visual_get_system();
74   window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
75   gtk_signal_connect(GTK_OBJECT(window),"destroy",
76      GTK_SIGNAL_FUNC(dst_exit),NULL);
77   gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_NONE);
78   /* try for shared image bfr, only seems to work with gtk_rgb */
79   img0 = gdk_image_new(GDK_IMAGE_SHARED, visual, width, height);
80   pbuf0 = gdk_pixbuf_new_from_data((const guchar *)img0->mem,
81      GDK_COLORSPACE_RGB,FALSE,8,width,height,linesize,NULL,NULL);
82   bfr0 = gdk_pixbuf_get_pixels(pbuf0);
83   memset(bfr0,0,height*linesize);
84   image = gtk_image_new_from_pixbuf(pbuf0);
85   /* double buffered */
86   img1 = gdk_image_new(GDK_IMAGE_SHARED, visual, width, height);
87   pbuf1 = gdk_pixbuf_new_from_data((const guchar *)img1->mem,
88      GDK_COLORSPACE_RGB,FALSE,8,width,height,linesize,NULL,NULL);
89   bfr1 = gdk_pixbuf_get_pixels(pbuf1);
90   memset(bfr1,0,height*linesize);
91
92   row0 = new unsigned char *[height];
93   row1 = new unsigned char *[height];
94
95   for( int i=0; i<height; ++i ) {
96     row0[i] = bfr0 + i*linesize;
97     row1[i] = bfr1 + i*linesize;
98   }
99   bfrs = bfr0;
100   rows = row0;
101
102   flip_bfrs = ((uint64_t)bfr0 ^ (uint64_t)bfr1);
103   flip_rows = ((uint64_t)row0 ^ (uint64_t)row1);
104   pthread_mutex_init(&draw, 0);
105   post();
106   
107   panel_hbox = gtk_hbox_new(FALSE,0);
108   gtk_container_add(GTK_CONTAINER(window), panel_hbox);
109   /* pack image into panel */
110   gtk_box_pack_start(GTK_BOX(panel_hbox), image, TRUE, TRUE, 0);
111   gtk_widget_show_all(window);
112 }
113
114 gtk_window::~gtk_window()
115 {
116   gdk_flush();
117   gtk_widget_destroy(window);
118   g_object_unref(pbuf0);
119   g_object_unref(img0);
120   g_object_unref(pbuf1);
121   g_object_unref(img1);
122   delete [] row0;
123   delete [] row1;
124   pthread_mutex_destroy(&draw);
125 }
126
127 void *gtk_window::entry(void *t)
128 {
129   return ((gtk_window*)t)->run();
130 }
131
132 void gtk_window::start()
133 {
134   pthread_attr_t attr;
135   pthread_attr_init(&attr);
136   pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
137   done = 0;
138   pthread_create(&tid, &attr, &entry, this);
139   pthread_attr_destroy(&attr);
140 }
141
142 void *gtk_window::run()
143 {
144   while( !done ) {
145     if( !gtk_events_pending() ) {
146       if( !bfr ) { usleep(10000);  continue; }
147       GdkGC *blk = image->style->black_gc;
148       gdk_draw_rgb_image(image->window,blk, 0,0,width,height,
149          GDK_RGB_DITHER_NONE,bfr,linesize);
150       gdk_flush();
151       unsigned long *fbfrs = (unsigned long *)&bfrs;  *fbfrs ^= flip_bfrs;
152       unsigned long *frows = (unsigned long *)&rows;  *frows ^= flip_rows;
153       bfr = 0;
154       draw_unlock();
155     }
156     else
157       gtk_main_iteration();
158   }
159
160   return (void*)0;
161 }
162
163 uint8_t *gtk_window::next_bfr()
164 {
165   return bfrs;
166 }
167
168 void gtk_window::post()
169 {
170   draw_lock();
171   bfr = bfrs;
172 }
173
174
175 class ffcmpr {
176 public:
177   ffcmpr();
178   ~ffcmpr();
179   AVPacket ipkt;
180   AVFormatContext *fmt_ctx;
181   AVFrame *ipic;
182   AVStream *st;
183   AVCodecContext *ctx;
184   AVPixelFormat pix_fmt;
185   double frame_rate;
186   int width, height;
187   int need_packet, eof;
188   int open_decoder(const char *filename, int vid_no);
189   void close_decoder();
190   AVFrame *read_frame();
191 };
192
193 ffcmpr::ffcmpr()
194 {
195   av_init_packet(&this->ipkt);
196   this->fmt_ctx = 0;
197   this->ipic = 0;
198   this->st = 0;
199   this->ctx = 0 ;
200   this->frame_rate = 0;
201   this->need_packet = 0;
202   this->eof = 0;
203   this->pix_fmt = AV_PIX_FMT_NONE;
204   width = height = 0;
205 }
206
207 void ffcmpr::close_decoder()
208 {
209   av_packet_unref(&ipkt);
210   if( !fmt_ctx ) return;
211   if( ctx ) avcodec_free_context(&ctx);
212   avformat_close_input(&fmt_ctx);
213   av_frame_free(&ipic);
214 }
215
216 ffcmpr::~ffcmpr()
217 {
218   close_decoder();
219 }
220
221 int ffcmpr::open_decoder(const char *filename, int vid_no)
222 {
223   struct stat fst;
224   if( stat(filename, &fst) ) return 1;
225
226   av_log_set_level(AV_LOG_VERBOSE);
227   fmt_ctx = 0;
228   AVDictionary *fopts = 0;
229   av_register_all();
230   av_dict_set(&fopts, "formatprobesize", "5000000", 0);
231   av_dict_set(&fopts, "scan_all_pmts", "1", 0);
232   av_dict_set(&fopts, "threads", "auto", 0);
233   int ret = avformat_open_input(&fmt_ctx, filename, NULL, &fopts);
234   av_dict_free(&fopts);
235   if( ret < 0 ) {
236     fprintf(stderr,"file open failed: %s\n", filename);
237     return ret;
238   }
239   ret = avformat_find_stream_info(fmt_ctx, NULL);
240   if( ret < 0 ) {
241     fprintf(stderr,"file probe failed: %s\n", filename);
242     return ret;
243   }
244
245   this->st = 0;
246   for( int i=0; !this->st && ret>=0 && i<(int)fmt_ctx->nb_streams; ++i ) {
247     AVStream *fst = fmt_ctx->streams[i];
248     AVMediaType type = fst->codecpar->codec_type;
249     if( type != AVMEDIA_TYPE_VIDEO ) continue;
250     if( --vid_no < 0 ) this->st = fst;
251   }
252
253   AVCodecID codec_id = st->codecpar->codec_id;
254   AVDictionary *copts = 0;
255   //av_dict_copy(&copts, opts, 0);
256   AVCodec *decoder = avcodec_find_decoder(codec_id);
257   ctx = avcodec_alloc_context3(decoder);
258   avcodec_parameters_to_context(ctx, st->codecpar);
259   if( avcodec_open2(ctx, decoder, &copts) < 0 ) {
260     fprintf(stderr,"codec open failed: %s\n", filename);
261     return -1;
262   }
263   av_dict_free(&copts);
264   ipic = av_frame_alloc();
265   eof = 0;
266   need_packet = 1;
267
268   AVRational framerate = av_guess_frame_rate(fmt_ctx, st, 0);
269   this->frame_rate = !framerate.den ? 0 : (double)framerate.num / framerate.den;
270   this->pix_fmt = (AVPixelFormat)st->codecpar->format;
271   this->width  = st->codecpar->width;
272   this->height = st->codecpar->height;
273   return 0;
274 }
275
276 AVFrame *ffcmpr::read_frame()
277 {
278   av_frame_unref(ipic);
279
280   for( int retrys=1000; --retrys>=0; ) {
281     if( need_packet ) {
282       if( eof ) return 0;
283       AVPacket *pkt = &ipkt;
284       av_packet_unref(pkt);
285       int ret = av_read_frame(fmt_ctx, pkt);
286       if( ret < 0 ) {
287         if( ret != AVERROR_EOF ) return 0;
288         ret = 0;  eof = 1;  pkt = 0;
289       }
290       if( pkt ) {
291         if( pkt->stream_index != st->index ) continue;
292         if( !pkt->data || !pkt->size ) continue;
293       }
294       avcodec_send_packet(ctx, pkt);
295       need_packet = 0;
296     }
297     int ret = avcodec_receive_frame(ctx, ipic);
298     if( ret >= 0 ) return ipic;
299     if( ret != AVERROR(EAGAIN) ) {
300       eof = 1; need_packet = 0;
301       break;
302     }
303     need_packet = 1;
304   }
305   return 0;
306 }
307
308 static int diff_frame(AVFrame *afrm, AVFrame *bfrm, uint8_t *fp, int w, int h)
309 {
310   int n = 0, m = 0;
311   uint8_t *arow = afrm->data[0];
312   uint8_t *brow = bfrm->data[0];
313   int asz = afrm->linesize[0], bsz = afrm->linesize[0];
314   int rsz = w * 3;
315   for( int y=h; --y>=0; arow+=asz, brow+=bsz ) {
316     uint8_t *ap = arow, *bp = brow;
317     for( int x=rsz; --x>=0; ++ap,++bp ) {
318       int d = *ap - *bp, v = d + 128;
319       if( v > 255 ) v = 255;
320       else if( v < 0 ) v = 0;
321       *fp++ = v;
322       m += d;
323       if( d < 0 ) d = -d;
324       n += d;
325     }
326   }
327   int sz = h*rsz;
328   printf("%d %d %d %f", sz, m, n, (double)n/sz);
329   return n;
330 }
331
332 int main(int ac, char **av)
333 {
334   int ret;
335   setbuf(stdout,NULL);
336
337   gtk_set_locale();
338   gtk_init(&ac, &av);
339
340   ffcmpr a, b;
341   if( a.open_decoder(av[1],0) ) return 1;
342   if( b.open_decoder(av[2],0) ) return 1;
343
344   printf("file a:%s\n", av[1]);
345   printf("  id 0x%06x:", a.ctx->codec_id);
346   const AVCodecDescriptor *adesc = avcodec_descriptor_get(a.ctx->codec_id);
347   printf("  video %s\n", adesc ? adesc->name : " (unkn)");
348   printf(" %dx%d %5.2f", a.width, a.height, a.frame_rate);
349   const char *apix = av_get_pix_fmt_name(a.pix_fmt);
350   printf(" pix %s\n", apix ? apix : "(unkn)");
351
352   printf("file b:%s\n", av[2]);
353   printf("  id 0x%06x:", b.ctx->codec_id);
354   const AVCodecDescriptor *bdesc = avcodec_descriptor_get(b.ctx->codec_id);
355   printf("  video %s\n", bdesc ? bdesc->name : " (unkn)");
356   printf(" %dx%d %5.2f", b.width, b.height, b.frame_rate);
357   const char *bpix = av_get_pix_fmt_name(b.pix_fmt);
358   printf(" pix %s\n", bpix ? bpix : "(unkn)");
359
360 //  if( a.ctx->codec_id != b.ctx->codec_id ) { printf("codec mismatch\n"); return 1;}
361   if( a.width != b.width ) { printf("width mismatch\n"); return 1;}
362   if( a.height != b.height ) { printf("height mismatch\n"); return 1;}
363   if( a.frame_rate != b.frame_rate ) { printf("framerate mismatch\n"); return 1;}
364 //  if( a.pix_fmt != b.pix_fmt ) { printf("format mismatch\n"); return 1;}
365
366   signal(SIGINT,sigint);
367
368   struct SwsContext *a_cvt = sws_getCachedContext(0, a.width, a.height, a.pix_fmt,
369                 a.width, a.height, AV_PIX_FMT_RGB24, SWS_POINT, 0, 0, 0);
370   struct SwsContext *b_cvt = sws_getCachedContext(0, b.width, b.height, b.pix_fmt,
371                 b.width, b.height, AV_PIX_FMT_RGB24, SWS_POINT, 0, 0, 0);
372   if( !a_cvt || !b_cvt ) {
373     printf("sws_getCachedContext() failed\n");
374     return 1;
375   }
376
377   AVFrame *afrm = av_frame_alloc();
378   av_image_alloc(afrm->data, afrm->linesize,
379      a.width, a.height, AV_PIX_FMT_RGB24, 1);
380
381   AVFrame *bfrm = av_frame_alloc();
382   av_image_alloc(bfrm->data, bfrm->linesize,
383      b.width, b.height, AV_PIX_FMT_RGB24, 1);
384
385   gtk_window gw(a.width, a.height);
386   gw.start();
387
388   int64_t err = 0;
389   int frm_no = 0;
390
391   if( ac>3 && (ret=atoi(av[3])) ) {
392     while( ret > 0 ) { a.read_frame(); --ret; }
393     while( ret < 0 ) { b.read_frame(); ++ret; }
394   }
395
396   while( !done ) {
397     AVFrame *ap = a.read_frame();
398     if( !ap ) break;
399     AVFrame *bp = b.read_frame();
400     if( !bp ) break;
401     sws_scale(a_cvt, ap->data, ap->linesize, 0, ap->height,
402        afrm->data, afrm->linesize);
403     sws_scale(b_cvt, bp->data, bp->linesize, 0, bp->height,
404        bfrm->data, bfrm->linesize);
405     uint8_t *fbfr = gw.next_bfr();
406     ret = diff_frame(afrm, bfrm, fbfr, ap->width, ap->height);
407     err += ret;  ++frm_no;
408     printf("  %d\n",frm_no);
409     gw.post();
410   }
411
412   av_freep(&afrm->data);
413   av_frame_free(&afrm);
414   av_freep(&bfrm->data);
415   av_frame_free(&bfrm);
416   
417   b.close_decoder();
418   a.close_decoder();
419   return 0;
420 }
421