ffmpeg获取运动矢量问题

解码过程中得到的运动矢量, 在avcodec_decode_video2()函数解码之后就可以从AVFrame中提取运动矢量信息了。运动矢量提取与编码方式有关,一些格式无法提取运动矢量,近几年较为流行的如H264等均可以。

运动矢量关注motion_val变量。注意画运动矢量图时,需要考虑视频块是8*8,16*8,8*16还是16*16的。针对雷霄骅的100行简易ffmpeg播放器代码
http://blog.csdn.net/leixiaohua1020?viewmode=list:
加上提取运动矢量部分。
#include "stdafx.h"

#define IS_INTERLACED(a) ((a)&MB_TYPE_INTERLACED)
#define IS_16X16(a)      ((a)&MB_TYPE_16x16)
#define IS_16X8(a)       ((a)&MB_TYPE_16x8)
#define IS_8X16(a)       ((a)&MB_TYPE_8x16)
#define IS_8X8(a)        ((a)&MB_TYPE_8x8)
#define USES_LIST(a, list) ((a) & ((MB_TYPE_P0L0|MB_TYPE_P1L0)<<(2*(list))))
void print_vector(FILE *fp1, int frame, int code, int x, int y, int dx, int dy)
{
	fprintf(fp1,"%d %d %d %d %d %d\n", frame, code, x, y, dx, dy);
}

void printMVMatrix(FILE *fp2, int index, AVFrame *pict, AVCodecContext *ctx)
{
    const int mb_width  = (ctx->width + 15) / 16;
    const int mb_height = (ctx->height + 15) / 16;
    const int mb_stride = mb_width + 1;
    const int mv_sample_log2 = 4 - pict->motion_subsample_log2;
    const int mv_stride = (mb_width << mv_sample_log2) + (ctx->codec_id == CODEC_ID_H264 ? 0 : 1);
    const int quarter_sample = (ctx->flags & CODEC_FLAG_QPEL) != 0;
    const int shift = 1 + quarter_sample;
	


    for (int mb_y = 0; mb_y < mb_height; mb_y++) {
	for (int mb_x = 0; mb_x < mb_width; mb_x++) {		
	    const int mb_index = mb_x + mb_y * mb_stride;
	    if (pict->motion_val) {
		for (int type = 0; type < 3; type++) {
		    int direction = 0;
		    switch (type) {
			case 0:
			    if (pict->pict_type != AV_PICTURE_TYPE_P)
				continue;
			    direction = 0;
			    break;
			case 1:
			    if (pict->pict_type != AV_PICTURE_TYPE_B)
			       	continue;
			    direction = 0;
			    break;
			case 2:
			    if (pict->pict_type != AV_PICTURE_TYPE_B)
				continue;
			    direction = 1;
			    break;
		    }

		    if (!USES_LIST(pict->mb_type[mb_index], direction)) {
#define NO_MV 0
			if (IS_8X8(pict->mb_type[mb_index])) {
			    print_vector(fp2, index, 0, mb_x, mb_y, NO_MV, NO_MV);
			    print_vector(fp2, index, 1, mb_x, mb_y, NO_MV, NO_MV);
			    print_vector(fp2, index, 2, mb_x, mb_y, NO_MV, NO_MV);
			    print_vector(fp2, index, 3, mb_x, mb_y, NO_MV, NO_MV);
			} else if (IS_16X8(pict->mb_type[mb_index])) {
			    print_vector(fp2, index, 0, mb_x, mb_y, NO_MV, NO_MV);
			    print_vector(fp2, index, 1, mb_x, mb_y, NO_MV, NO_MV);
				print_vector(fp2, index, 2, mb_x, mb_y, NO_MV, NO_MV);
				print_vector(fp2, index, 3, mb_x, mb_y, NO_MV, NO_MV);
			} else if (IS_8X16(pict->mb_type[mb_index])) {
			    print_vector(fp2, index, 0, mb_x, mb_y, NO_MV, NO_MV);
			    print_vector(fp2, index, 1, mb_x, mb_y, NO_MV, NO_MV);
				print_vector(fp2, index, 2, mb_x, mb_y, NO_MV, NO_MV);
				print_vector(fp2, index, 3, mb_x, mb_y, NO_MV, NO_MV);
			} else {
			    print_vector(fp2, index, 0, mb_x, mb_y, NO_MV, NO_MV);
				print_vector(fp2, index, 1, mb_x, mb_y, NO_MV, NO_MV);
				print_vector(fp2, index, 2, mb_x, mb_y, NO_MV, NO_MV);
				print_vector(fp2, index, 3, mb_x, mb_y, NO_MV, NO_MV);
			}
#undef NO_MV
			continue;
		    }

		    if (IS_8X8(pict->mb_type[mb_index])) {
			for (int i = 0; i < 4; i++) {
			    int xy = (mb_x*2 + (i&1) + (mb_y*2 + (i>>1))*mv_stride) << (mv_sample_log2-1);				
			    int dx = (pict->motion_val[direction][xy][0]>>shift);
			    int dy = (pict->motion_val[direction][xy][1]>>shift);
			    print_vector(fp2, index, i, mb_x, mb_y, dx, dy);
			}
		    } else if (IS_16X8(pict->mb_type[mb_index])) {
			for (int i = 0; i < 2; i++) {
			    int xy = (mb_x*2 + (mb_y*2 + i)*mv_stride) << (mv_sample_log2-1);
			    int dx = (pict->motion_val[direction][xy][0]>>shift);
			    int dy = (pict->motion_val[direction][xy][1]>>shift);

			    if (IS_INTERLACED(pict->mb_type[mb_index]))
				dy *= 2;

			    print_vector(fp2, index, i*2, mb_x, mb_y, dx, dy);
				print_vector(fp2, index, i*2+1, mb_x, mb_y, dx, dy);
			}
		    } else if (IS_8X16(pict->mb_type[mb_index])) {
			for (int i = 0; i < 2; i++) {
			    int xy =  (mb_x*2 + i + mb_y*2*mv_stride) << (mv_sample_log2-1);
			    int dx = (pict->motion_val[direction][xy][0]>>shift);
			    int dy = (pict->motion_val[direction][xy][1]>>shift);

			    if (IS_INTERLACED(pict->mb_type[mb_index]))
				dy *= 2;

			    print_vector(fp2, index, i, mb_x, mb_y, dx, dy);
				print_vector(fp2, index, i+2, mb_x, mb_y, dx, dy);
			}
		    } else {
			int xy = (mb_x + mb_y*mv_stride) << mv_sample_log2;
			int dx = (pict->motion_val[direction][xy][0]>>shift);
			int dy = (pict->motion_val[direction][xy][1]>>shift);
			print_vector(fp2, index, 0, mb_x, mb_y, dx, dy);
			print_vector(fp2, index, 1, mb_x, mb_y, dx, dy);
			print_vector(fp2, index, 2, mb_x, mb_y, dx, dy);
			print_vector(fp2, index, 3, mb_x, mb_y, dx, dy);
		    }
		}
	    }
	}
    }
}
int _tmain(int argc, _TCHAR* argv[])
{
	AVFormatContext	*pFormatCtx;
	int				i, videoindex;
	int             q_number;
	AVCodecContext	*pCodecCtx;
	AVCodec			*pCodec;
	FILE *fp;

	for (q_number = 1; q_number < 2; q_number++){
	int gindex=0;

	char filepath[]="";
	char querynumber[5];
	itoa(q_number, querynumber, 10);
	strcat(filepath, querynumber);
	strcat(filepath, ".avi");
	char motionname[] = "WZM";
	strcat(motionname, querynumber);
	strcat(motionname, ".txt");
	fp = fopen(motionname, "w");

	av_register_all();
	avformat_network_init();
	pFormatCtx = avformat_alloc_context();
	if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=0){
		printf("无法打开文件\n");
		return -1;
	}
	if(av_find_stream_info(pFormatCtx)<0)
	{
		printf("Couldn't find stream information.\n");
		return -1;
	}
	videoindex=-1;
	for(i=0; inb_streams; i++) 
		if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
		{
			videoindex=i;
			break;
		}
		if(videoindex==-1)
		{
			printf("Didn't find a video stream.\n");
			return -1;
		}
		pCodecCtx=pFormatCtx->streams[videoindex]->codec;
		pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
		if(pCodec==NULL)
		{
			printf("Codec not found.\n");
			return -1;
		}
		if(avcodec_open(pCodecCtx, pCodec)<0)
		{
			printf("Could not open codec.\n");
			return -1;
		}
		AVFrame	*pFrame,*pFrameYUV;
		pFrame=avcodec_alloc_frame();
		pFrameYUV=avcodec_alloc_frame();
		uint8_t *out_buffer;
		out_buffer=new uint8_t[avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height)];
		avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);
