[FFmpeg-devel] [PATCH] avfilter: initial macroblock types export and visualization

Paul B Mahol onemda at gmail.com
Fri Oct 27 23:03:54 EEST 2017


Signed-off-by: Paul B Mahol <onemda at gmail.com>
---
 libavcodec/mpegvideo.c     |  10 +++++
 libavfilter/vf_codecview.c | 105 +++++++++++++++++++++++++++++++++++++++++++++
 libavutil/frame.h          |   4 ++
 3 files changed, 119 insertions(+)

diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c
index 2f5793b9a4..ce6108d094 100644
--- a/libavcodec/mpegvideo.c
+++ b/libavcodec/mpegvideo.c
@@ -1603,6 +1603,16 @@ void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, uint8_t *mbskip_
         }
     }
 
+    if (mb_height && mb_width) {
+        AVFrameSideData *sd;
+
+        av_log(avctx, AV_LOG_DEBUG, "Adding %d MB types info to frame %d\n", mb_width * mb_height, avctx->frame_number);
+        sd = av_frame_new_side_data(pict, AV_FRAME_DATA_MACROBLOCK_TYPES, mb_width * mb_height * sizeof(uint32_t));
+        if (!sd)
+            return;
+        memcpy(sd->data, mbtype_table, mb_width * mb_height * sizeof(uint32_t));
+    }
+
 #if FF_API_DEBUG_MV
     if ((avctx->debug & (FF_DEBUG_VIS_QP | FF_DEBUG_VIS_MB_TYPE)) ||
         (avctx->debug_mv)) {
diff --git a/libavfilter/vf_codecview.c b/libavfilter/vf_codecview.c
index 331bfba777..40fb8dfb7a 100644
--- a/libavfilter/vf_codecview.c
+++ b/libavfilter/vf_codecview.c
@@ -29,6 +29,7 @@
  * TODO: segmentation
  */
 
+#include "libavutil/avassert.h"
 #include "libavutil/imgutils.h"
 #include "libavutil/motion_vector.h"
 #include "libavutil/opt.h"
@@ -44,9 +45,23 @@
 #define FRAME_TYPE_P (1<<1)
 #define FRAME_TYPE_B (1<<2)
 
+#define IS_PCM(a)           ((a) & (1 << 2))
+#define IS_INTRA(a)         ((a) & 7)
+#define IS_ACPRED(a)        ((a) & (1 << 9))
+#define IS_INTRA16x16(a)    ((a) & (1 << 1))
+#define IS_INTRA4x4(a)      ((a) & (1 << 0))
+#define IS_DIRECT(a)        ((a) & (1 << 8))
+#define IS_SKIP(a)          ((a) & (1 << 11))
+#define IS_GMC(a)           ((a) & (1 << 10))
+#define USES_LIST(a, list)  ((a) & (((1 << 12) | (1 << 13)) << (2 * (list))))
+#define IS_8X8(a)           ((a) & ((1 << 6)))
+#define IS_16X8(a)          ((a) & ((1 << 4)))
+#define IS_8X16(a)          ((a) & ((1 << 5)))
+
 typedef struct CodecViewContext {
     const AVClass *class;
     unsigned mv;
+    unsigned mbtypes;
     unsigned frame_type;
     unsigned mv_type;
     int hsub, vsub;
@@ -72,6 +87,7 @@ static const AVOption codecview_options[] = {
         CONST("if", "I-frames", FRAME_TYPE_I, "frame_type"),
         CONST("pf", "P-frames", FRAME_TYPE_P, "frame_type"),
         CONST("bf", "B-frames", FRAME_TYPE_B, "frame_type"),
+    { "mb", "visualize macroblock types", OFFSET(mbtypes), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS, },
     { NULL }
 };
 
@@ -277,6 +293,95 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
         }
     }
 
