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"
34 void dst_exit(GtkWidget *widget, gpointer data)
41 gtk_window(int width, int height);
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;
57 static void *entry(void *t);
64 void draw_lock() { pthread_mutex_lock(&draw); }
65 void draw_unlock() { pthread_mutex_unlock(&draw); }
68 gtk_window::gtk_window(int width, int height)
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);
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);
92 row0 = new unsigned char *[height];
93 row1 = new unsigned char *[height];
95 for( int i=0; i<height; ++i ) {
96 row0[i] = bfr0 + i*linesize;
97 row1[i] = bfr1 + i*linesize;
102 flip_bfrs = ((uint64_t)bfr0 ^ (uint64_t)bfr1);
103 flip_rows = ((uint64_t)row0 ^ (uint64_t)row1);
104 pthread_mutex_init(&draw, 0);
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);
114 gtk_window::~gtk_window()
118 pthread_mutex_destroy(&draw);
121 void *gtk_window::entry(void *t)
123 return ((gtk_window*)t)->run();
126 void gtk_window::start()
129 pthread_attr_init(&attr);
130 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
132 pthread_create(&tid, &attr, &entry, this);
133 pthread_attr_destroy(&attr);
136 void *gtk_window::run()
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);
145 unsigned long *fbfrs = (unsigned long *)&bfrs; *fbfrs ^= flip_bfrs;
146 unsigned long *frows = (unsigned long *)&rows; *frows ^= flip_rows;
151 gtk_main_iteration();
157 uint8_t *gtk_window::next_bfr()
162 void gtk_window::post()
174 AVFormatContext *fmt_ctx;
178 AVPixelFormat pix_fmt;
181 int open_decoder(const char *filename, int vid_no);
182 void close_decoder();
183 AVFrame *read_frame();
188 av_init_packet(&this->ipkt);
193 this->frame_rate = 0;
194 this->pix_fmt = AV_PIX_FMT_NONE;
198 void ffcmpr::close_decoder()
200 av_packet_unref(&ipkt);
201 if( !fmt_ctx ) return;
202 avformat_close_input(&fmt_ctx);
203 av_frame_free(&ipic);
211 int ffcmpr::open_decoder(const char *filename, int vid_no)
214 if( stat(filename, &fst) ) return 1;
216 av_log_set_level(AV_LOG_VERBOSE);
218 AVDictionary *fopts = 0;
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);
226 fprintf(stderr,"file open failed: %s\n", filename);
229 ret = avformat_find_stream_info(fmt_ctx, NULL);
231 fprintf(stderr,"file probe failed: %s\n", filename);
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;
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);
251 av_dict_free(&copts);
252 ipic = av_frame_alloc();
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;
263 AVFrame *ffcmpr::read_frame()
265 av_frame_unref(ipic);
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 ) {
276 ret = avcodec_decode_video2(st->codec, ipic, &got_frame, &ipkt);
277 if( ret <= 0 ) break;
287 static int diff_frame(AVFrame *afrm, AVFrame *bfrm, uint8_t *fp, int w, int h)
290 uint8_t *arow = afrm->data[0];
291 uint8_t *brow = bfrm->data[0];
292 int asz = afrm->linesize[0], bsz = afrm->linesize[0];
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;
307 printf("%d %d %d %f", sz, m, n, (double)n/sz);
311 int main(int ac, char **av)
320 if( a.open_decoder(av[1],0) ) return 1;
321 if( b.open_decoder(av[2],0) ) return 1;
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)");
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)");
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;}
345 signal(SIGINT,sigint);
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");
356 AVFrame *afrm = av_frame_alloc();
357 av_image_alloc(afrm->data, afrm->linesize,
358 a.width, a.height, AV_PIX_FMT_RGB24, 1);
360 AVFrame *bfrm = av_frame_alloc();
361 av_image_alloc(bfrm->data, bfrm->linesize,
362 b.width, b.height, AV_PIX_FMT_RGB24, 1);
364 gtk_window gw(a.width, a.height);
370 if( ac>3 && (ret=atoi(av[3])) ) {
371 while( ret > 0 ) { a.read_frame(); --ret; }
372 while( ret < 0 ) { b.read_frame(); ++ret; }
376 AVFrame *ap = a.read_frame();
378 AVFrame *bp = b.read_frame();
380 sws_scale(a_cvt, ap->data, ap->linesize, 0, ap->height,
381 afrm->data, afrm->linesize);
382 sws_scale(b_cvt, bp->data, bp->linesize, 0, bp->height,
383 bfrm->data, bfrm->linesize);
384 uint8_t *fbfr = gw.next_bfr();
385 ret = diff_frame(afrm, bfrm, fbfr, ap->width, ap->height);
386 err += ret; ++frm_no;
387 printf(" %d\n",frm_no);
391 av_frame_free(&afrm);
392 av_frame_free(&bfrm);