笔记——H264移植中从DDR读出的YUV数据处理

待处理的数据

图片中的数据是 720P YUV420YV12格式下,解码端在DDR存储的数据。这是第一个 BLOCK的数据(16*16像素),所以要有 Y值16*16个 ,UV 各有8*8个(由YUV44行列均隔行抽样得到YUV420格式)。如图中示意,16行Y,8行V,8行U。

整个decoder_data_720p.txt中的数据是按 BLOCK 存储的,而且是按列遍历整张照片。一张720p(1280*720像素)照片的BLOCK示意图,即先存满BLOCK1,1~45,到第二行的BLOCK2,1~45。在解析时要注意存储顺序。

 

问题来了:本来每个像素值应该是8bit,刚好2个十六进制数,但是由于FPGA系统内部的处理,每个值占了10bits 。因此如下的数据是需要解析bit的。

图1 从DDR导出的待处理数据

如何解析出数据呢?

以第一行数据为例:300c0300c0300c0300c0300c0300c0300c0300c0,16个Y值,有16*10 bits(高8位有效,补2个0) = 20 Byte 数据。

假设给第一行数据按字节编号:B0B1B2...B19。可以看出每5个字节呈现出一定的规律,阴影表示补的0。20Byte/5 = 4次循环。

从单行来看像素Y值,

Y0 = B0,

Y1高4位数据 = (B1>>2)<<4,Y1低4位数据 = (B1&0x03) + (B2>>6)&0x03 (这里要注意右移时最高位是否市符号位拓展,保险起见 &0X03), Y1=Y1高4位数据 +Y1低4位数据。

Y2 = B2<<4 + B3>>4

Y3 = (B3&0x03)<<6 + (B4>>2)

...

这样循环4次就能遍历一行,取出16个Y值。

其他UV等数据类似取出。

 

看看如何取出1个BLOCK?

读取数据

posy = 1;posv = 2;posu = 3; %根据数据来定义的顺序

inblock = zeros(16,20,3);
inblock(:,:,posy) = fscanf(fid_txtin,'%02x',[20 16])';
tempuv = fscanf(fid_txtin,'%02x',[20 8])';

 取出V,前10列数据是V,然后补满 inblock 其他位置,方便处理。

inblock(1:8,1:10,posv) = tempuv(1:8,1:10); 
inblock(1:8,11:20,posv) = tempuv(1:8,1:10);
inblock(9:16,:,posv) = inblock(1:8,:,posv); 

取出U,后10列数据是U,然后补满 inblock 其他位置,方便处理。

inblock(1:8,1:10,posu) = tempuv(1:8,11:20);
inblock(1:8,11:20,posu) = inblock(1:8,1:10,posu);
inblock(9:16,:,posu) = inblock(1:8,:,posu);
inblock = uint8(inblock); 

这样YUV的数据按相应位置存储到数组 inblock里面了。维度 16x20。

解析inblock的数据 存入到 imgblock,分别解析 YUV数据。列遍历时(每次循环5个字节),解析出4个YUV值。解释见上面的字节图形说明。

imgblock = zeros(16,16,3);
for yuv=1:3
    for row=1:16
        incol = 1;
        for column=1:4:16
            %
            imgblock(row,column+0,yuv) = inblock(row,incol+0,yuv); 
            %
            tempH = bitshift(inblock(row,incol+1,yuv),-2);
            tempH = bitshift(tempH,4);
            tempL = bitand(inblock(row,incol+1,yuv),3);
            tempL = bitshift(tempL,2);
            tempL = tempL + bitshift(inblock(row,incol+2,yuv),-6);
            temp = tempH+tempL;
            imgblock(row,column+1,yuv) = temp;
            %
            tempH = bitshift(inblock(row,incol+2,yuv),4);
            tempL = bitshift(inblock(row,incol+3,yuv),-4);
            temp = tempH+tempL;
            imgblock(row,column+2,yuv) = temp;    
            %
            tempH = bitand(inblock(row,incol+3,yuv),3);
            tempH = bitshift(tempH,6);
            tempL = bitshift(inblock(row,incol+4,yuv),-2);
            temp = tempH + tempL;
            imgblock(row,column+3,yuv) = temp;  
            incol = incol+5;
        end
    end
