JPEG解码:状态控制模块

状态控制模块主要是对JPEG图像组成的各个部分进行识别,并读取其中的有效信息。主要有以下几个模块:

(1)图像开始(SOI),标识为FFD8,标志一副jpeg图像的开始。

(2)图像识别信息(APP),标识为FFE0,可以读取图像的各种信息,比如XY像素单位,密度等。

(3)量化表(DQT),标识为FFDB,一个AC量化表,一个DC量化表,每个量化表64个数据。

(4)图像信息段(SOF),标识为FFCO,可以读取图片精度,图片高度,图片宽度等信息。

(5)huffman表(DHT),标识为FFC4,读取4个huffman表数据,分别是亮度DC表,亮度AC表,色度DC表,色度AC表。

(6)图像数据段(SOS),标识为FFDA,这个段中存放的是压缩数据。

(7)图像结束(EOI),标识为FFD9,标志一副图片的结束。

 

数据的排解顺序为:SOI,APP,DQT,DQT,SOF,DHT,DHT,DHT,DHT,SOS,EOI.

其实在DHT段,读取的数据不仅仅是huffman表,还读取了两个表,一个用于存放相同长度的最小编码,另个是最小编码的首地址,对需要解压的数据先判断他的码长,然后再减去相同码长的最小编码可以得到与最小编码的地址差值,然后再加上最小编码的地址就可以得到解码的地址,然后按地址到DHT表中找到对应的数据即可,后面就是huffman解码的事情,本文不讨论。

 代码:

