[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