YUV图像旋转

近期参与了Android程序开发,涉及到音视频。由于Android的窗口模式不同于传统的窗口,有时候需要对图像进行90度旋转。对图像旋转主要是对YUV图片的旋转,以下代码是将一个格式为YUV420的图片进行逆时针旋转。

void yuv_rotate_90(uchar *des,uchar *src,int width,int height)  
{  
    int n = 0;  
    int hw = width>>1;  
    int hh = height>>1;
    int size = width * height;
    int hsize = size>>2;
	
    int pos = 0;
    //copy y  
    for(int j = 0; j < width;j++)  
    {  
        pos = size;
        for(int i = height - 1; i >= 0; i--)  
        {	pos-=width;
            des[n++] = src[pos + j];
        }  
    }
    //copy uv  
    uchar *ptemp = src + size;
    int m = n + hsize;
    for(int j = 0;j < hw;j++)  
    {  	pos= hsize;
        for(int i = hh - 1;i >= 0;i--)  
        {  
	    pos-=hw;
            des[n++] = ptemp[ pos + j ];
	    des[m++] = ptemp[ pos + j+ hsize ]; 
        }  
    }
}


很多音视频相关的项目里面用到了ffmpeg,对ffmpeg里面的视频帧进行旋转主要是在视频解码后,图片显示前完成,于是将以上代码改到ffmpeg的应用环境。ffmpeg里面解码完成后的视频帧结构是AVFrame,以下代码是所述代码。


逆时针90度

void frame_rotate_90( AVFrame *src,AVFrame*des)  
{  
    int n = 0;  
    int hw = src->width>>1;
    int hh = src->height>>1;
    int size = src->width * src->height;
    int hsize = size>>2;
	
    int pos = 0;
    //copy y  
    for(int j = 0; j < src->width;j++)  
    {  
	pos = size;
        for(int i = src->height - 1; i >= 0; i--)
        {   pos-=src->width;
            des->data[0][n++] = src->data[0][pos + j];
        }  
    }
    //copy uv
    n = 0;
    for(int j = 0;j < hw;j++)  
    {  	pos= hsize;
        for(int i = hh - 1;i >= 0;i--)  
        {
	    pos-=hw;
            des->data[1][n] = src->data[1][ pos + j];
	    des->data[2][n] = src->data[2][ pos + j];
	    n++;
        }
    }
	
    des->linesize[0] = src->height;
    des->linesize[1] = src->height>>1;
    des->linesize[2] = src->height>>1;
    des->height = src->width;
    des->width = src->height;
}

逆时针180度旋转

void frame_rotate_180(AVFrame *src,AVFrame*des)
{
	int n = 0,i= 0,j = 0;  
    int hw = src->width>>1;
    int hh = src->height>>1;
    int pos= src->width * src->height;
	
    for (i = 0; i < src->height; i++)
	{
        pos-= src->width;
        for (int j = 0; j < src->width; j++) {
            des->data[0][n++] = src->data[0][pos + j];
        }
    }

	n = 0;
	pos = src->width * src->height>>2;
	
	for (i = 0; i < hh;i++) {
        pos-= hw;
        for (int j = 0; j < hw;j++) {
			
			des->data[1][n] = src->data[1][ pos + j];
			des->data[2][n] = src->data[2][ pos + j];
			n++;
        }
    }
	
	des->linesize[0] = src->width;
	des->linesize[1] = src->width>>1;
	des->linesize[2] = src->width>>1;
	
	des->width = src->width;
	des->height = src->height;
	des->format = src->format;
	
	des->pts = src->pts;
	des->pkt_pts = src->pkt_pts;
	des->pkt_dts = src->pkt_dts;
	
	des->key_frame = src->key_frame;
}

逆时针270度旋转:

void frame_rotate_270(AVFrame *src,AVFrame*des)
{
	int n = 0,i= 0,j = 0;
    int hw = src->width>>1;
    int hh = src->height>>1;
    int pos = 0;
	
	for(i = src->width-1;i >= 0;i--)
	{
		pos = 0;
		for(j= 0;j < src->height;j++)
		{
            des->data[0][n++]= src->data[0][pos+i];
			pos += src->width;
		}
	}
	
	n = 0;
	for (i = hw-1; i >= 0;i--) {
        pos= 0;
        for (j = 0; j < hh;j++) {
            des->data[1][n]= src->data[1][pos+i];
            des->data[2][n]= src->data[2][pos+i];
			pos += hw;
            n++;
        }
    }
	
	des->linesize[0] = src->height;
	des->linesize[1] = src->height>>1;
	des->linesize[2] = src->height>>1;
	
	des->width = src->height;
	des->height = src->width;
	des->format = src->format;
	
	des->pts = src->pts;
	des->pkt_pts = src->pkt_pts;
	des->pkt_dts = src->pkt_dts;
	
	des->key_frame = src->key_frame;
}

注意:

1,在ffmpeg环境下,调用frame_rotate系列函数之前需要对 AVFrame*des 进行初始化,否则内存是否发进行拷贝的。初始化代码如下:

AVFrame *des = av_frame_alloc();
unsigned char *rotate_buffer=(unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P,  pCodecCtx->height, pCodecCtx->width,1));
av_image_fill_arrays(des->data, des->linesize,rotate_buffer,AV_PIX_FMT_YUV420P,pCodecCtx->height, pCodecCtx->width,1);

2,经过旋转后,视频帧的宽和高已经发生了变化,所以进行显示时,应该以旋转后的宽高进行显示,不再是AVCodecContext里面的宽和高,SDL里面的Window和Texture都要进行调整,否则图片会花,或者崩溃。


参考:

1,http://blog.csdn.net/kl222/article/details/24470305 感觉算法有点问题,图片经过旋转后UV部分存在问题。

2,http://blog.csdn.net/codefoxtiger/article/details/23549553 算法对,但是性能需要优化,旋转一次,会调用太多乘法,对Android环境不太适用。






猜你喜欢

转载自blog.csdn.net/veilling/article/details/52200326
今日推荐