FSM
`timescale 1ns / 1ps

module fsm(
clk,
rst_n,
data_en,
data,

start,
data_end,

width,
height,
blockwidth,

dqt_en,
dqt_table,
dqt_addr,
dqt_data,

dht_en,
dht_table,
dht_addr,
dht_data,

//
huffman_en,
huffman_table,
huffman_count,
huffman_data,
huffman_startaddr,

//
FF00,
image_en,

//
use_byte,
use_word
);

input clk; //输入时钟信号
input rst_n;//复位信号,低电平有效
input start;//开始解码信号
input data_end;
input data_en;//输入允许信号
input [31:0] data;//输入数据

output [15:0] width;//图片的宽度
output [15:0] height;//图片的高度
output [11:0] blockwidth;//MCU的个数

output dqt_en;//量化表使能信号
output dqt_table;//量化表类型
output [5:0] dqt_addr;//当前值对应的量化表的地址
output [7:0] dqt_data;//量化表的数据

output dht_en;//huffman表使能
output [1:0] dht_table;//huffman表类型
output [7:0] dht_addr;//当前值对应的huffman表的地址
output [7:0] dht_data;//huffman表的数据

//
output huffman_en;//huffman查找表的使能
output [1:0] huffman_table;//查找表的类型
output [3:0] huffman_count;//数据的宽度,0-16
output [15:0] huffman_data;//不同宽度对应的最小的数据
output [7:0] huffman_startaddr;//不同宽度对应的首地址

//
output FF00;//允许去除冗余信息,在SOS段
output image_en;//huffman解码开始信号

//
output use_byte;//传输8位数据
output use_word;//传输16位数据

//--------------------------------------------------------------------------
// FSM
//--------------------------------------------------------------------------
// state Machine Parameter
parameter IDLE = 5'd0;
parameter GetMarker = 5'd1;
parameter ImageData = 5'd2;
// APP Segment
parameter APP_length = 5'd3;
parameter APP_read = 5'd4;
// DQT Segment
parameter DQT_length = 5'd5;
parameter DQT_table = 5'd6;
parameter DQT_read = 5'd7;
// SOF Segment
parameter SOF_length = 5'd8;
parameter SOF_read0 = 5'd9;
parameter SOF_ready = 5'd10;
parameter SOF_readx = 5'd11;
parameter SOF_readcomp = 5'd12;
parameter SOF_makeblock0 = 5'd13;
parameter SOF_makeblock1 = 5'd14;
// DHT Segment
parameter DHT_length = 5'd15;
parameter DHT_table = 5'd16;
parameter DHT_makehm0 = 5'd17;
parameter DHT_makehm1 = 5'd18;
parameter DHT_makehm2 = 5'd19;
parameter DHT_readtable = 5'd20;
// SOS Segment
parameter SOS_length = 5'd21;
parameter SOS_read0 = 5'd22;
parameter SOS_read1 = 5'd23;
parameter SOS_read2 = 5'd24;
parameter SOS_read3 = 5'd25;
parameter SOS_read4 = 5'd26;


reg [4:0] state;
reg [15:0] reg_data;

reg [15:0] width_r;
reg [15:0] height_r;
reg dqt_table_r;
reg [1:0] dht_table_r;

reg [15:0] HmShift;
reg [15:0] HmData;
reg [7:0] HmMax;
reg [7:0] HmCount;
reg HmEnable;

reg [15:0] blockwidth_r;
reg [15:0] blockheight_r;

reg FF00 ;
reg image_r;

always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
state <= IDLE;
reg_data <= 16'd0;
width_r <= 16'd0;
height_r <= 16'd0;
dqt_table_r <= 1'b0;
dht_table_r <= 2'd0;
HmShift <= 16'd0;
HmData <= 16'd0;
HmMax <= 8'd0;
HmCount <= 8'd0;
HmEnable <= 1'b0;
blockwidth_r <= 16'd0;
blockheight_r <= 16'd0;
FF00 <= 1'b0;
image_r <= 1'b0;
end
else begin
case(state)
IDLE:
begin
if(start == 1'b1)
state <= GetMarker;
end

GetMarker:
begin
if(data_en == 1'b1)
case(data[31:16])
16'hFFD8: // SOI Segment
state <= GetMarker;

16'hFFE0: // APP0 Segment
state <= APP_length;

16'hFFDB: // DQT Segment
state <= DQT_length;

16'hFFC0: // SOF0 Segment
state <= SOF_length;

16'hFFC4: // DHT Segment
state <= DHT_length;

16'hFFDA: // SOS Segment
state <= SOS_length;

default:
state <= GetMarker;

endcase
end
APP_length:
begin
if(data_en == 1'b1)
begin
reg_data <= data[31:16] -16'd2;
state <= APP_read;
end
end
APP_read:
begin
if(data_en == 1'b1)
begin
if(reg_data == 16'd1)
state <= GetMarker;
else
reg_data <= reg_data -16'd1;
end
end
DQT_length:
begin
if(data_en == 1'b1)
begin
state <= DQT_table;
reg_data <= data[31:16] -16'd2;
end
end
DQT_table:
begin
if(data_en == 1'b1)
begin
state <= DQT_read;
dqt_table_r <= data[24];
reg_data <= 16'd0;
end
end
DQT_read:
begin
if(data_en == 1'b1)
begin
reg_data <= reg_data +16'd1;
if(reg_data ==63)
state <= GetMarker;
end
end

// SOF0 Segment
SOF_length:
begin
if(data_en == 1'b1)
begin
state <= SOF_read0;
reg_data <= data[31:16];
end
end
SOF_read0:
begin
if(data_en == 1'b1)
state <= SOF_ready;
end
SOF_ready:
begin
if(data_en == 1'b1)
begin
state <= SOF_readx;
height_r <= data[31:16];
blockheight_r <= data[31:16];
end
end
SOF_readx:
begin
if(data_en == 1'b1)
begin
state <= SOF_readcomp;
width_r <= data[31:16];
blockwidth_r <= data[31:16];
reg_data <= 16'd0;
end
end
SOF_readcomp:
begin
if(data_en == 1'b1)
begin
if(reg_data == 9)
state <= SOF_makeblock0;
else
reg_data <= reg_data +16'd1;
end
end
SOF_makeblock0:
begin
state <= SOF_makeblock1;
blockwidth_r <= blockwidth_r +16'd15;
blockheight_r <= blockheight_r +16'd15;
end
SOF_makeblock1:
begin
state <= GetMarker;
blockwidth_r <= blockwidth_r >> 4;
blockheight_r <= blockheight_r >> 4;
end

DHT_length:
begin
if(data_en == 1'b1)
begin
state <= DHT_table;
reg_data <= data[31:16];
end
end
DHT_table:
begin
if(data_en == 1'b1)
begin
state <=DHT_makehm0;
case(data[31:24])
8'h00: dht_table_r <= 2'b00;
8'h10: dht_table_r <= 2'b01;
8'h01: dht_table_r <= 2'b10;
8'h11: dht_table_r <= 2'b11;
endcase
end
HmShift <= 16'h8000;
HmData <= 16'h0000;
HmMax <= 8'h00;
reg_data <= 16'd0;
end
DHT_makehm0:
begin
if(data_en == 1'b1)
begin
state <= DHT_makehm1;
HmCount <= data[31:24];
end
HmEnable <= 1'b0;
end
DHT_makehm1:
begin
state <= DHT_makehm2;
HmMax <= HmMax + HmCount;
end
DHT_makehm2:
begin
if(HmCount != 0)
begin
HmData <= HmData + HmShift;
HmCount <= HmCount -8'd1;
end
else
begin
if(reg_data == 15)
begin
state <= DHT_readtable;
HmCount <= 8'h00;
end else begin
HmEnable <= 1'b1;
state <= DHT_makehm0;
reg_data <= reg_data +16'd1;
end
HmShift <= HmShift >> 1;
end
end
DHT_readtable:
begin
HmEnable <= 1'b0;
if(data_en == 1'b1)
begin
HmCount <= HmCount +8'd1;
if(HmMax == HmCount +1)
begin
state <= GetMarker;
end
end
end

SOS_length:
begin
if(data_en == 1'b1)
begin
state <= SOS_read0;
reg_data <= data[31:16];
FF00 <= 1'b1;
end
end
SOS_read0:
begin
if(data_en == 1'b1)
begin
state <= SOS_read1;
reg_data <= {8'h00,data[31:24]};
end
end
SOS_read1:
begin
if(data_en == 1'b1)
begin
if(reg_data == 1)
state <= SOS_read2;
else
reg_data <= reg_data -16'd1;
end
end
SOS_read2:
begin
if(data_en == 1'b1)
state <= SOS_read3;
end
SOS_read3:
begin
if(data_en == 1'b1)
state <= SOS_read4;
end
SOS_read4:
begin
if(data_en == 1'b1)
begin
state <= ImageData;
image_r <= 1'b1;
end
end


ImageData:
begin
if ( data_end== 1'b1 )
begin
state <= IDLE;
image_r <= 1'b0;
end
end
endcase
end
end
//-------------------------------------------------------------------

assign use_byte = (data_en == 1'b1) & ((state == APP_read) |
(state == DQT_read) |
(state == DQT_table) |
(state == DHT_table) |
(state == DHT_makehm0) |
(state == DHT_readtable) |
(state == SOS_read0) |
(state == SOS_read2) |
(state == SOS_read3) |
(state == SOS_read4) |
(state == SOF_read0) |
(state == SOF_readcomp)
);
assign use_word = (data_en == 1'b1) & ((state == GetMarker) |
(state == APP_length) |
(state == DQT_length) |
(state == DHT_length) |
(state == SOS_length) |
(state == SOS_read1) |
(state == SOF_length) |
(state == SOF_readx) |
(state == SOF_ready)
);

assign width = width_r;
assign height = height_r;
assign blockwidth = blockwidth_r[11:0];

assign dqt_en = (state == DQT_read);
assign dqt_table = dqt_table_r;
assign dqt_addr = reg_data[5:0];
assign dqt_data = data[31:24];

assign dht_en = (state == DHT_readtable);
assign dht_table = dht_table_r;
assign dht_addr = HmCount;
assign dht_data = data[31:24];

assign huffman_en = HmEnable;
assign huffman_table = dht_table_r;
assign huffman_count = reg_data[3:0];
assign huffman_data = HmData;
assign huffman_startaddr = HmMax;

assign image_en=image_r ;
endmodule

 

 

GetMarker
            GetMarker:
begin
if(data_en == 1'b1)
case(data[31:16])
16'hFFD8: // SOI Segment
state <= GetMarker;

16'hFFE0: // APP0 Segment
state <= APP_length;

16'hFFDB: // DQT Segment
state <= DQT_length;

16'hFFC0: // SOF0 Segment
state <= SOF_length;

16'hFFC4: // DHT Segment
state <= DHT_length;

16'hFFDA: // SOS Segment
state <= SOS_length;

default:
state <= GetMarker;

endcase
end

 

是对各种不同的头标识的判断 ,然后转入相应的状态执行不同的操作。

 

 

DQT
  DQT_length: 
begin
if(data_en == 1'b1)
begin
state <= DQT_table;
reg_data <= data[31:16] -16'd2;
end
end
DQT_table:
begin
if(data_en == 1'b1)
begin
state <= DQT_read;
dqt_table_r <= data[24];
reg_data <= 16'd0;
end
end
DQT_read:
begin
if(data_en == 1'b1)
begin
reg_data <= reg_data +16'd1;
if(reg_data ==63)
state <= GetMarker;
end
end

 


在量化表读取中,最先读到的是量化表的长度,占2个字节,接下来读到的是量化表的编号,区分DC和AC量化表,占一个字节,再接下来读到的就是64个量化表的数据了,每次读取一个字节,共64字节。

SOF
            // SOF0 Segment
SOF_length:
begin
if(data_en == 1'b1)
begin
state <= SOF_read0;
reg_data <= data[31:16];
end
end
SOF_read0:
begin
if(data_en == 1'b1)
state <= SOF_ready;
end
SOF_ready:
begin
if(data_en == 1'b1)
begin
state <= SOF_readx;
height_r <= data[31:16];
blockheight_r <= data[31:16];
end
end
SOF_readx:
begin
if(data_en == 1'b1)
begin
state <= SOF_readcomp;
width_r <= data[31:16];
blockwidth_r <= data[31:16];
reg_data <= 16'd0;
end
end
SOF_readcomp:
begin
if(data_en == 1'b1)
begin
if(reg_data == 9)
state <= SOF_makeblock0;
else
reg_data <= reg_data +16'd1;
end
end
SOF_makeblock0:
begin
state <= SOF_makeblock1;
blockwidth_r <= blockwidth_r +16'd15;
blockheight_r <= blockheight_r +16'd15;
end
SOF_makeblock1:
begin
state <= GetMarker;
blockwidth_r <= blockwidth_r >> 4;
blockheight_r <= blockheight_r >> 4;
end

 

在sof段读取图片的信息:

长度:2个字节

样本位数:1个字节

图片高度:2个字节

图片宽度:2个字节

component的个数,1个字节(若为YCBCR此值为3)

接下来为3组数据,每组数据3个字节,第一个字节代表component,第二个字节代表采样系数,第三个字节代表量化表的编号

DHT
            
DHT_length:
begin
if(data_en == 1'b1)
begin
state <= DHT_table;
reg_data <= data[31:16];
end
end
DHT_table:
begin
if(data_en == 1'b1)
begin
state <=DHT_makehm0;
case(data[31:24])
8'h00: dht_table_r <= 2'b00;
8'h10: dht_table_r <= 2'b01;
8'h01: dht_table_r <= 2'b10;
8'h11: dht_table_r <= 2'b11;
endcase
end
HmShift <= 16'h8000;
HmData <= 16'h0000;
HmMax <= 8'h00;
reg_data <= 16'd0;
end
DHT_makehm0:
begin
if(data_en == 1'b1)
begin
state <= DHT_makehm1;
HmCount <= data[31:24];
end
HmEnable <= 1'b0;
end
DHT_makehm1:
begin
state <= DHT_makehm2;
HmMax <= HmMax + HmCount;
end
DHT_makehm2:
begin
if(HmCount != 0)
begin
HmData <= HmData + HmShift;
HmCount <= HmCount -8'd1;
end
else
begin
if(reg_data == 15)
begin
state <= DHT_readtable;
HmCount <= 8'h00;
end else begin
HmEnable <= 1'b1;
state <= DHT_makehm0;
reg_data <= reg_data +16'd1;
end
HmShift <= HmShift >> 1;
end
end
DHT_readtable:
begin
HmEnable <= 1'b0;
if(data_en == 1'b1)
begin
HmCount <= HmCount +8'd1;
if(HmMax == HmCount +1)
begin
state <= GetMarker;
end
end
end

 

DHT段中:

长度,2个字节。

huffman表的类型,1个字节。

接下来的16字节中每个字节代表对应长度的代码个数,16字节。

再往下就是huffman表的数据,大小有上面的16字节数据总和决定。

 

SOS
            SOS_length:
begin
if(data_en == 1'b1)
begin
state <= SOS_read0;
reg_data <= data[31:16];
FF00 <= 1'b1;
end
end
SOS_read0:
begin
if(data_en == 1'b1)
begin
state <= SOS_read1;
reg_data <= {8'h00,data[31:24]};
end
end
SOS_read1:
begin
if(data_en == 1'b1)
begin
if(reg_data == 1)
state <= SOS_read2;
else
reg_data <= reg_data -16'd1;
end
end
SOS_read2:
begin
if(data_en == 1'b1)
state <= SOS_read3;
end
SOS_read3:
begin
if(data_en == 1'b1)
state <= SOS_read4;
end
SOS_read4:
begin
if(data_en == 1'b1)
begin
state <= ImageData;
image_r <= 1'b1;
end
end


ImageData:
begin
if ( data_end== 1'b1 )
begin
state <= IDLE;
image_r <= 1'b0;
end
end
endcase
end
end



SOS段:

长度,2个字节。

component个数,1个字节。

接下来三组数据,每组2个字节,第一个字节为component ID,第二个字节为使用的huffman表。

3个字节。

接下来就是要解码的数据,启动解码。

use
assign use_byte = (data_en == 1'b1) &   ((state == APP_read) |
(state == DQT_read) |
(state == DQT_table) |
(state == DHT_table) |
(state == DHT_makehm0) |
(state == DHT_readtable) |
(state == SOS_read0) |
(state == SOS_read2) |
(state == SOS_read3) |
(state == SOS_read4) |
(state == SOF_read0) |
(state == SOF_readcomp)
);
assign use_word = (data_en == 1'b1) & ((state == GetMarker) |
(state == APP_length) |
(state == DQT_length) |
(state == DHT_length) |
(state == SOS_length) |
(state == SOS_read1) |
(state == SOF_length) |
(state == SOF_readx) |
(state == SOF_ready)
);



为每个状态下消耗的字节数和字数。

posted on 2012-03-16 03:51  @火枪手@  阅读(1861)  评论(1编辑  收藏  举报

导航