end

 

取出解析后的一个BLOCK YUV数据,fliplr 用于将矩阵对折,这个是和李师兄对数据时,发现的其输出的数据格式问题。

tempy = imgblock(:,:,1);
tempu = imgblock(1:8,1:8,posu);
tempv = imgblock(1:8,1:8,posv);
tempy = fliplr(tempy);
tempu = fliplr(tempu);
tempv = fliplr(tempv);

 如: tempv值如下,

 

对折后:

存下每 16行中所有列的BLOCK数据

Y = [Y tempy];
U = [U tempu];
V = [V tempv];

对这16行的BLOCK数据整理,以保证与输出数据的格式对应。 Y0,Y1,Y2...

Y = uint8(Y)';
Y = reshape(Y,1,16*16*Vs/16);
U = uint8(U)';
U = reshape(U,1,16*16*Vs/16/4);
V = uint8(V)';
V = reshape(V,1,16*16*Vs/16/4);  

 存下所有行的数据

YY = [YY Y];
UU = [UU U];
VV = [VV V];

  

处理数据的Matlab完整代码

%
% 2016-01-18 hy
%   1.读取文本中的第一个BLOCK,数据为4:2:0的YUV数据
%   2.从文本中取出Y,U,V的数据,然后输出到 *.yuv文件,
% 用软件 “7yuv”打开,调整格式为 YVU420 planar YV12 可正常显示
%   3.运行程序时,注意修改输入、输出数据的文件名。
%   4.本程序读入的是一张完整的720p的图片数据,要用于1080P需要略作修改
%
%  这个420的转换显示脚本先修改图片尺寸Vs*Hs (720P或1080P),
% 然后直接运行,点击选择输入文件(不必拷贝到当前目录下),即可等待运行结果
clc;close all;clear 

%%
% rgb2ycbcr
posy = 1;posv = 2;posu = 3; %根据数据来定义的顺序

