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)
    );



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

  • 相关阅读:
    UOJ #455 [UER #8]雪灾与外卖 (贪心、模拟费用流)
    Codeforces 482E ELCA (LCT)
    Codeforces 798D Mike and distribution (构造)
    AtCoder AGC017C Snuke and Spells
    HDU 6089 Rikka with Terrorist (线段树)
    HDU 6136 Death Podracing (堆)
    AtCoder AGC032D Rotation Sort (DP)
    jenkins+python+kubectl实现批量更新k8s镜像
    Linux 下载最新kubectl版本的命令:
    jenkins X 和k8s CI/CD
  • 原文地址:https://www.cnblogs.com/tony1224/p/2399607.html
Copyright © 2011-2022 走看看