最近在做RK平台的相关东东,RK内存的数据排序如下图(以12bit为例):
图1 大端存储(高地址,低字节)
如图1所示,在RK内存中,(个人认为)以大端存储,像素的高字节数据(11~4bit)保存在内存的低地址中。以代码中打印的数据为例,P0像素的数据为0x7F(内存低地址,11~4bit),0xE0(内存高地址,3~0bit,0000),P1像素的数据为0x7E(内存低地址,11~4bit),0x30(内存高地址,0000)。
随后,在RK平台使用fwrite()函数保存文件(例如RAW_1)到SD卡中,(个人认为),RAW_1文件起始的16位数据存储为0x7FE0,如图2所示(好吧,其实和图1差不多)。
ps:这个0x7FE0是指如果我们在其他的大端机上用fread函数读取RAW_1文件,则读取到的数据也是0x7FE0。
图2
之后,将SD卡中的文件RAW_1拷贝到PC机中,在PC机里是小端存储(高地址,高字节),如果使用fread函数读出来,则读取到的数据是0xE07F,如图3所示。
ps:(个人猜测)文件RAW_1在由大端机上向小端机上拷贝的过程中发生了存储方式的改变。
另外,要记住,这些文件其实本质上存储的事宜ASCII码值。
图3 小端存储(低地址,低字节)
但是,我们希望保存下来的数据在PC机上显示是高字节4位无数据,也就是如图4所示(图越来越渣了)
图4 小端存储(高字节4bit无数据)
所以这就要求保存在SD卡中的文件,或者说在RK内存(大端)中的数据排序应该如图5所示
图5
所以希望在保存数据前进行内存中数据排序的转换,写了一个不咋地的小程序,但是总算可以实现想要的功能。
#include <stdio.h> #include <stdlib.h> #include <string.h> unsigned short exchange(char *buffer_hi,char *buffer_lo) { unsigned short value_hi=((unsigned short)*buffer_hi<<8)&0xff00; unsigned short value_lo=(unsigned short)*buffer_lo&0xff; unsigned short temp1=((value_hi|value_lo)&0x000f)<<12&0xf000; unsigned short temp2=(value_hi|value_lo)>>4&0x0fff; unsigned short value_out=temp1|temp2; return value_out; } int main() { char buffer[6]; buffer[0]=0xC3; //1100 0011 buffer[1]=0x61; //1000 0001 buffer[2]=0x42; //0100 0010 buffer[3]=0x51; //0101 0001 buffer[4]=0x21; //0010 0001 buffer[5]=0x50; //0101 0000 for(int i=0;i<6;i++) { printf("buffer[%d] is %x\n",i,buffer[i]); } char *p=NULL; p=(char *)malloc(sizeof(char)*6); if(p) printf("Memory Allocated at: %x\n",p); else printf("Not Enough Memory!\n"); char *p1=p; memcpy(p,&buffer[0],sizeof(buffer)); unsigned short buffer_out[3]; memset(buffer_out,0,sizeof(unsigned short)*3); printf("开始转换\n"); for(int k=0;k<3;k++) { char temp1=*p; char temp2=*(++p); printf("temp1 is %x, temp2 is %x\n",temp1,temp2); buffer_out[k]=exchange(&temp1,&temp2); p++; } printf("转换结束\n"); p=p1; //p指针已经偏移,要free一定要指回来 free(p); p=NULL; //置NULL p1=NULL; for(int m=0;m<3;m++) { printf("buffer_out[%d] is %x\n",m,buffer_out[m]); } return 0; }
运行结果为:
buffer[0] is ffffffc3 buffer[1] is 61 buffer[2] is 42 buffer[3] is 51 buffer[4] is 21 buffer[5] is 50 Memory Allocated at: 780f30 开始转换 temp1 is ffffffc3, temp2 is 61 temp1 is 42, temp2 is 51 temp1 is 21, temp2 is 50 转换结束 buffer_out[0] is 1c36 buffer_out[1] is 1425 buffer_out[2] is 215 请按任意键继续. . .
在后续的开发过程中发现大量的数据转换耗时真的太长,以RK1108来说,转换224*172*9这么大的数据(也就是上面代码的循环次数k<224*179*9),总共需要大概20.6ms,于是想着怎么优化,先想到一条,不调用exchange函数,直接在循环里进行转换,这样可以减少出战入栈的时间,运行了一下,现在转换一次,大概需要13.9ms,提升了35%。后面继续优化,想到再来添加。
说真的,不到用的时候真的不算深入了解这些知识,以前对大小端的认识只是停留在概念,经过这次后,理解加深了很多。
后续附上一个关于大小端的网址,感觉这个说的挺全面的。
http://www.52rd.com/Blog/Detail_RD.Blog_imjacob_14837.html