视频YUV4:2:2转4:2:0的TI DSP源代码

简介:
     网络上有很多有关YUV4:2:2转YUV4:2:0的描述,但大多数都是讲解原理,没有实际性的做法,本文把自己在TI DAVINCI DM6446 端的测试过的代码奉献出来,供大家参考和学习,同时抛砖引玉,希望得到大家的指点。本方法适合TI DM642,DM643x,DM644x等DSP系列,前段图像采集格式一般都是YCbCr 4:2:2(YUV4:2:2),但很多视频应用都需要对YUV4:2:2进行转化成YUV4:2:0的格式,比如jpeg,MPEG4,H.264等,在DM643x,DM644x上,TI 采用EDMA3的方式实现转换,那是另外的方法,这里专门介绍通用的做法,在DM6441(513MHz)上处理640x480只需要7.5ms,而且还可以再优化,这个大家可以试试。
 
 
/***********************************************/
以PAL制为例,这里的YCbCr 4:2:2(YUV4:2:2)像素排列方式是:
U0,0 Y0,0 V0,0 Y 0,1  U0,1 Y0,2 V0,1 Y 0,3......U0,359 Y0,718 V0,359 Y 0,719
..............................
U575,0 Y575,0 V575,0 Y 575,1 ...........U575,359 Y575,718 V575,359 Y 575,719
NTSC
 
 
我们要转化成YUV4:2:0的格式:
 
  NTSC
/*视频输入格式定义*/
#define PAL    1   /*PAL制CCD摄像头图像采集*/
#define NTSC  0   /*NTSC制CCD摄像头图像采集*/
#define CMOS  0   /*CMOS摄像头图像采集*/
#if (1== PAL)
#define ORG_IMG_WIDTH     720      /*D1 格式*/
#define ORG_IMG_HEIGHT    576
#elif  (1==NTSC )
#define ORG_IMG_WIDTH     720      /*D1 格式*/
#define ORG_IMG_HEIGHT    480
#elif (1==CMOS)
#define ORG_IMG_WIDTH     640     /*VGA 格式*/
#define ORG_IMG_HEIGHT    480
#endif
 