+    if (s->mbtypes) {
+        AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_MACROBLOCK_TYPES);
+        if (sd) {
+            int mb_height = (frame->height + 31) / 32 * 2;
+            int mb_width = (frame->width + 15) / 16;
+            int block_height = 16 >> 1;
+            int mb_stride = mb_width + 1;
+            int mb_y, mb_x;
+            uint32_t *mbtype_table = (uint32_t *)sd->data;
+
+            for (mb_y = 0; mb_y < mb_height; mb_y++) {
+                for (mb_x = 0; mb_x < mb_width; mb_x++) {
+                    const int mb_index = mb_x + mb_y * mb_stride;
+                  /*{
+                        uint64_t c = (qscale_table[mb_index] * 128 / 31) *
+                                 0x0101010101010101ULL;
+                        int y;
+                        for (y = 0; y < block_height; y++) {
+                            *(uint64_t *)(frame->data[1] + 8 * mb_x +
+                                          (block_height * mb_y + y) *
+                                          frame->linesize[1]) = c;
+                            *(uint64_t *)(frame->data[2] + 8 * mb_x +
+                                          (block_height * mb_y + y) *
+                                          frame->linesize[2]) = c;
+                        }
+                    } */
+                    {
+                        int mb_type = mbtype_table[mb_index];
+                        uint64_t u,v;
+                        int y;
+
+#define COLOR(theta, r) \
+    u = (int)(128 + r * cos(theta * M_PI / 180)); \
+    v = (int)(128 + r * sin(theta * M_PI / 180));
+
+                        u = v = 128;
+                        if (IS_PCM(mb_type)) {
+                            COLOR(120, 48)
+                        } else if ((IS_INTRA(mb_type) && IS_ACPRED(mb_type)) ||
+                                   IS_INTRA16x16(mb_type)) {
+                            COLOR(30, 48)
+                        } else if (IS_INTRA4x4(mb_type)) {
+                            COLOR(90, 48)
+                        } else if (IS_DIRECT(mb_type) && IS_SKIP(mb_type)) {
+                            COLOR(120, 48)
+                        } else if (IS_DIRECT(mb_type)) {
+                            COLOR(150, 48)
+                        } else if (IS_GMC(mb_type) && IS_SKIP(mb_type)) {
+                            COLOR(170, 48)
+                        } else if (IS_GMC(mb_type)) {
+                            COLOR(190, 48)
+                        } else if (IS_SKIP(mb_type)) {
+                            COLOR(180, 48)
+                        } else if (!USES_LIST(mb_type, 1)) {
+                            COLOR(240, 48)
+                        } else if (!USES_LIST(mb_type, 0)) {
+                            COLOR(0, 48)
+                        } else {
+                            av_assert2(USES_LIST(mb_type, 0) && USES_LIST(mb_type, 1));
+                            COLOR(300,48)
+                        }
+
+                        u *= 0x0101010101010101ULL;
+                        v *= 0x0101010101010101ULL;
+                        for (y = 0; y < block_height; y++) {
+                            *(uint64_t *)(frame->data[1] + 8 * mb_x +
+                                          (block_height * mb_y + y) * frame->linesize[1]) = u;
+                            *(uint64_t *)(frame->data[2] + 8 * mb_x +
+                                          (block_height * mb_y + y) * frame->linesize[2]) = v;
+                        }
+
+                        // segmentation
+                        if (IS_8X8(mb_type) || IS_16X8(mb_type)) {
+                            *(uint64_t *)(frame->data[0] + 16 * mb_x + 0 +
+                                          (16 * mb_y + 8) * frame->linesize[0]) ^= 0x8080808080808080ULL;
+                            *(uint64_t *)(frame->data[0] + 16 * mb_x + 8 +
+                                          (16 * mb_y + 8) * frame->linesize[0]) ^= 0x8080808080808080ULL;
+                        }
+                        if (IS_8X8(mb_type) || IS_8X16(mb_type)) {
+                            for (y = 0; y < 16; y++)
+                                frame->data[0][16 * mb_x + 8 + (16 * mb_y + y) *
+                                              frame->linesize[0]] ^= 0x80;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     return ff_filter_frame(outlink, frame);
 }
 
diff --git a/libavutil/frame.h b/libavutil/frame.h
index fef558ea2f..8481dc080b 100644
--- a/libavutil/frame.h
+++ b/libavutil/frame.h
@@ -141,6 +141,10 @@ enum AVFrameSideDataType {
      * metadata key entry "name".
      */
     AV_FRAME_DATA_ICC_PROFILE,
+    /**
+     * Macroblock types exported by some codecs.
+     */
+    AV_FRAME_DATA_MACROBLOCK_TYPES,
 };
 
 enum AVActiveFormatDescription {
-- 
2.11.0



More information about the ffmpeg-devel mailing list