CLI option: --visualize
authorLoren Merritt <pengvado@videolan.org>
Thu, 12 May 2005 23:03:49 +0000 (23:03 +0000)
committerLoren Merritt <pengvado@videolan.org>
Thu, 12 May 2005 23:03:49 +0000 (23:03 +0000)
Displays the encoded video along with MB types and motion vectors.
patch by Tuukka Toivonen.

git-svn-id: svn://svn.videolan.org/x264/trunk@227 df754926-b1dd-0310-bc7b-ec298dee348c

Makefile
common/common.h
common/display-x11.c [new file with mode: 0644]
common/display.h [new file with mode: 0644]
common/visualize.c [new file with mode: 0644]
common/visualize.h [new file with mode: 0644]
configure
encoder/encoder.c
x264.c
x264.h

index 0895d3a..cf867ae 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -9,6 +9,11 @@ SRCS = common/mc.c common/predict.c common/pixel.c common/macroblock.c \
        encoder/set.c encoder/macroblock.c encoder/cabac.c \
        encoder/cavlc.c encoder/encoder.c encoder/eval.c
 
+# Visualization sources
+ifeq ($(VIS),yes)
+SRCS   += common/visualize.c common/display-x11.c
+endif
+
 # MMX/SSE optims
 ifeq ($(ARCH),X86)
 SRCS   += common/i386/mc-c.c common/i386/dct-c.c common/i386/predict.c
index 75a15d0..cefdde7 100644 (file)
@@ -455,6 +455,10 @@ struct x264_t
     x264_vlc_table_t *x264_total_zeros_lookup[15];
     x264_vlc_table_t *x264_total_zeros_dc_lookup[3];
     x264_vlc_table_t *x264_run_before_lookup[7];
+
+#if VISUALIZE
+    struct visualize_t *visualize;
+#endif
 };
 
 #endif