yuv422to420(const *unsigned char YCbCr_buf) /*YCbCr_buf指向YUV4:2:2的空间*/
{
        unsigned int m0,m1,m2,m3,x,y;
        unsigned int tmp,tmp0,tmp1,tmp2;

        tmp = (unsigned int)YCbCr_buf;/*对于D1,CIF,QCIF,VGA,QVGA的BUF肯定是4字节对齐,所以这里定义unsigned int也是可以的,当然你也可以使用指针*/
        tmp0 = (unsigned int)Y_buf;
        for(y=0;y<ORG_IMG_HEIGHT;y++)
       {
            for(x=0;x<(ORG_IMG_WIDTH>>1);x+=4)
           { 
                 m0 = *(unsigned int*)(tmp+y*(ORG_IMG_WIDTH<<1) + (x<<2)); /
                 m1 = *(unsigned int*)(tmp+y*(ORG_IMG_WIDTH<<1) + ((x+1)<<2));
                 m2 = *(unsigned int*)(tmp+y*(ORG_IMG_WIDTH<<1) + ((x+2)<<2));
                m3 = *(unsigned int*)(tmp+y*(ORG_IMG_WIDTH<<1) + ((x+3)<<2));
                *(unsigned short*)(tmp0+y*ORG_IMG_WIDTH + (x<<1))=(unsigned short)(((m0>>16)&0xFF00)|((m0>>8)&0x00FF));
                 *(unsigned short*)(tmp0+y*ORG_IMG_WIDTH + ((x+1)<<1))=(unsigned short)(((m1>>16)&0xFF00)|((m1>>8)&0x00FF));
                 *(unsigned short*)(tmp0+y*ORG_IMG_WIDTH + ((x+2)<<1))=(unsigned short)(((m2>>16)&0xFF00)|((m2>>8)&0x00FF));
                 *(unsigned short*)(tmp0+y*RG_IMG_WIDTH + ((x+3)<<1))=(unsigned short)(((m3>>16)&0xFF00)|((m3>>8)&0x00FF));
             }
       }
       tmp1=(unsigned int)U_buf;
       tmp2=(unsigned int)V_buf;
       for(y=0;y<(ORG_IMG_HEIGHT>>1);y++)
      {
             for(x=0;x<(ORG_IMG_WIDTH>>1);x+=4)
             {
                  m0 = *(unsigned int*)(tmp+y*(ORG_IMG_WIDTH<<2) + (x<<2));
                  m1 = *(unsigned int*)(tmp+y*(ORG_IMG_WIDTH<<2) + ((x+1)<<2));
                  m2 = *(unsigned int*)(tmp+y*(ORG_IMG_WIDTH<<2) + ((x+2)<<2));
                 m3 = *(unsigned int*)(tmp+y*(ORG_IMG_WIDTH<<2) + ((x+3)<<2));
     
                 *(unsigned char*)(tmp1+y*(ORG_IMG_WIDTH>>1) + x)=(unsigned char)m0;
                 *(unsigned char*)(tmp2+y*(ORG_IMG_WIDTH>>1) + x)=(unsigned char)(m0>>16);
                *(unsigned char*)(tmp1+y*(ORG_IMG_WIDTH>>1) + x + 1)=(unsigned char)m1;
                *(unsigned char*)(tmp2+y*(ORG_IMG_WIDTH>>1) + x + 1)=(unsigned char)(m1>>16);
               *(unsigned char*)(tmp1+y*(ORG_IMG_WIDTH>>1) + x + 2)=(unsigned char)m2;
               *(unsigned char*)(tmp2+y*(ORG_IMG_WIDTH>>1) + x + 2)=(unsigned char)(m2>>16);
              *(unsigned char*)(tmp1+y*(ORG_IMG_WIDTH>>1) + x + 3)=(unsigned char)m3;
              *(unsigned char*)(tmp2+y*(ORG_IMG_WIDTH>>1) + x + 3)=(unsigned char)(m3>>16);

            }
       }
}
对上面的代码点评:DSP的优化原则,能移位,就不要乘除;能int 读内存,就不要用char读内存,因为C64,C64+的DSP 读内存指令需要4个时钟周期;循环能成4的倍数,最好拆4次操作,形成管道流水线操作,当然循环内部不能有if, break等语句。
 
 
另外,DM642或DM643有自己的效率更高的程序,这里也奉献给大家。
#include <csl.h>
#include <csl_dat.h>
#include <csl_cache.h>
#pragma DATA_SECTION(int_mem_temp, ".img_buf");/*可以把.img_buf定义到L2RAM*/
#pragma DATA_ALIGN(int_mem_temp, 128);
unsigned char int_mem_temp[720];
 
void yuv422to420( char *frameIn[], char *frm_out[],
                  int width, int height)
{
    char *pSrcY = frameIn[0];
    char *pSrcU = frameIn[1];
    char *pSrcV = frameIn[2];
    char *pDestY = frm_out[0];
    char *pDestU = frm_out[1];
    char *pDestV = frm_out[2];
    unsigned int id;
    unsigned int i;
    for( i = 0; i < height; i++)
    {
        id = DAT_copy(pSrcY + (i * 720), int_mem_temp, 720);
        id = DAT_copy(int_mem_temp,      pDestY + (i * 720),  720);
        DAT_wait(id);
    }
    for( i = 0; i < (height >> 1); i++)
    {
        id = DAT_copy(pSrcU + (i * 720), int_mem_temp, 360);
        id = DAT_copy(int_mem_temp,      pDestU + (i * 360),  360);
        DAT_wait(id);
    }
    for( i = 0; i < (height >> 1); i++)
    {
        id = DAT_copy(pSrcV + (i * 720), int_mem_temp, 360);
        id = DAT_copy(int_mem_temp,      pDestV + (i * 360),  360);
        DAT_wait(id);
    }
    return ;
}
void yuv420to422( char *frameIn[], char *frm_out[],
                int width, int height)
{
    char *pSrcY = frameIn[0];
    char *pSrcU = frameIn[1];
    char *pSrcV = frameIn[2];
    char *pDestY = frm_out[0];
    char *pDestU = frm_out[1];
    char *pDestV = frm_out[2];
    unsigned int id;
    unsigned int i;
    for( i = 0; i < height; i++)
    {
        id = DAT_copy(pSrcY + (i * 720), int_mem_temp, 720);
        id = DAT_copy(int_mem_temp,      pDestY + (i * 720),  720);
        DAT_wait(id);
    }
    for( i = 0; i < (height >> 1); i++)
    {
        id = DAT_copy(pSrcU + (i * 360), int_mem_temp, 360);
        id = DAT_copy(int_mem_temp,      pDestU + ((2 * i) * 360),   360);
        id = DAT_copy(int_mem_temp,      pDestU + ((2*i + 1)* 360),  360);
        DAT_wait(id);
    }
    for( i = 0; i < (height >> 1); i++)
    {
        id = DAT_copy(pSrcV + (i * 360), int_mem_temp, 360);
        id = DAT_copy(int_mem_temp,      pDestV + ((2*i) * 360),    360);
        id = DAT_copy(int_mem_temp,      pDestV + ((2*i+1) * 360),  360);
        DAT_wait(id);
    }
   return ;
}









