我是靠谱客的博主 怕黑时光,最近开发中收集的这篇文章主要介绍YUV格式初探(一)---NV12格式转RGB24的两种方式,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

最新需要将ffmpeg对视频硬解码之后的NV12格式通过操作像素的方式转换成RGB24,不是使用sws_getContext函数直接转换。网上找到了两个方法,分别测试可用但是效率大不相同

方式一:耗时:210ms左右  

/*
功能:NV12 转 RGB24
耗时:210ms左右  

使用举例:NV12_to_rgb24(0, srcSlice[0], RGB24, tex_w, tex_h) ;

     因为没有区分 格式,因此第一个参数 随便写,
     同时定义一个转换之后的指针:
     		unsigned char RGB24[1920*1080*10] = {0};
*/
static long int crv_tab[256];   
static long int cbu_tab[256];   
static long int cgu_tab[256];   
static long int cgv_tab[256];   
static long int tab_76309[256]; 
static unsigned char clp[1024];   //for clip in CCIR601   

void init_yuv420p_table() 
{   
    long int crv,cbu,cgu,cgv;   
    int i,ind;      
    static int init = 0;

    if (init == 1) return;

    crv = 104597; cbu = 132201;  /* fra matrise i global.h */   
    cgu = 25675;  cgv = 53279;   
   
    for (i = 0; i < 256; i++)    
    {   
        crv_tab[i] = (i-128) * crv;   
        cbu_tab[i] = (i-128) * cbu;   
        cgu_tab[i] = (i-128) * cgu;   
        cgv_tab[i] = (i-128) * cgv;   
        tab_76309[i] = 76309*(i-16);   
    }   
   
    for (i = 0; i < 384; i++)   
        clp[i] = 0;   
    ind = 384;   
    for (i = 0;i < 256; i++)   
        clp[ind++] = i;   
    ind = 640;   
    for (i = 0;i < 384; i++)   
        clp[ind++] = 255;

    init = 1;
}

/*
	函数功能:将NV12或者NV21格式数据 转换成RGB24
	参数说明:
	   frame_type:指的是pixfmt.h中结构体 AVPixelFormat 中对应的帧格式
*/
void NV12_or_NV21_to_rgb24(int frame_type, unsigned char* yuvbuffer,unsigned char* rgbbuffer, int width,int height)   
{
    int y1, y2, u, v;    
    unsigned char *py1, *py2;   
    int i, j, c1, c2, c3, c4;   
    unsigned char *d1, *d2;   
    unsigned char *src_u;
    static int init_yuv420p = 0;

    src_u = yuvbuffer + width * height;   // u

    py1 = yuvbuffer;   // y
    py2 = py1 + width;   
    d1 = rgbbuffer;   
    d2 = d1 + 3 * width;   

    init_yuv420p_table();

    for (j = 0; j < height; j += 2)    
    {    
        for (i = 0; i < width; i += 2)    
        {
      
            if (frame_type ==  AV_PIX_FMT_NV12)
            {
                u = *src_u++;   
                v = *src_u++;      // v紧跟u,在u的下一个位置
            }
            if (frame_type == AV_PIX_FMT_NV21)
            {
                v = *src_u++;   
                u = *src_u++;      // u紧跟v,在v的下一个位置
            }

            c1 = crv_tab[v];   
            c2 = cgu_tab[u];   
            c3 = cgv_tab[v];   
            c4 = cbu_tab[u];   

            //up-left   
            y1 = tab_76309[*py1++];    
            *d1++ = clp[384+((y1 + c1)>>16)];     
            *d1++ = clp[384+((y1 - c2 - c3)>>16)];   
            *d1++ = clp[384+((y1 + c4)>>16)];   

            //down-left   
            y2 = tab_76309[*py2++];   
            *d2++ = clp[384+((y2 + c1)>>16)];     
            *d2++ = clp[384+((y2 - c2 - c3)>>16)];   
            *d2++ = clp[384+((y2 + c4)>>16)];   

            //up-right   
            y1 = tab_76309[*py1++];   
            *d1++ = clp[384+((y1 + c1)>>16)];     
            *d1++ = clp[384+((y1 - c2 - c3)>>16)];   
            *d1++ = clp[384+((y1 + c4)>>16)];   

            //down-right   
            y2 = tab_76309[*py2++];   
            *d2++ = clp[384+((y2 + c1)>>16)];     
            *d2++ = clp[384+((y2 - c2 - c3)>>16)];   
            *d2++ = clp[384+((y2 + c4)>>16)];   
        }
        d1  += 3*width;
        d2  += 3*width;
        py1 += width;
        py2 += width;
    }
}