diff --git a/common/display-x11.c b/common/display-x11.c
new file mode 100644 (file)
index 0000000..3607618
--- /dev/null
@@ -0,0 +1,231 @@
+/*****************************************************************************
+ * x264: h264 encoder
+ *****************************************************************************
+ * Copyright (C) 2005 x264 project
+ *
+ * Author: Tuukka Toivonen <tuukkat@ee.oulu.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "display.h"
+
+static long event_mask = ConfigureNotify|ExposureMask|KeyPressMask|ButtonPressMask|StructureNotifyMask|ResizeRedirectMask;
+
+static Display *disp_display = NULL;
+static struct disp_window {
+       int init;
+       Window window;
+} disp_window[10];
+
+static inline void disp_chkerror(int cond, char *e) {
+       if (!cond) return;
+       fprintf(stderr, "error: %s\n", e ? e : "?");
+       abort();
+}
+
+static void disp_init_display(void) {
+       Visual *visual;
+       int dpy_class;
+       int screen;
+       int dpy_depth;
+
+       if (disp_display != NULL) return;
+       memset(&disp_window, 0, sizeof(disp_window));
+       disp_display = XOpenDisplay("");
+       disp_chkerror(!disp_display, "no display");
+       screen = DefaultScreen(disp_display);
+       visual = DefaultVisual(disp_display, screen);
+       dpy_class = visual->class;
+       dpy_depth = DefaultDepth(disp_display, screen);
+       disp_chkerror(!((dpy_class == TrueColor && dpy_depth == 32)
+               || (dpy_class == TrueColor && dpy_depth == 24)
+               || (dpy_class == TrueColor && dpy_depth == 16)
+               || (dpy_class == PseudoColor && dpy_depth == 8)),
+               "requires 8 bit PseudoColor or 16/24/32 bit TrueColor display");
+}
+
+static void disp_init_window(int num, int width, int height, const unsigned char *tit) {
+       XSizeHints *shint;
+       XSetWindowAttributes xswa;
+       XEvent xev;
+       int screen = DefaultScreen(disp_display);
+       Visual *visual = DefaultVisual (disp_display, screen);
+       unsigned int fg, bg;
+       unsigned int mask;
+       char title[200];
+       Window window;
+       int dpy_depth;
+
+       if (tit) {
+               snprintf(title, 200, "%s: %i/disp", tit, num);
+       } else {
+               snprintf(title, 200, "%i/disp", num);
+       }
+       shint = XAllocSizeHints();
+       disp_chkerror(!shint, "memerror");
+       shint->min_width = shint->max_width = shint->width = width;
+       shint->min_height = shint->max_height = shint->height = height;
+       shint->flags = PSize | PMinSize | PMaxSize;
+       disp_chkerror(num<0 || num>=10, "bad win num");
+       if (!disp_window[num].init) {
+               disp_window[num].init = 1;
+               bg = WhitePixel(disp_display, screen);
+               fg = BlackPixel(disp_display, screen);
+               dpy_depth = DefaultDepth(disp_display, screen);
+               if (dpy_depth==32 || dpy_depth==24 || dpy_depth==16) {
+                       mask |= CWColormap;
+                       xswa.colormap = XCreateColormap(disp_display, DefaultRootWindow(disp_display), visual, AllocNone);
+               }
+               xswa.background_pixel = bg;
+               xswa.border_pixel = fg;
+               xswa.backing_store = Always;
+               xswa.backing_planes = -1;
+               xswa.bit_gravity = NorthWestGravity;
+               mask = CWBackPixel | CWBorderPixel | CWBackingStore | CWBackingPlanes | CWBitGravity;
+               window = XCreateWindow(disp_display, DefaultRootWindow(disp_display),
+                               shint->x, shint->y, shint->width, shint->height,
+                               1, dpy_depth, InputOutput, visual, mask, &xswa);
+               disp_window[num].window = window;
+
+               XSelectInput(disp_display, window, event_mask);
+               XSetStandardProperties(disp_display, window, title, title, None, NULL, 0, shint);       /* Tell other applications about this window */
+               XMapWindow(disp_display, window);                                                       /* Map window. */
+               do {                                                                                    /* Wait for map. */
+                       XNextEvent(disp_display, &xev);
+               } while (xev.type!=MapNotify || xev.xmap.event!=window);
+               //XSelectInput(disp_display, window, KeyPressMask);                                     /*  XSelectInput(display, window, NoEventMask);*/
+       }
+       window = disp_window[num].window;
+       XSetStandardProperties(disp_display, window, title, title, None, NULL, 0, shint);               /* Tell other applications about this window */
+       XResizeWindow(disp_display, window, width, height);
+       XSync(disp_display, 1);
+       XFree(shint);
+}
+
+void disp_sync(void) {
+       XSync(disp_display, 1);
+}
+
+void disp_setcolor(unsigned char *name) {
+       int screen;
+       GC gc;
+       XColor c_exact, c_nearest;
+       Colormap cm;
+       Status st;
+
+       screen = DefaultScreen(disp_display);
+       gc = DefaultGC(disp_display, screen);           /* allocate colors */
+       cm = DefaultColormap(disp_display, screen);
+       st = XAllocNamedColor(disp_display, cm, name, &c_nearest, &c_exact);
+       disp_chkerror(st!=1, "XAllocNamedColor error");
+       XSetForeground(disp_display, gc, c_nearest.pixel);
+}
+
+void disp_gray(int num, char *data, int width, int height, int stride, const unsigned char *tit) {
+       Visual *visual;
+       XImage *ximage;
+       unsigned char *image;
+       int y,x,pixelsize;
+       char dummy;
+       int t = 1;
+       int dpy_depth;
+       int screen;
+       GC gc;
+       //XEvent xev;
+
+       disp_init_display();
+       disp_init_window(num, width, height, tit);
+       screen = DefaultScreen(disp_display);
+       visual = DefaultVisual(disp_display, screen);
+       dpy_depth = DefaultDepth(disp_display, screen);
+       ximage = XCreateImage(disp_display, visual, dpy_depth, ZPixmap, 0, &dummy, width, height, 8, 0);
+       disp_chkerror(!ximage, "no ximage");
+       if (*(char *)&t == 1) {
+               ximage->byte_order = LSBFirst;
+               ximage->bitmap_bit_order = LSBFirst;
+       } else {
+               ximage->byte_order = MSBFirst;
+               ximage->bitmap_bit_order = MSBFirst;
+       }
+       pixelsize = dpy_depth>8 ? sizeof(int) : sizeof(unsigned char);
+       image = malloc(width * height * pixelsize);
+       disp_chkerror(!image, "malloc failed");
+       for (y=0; y<height; y++) for (x=0; x<width; x++) {
+               memset(&image[(width*y + x)*pixelsize], data[y*stride+x], pixelsize);
+       }
+       ximage->data = image;
+       gc = DefaultGC(disp_display, screen);   /* allocate colors */
+
+//     XUnmapWindow(disp_display, disp_window[num].window);                                                    /* Map window. */
+//     XMapWindow(disp_display, disp_window[num].window);                                                      /* Map window. */
+       XPutImage(disp_display, disp_window[num].window, gc, ximage, 0, 0, 0, 0, width, height);
+//             do {                                                                                    /* Wait for map. */
+//                     XNextEvent(disp_display, &xev);
+//             } while (xev.type!=MapNotify || xev.xmap.event!=disp_window[num].window);
+       XPutImage(disp_display, disp_window[num].window, gc, ximage, 0, 0, 0, 0, width, height);
+
+       XDestroyImage(ximage);
+       XSync(disp_display, 1);
+
+}
+
+void disp_gray_zoom(int num, char *data, int width, int height, int stride, const unsigned char *tit, int zoom) {
+       unsigned char *dataz;
+       int y,x,y0,x0;
+       dataz = malloc(width*zoom * height*zoom);
+       disp_chkerror(!dataz, "malloc");
+       for (y=0; y<height; y++) for (x=0; x<width; x++) {
+               for (y0=0; y0<zoom; y0++) for (x0=0; x0<zoom; x0++) {
+                       dataz[(y*zoom + y0)*width*zoom + x*zoom + x0] = data[y*stride+x];
+               }
+       }
+       disp_gray(num, dataz, width*zoom, height*zoom, width*zoom, tit);
+       free(dataz);
+}
+
+void disp_point(int num, int x1, int y1) {
+       int screen;
+       GC gc;
+       screen = DefaultScreen(disp_display);
+       gc = DefaultGC(disp_display, screen);           /* allocate colors */
+       XDrawPoint(disp_display, disp_window[num].window, gc, x1, y1);
+//     XSync(disp_display, 1);
+}
+
+void disp_line(int num, int x1, int y1, int x2, int y2) {
+       int screen;
+       GC gc;
+       screen = DefaultScreen(disp_display);
+       gc = DefaultGC(disp_display, screen);           /* allocate colors */
+       XDrawLine(disp_display, disp_window[num].window, gc, x1, y1, x2, y2);
+//     XSync(disp_display, 1);
+}
+
+void disp_rect(int num, int x1, int y1, int x2, int y2) {
+       int screen;
+       GC gc;
+       screen = DefaultScreen(disp_display);
+
+       gc = DefaultGC(disp_display, screen);           /* allocate colors */
+       XDrawRectangle(disp_display, disp_window[num].window, gc, x1, y1, x2-x1, y2-y1);
+//     XSync(disp_display, 1);
+}
diff --git a/common/display.h b/common/display.h
new file mode 100644 (file)
index 0000000..6f2db0c
--- /dev/null
@@ -0,0 +1,38 @@
+/*****************************************************************************
+ * x264: h264 encoder
+ *****************************************************************************
+ * Copyright (C) 2005 x264 project
+ *
+ * Author: Tuukka Toivonen <tuukkat@ee.oulu.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#ifndef _DISPLAY_H
+#define _DISPLAY_H 1
+
+void disp_sync(void);
+void disp_setcolor(unsigned char *name);
+/* Display a region of byte wide memory as a grayscale image.
+ * num is the window to use for displaying. */
+void disp_gray(int num, char *data, int width, int height,
+               int stride, const unsigned char *title);
+void disp_gray_zoom(int num, char *data, int width, int height,
+               int stride, const unsigned char *title, int zoom);
+void disp_point(int num, int x1, int y1);
+void disp_line(int num, int x1, int y1, int x2, int y2);
+void disp_rect(int num, int x1, int y1, int x2, int y2);
+
+#endif
diff --git a/common/visualize.c b/common/visualize.c
new file mode 100644 (file)
index 0000000..c76db8b
--- /dev/null
@@ -0,0 +1,324 @@
+/*****************************************************************************
+ * x264: h264 encoder
+ *****************************************************************************
+ * Copyright (C) 2005 x264 project
+ *
+ * Author: Tuukka Toivonen <tuukkat@ee.oulu.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*
+ * Some explanation of the symbols used:
+ * Red/pink: intra block
+ * Blue: inter block
+ * Green: skip block
+ * Yellow: B-block (not visualized properly yet)
+ *
+ * The intra blocks have generally lines drawn perpendicular
+ * to the prediction direction, so for example, if there is a pink block
+ * with horizontal line at the top of it, it is interpolated by assuming
+ * luma to be vertically constant.
+ * DC predicted blocks have both horizontal and vertical lines,
+ * pink blocks with a diagonal line are predicted using the planar function.
+ */
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#else
+#include <inttypes.h>
+#endif
+#include <stddef.h>                 /* NULL */
+#include <stdio.h>                  /* getchar */
+#include <stdlib.h>                 /* abort */
+
+#include "common.h"
+#include "visualize.h"
+#include "macroblock.h"
+#include "display.h"
+
+typedef struct {
+    int     i_type;
+    int     i_partition;
+    int     i_sub_partition[4];
+    int     i_intra16x16_pred_mode;
+    int     intra4x4_pred_mode[4][4];
+    int8_t  ref[2][4][4];                  /* [list][y][x] */
+    int16_t mv[2][4][4][2];                /* [list][y][x][mvxy] */
+} visualize_t;
+
+/* {{{ [fold] char *get_string(const stringlist_t *sl, int entries, int code) */
+/* Return string from stringlist corresponding to the given code */
+#define GET_STRING(sl, code) get_string((sl), sizeof(sl)/sizeof(*(sl)), code)
+
+typedef struct {
+    int code;
+    char *string;
+} stringlist_t;
+
+static char *get_string(const stringlist_t *sl, int entries, int code)
+{
+    int i;
+
+    for (i=0; i<entries; i++) {
+        if (sl[i].code==code) break;
+    }
+    return (i>=entries) ? "?" : sl[i].string;
+}
+/* }}} */
+/* {{{ [fold] void mv(int x0, int y0, int16_t dmv[2], int zoom, char *col) */
+/* Plot motion vector */
+static void mv(int x0, int y0, int16_t dmv[2], int zoom, char *col)
+{
+    int dx = dmv[0];
+    int dy = dmv[1];
+
+    dx = (dx*zoom)/4;           /* Quarter pixel accurate MVs */
+    dy = (dy*zoom)/4;
+    disp_line(0, x0, y0, x0+dx, y0+dy);
+    disp_setcolor("black");
+    disp_point(0, x0, y0);
+    disp_setcolor(col);
+}
+/* }}} */
+
+/* {{{ [fold] void x264_visualize_init( x264_t *h ) */
+void x264_visualize_init( x264_t *h )
+{
+    int mb = h->sps->i_mb_width * h->sps->i_mb_height;
+    h->visualize = x264_malloc(mb * sizeof(visualize_t));
+}
+/* }}} */
+/* {{{ [fold] void x264_visualize_mb( x264_t *h ) */
+void x264_visualize_mb( x264_t *h )
+{
+    visualize_t *v = (visualize_t*)h->visualize + h->mb.i_mb_xy;
+    int i, l, x, y;
+
+    /* Save all data for the MB what we need for drawing the visualization */
+    v->i_type = h->mb.i_type;
+    v->i_partition = h->mb.i_partition;
+    for (i=0; i<4; i++) v->i_sub_partition[i] = h->mb.i_sub_partition[i];
+    for (y=0; y<4; y++) for (x=0; x<4; x++)
+        v->intra4x4_pred_mode[y][x] = h->mb.cache.intra4x4_pred_mode[X264_SCAN8_0+y*8+x];
+    for (l=0; l<2; l++) for (y=0; y<4; y++) for (x=0; x<4; x++) {
+        for (i=0; i<2; i++) {
+            v->mv[l][y][x][i] = h->mb.cache.mv[l][X264_SCAN8_0+y*8+x][i];
+        }
+        v->ref[l][y][x] = h->mb.cache.ref[i][X264_SCAN8_0+y*8+x];
+    }
+    v->i_intra16x16_pred_mode = h->mb.i_intra16x16_pred_mode;
+}
+/* }}} */
+/* {{{ [fold] void x264_visualize_close( x264_t *h ) */
+void x264_visualize_close( x264_t *h )
+{
+    x264_free(h->visualize);
+}
+/* }}} */
+/* {{{ [fold] void x264_visualize( x264_t *h ) */
+/* Display visualization (block types, MVs) of the encoded frame */
+/* FIXME: B-type MBs not handled yet properly
+ * Reference frame number not visualized */
+void x264_visualize_show( x264_t *h )
+{
+    int mb_xy;
+    static const stringlist_t mb_types[] = {
+        /* Block types marked as NULL will not be drawn */
+        { I_4x4   , "red" },
+        { I_16x16 , "pink" },
+        { I_PCM   , "violet" },
+        { P_L0    , "SlateBlue" },
+        { P_8x8   , "blue" },
+        { P_SKIP  , "green" },
+        { B_DIRECT, "yellow" },
+        { B_L0_L0 , "yellow" },
+        { B_L0_L1 , "yellow" },
+        { B_L0_BI , "yellow" },
+        { B_L1_L0 , "yellow" },
+        { B_L1_L1 , "yellow" },
+        { B_L1_BI , "yellow" },
+        { B_BI_L0 , "yellow" },
+        { B_BI_L1 , "yellow" },
+        { B_BI_BI , "yellow" },
+        { B_8x8   , "yellow" },
+        { B_SKIP  , "yellow" },
+    };
+
+    static const int waitkey = 1;
+    static const int drawbox = 1;
+    static const int borders = 0;
+
+    static const int pad = 32;
+    static const int zoom = 2;
+    uint8_t *const frame = h->fdec->plane[0];
+    const int width = h->param.i_width;
+    const int height = h->param.i_height;
+    const int stride = h->fdec->i_stride[0];
+
+    if (borders) {
+        disp_gray_zoom(0, frame - pad*stride - pad, width+2*pad, height+2*pad, stride, "fdec", zoom);
+    } else {
+        disp_gray_zoom(0, frame, width, height, stride, "fdec", zoom);
+    }
+
+    for( mb_xy = 0; mb_xy < h->sps->i_mb_width * h->sps->i_mb_height; mb_xy++ )
+    {
+        visualize_t *v = (visualize_t*)h->visualize + mb_xy;
+        const int mb_y = mb_xy / h->sps->i_mb_width;
+        const int mb_x = mb_xy % h->sps->i_mb_width;
+        int x = mb_x*16*zoom;
+        int y = mb_y*16*zoom;
+        if (borders) {
+            x += pad*zoom;
+            y += pad*zoom;
+        }
+        int l = 0;
+        char *col = GET_STRING(mb_types, v->i_type);
+        unsigned int i, j;
+        if (col==NULL) continue;
+        disp_setcolor(col);
+        if (drawbox) disp_rect(0, x, y, x+16*zoom-1, y+16*zoom-1);
+
+        if (v->i_type==P_L0 || v->i_type==P_8x8 || v->i_type==P_SKIP) {
+
+            /* Predicted (inter) mode, with motion vector */
+            if (v->i_partition==D_16x16 || v->i_type==P_SKIP) {
+                mv(x+8*zoom, y+8*zoom, v->mv[l][0][0], zoom, col);
+            }
+            if (v->i_partition==D_16x8) {
+                if (drawbox) disp_rect(0, x, y, x+16*zoom, y+8*zoom);
+                mv(x+8*zoom, y+4*zoom, v->mv[l][0][0], zoom, col);
+                if (drawbox) disp_rect(0, x, y+8*zoom, x+16*zoom, y+16*zoom);
+                mv(x+8*zoom, y+12*zoom, v->mv[l][2][0], zoom, col);
+            }
+            if (v->i_partition==D_8x16) {
+                if (drawbox) disp_rect(0, x,          y, x+8*zoom,  y+16*zoom);
+                mv(x+4*zoom, y+8*zoom, v->mv[l][0][0], zoom, col);
+                if (drawbox) disp_rect(0, x+8*zoom,   y, x+16*zoom, y+16*zoom);
+                mv(x+12*zoom, y+8*zoom, v->mv[l][0][2], zoom, col);
+            }
+            if (v->i_partition==D_8x8) {
+                for (i=0; i<2; i++) for (j=0; j<2; j++) {
+                    int sp = v->i_sub_partition[i*2+j];
+                    const int x0 = x + j*8*zoom;
+                    const int y0 = y + i*8*zoom;
+                    if (sp==D_L1_8x8) sp = D_L0_8x8;
+                    if (sp==D_L1_4x8) sp = D_L0_4x8;
+                    if (sp==D_L1_8x4) sp = D_L0_8x4;
+                    if (sp==D_L1_4x4) sp = D_L0_4x4;
+                    if (sp==D_L0_8x8) {
+                        if (drawbox) disp_rect(0, x0, y0, x0+8*zoom, y0+8*zoom);
+                        mv(x0+4*zoom, y0+4*zoom, v->mv[l][2*i][2*j], zoom, col);
+                    }
+                    if (sp==D_L0_8x4) {
+                        if (drawbox) disp_rect(0, x0, y0, x0+8*zoom, y0+4*zoom);
+                        if (drawbox) disp_rect(0, x0, y0+4*zoom, x0+8*zoom, y0+8*zoom);
+                        mv(x0+4*zoom, y0+2*zoom, v->mv[l][2*i][2*j], zoom, col);
+                        mv(x0+4*zoom, y0+6*zoom, v->mv[l][2*i+1][2*j], zoom, col);
+                    }
+                    if (sp==D_L0_4x8) {
+                        if (drawbox) disp_rect(0, x0, y0, x0+4*zoom, y0+8*zoom);
+                        if (drawbox) disp_rect(0, x0+4*zoom, y0, x0+8*zoom, y0+8*zoom);
+                        mv(x0+2*zoom, y0+4*zoom, v->mv[l][2*i][2*j], zoom, col);
+                        mv(x0+6*zoom, y0+4*zoom, v->mv[l][2*i][2*j+1], zoom, col);
+                    }
+                    if (sp==D_L0_4x4) {
+                        if (drawbox) disp_rect(0, x0, y0, x0+4*zoom, y0+4*zoom);
+                        if (drawbox) disp_rect(0, x0+4*zoom, y0, x0+8*zoom, y0+4*zoom);
+                        if (drawbox) disp_rect(0, x0, y0+4*zoom, x0+4*zoom, y0+8*zoom);
+                        if (drawbox) disp_rect(0, x0+4*zoom, y0+4*zoom, x0+8*zoom, y0+8*zoom);
+                        mv(x0+2*zoom, y0+2*zoom, v->mv[l][2*i][2*j], zoom, col);
+                        mv(x0+6*zoom, y0+2*zoom, v->mv[l][2*i][2*j+1], zoom, col);
+                        mv(x0+2*zoom, y0+6*zoom, v->mv[l][2*i+1][2*j], zoom, col);
+                        mv(x0+6*zoom, y0+6*zoom, v->mv[l][2*i+1][2*j+1], zoom, col);
+                    }
+                }
+            }
+        }
+
+        if (v->i_type==I_4x4 || v->i_type==I_16x16 || v->i_type==I_PCM) {
+            /* Intra coded */
+            if (v->i_type==I_16x16) {
+                switch (v->i_intra16x16_pred_mode) {
+                case I_PRED_16x16_V:
+                    disp_line(0, x+2*zoom, y+2*zoom, x+14*zoom, y+2*zoom);
+                    break;
+                case I_PRED_16x16_H:
+                    disp_line(0, x+2*zoom, y+2*zoom, x+2*zoom, y+14*zoom);
+                    break;
+                case I_PRED_16x16_DC:
+                case I_PRED_16x16_DC_LEFT:
+                case I_PRED_16x16_DC_TOP:
+                case I_PRED_16x16_DC_128:
+                    disp_line(0, x+2*zoom, y+2*zoom, x+14*zoom, y+2*zoom);
+                    disp_line(0, x+2*zoom, y+2*zoom, x+2*zoom, y+14*zoom);
+                    break;
+                case I_PRED_16x16_P:
+                    disp_line(0, x+2*zoom, y+2*zoom, x+8*zoom, y+8*zoom);
+                    break;
+                default: abort();
+                }
+            }
+            if (v->i_type==I_4x4) {
+                for (i=0; i<4; i++) for (j=0; j<4; j++) {
+                    const int x0 = x + j*4*zoom;
+                    const int y0 = y + i*4*zoom;
+                    if (drawbox) disp_rect(0, x0, y0, x0+4*zoom, y0+4*zoom);
+                    switch (v->intra4x4_pred_mode[i][j]) {
+                    case I_PRED_4x4_V:         /* Vertical */
+                        disp_line(0, x0+0*zoom, y0+1*zoom, x0+4*zoom, y0+1*zoom);
+                        break;
+                    case I_PRED_4x4_H:         /* Horizontal */
+                        disp_line(0, x0+1*zoom, y0+0*zoom, x0+1*zoom, y0+4*zoom);
+                        break;
+                    case I_PRED_4x4_DC:                /* DC, average from top and left sides */
+                    case I_PRED_4x4_DC_LEFT:
+                    case I_PRED_4x4_DC_TOP:
+                    case I_PRED_4x4_DC_128:
+                        disp_line(0, x0+1*zoom, y0+1*zoom, x0+4*zoom, y0+1*zoom);
+                        disp_line(0, x0+1*zoom, y0+1*zoom, x0+1*zoom, y0+4*zoom);
+                        break;
+                    case I_PRED_4x4_DDL:       /* Topright-downleft */
+                        disp_line(0, x0+0*zoom, y0+0*zoom, x0+4*zoom, y0+4*zoom);
+                        break;
+                    case I_PRED_4x4_DDR:       /* Topleft-downright */
+                        disp_line(0, x0+0*zoom, y0+4*zoom, x0+4*zoom, y0+0*zoom);
+                        break;
+                    case I_PRED_4x4_VR:                /* Mix of topleft-downright and vertical */
+                        disp_line(0, x0+0*zoom, y0+2*zoom, x0+4*zoom, y0+1*zoom);
+                        break;
+                    case I_PRED_4x4_HD:                /* Mix of topleft-downright and horizontal */
+                        disp_line(0, x0+2*zoom, y0+0*zoom, x0+1*zoom, y0+4*zoom);
+                        break;
+                    case I_PRED_4x4_VL:                /* Mix of topright-downleft and vertical */
+                        disp_line(0, x0+0*zoom, y0+1*zoom, x0+4*zoom, y0+2*zoom);
+                        break;
+                    case I_PRED_4x4_HU:                /* Mix of topright-downleft and horizontal */
+                        disp_line(0, x0+1*zoom, y0+0*zoom, x0+2*zoom, y0+4*zoom);
+                        break;
+                    default: abort();
+                    }
+                }
+            }
+        }
+    }
+
+    disp_sync();
+    if (waitkey) getchar();
+}
+/* }}} */
+
+//EOF
diff --git a/common/visualize.h b/common/visualize.h
new file mode 100644 (file)
index 0000000..92c8b00
--- /dev/null
@@ -0,0 +1,33 @@
+/*****************************************************************************
+ * x264: h264 encoder
+ *****************************************************************************
+ * Copyright (C) 2005 x264 project
+ *
+ * Author: Tuukka Toivonen <tuukkat@ee.oulu.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#ifndef _VISUALIZE_H
+#define _VISUALIZE_H 1
+
+#include "common/common.h"
+
+void x264_visualize_init( x264_t *h );
+void x264_visualize_mb( x264_t *h );
+void x264_visualize_show( x264_t *h );
+void x264_visualize_close( x264_t *h );
+
+#endif
index 8b3dd33..6128c11 100755 (executable)
--- a/configure
+++ b/configure
@@ -11,6 +11,7 @@ echo "  --enable-avis-input      enables avisynth input (win32 only)"
 echo "  --enable-mp4-output      enables mp4 output (using gpac)"
 echo "  --enable-vfw             compiles the VfW frontend"
 echo "  --enable-debug           adds -g, doesn't strip"
+echo "  --enable-visualize       enables visualization (X11 only)"
 echo "  --extra-cflags=ECFLAGS   add ECFLAGS to CFLAGS"
 echo "  --extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS"
 echo ""
@@ -21,6 +22,7 @@ avis_input="no"
 mp4_output="no"
 debug="no"
 vfw="no"
+vis="no"
 
 CC="gcc"
 CFLAGS="-Wall -I. -O4 -funroll-loops -ffast-math -D__X264__"
@@ -132,6 +134,11 @@ for opt do
         --enable-vfw)
             vfw="yes"
             ;;
+        --enable-visualize)
+            LDFLAGS="$LDFLAGS -L/usr/X11R6/lib -lX11"
+            CFLAGS="$CFLAGS -DVISUALIZE=1"
+            vis="yes"
+            ;;
         *)
             echo "Unknown option $opt, ignored"
             ;;
@@ -156,6 +163,7 @@ AS=$AS
 ASFLAGS=$ASFLAGS
 VFW=$vfw
 EXE=$EXE
+VIS=$vis
 EOF
 
 if [ "$vfw" == "yes" ]; then
@@ -173,6 +181,7 @@ echo "avis input: $avis_input"
 echo "mp4 output: $mp4_output"
 echo "vfw:        $vfw"
 echo "debug:      $debug"
+echo "visualize:  $vis"
 echo
 echo "You can run 'make' now."
 
index de9c130..5797ca5 100644 (file)
 #include "ratecontrol.h"
 #include "macroblock.h"
 
+#if VISUALIZE
+#include "common/visualize.h"
+#endif
+
 //#define DEBUG_MB_TYPE
 //#define DEBUG_DUMP_FRAME
 //#define DEBUG_BENCHMARK
@@ -863,6 +867,11 @@ static inline void x264_slice_write( x264_t *h, int i_nal_type, int i_nal_ref_id
     h->mb.i_last_qp = h->pps->i_pic_init_qp + h->sh.i_qp_delta;
     h->mb.i_last_dqp = 0;
 
+#if VISUALIZE
+    if( h->param.b_visualize )
+        x264_visualize_init( h );
+#endif
+
     for( mb_xy = 0, i_skip = 0; mb_xy < h->sps->i_mb_width * h->sps->i_mb_height; mb_xy++ )
     {
         const int i_mb_y = mb_xy / h->sps->i_mb_width;
@@ -931,6 +940,11 @@ static inline void x264_slice_write( x264_t *h, int i_nal_type, int i_nal_ref_id
         }
         TIMER_STOP( i_mtime_write );
 
+#if VISUALIZE
+        if( h->param.b_visualize )
+            x264_visualize_mb( h );
+#endif
+
         /* save cache */
         x264_macroblock_cache_save( h );
 
