From 0c9bbaec6021ff2ab6017e8b99354a26c2394b47 Mon Sep 17 00:00:00 2001 From: Wolfgang Hesseler Date: Tue, 30 Dec 2003 02:12:12 +0000 Subject: [PATCH] motion vector vissualization improvements patch by (Wolfgang Hesseler ) Originally committed as revision 2636 to svn://svn.ffmpeg.org/ffmpeg/trunk --- ffmpeg.c | 16 +++++-- ffplay.c | 10 ++++- libavcodec/avcodec.h | 12 +++++- libavcodec/h263dec.c | 4 +- libavcodec/h264.c | 2 +- libavcodec/mpeg12.c | 4 +- libavcodec/mpegvideo.c | 94 ++++++++++++++++++++++++++++++------------ libavcodec/mpegvideo.h | 3 +- libavcodec/rv10.c | 4 +- 9 files changed, 109 insertions(+), 40 deletions(-) diff --git a/ffmpeg.c b/ffmpeg.c index ff782d285e..0724984678 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -131,6 +131,7 @@ static int packet_size = 0; static int error_rate = 0; static int strict = 0; static int debug = 0; +static int debug_mv = 0; extern int loop_input; /* currently a hack */ static int gop_size = 12; @@ -1672,6 +1673,11 @@ static void opt_debug(const char *arg) debug = atoi(arg); } +static void opt_vismv(const char *arg) +{ + debug_mv = atoi(arg); +} + static void opt_verbose(const char *arg) { verbose = atoi(arg); @@ -2171,8 +2177,9 @@ static void opt_input_file(const char *filename) enc->workaround_bugs = workaround_bugs; enc->error_resilience = error_resilience; enc->error_concealment = error_concealment; - enc->idct_algo= idct_algo; - enc->debug= debug; + enc->idct_algo = idct_algo; + enc->debug = debug; + enc->debug_mv = debug_mv; if(bitexact) enc->flags|= CODEC_FLAG_BITEXACT; @@ -2382,8 +2389,8 @@ static void opt_output_file(const char *filename) video_enc->qblur = video_qblur; video_enc->qcompress = video_qcomp; video_enc->rc_eq = video_rc_eq; - video_enc->debug= debug; - + video_enc->debug = debug; + video_enc->debug_mv = debug_mv; p= video_rc_override_string; for(i=0; p; i++){ int start, end, q; @@ -2913,6 +2920,7 @@ const OptionDef options[] = { { "copyright", HAS_ARG | OPT_STRING, {(void*)&str_copyright}, "set the copyright", "string" }, { "comment", HAS_ARG | OPT_STRING, {(void*)&str_comment}, "set the comment", "string" }, { "debug", HAS_ARG | OPT_EXPERT, {(void*)opt_debug}, "print specific debug info", "" }, + { "vismv", HAS_ARG | OPT_EXPERT, {(void*)opt_vismv}, "visualize motion vectors", "" }, { "benchmark", OPT_BOOL | OPT_EXPERT, {(void*)&do_benchmark}, "add timings for benchmarking" }, { "dump", OPT_BOOL | OPT_EXPERT, {(void*)&do_pkt_dump}, diff --git a/ffplay.c b/ffplay.c index 8f06f8fb17..c5c2ca1349 100644 --- a/ffplay.c +++ b/ffplay.c @@ -166,6 +166,7 @@ static int show_status; static int av_sync_type = AV_SYNC_AUDIO_MASTER; static int64_t start_time = AV_NOPTS_VALUE; static int debug = 0; +static int debug_mv = 0; static int step = 0; /* current context */ @@ -1196,7 +1197,8 @@ static int stream_component_open(VideoState *is, int stream_index) packet_queue_init(&is->videoq); is->video_tid = SDL_CreateThread(video_thread, is); - enc->debug= debug; + enc->debug = debug; + enc->debug_mv = debug_mv; break; default: break; @@ -1784,6 +1786,11 @@ static void opt_debug(const char *arg) debug = atoi(arg); } +static void opt_vismv(const char *arg) +{ + debug_mv = atoi(arg); +} + const OptionDef options[] = { { "h", 0, {(void*)show_help}, "show help" }, { "x", HAS_ARG, {(void*)opt_width}, "force displayed width", "width" }, @@ -1800,6 +1807,7 @@ const OptionDef options[] = { { "img", HAS_ARG, {(void*)opt_image_format}, "force image format", "img_fmt" }, { "stats", OPT_BOOL | OPT_EXPERT, {(void*)&show_status}, "show status", "" }, { "debug", HAS_ARG | OPT_EXPERT, {(void*)opt_debug}, "print specific debug info", "" }, + { "vismv", HAS_ARG | OPT_EXPERT, {(void*)opt_vismv}, "visualize motion vectors", "" }, #ifdef CONFIG_NETWORK { "rtp_tcp", OPT_EXPERT, {(void*)&opt_rtp_tcp}, "force RTP/TCP protocol usage", "" }, #endif diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 39a71662fb..ef9950bf43 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -1133,7 +1133,7 @@ typedef struct AVCodecContext { #define FF_DEBUG_MB_TYPE 8 #define FF_DEBUG_QP 16 #define FF_DEBUG_MV 32 -#define FF_DEBUG_VIS_MV 0x00000040 +//#define FF_DEBUG_VIS_MV 0x00000040 #define FF_DEBUG_SKIP 0x00000080 #define FF_DEBUG_STARTCODE 0x00000100 #define FF_DEBUG_PTS 0x00000200 @@ -1143,6 +1143,16 @@ typedef struct AVCodecContext { #define FF_DEBUG_VIS_QP 0x00002000 #define FF_DEBUG_VIS_MB_TYPE 0x00004000 + /** + * debug. + * - encoding: set by user. + * - decoding: set by user. + */ + int debug_mv; +#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames +#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames +#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames + /** * error. * - encoding: set by lavc if flags&CODEC_FLAG_PSNR diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c index 1372e4a7e1..fd02268f73 100644 --- a/libavcodec/h263dec.c +++ b/libavcodec/h263dec.c @@ -703,10 +703,10 @@ assert(s->current_picture.pict_type == s->current_picture_ptr->pict_type); assert(s->current_picture.pict_type == s->pict_type); if(s->pict_type==B_TYPE || s->low_delay){ *pict= *(AVFrame*)&s->current_picture; - ff_print_debug_info(s, s->current_picture_ptr); + ff_print_debug_info(s, pict); } else { *pict= *(AVFrame*)&s->last_picture; - ff_print_debug_info(s, s->last_picture_ptr); + ff_print_debug_info(s, pict); } /* Return the Picture timestamp as the frame number */ diff --git a/libavcodec/h264.c b/libavcodec/h264.c index 07422773f3..0de3827a53 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c @@ -4172,7 +4172,7 @@ static int decode_frame(AVCodecContext *avctx, } *pict= *(AVFrame*)&s->current_picture; //FIXME - ff_print_debug_info(s, s->current_picture_ptr); + ff_print_debug_info(s, pict); assert(pict->data[0]); //printf("out %d\n", (int)pict->data[0]); #if 0 //? diff --git a/libavcodec/mpeg12.c b/libavcodec/mpeg12.c index 8a240da276..4cc164de31 100644 --- a/libavcodec/mpeg12.c +++ b/libavcodec/mpeg12.c @@ -2305,14 +2305,14 @@ static int slice_end(AVCodecContext *avctx, AVFrame *pict) if (s->pict_type == B_TYPE || s->low_delay) { *pict= *(AVFrame*)s->current_picture_ptr; - ff_print_debug_info(s, s->current_picture_ptr); + ff_print_debug_info(s, pict); } else { s->picture_number++; /* latency of 1 frame for I and P frames */ /* XXX: use another variable than picture_number */ if (s->last_picture_ptr != NULL) { *pict= *(AVFrame*)s->last_picture_ptr; - ff_print_debug_info(s, s->last_picture_ptr); + ff_print_debug_info(s, pict); } } diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index dae3cd4f82..fce7135b1b 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -337,7 +337,7 @@ static int alloc_picture(MpegEncContext *s, Picture *pic, int shared){ CHECKED_ALLOCZ(pic->ref_index[i] , b8_array_size * sizeof(uint8_t)) } pic->motion_subsample_log2= 2; - }else if(s->out_format == FMT_H263 || s->encoding || (s->avctx->debug&(FF_DEBUG_VIS_MV|FF_DEBUG_MV))){ + }else if(s->out_format == FMT_H263 || s->encoding || (s->avctx->debug&FF_DEBUG_MV) || (s->avctx->debug_mv)){ for(i=0; i<2; i++){ CHECKED_ALLOCZ(pic->motion_val_base[i], 2 * (b8_array_size+1) * sizeof(uint16_t)*2) //FIXME pic->motion_val[i]= pic->motion_val_base[i]+1; @@ -564,6 +564,11 @@ int MPV_common_init(MpegEncContext *s) } s->parse_context.state= -1; + if((s->avctx->debug&(FF_DEBUG_VIS_QP|FF_DEBUG_VIS_MB_TYPE)) || (s->avctx->debug_mv)){ + s->visualization_buffer[0] = av_malloc((s->mb_width*16 + 2*EDGE_WIDTH) * s->mb_height*16 + 2*EDGE_WIDTH); + s->visualization_buffer[1] = av_malloc((s->mb_width*8 + EDGE_WIDTH) * s->mb_height*8 + EDGE_WIDTH); + s->visualization_buffer[2] = av_malloc((s->mb_width*8 + EDGE_WIDTH) * s->mb_height*8 + EDGE_WIDTH); + } s->context_initialized = 1; return 0; @@ -641,6 +646,9 @@ void MPV_common_end(MpegEncContext *s) s->last_picture_ptr= s->next_picture_ptr= s->current_picture_ptr= NULL; + for(i=0; i<3; i++) + if (s->visualization_buffer[i]) + av_free(s->visualization_buffer[i]); } #ifdef CONFIG_ENCODERS @@ -1361,13 +1369,22 @@ static void draw_arrow(uint8_t *buf, int sx, int sy, int ex, int ey, int w, int /** * prints debuging info for the given picture. */ -void ff_print_debug_info(MpegEncContext *s, Picture *pict){ +void ff_print_debug_info(MpegEncContext *s, AVFrame *pict){ if(!pict || !pict->mb_type) return; if(s->avctx->debug&(FF_DEBUG_SKIP | FF_DEBUG_QP | FF_DEBUG_MB_TYPE)){ int x,y; - + + av_log(s->avctx,AV_LOG_DEBUG,"New frame, type: "); + switch (pict->pict_type) { + case FF_I_TYPE: av_log(s->avctx,AV_LOG_DEBUG,"I\n"); break; + case FF_P_TYPE: av_log(s->avctx,AV_LOG_DEBUG,"P\n"); break; + case FF_B_TYPE: av_log(s->avctx,AV_LOG_DEBUG,"B\n"); break; + case FF_S_TYPE: av_log(s->avctx,AV_LOG_DEBUG,"S\n"); break; + case FF_SI_TYPE: av_log(s->avctx,AV_LOG_DEBUG,"SI\n"); break; + case FF_SP_TYPE: av_log(s->avctx,AV_LOG_DEBUG,"SP\n"); break; + } for(y=0; ymb_height; y++){ for(x=0; xmb_width; x++){ if(s->avctx->debug&FF_DEBUG_SKIP){ @@ -1380,7 +1397,6 @@ void ff_print_debug_info(MpegEncContext *s, Picture *pict){ } if(s->avctx->debug&FF_DEBUG_MB_TYPE){ int mb_type= pict->mb_type[x + y*s->mb_stride]; - //Type & MV direction if(IS_PCM(mb_type)) av_log(s->avctx, AV_LOG_DEBUG, "P"); @@ -1433,45 +1449,71 @@ void ff_print_debug_info(MpegEncContext *s, Picture *pict){ } } - if(s->avctx->debug&(FF_DEBUG_VIS_MV|FF_DEBUG_VIS_QP|FF_DEBUG_VIS_MB_TYPE)){ + if((s->avctx->debug&(FF_DEBUG_VIS_QP|FF_DEBUG_VIS_MB_TYPE)) || (s->avctx->debug_mv)){ const int shift= 1 + s->quarter_sample; int mb_y; - uint8_t *ptr= pict->data[0]; + uint8_t *ptr; s->low_delay=0; //needed to see the vectors without trashing the buffers + int i; + + for(i=0; i<3; i++){ + memcpy(s->visualization_buffer[i], pict->data[i], (i==0) ? pict->linesize[i]*s->height:pict->linesize[i]*s->height/2); + pict->data[i]= s->visualization_buffer[i]; + } + pict->type= FF_BUFFER_TYPE_COPY; + ptr= pict->data[0]; for(mb_y=0; mb_ymb_height; mb_y++){ int mb_x; for(mb_x=0; mb_xmb_width; mb_x++){ const int mb_index= mb_x + mb_y*s->mb_stride; - if((s->avctx->debug&FF_DEBUG_VIS_MV) && pict->motion_val){ - if(IS_8X8(pict->mb_type[mb_index])){ - int i; - for(i=0; i<4; i++){ + if((s->avctx->debug_mv) && pict->motion_val){ + int type; + for(type=0; type<3; type++){ + int direction; + switch (type) { + case 0: if ((!(s->avctx->debug_mv&FF_DEBUG_VIS_MV_P_FOR)) || (pict->pict_type!=FF_P_TYPE)) + continue; + direction = 0; + break; + case 1: if ((!(s->avctx->debug_mv&FF_DEBUG_VIS_MV_B_FOR)) || (pict->pict_type!=FF_B_TYPE)) + continue; + direction = 0; + break; + case 2: if ((!(s->avctx->debug_mv&FF_DEBUG_VIS_MV_B_BACK)) || (pict->pict_type!=FF_B_TYPE)) + continue; + direction = 1; + break; + } + if(IS_8X8(pict->mb_type[mb_index])){ + int i; + for(i=0; i<4; i++){ int sx= mb_x*16 + 4 + 8*(i&1); int sy= mb_y*16 + 4 + 8*(i>>1); int xy= 1 + mb_x*2 + (i&1) + (mb_y*2 + 1 + (i>>1))*(s->mb_width*2 + 2); - int mx= (pict->motion_val[0][xy][0]>>shift) + sx; - int my= (pict->motion_val[0][xy][1]>>shift) + sy; + int mx= (pict->motion_val[direction][xy][0]>>shift) + sx; + int my= (pict->motion_val[direction][xy][1]>>shift) + sy; draw_arrow(ptr, sx, sy, mx, my, s->width, s->height, s->linesize, 100); - } - }else if(IS_16X8(pict->mb_type[mb_index])){ - int i; - for(i=0; i<2; i++){ + } + }else if(IS_16X8(pict->mb_type[mb_index])){ + int i; + for(i=0; i<2; i++){ int sx=mb_x*16 + 8; int sy=mb_y*16 + 4 + 8*i; int xy=1 + mb_x*2 + (mb_y*2 + 1 + i)*(s->mb_width*2 + 2); - int mx=(pict->motion_val[0][xy][0]>>shift) + sx; - int my=(pict->motion_val[0][xy][1]>>shift) + sy; + int mx=(pict->motion_val[direction][xy][0]>>shift) + sx; + int my=(pict->motion_val[direction][xy][1]>>shift) + sy; draw_arrow(ptr, sx, sy, mx, my, s->width, s->height, s->linesize, 100); + } + }else{ + int sx= mb_x*16 + 8; + int sy= mb_y*16 + 8; + int xy= 1 + mb_x*2 + (mb_y*2 + 1)*(s->mb_width*2 + 2); + int mx= (pict->motion_val[direction][xy][0]>>shift) + sx; + int my= (pict->motion_val[direction][xy][1]>>shift) + sy; + draw_arrow(ptr, sx, sy, mx, my, s->width, s->height, s->linesize, 100); } - }else{ - int sx= mb_x*16 + 8; - int sy= mb_y*16 + 8; - int xy= 1 + mb_x*2 + (mb_y*2 + 1)*(s->mb_width*2 + 2); - int mx= (pict->motion_val[0][xy][0]>>shift) + sx; - int my= (pict->motion_val[0][xy][1]>>shift) + sy; - draw_arrow(ptr, sx, sy, mx, my, s->width, s->height, s->linesize, 100); - } + } } if((s->avctx->debug&FF_DEBUG_VIS_QP) && pict->motion_val){ uint64_t c= (pict->qscale_table[mb_index]*128/31) * 0x0101010101010101ULL; diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index 39461f7e32..cf2b5cf258 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -304,6 +304,7 @@ typedef struct MpegEncContext { Picture *last_picture_ptr; ///< pointer to the previous picture. Picture *next_picture_ptr; ///< pointer to the next picture (for bidir pred) Picture *current_picture_ptr; ///< pointer to the current picture + uint8_t *visualization_buffer[3]; //< temporary buffer vor MV visualization int last_dc[3]; ///< last DC values for MPEG1 int16_t *dc_val[3]; ///< used for mpeg4 DC prediction, all 3 arrays must be continuous int16_t dc_cache[4*5]; @@ -705,7 +706,7 @@ void ff_emulated_edge_mc(uint8_t *buf, uint8_t *src, int linesize, int block_w, #define END_NOT_FOUND -100 int ff_combine_frame( MpegEncContext *s, int next, uint8_t **buf, int *buf_size); void ff_mpeg_flush(AVCodecContext *avctx); -void ff_print_debug_info(MpegEncContext *s, Picture *pict); +void ff_print_debug_info(MpegEncContext *s, AVFrame *pict); void ff_write_quant_matrix(PutBitContext *pb, int16_t *matrix); int ff_find_unused_picture(MpegEncContext *s, int shared); void ff_denoise_dct(MpegEncContext *s, DCTELEM *block); diff --git a/libavcodec/rv10.c b/libavcodec/rv10.c index 01623c730a..832e5e1f50 100644 --- a/libavcodec/rv10.c +++ b/libavcodec/rv10.c @@ -662,10 +662,10 @@ static int rv10_decode_frame(AVCodecContext *avctx, if(s->pict_type==B_TYPE || s->low_delay){ *pict= *(AVFrame*)&s->current_picture; - ff_print_debug_info(s, s->current_picture_ptr); + ff_print_debug_info(s, pict); } else { *pict= *(AVFrame*)&s->last_picture; - ff_print_debug_info(s, s->last_picture_ptr); + ff_print_debug_info(s, pict); } *data_size = sizeof(AVFrame);