//------------SDL----------------
	/*	if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {  
			printf( "Could not initialize SDL - %s\n", SDL_GetError()); 
			exit(1);
		} 
		SDL_Surface *screen; 
		screen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, 0);
		if(!screen) {  printf("SDL: could not set video mode - exiting\n");  
		exit(1);
		}
		SDL_Overlay *bmp; 
		bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height,SDL_YV12_OVERLAY, screen); 
		SDL_Rect rect;*/
//---------------
		int ret, got_picture;
		static struct SwsContext *img_convert_ctx;
		int y_size = pCodecCtx->width * pCodecCtx->height;

		AVPacket *packet=(AVPacket *)malloc(sizeof(AVPacket));
		av_new_packet(packet, y_size);
		//输出一下信息-----------------------------
		printf("文件信息-----------------------------------------\n");
		av_dump_format(pFormatCtx,0,filepath,0);
		printf("-------------------------------------------------\n");
		//------------------------------
		while(av_read_frame(pFormatCtx, packet)>=0)
		{
			if(packet->stream_index==videoindex)
			{
				ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
				gindex++;
				if(ret < 0)
				{
					printf("解码错误\n");
					return -1;
				}
				if(got_picture)
				{
					
					printMVMatrix(fp, gindex, pFrame, pCodecCtx);					
				}
			}
			av_free_packet(packet);
		}
		fclose(fp);
		delete[] out_buffer;
		av_free(pFrameYUV);
		avcodec_close(pCodecCtx);
		avformat_close_input(&pFormatCtx);
		}
		return 0;
}


你可能感兴趣的:(ffmpeg获取运动矢量问题)