zoukankan      html  css  js  c++  java
  • 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)
    );



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

  • 相关阅读:
    leetcode 2 Add Two Numbers
    log4j2 springboot 特点与使用方法
    数据类型和运算符
    初识Java
    《梦断代码》阅读笔记02
    《梦断代码》阅读笔记01
    场景调研
    【站立会议】第九天
    【站立会议】第八天
    【站立会议】第七天
  • 原文地址:https://www.cnblogs.com/tony1224/p/2399607.html
Copyright © 2011-2022 走看看