%%通过 GUI 选择 *.txt 输入文件
[FileName, PathName, FilterIndex] = uigetfile('*.txt');
filename = [PathName,FileName]  
fid_txtin = fopen(filename,'r');
%
%86400/24 = 3600
%%
%!!!!
%%请更改图像对应的尺寸Vs*Hs
FRAME_NUM = 1            %%帧数, txt文件中有几帧yuv数据
% Hs = 96; Vs = 128;       %%128*96
Hs = 720; Vs = 1280;    %%720p
% Hs = 1080;Vs = 1920;   %%1080p
Hs = FRAME_NUM*Hs
Vs = FRAME_NUM*Vs
YY = []; UU=[]; VV=[]; 
for rcount = 1:Hs/16            %45*16 = 720 如果是1080P的照片请修改45为 1080/16=67
    Y = []; U=[]; V=[];
    for colcount = 1:Vs/16      %80*16=1280 如果是1080P的照片请修改80为 1920/16=120
        inblock = zeros(16,20,3);
        inblock(:,:,posy) = fscanf(fid_txtin,'%02x',[20 16])';
        tempuv = fscanf(fid_txtin,'%02x',[20 8])';
        %inblock(1:8,:,posv) = fscanf(fid_txtin,'%2x',[8 20]);

        inblock(1:8,1:10,posv) = tempuv(1:8,1:10); 
        inblock(1:8,11:20,posv) = tempuv(1:8,1:10);
        inblock(9:16,:,posv) = inblock(1:8,:,posv);

        inblock(1:8,1:10,posu) = tempuv(1:8,11:20);
        inblock(1:8,11:20,posu) = inblock(1:8,1:10,posu); 
        inblock(9:16,:,posu) = inblock(1:8,:,posu);
        inblock = uint8(inblock);
        % Y = inblock(:,:,posy);
        % U = inblock(:,:,posu);
        % V = inblock(:,:,posv);
        %%
        imgblock = zeros(16,16,3);
        for yuv=1:3
            for row=1:16
                incol = 1;
                for column=1:4:16
                    %
                    imgblock(row,column+0,yuv) = inblock(row,incol+0,yuv); 
                    %
                    tempH = bitshift(inblock(row,incol+1,yuv),-2);
                    tempH = bitshift(tempH,4);
                    tempL = bitand(inblock(row,incol+1,yuv),3);
                    tempL = bitshift(tempL,2);
                    tempL = tempL + bitshift(inblock(row,incol+2,yuv),-6);
                    temp = tempH+tempL;
                    imgblock(row,column+1,yuv) = temp;
                    %
                    tempH = bitshift(inblock(row,incol+2,yuv),4);
                    tempL = bitshift(inblock(row,incol+3,yuv),-4);
                    temp = tempH+tempL;
                    imgblock(row,column+2,yuv) = temp;    
                    %
                    tempH = bitand(inblock(row,incol+3,yuv),3);
                    tempH = bitshift(tempH,6);
                    tempL = bitshift(inblock(row,incol+4,yuv),-2);
                    temp = tempH + tempL;
                    imgblock(row,column+3,yuv) = temp;  
                    incol = incol+5;
                end
            end
        end
        tempy = imgblock(:,:,1);
        tempu = imgblock(1:8,1:8,posu);
        tempv = imgblock(1:8,1:8,posv);
        tempy = fliplr(tempy);
        tempu = fliplr(tempu);
        tempv = fliplr(tempv);
        Y = [Y tempy];
        U = [U tempu];
        V = [V tempv];
        %tempy = uint8(imgblock(:,:,1))';
        %tempy = reshape(tempy,1,16*16);
        %tempu = uint8(imgblock(:,:,2))';
        %tempu = reshape(tempu,1,16*16);
        %tempv = uint8(imgblock(:,:,3))';
        %tempv = reshape(tempv,1,16*16);
    end
    Y = uint8(Y)';
    Y = reshape(Y,1,16*16*Vs/16);
    U = uint8(U)';
    U = reshape(U,1,16*16*Vs/16/4);
    V = uint8(V)';
    V = reshape(V,1,16*16*Vs/16/4);
    YY = [YY Y];
    UU = [UU U];
    VV = [VV V];
end
fclose(fid_txtin);

% % imgYUV = uint8(cat(3,Y,U,V));
% % imgRGB = ycbcr2rgb(imgYUV);
% % imshow(imgRGB(1:16,:));

%%
% 输出数据的文件名
% datestr(now) 获取时间函数
%
filename_out = ['yuvout_',datestr(now,30),'.yuv'] %
fid_txtout = fopen(filename_out,'wb');
    fwrite(fid_txtout,YY,'uint8');
    fwrite(fid_txtout,VV,'uint8');
    fwrite(fid_txtout,UU,'uint8');
fclose(fid_txtout);
filename_buff = 'yuvout_dispbuff.yuv'
cmd_str = ['copy ',filename_out,' ',filename_buff]
dos(cmd_str)
% yuvpath = [pwd,'\\',filename_buff]
cmd_str = ['7yuv.exe ',filename_buff]  %%添加7yuv 路径工具到用户环境变量
dos(cmd_str)

  

%
% 2016-01-18
%   1.读取文本中的第一个BLOCK,数据为4:2:0的YUV数据
%   2.从文本中取出Y,U,V的数据,然后输出到 *.yuv文件,
% 用软件 “7yuv”打开,调整显示格式为 YVU420 planar YV12 可正常显示
%   3.运行程序时,注意修改输入、输出数据的文件名。
%   4.本程序读入的是一张完整的720p的图片数据,要用于1080P需要略作修改
%
%
clc;close all;clear 

%%
% rgb2ycbcr
posy = 1;posv = 2;posu = 3; %根据数据来定义的顺序
%
% 输入数据的文件名
filename = 'huyong.txt';  
fid_txtin = fopen(filename,'r');
%
%86400/24 = 3600