本文转自 zjb_integrated 51CTO博客,原文链接:http://blog.51cto.com/zjbintsystem/235094,如需转载请自行联系原作者
目录
相关文章
|
4月前
|
算法 异构计算 索引
m基于FPGA的Hamming汉明编译码verilog实现,包含testbench测试文件,不使用IP核
m基于FPGA的Hamming汉明编译码verilog实现,包含testbench测试文件,不使用IP核
49 1
|
Linux 开发工具 git
Xilinx Bit文件格式详解
Xilinx Bit文件格式详解
773 0
Xilinx Bit文件格式详解
|
2月前
|
算法 异构计算
m基于FPGA的Alamouti编码verilog实现,包含testbench测试文件
m基于FPGA的Alamouti编码verilog实现,包含testbench测试文件
34 5
|
4月前
|
编解码 缓存 开发工具
Zynq7020 使用 Video Processing Subsystem 实现图像缩放
1、前言 没玩过图像缩放都不好意思说自己玩儿过FPGA,这是CSDN某大佬说过的一句话,鄙人深信不疑。。。 目前市面上主流的FPGA图像缩放方案如下:1:Xilinx的HLS方案,该方案简单,易于实现,但只能用于Xilinx自家的FPGA;2:非纯Verilog方案,大部分代码使用Verilog实现,但中间的fifo或ram等使用了IP,导致移植性变差,难以在Xilinx、Altera和国产FPGA之间自由移植;3:纯Verilog方案; 本文使用Xilinx Zynq7000系列FPGA Zynq7020实现Video Processing Subsystem图像缩放,输入视频源采用O
55 1
|
4月前
|
算法 计算机视觉 异构计算
基于FPGA的图像RGB转HLS实现,包含testbench和MATLAB辅助验证程序
基于FPGA的图像RGB转HLS实现,包含testbench和MATLAB辅助验证程序
|
8月前
|
编解码 监控 算法
基于simulink的MPEG4视频超分辨率重构仿真
基于simulink的MPEG4视频超分辨率重构仿真
|
12月前
|
算法 异构计算
基于FPGA的HDB3编译码verilog实现,包括testbench
基于FPGA的HDB3编译码verilog实现,包括testbench
150 0
|
12月前
|
存储 算法 异构计算
基于FPGA的Hamming编译码verilog开发实现,包括testbench测试程序
基于FPGA的Hamming编译码verilog开发实现,包括testbench测试程序
172 0
|
存储 编解码 芯片
ZYNQ裸板:LHB155304-RT篇
1553总线是一种指令/响应式串行总线标准,除了作为美军标在国外广泛应用于军用飞机坦克、船舶、卫星、导弹等领域,在国内已得到了广泛的应用。抗干扰能力强实时性好,且拥有着双冗余备份设计,数据传输极为可靠。就我个人认知来看,常见的实现形式一种是通过专用的接口协议芯片,相对比较简单集成度高;另一种是IP核,非常考验逻辑和软件设计的功底。此次工程选用了前者,LHB15530接口芯片,在不改变原有传输方式的前提下,突破了原有的1Mb/s的传输速率,可达4Mb/s,也能满足绝大部分应用场景。
362 0
ZYNQ裸板:LHB155304-RT篇
|
芯片 SoC
基于XQ6657Z35-EVM开发平台上TI TMS320C6657 TLV320AIC3206音频设计
TMS320C6657 Audio设计 评估板XQ6657Z35-EVM,音频输入输出设计,其引脚定义如下图: (TLV320AIC3206IRSBR音频接口芯片)
基于XQ6657Z35-EVM开发平台上TI TMS320C6657 TLV320AIC3206音频设计