@@ -971,6 +985,14 @@ static inline void x264_slice_write( x264_t *h, int i_nal_type, int i_nal_ref_id
 
     x264_nal_end( h );
 
+#if VISUALIZE
+    if( h->param.b_visualize )
+    {
+        x264_visualize_show( h );
+        x264_visualize_close( h );
+    }
+#endif
+
     /* Compute misc bits */
     h->stat.frame.i_misc_bits = bs_pos( &h->out.bs )
                               + NALU_OVERHEAD * 8
diff --git a/x264.c b/x264.c
index 6925689..f745e80 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -61,6 +61,9 @@ static int     i_ctrl_c = 0;
 static void    SigIntHandler( int a )
 {
     i_ctrl_c = 1;
+#if VISUALIZE
+    exit(0);
+#endif
 }
 
 /* input file operation function pointers */
@@ -228,6 +231,7 @@ static void Help( x264_param_t *defaults )
              "      --quiet                 Quiet Mode\n"
              "  -v, --verbose               Print stats for each frame\n"
              "      --progress              Show a progress indicator while encoding\n"
+             "      --visualize             Show MB types overlayed on the encoded video\n"
              "      --aud                   Use access unit delimiters\n"
              "\n",
             X264_BUILD, X264_VERSION,
@@ -340,6 +344,7 @@ static int  Parse( int argc, char **argv,
 #define OPT_VBVMAXRATE 287
 #define OPT_VBVBUFSIZE 288
 #define OPT_VBVINIT 289
+#define OPT_VISUALIZE 290
 
         static struct option long_options[] =
         {
@@ -390,6 +395,7 @@ static int  Parse( int argc, char **argv,
             { "quiet",   no_argument,       NULL, OPT_QUIET },
             { "verbose", no_argument,       NULL, 'v' },
             { "progress",no_argument,       NULL, OPT_PROGRESS },
+            { "visualize",no_argument,      NULL, OPT_VISUALIZE },
             { "aud",     no_argument,       NULL, OPT_AUD },
             {0, 0, 0, 0}
         };
@@ -635,6 +641,13 @@ static int  Parse( int argc, char **argv,
             case OPT_PROGRESS:
                 *b_progress = 1;
                 break;
+            case OPT_VISUALIZE:
+#ifdef VISUALIZE
+                param->b_visualize = 1;
+#else
+                fprintf( stderr, "not compiled with visualization support\n" );
+#endif
+                break;
             default:
                 fprintf( stderr, "unknown option (%c)\n", optopt );
                 return -1;
diff --git a/x264.h b/x264.h
index 9ca6497..e9b8a0d 100644 (file)
--- a/x264.h
+++ b/x264.h
@@ -135,6 +135,7 @@ typedef struct
     void        (*pf_log)( void *, int i_level, const char *psz, va_list );
     void        *p_log_private;
     int         i_log_level;
+    int         b_visualize;
 
     /* Encoder analyser parameters */
     struct