Hs = 720; Vs = 1280; %%720p
% Hs = 1080;Vs = 1920; %%1080p
YY = []; UU=[]; VV=[]; 
for rcount = 1:Hs/16  %45*16 = 720 如果是1080P的照片请修改45为 1080/16=67
    Y = []; U=[]; V=[];
    for colcount = 1:Vs/16 %80*16=1280 如果是1080P的照片请修改80为 1920/16=120
        inblock = zeros(16,20,3);
        inblock(:,:,posy) = fscanf(fid_txtin,'%02x',[20 16])';
        tempuv = fscanf(fid_txtin,'%02x',[20 8])';
        %inblock(1:8,:,posv) = fscanf(fid_txtin,'%2x',[8 20]);

        inblock(1:8,1:10,posu) = tempuv(1:8,1:10); 
        inblock(1:8,11:20,posu) = tempuv(1:8,1:10);
        inblock(9:16,:,posu) = inblock(1:8,:,posu);

        inblock(1:8,1:10,posv) = tempuv(1:8,11:20);
        inblock(1:8,11:20,posv) = inblock(1:8,1:10,posv) ; 
        inblock(9:16,:,posv) = inblock(1:8,:,posv);
        inblock = uint8(inblock);
        % Y = inblock(:,:,posy);
        % U = inblock(:,:,posu);
        % V = inblock(:,:,posv);
        %%
        imgblock = zeros(16,16,3);
        for yuv=1:3
            for row=1:16
                incol = 1;
                for column=1:4:16
                    %
                    imgblock(row,column+0,yuv) = inblock(row,incol+0,yuv); 
                    %
                    tempH = bitshift(inblock(row,incol+1,yuv),-2);
                    tempH = bitshift(tempH,4);
                    tempL = bitand(inblock(row,incol+1,yuv),3);
                    tempL = bitshift(tempL,2);
                    tempL = tempL + bitshift(inblock(row,incol+2,yuv),-6);
                    temp = tempH+tempL;
                    imgblock(row,column+1,yuv) = temp;
                    %
                    tempH = bitshift(inblock(row,incol+2,yuv),4);
                    tempL = bitshift(inblock(row,incol+3,yuv),-4);
                    temp = tempH+tempL;
                    imgblock(row,column+2,yuv) = temp;    
                    %
                    tempH = bitand(inblock(row,incol+3,yuv),3);
                    tempH = bitshift(tempH,6);
                    tempL = bitshift(inblock(row,incol+4,yuv),-2);
                    temp = tempH + tempL;
                    imgblock(row,column+3,yuv) = temp;  
                    incol = incol+5;
                end
            end
        end
        tempy = imgblock(:,:,1);
        tempu = imgblock(1:8,1:8,2);
        tempv = imgblock(1:8,1:8,3);
        tempy = fliplr(tempy);
        tempu = fliplr(tempu);
        tempv = fliplr(tempv);
        Y = [Y tempy];
        U = [U tempu];
        V = [V tempv];
        %tempy = uint8(imgblock(:,:,1))';
        %tempy = reshape(tempy,1,16*16);
        %tempu = uint8(imgblock(:,:,2))';
        %tempu = reshape(tempu,1,16*16);
        %tempv = uint8(imgblock(:,:,3))';
        %tempv = reshape(tempv,1,16*16);
    end
    Y = uint8(Y)';
    Y = reshape(Y,1,16*16*Vs/16);
    U = uint8(U)';
    U = reshape(U,1,16*16*Vs/16/4);
    V = uint8(V)';
    V = reshape(V,1,16*16*Vs/16/4);
    YY = [YY Y];
    UU = [UU U];
    VV = [VV V];
end
fclose(fid_txtin);

% imgYUV = uint8(cat(3,Y,U,V));
% imgRGB = ycbcr2rgb(imgYUV);
% imshow(imgRGB(1:16,:));

%%
%输出数据的文件名
fid_txtout = fopen('huyong_out_24.yuv','wb');
    fwrite(fid_txtout,YY,'uint8');
    fwrite(fid_txtout,VV,'uint8');
    fwrite(fid_txtout,UU,'uint8');
fclose(fi
  •  7yuv的显示

 

图2 用7yuv打开输出的 *.yuv文件  

posted @ 2017-11-15 10:33  .Think  阅读(899)  评论(0编辑  收藏  举报