最近在做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