方法二:耗时700ms,但是该方法转换之后RGB24图像是上下翻转的。

         该函数转换出来的RGB24函数是上下翻转的,因此可以采取以下任一方案补救
          1、在执行该函数之前将NV12 翻转180°
          2、在执行该函数之后将RGB24 翻转180°
    这里采取的方法一,翻转函数在后面


/*
  函数功能:NV12 转RGB24
 *  注意:
         该函数转换出来的RGB24函数是上下翻转的,因此可以采取以下任一方案补救
          1、在执行该函数之前将NV12 翻转180°
		  2、在执行该函数之后将RGB24 翻转180°
    这里采取的方法一,翻转函数在后面
 */ 
void NV12_T_RGB24(unsigned int width, unsigned int height, unsigned char *NV12_data, unsigned char *bgr_data) {
    const int nv_start = width * height;
    int i, j, index = 0, rgb_index = 0;
    unsigned char y, u, v;
    int r, g, b, nv_index = 0;

    for (i = 0; i < height; i++) {
         for (j = 0; j < width; j++) {
            nv_index = i / 2 * width + j - j % 2;

            y = NV12_data[rgb_index];
            v = NV12_data[nv_start + nv_index];
            u = NV12_data[nv_start + nv_index + 1];

            r = y + (140 * (v - 128)) / 100;  //r
            g = y - (34 * (u - 128)) / 100 - (71 * (v - 128)) / 100; //g
            b = y + (177 * (u - 128)) / 100; //b

            if (r > 255)
                r = 255;
            if (g > 255)
                g = 255;
            if (b > 255)
                b = 255;
            if (r < 0)
                r = 0;
            if (g < 0)
                g = 0;
            if (b < 0)
                b = 0;

            index = rgb_index % width + (height - i - 1) * width;
            bgr_data[index * 3 + 2] = r;
            bgr_data[index * 3 + 1] = g;
            bgr_data[index * 3 + 0] = b;
            rgb_index++;
        }
    }
}


 

NV12翻转180°函数:
 

/*
	函数功能:NV12 翻转180°
*/
int nv12rote180(unsigned char * src, unsigned char * dst, int srcW, int srcH)
{
	int wide = srcW;
	int high = srcH;

	unsigned char * srcUV = src + wide * high;
	unsigned char * destUV = dst + wide * high;

	int i, j;
	for(i = 0; i < high; i++){
		for(j = 0; j < wide; j++){
			dst[((high-1-i) * wide+wide-1-j)] = src[i * wide+j];
			
			destUV[(((( high-1-i) / 2) * (wide / 2)+((wide-1-j) / 2)) * 2+0)] = srcUV[(((i / 2) * (wide / 2)+(j / 2)) * 2+ 0)];
			destUV[(((( high-1-i) / 2) * (wide / 2)+((wide-1-j) / 2)) * 2+1)] = srcUV[(((i / 2) * (wide / 2)+(j / 2)) * 2+1)];
		}
	}
	return 0;
}

参考链接:

1、http://www.cnblogs.com/lance-ehf/p/5310092.html

参考的其他文章记不清了,如有侵权请联系!

 

 

 

 

 

 


 

最后

以上就是怕黑时光为你收集整理的YUV格式初探(一)---NV12格式转RGB24的两种方式的全部内容,希望文章能够帮你解决YUV格式初探(一)---NV12格式转RGB24的两种方式所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(44)

评论列表共有 0 条评论

立即
投稿
返回
顶部