add h264 lossless, ru po upd, add ydiff, ffmpeg cmdl/xfer fixes, build upgrades,...
[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   delete [] row0;
117   delete [] row1;
118   pthread_mutex_destroy(&draw);
119 }
120
121 void *gtk_window::entry(void *t)
122 {
123   return ((gtk_window*)t)->run();
124 }
125
126 void gtk_window::start()
127 {
128   pthread_attr_t attr;
129   pthread_attr_init(&attr);
130   pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
131   done = 0;
132   pthread_create(&tid, &attr, &entry, this);
133   pthread_attr_destroy(&attr);
134 }
135
136 void *gtk_window::run()
137 {
138   while( !done ) {
139     if( !gtk_events_pending() ) {
140       if( !bfr ) { usleep(10000);  continue; }
141       GdkGC *blk = image->style->black_gc;
142       gdk_draw_rgb_image(image->window,blk, 0,0,width,height,
143          GDK_RGB_DITHER_NONE,bfr,linesize);
144       gdk_flush();
145       uint64_t *fbfrs = (uint64_t *)&bfrs;  *fbfrs ^= flip_bfrs;
146       uint64_t *frows = (uint64_t *)&rows;  *frows ^= flip_rows;
147       bfr = 0;
148       draw_unlock();
149     }
150     else
151       gtk_main_iteration();
152   }
153
154   return (void*)0;
155 }
156
157 uint8_t *gtk_window::next_bfr()
158 {
159   return bfrs;
160 }
161
162 void gtk_window::post()
163 {
164   draw_lock();
165   bfr = bfrs;
166 }
167
168
169 class ffcmpr {
170 public:
171   ffcmpr();
172   ~ffcmpr();
173   AVPacket ipkt;
174   AVFormatContext *fmt_ctx;
175   AVFrame *ipic;
176   AVStream *st;
177   AVCodecContext *ctx;
178   AVPixelFormat pix_fmt;
179   double frame_rate;
180   int width, height;
181   int open_decoder(const char *filename, int vid_no);
182   void close_decoder();
183   AVFrame *read_frame();
184 };
185
186 ffcmpr::ffcmpr()
187 {
188   av_init_packet(&this->ipkt);
189   this->fmt_ctx = 0;
190   this->ipic = 0;
191   this->st = 0;
192   this->ctx = 0 ;
193   this->frame_rate = 0;
194   this->pix_fmt = AV_PIX_FMT_NONE;
195   width = height = 0;
196 }
197
198 void ffcmpr::close_decoder()
199 {
200   av_packet_unref(&ipkt);
201   if( !fmt_ctx ) return;
202   avformat_close_input(&fmt_ctx);
203   av_frame_free(&ipic);
204 }
205
206 ffcmpr::~ffcmpr()
207 {
208   close_decoder();
209 }
210
211 int ffcmpr::open_decoder(const char *filename, int vid_no)
212 {
213   struct stat fst;
214   if( stat(filename, &fst) ) return 1;
215
216   av_log_set_level(AV_LOG_VERBOSE);
217   fmt_ctx = 0;
218   AVDictionary *fopts = 0;
219   av_register_all();
220   av_dict_set(&fopts, "formatprobesize", "5000000", 0);
221   av_dict_set(&fopts, "scan_all_pmts", "1", 0);
222   av_dict_set(&fopts, "threads", "auto", 0);
223   int ret = avformat_open_input(&fmt_ctx, filename, NULL, &fopts);
224   av_dict_free(&fopts);
225   if( ret < 0 ) {
226     fprintf(stderr,"file open failed: %s\n", filename);
227     return ret;
228   }
229   ret = avformat_find_stream_info(fmt_ctx, NULL);
230   if( ret < 0 ) {
231     fprintf(stderr,"file probe failed: %s\n", filename);
232     return ret;
233   }
234
235   this->st = 0;
236   for( int i=0; !this->st && ret>=0 && i<(int)fmt_ctx->nb_streams; ++i ) {
237     AVStream *fst = fmt_ctx->streams[i];
238     AVMediaType type = fst->codec->codec_type;
239     if( type != AVMEDIA_TYPE_VIDEO ) continue;
240     if( --vid_no < 0 ) this->st = fst;
241   }
242
243   AVCodecID codec_id = st->codec->codec_id;
244   AVDictionary *copts = 0;
245   //av_dict_copy(&copts, opts, 0);
246   AVCodec *decoder = avcodec_find_decoder(codec_id);
247   if( avcodec_open2(st->codec, decoder, &copts) < 0 ) {
248     fprintf(stderr,"codec open failed: %s\n", filename);
249     return -1;
250   }
251   av_dict_free(&copts);
252   ipic = av_frame_alloc();
253
254   AVRational framerate = av_guess_frame_rate(fmt_ctx, st, 0);
255   this->frame_rate = !framerate.den ? 0 : (double)framerate.num / framerate.den;
256   this->ctx = st->codec;
257   this->pix_fmt = ctx->pix_fmt;
258   this->width  = ctx->width;
259   this->height = ctx->height;
260   return 0;
261 }
262
263 AVFrame *ffcmpr::read_frame()
264 {
265   av_frame_unref(ipic);
266
267   for( int retrys=1000; --retrys>=0; ) {
268     av_packet_unref(&ipkt);
269     int ret = av_read_frame(fmt_ctx, &ipkt);
270     if( ret == AVERROR_EOF ) break;
271     if( ret != 0 ) continue;
272     if( !ipkt.data ) continue;
273     if( ipkt.stream_index != st->index ) continue;
274     while( ipkt.size > 0 ) {
275       int got_frame = 0;
276       ret = avcodec_decode_video2(st->codec, ipic, &got_frame, &ipkt);
277       if( ret <= 0 ) break;
278       if( got_frame )
279         return ipic;
280       ipkt.data += ret;
281       ipkt.size -= ret;
282     }
283   }
284   return 0;
285 }
286
287 static int diff_frame(AVFrame *afrm, AVFrame *bfrm, uint8_t *fp, int w, int h)
288 {
289   int n = 0, m = 0;
290   uint8_t *arow = afrm->data[0];
291   uint8_t *brow = bfrm->data[0];
292   int asz = afrm->linesize[0], bsz = afrm->linesize[0];
293   int rsz = w * 3;
294   for( int y=h; --y>=0; arow+=asz, brow+=bsz ) {
295     uint8_t *ap = arow, *bp = brow;
296     for( int x=rsz; --x>=0; ++ap,++bp ) {
297       int d = *ap - *bp, v = d + 128;
298       if( v > 255 ) v = 255;
299       else if( v < 0 ) v = 0;
300       *fp++ = v;
301       m += d;
302       if( d < 0 ) d = -d;
303       n += d;
304     }
305   }
306   int sz = h*rsz;
307   printf("%d %d %d %f", sz, m, n, (double)n/sz);
308   return n;
309 }
310
311 int main(int ac, char **av)
312 {
313   int ret;
314   setbuf(stdout,NULL);
315
316   gtk_set_locale();
317   gtk_init(&ac, &av);
318
319   ffcmpr a, b;
320   if( a.open_decoder(av[1],0) ) return 1;
321   if( b.open_decoder(av[2],0) ) return 1;
322
323   printf("file a:%s\n", av[1]);
324   printf("  id 0x%06x:", a.ctx->codec_id);
325   const AVCodecDescriptor *adesc = avcodec_descriptor_get(a.ctx->codec_id);
326   printf("  video %s\n", adesc ? adesc->name : " (unkn)");
327   printf(" %dx%d %5.2f", a.width, a.height, a.frame_rate);
328   const char *apix = av_get_pix_fmt_name(a.pix_fmt);
329   printf(" pix %s\n", apix ? apix : "(unkn)");
330
331   printf("file b:%s\n", av[2]);
332   printf("  id 0x%06x:", b.ctx->codec_id);
333   const AVCodecDescriptor *bdesc = avcodec_descriptor_get(b.ctx->codec_id);
334   printf("  video %s\n", bdesc ? bdesc->name : " (unkn)");
335   printf(" %dx%d %5.2f", b.width, b.height, b.frame_rate);
336   const char *bpix = av_get_pix_fmt_name(b.pix_fmt);
337   printf(" pix %s\n", bpix ? bpix : "(unkn)");
338
339 //  if( a.ctx->codec_id != b.ctx->codec_id ) { printf("codec mismatch\n"); return 1;}
340   if( a.width != b.width ) { printf("width mismatch\n"); return 1;}
341   if( a.height != b.height ) { printf("height mismatch\n"); return 1;}
342   if( a.frame_rate != b.frame_rate ) { printf("framerate mismatch\n"); return 1;}
343 //  if( a.pix_fmt != b.pix_fmt ) { printf("format mismatch\n"); return 1;}
344
345   signal(SIGINT,sigint);
346
347   struct SwsContext *a_cvt = sws_getCachedContext(0, a.width, a.height, a.pix_fmt,
348                 a.width, a.height, AV_PIX_FMT_RGB24, SWS_POINT, 0, 0, 0);
349   struct SwsContext *b_cvt = sws_getCachedContext(0, b.width, b.height, b.pix_fmt,
350                 b.width, b.height, AV_PIX_FMT_RGB24, SWS_POINT, 0, 0, 0);
351   if( !a_cvt || !b_cvt ) {
352     printf("sws_getCachedContext() failed\n");
353     return 1;
354   }
355
356   AVFrame *afrm = av_frame_alloc();
357   av_image_alloc(afrm->data, afrm->linesize,
358      a.width, a.height, AV_PIX_FMT_RGB24, 1);
359
360   AVFrame *bfrm = av_frame_alloc();
361   av_image_alloc(bfrm->data, bfrm->linesize,
362      b.width, b.height, AV_PIX_FMT_RGB24, 1);
363
364   gtk_window gw(a.width, a.height);
365   gw.start();
366
367   int64_t err = 0;
368   int frm_no = 0;
369
370   while( !done ) {
371     AVFrame *ap = a.read_frame();
372     if( !ap ) break;
373     AVFrame *bp = b.read_frame();
374     if( !bp ) break;
375     sws_scale(a_cvt, ap->data, ap->linesize, 0, ap->height,
376        afrm->data, afrm->linesize);
377     sws_scale(b_cvt, bp->data, bp->linesize, 0, bp->height,
378        bfrm->data, bfrm->linesize);
379     uint8_t *fbfr = gw.next_bfr();
380     ret = diff_frame(afrm, bfrm, fbfr, ap->width, ap->height);
381     err += ret;  ++frm_no;
382     printf("  %d\n",frm_no);
383     gw.post();
384   }
385
386   av_frame_free(&afrm);
387   av_frame_free(&bfrm);
388   
389   b.close_decoder();
390   a.close_decoder();
391   return 0;
392 }
393