【FPGA图像处理】BT1120格式

声明:本博客并非严格的、完整的技术型文章,只是将本人所接触到的内容作学习记录,如有错误欢迎大家在评论区指正。如果这篇博客对你有帮助的话,请给我点一个免费的赞或关注,谢谢。

引言

BT1120协议的全称是"ITU-R BT.1120"。"ITU"是"国际电信联盟International Telecommunication Union"的简称。BT1120技术标准由国际电信联盟(ITU-T)负责制定和维护。最新的标准是BT.1120-9 (12/2017),用于1080P视屏的传输,其属于BT族协议的一部分。下面的链接可以找到相关的技术文档(有中文版本)。
BT1120 / 2017
BT族协议
我们常见的除了BT1120,还有BT656。其协议格式基本一样,只是图像的分辨率不同。本博客只提供BT1120的部分相关知识,其余内容可以在BT族协议链接中找到。注意:BT1120的协议手册中的一些内容本博客也没有讲到,具体可以查看原版协议。

BT1120规范

首先要明确什么是逐行扫描和隔行扫描。拿1080p和1080i举个例子。
1080i的特点

  1. 1080i是高清电视的一种分辨率格式,其中的“i”代表隔行扫描(interlaced),意味着图像数据是分两次扫描完成的,每次扫描一半的图像线。
  2. 1080i的分辨率为1920x1080,但实际显示的图像分辨率为1920x540,因为图像数据是分两次扫描完成的。
  3. 1080i的图像质量相对较低,因为图像数据是通过隔行扫描的方式显示的,这可能导致图像边缘出现锯齿状的闪烁。

1080p的特点

  1. 1080p是高清电视的另一种分辨率格式,其中的“p”代表逐行扫描(progressive),意味着图像数据是一次性完整扫描完成的。
  2. 1080p的分辨率为1920x1080,并且实际显示的图像分辨率也是1920x1080,因为图像数据是一次性完整扫描完成的。
  3. 1080p的图像质量相对较高,因为图像数据是通过逐行扫描的方式显示的,这可以提供更加平滑和清晰的图像效果。

下图是BT1120中隔行与逐行的图像格式示意图。其中SAV和EAV称之为定时基准码。SAV代表每个视频数据块的起始,EAV代表每个视频数据位的结束。有效视频所在的行其余数据为行消隐,有效视频不在的行所有内容为场消隐。
逐行与隔行在BT1120的具体格式
下面图是分别对隔行与逐行的行号数做定义。
在这里插入图片描述
定时基准码分为4个字,每个字拥有10个或8个bit,其具体的bit分配可以通过下面的图推断出来。其中前三个字是固定的,第四个字的FVH分别由隔行/逐行扫描、场/帧消隐期、SAV/EAV决定,而保护比特P0、P1、P2、P3是通过FVH对应的查找表得到。
在这里插入图片描述
当然我这里也给出我们最常用的1080p的SAV与EAV的第4个字的数据。其他前面的三个字分别为8‘hFF(或10‘h3FF)、00、00。
在这里插入图片描述

FPGA中的BT1120

在FPGA中BT1120格式常用于SDI高速接口、FPGA与外设芯片(如Hi3519)等传递图像数据。

管脚绑定

最常用的管脚是1bit的随路时钟与16bit的数据,其中16bit数据是YUV422的格式,8bit为Y代表亮度分量,8bit为U/V代表颜色分量。
此外BT1120可以通过SDI高速接口发送,或通过1bit差分时钟加4bit差分数据的方式与Hi3519等芯片交互。具体的硬件接口需要与实际工程相结合。

代码示例

下面提供一份代码示例,输入是DVP图像数据格式,输出是BT1120数据。

module dvp_to_bt1120(
    //--- bt1120 interface ---//
    o_bt1120_data,
    //--- dvp interface ---//
    i_vs, i_hs, i_de, i_data,
    //--- system interface ---//
    i_clk, i_rst
);


    //--------------------------------------------------------------------------------
    // input and output ports
    //--------------------------------------------------------------------------------
    
    //--- system interface ---//
    input                       i_clk;
    input                       i_rst;

    //--- dvp interface ---//
    input						i_vs;
    input						i_hs;
    input						i_de;
    input		[19:0]          i_data; // YUV422 {Y[9:0], UV[9:0]}

    //--- bt1120 interface ---//
    output		[19:0]          o_bt1120_data;
    
    //--------------------------------------------------------------------------------
    // register and wire declaration for output ports
    //--------------------------------------------------------------------------------
    
    reg		    [19:0]          o_bt1120_data;
    
    //--------------------------------------------------------------------------------
    // register and wire declaration for internal signals
    //--------------------------------------------------------------------------------
    
    //--- delay signals
    reg         [3:0]           vs_in_dly;
    reg                         hs_in_dly;
    reg         [4:0]           de_in_dly;
    reg         [19:0]          data_in_dly [4:0];

    //--- gen sav/eav valid
    wire                        hs_in_pos;
    wire                        hs_in_neg;
    reg                         sav_de;
    reg                         eav_de;
    reg         [2:0]           sav_cnt;
    reg         [2:0]           eav_cnt;
    
    //********************************************************************************
    // functional block start
    //********************************************************************************
    
    //--- delay signals
    always @(posedge i_clk or posedge i_rst) begin
       if (i_rst) begin
            vs_in_dly   <=  4'd0;
       end else begin
            vs_in_dly   <=  {vs_in_dly[2:0], i_vs};
       end 
    end
    always @(posedge i_clk or posedge i_rst) begin
        if (i_rst) begin
            hs_in_dly   <=  1'b0;
        end else begin
            hs_in_dly   <=  i_hs;
        end
    end
    always @(posedge i_clk or posedge i_rst) begin
        if (i_rst) begin
            de_in_dly   <=  5'd0;
        end else begin
            de_in_dly   <=  {de_in_dly[3:0], i_de};
        end
    end
    always @(posedge i_clk or posedge i_rst) begin
        if (i_rst) begin
            data_in_dly[0]  <=  20'd0;  
            data_in_dly[1]  <=  20'd0;  
            data_in_dly[2]  <=  20'd0;  
            data_in_dly[3]  <=  20'd0;  
            data_in_dly[4]  <=  20'd0;  
        end else begin
            data_in_dly[0]  <=  i_data;  
            data_in_dly[1]  <=  data_in_dly[0];  
            data_in_dly[2]  <=  data_in_dly[1];  
            data_in_dly[3]  <=  data_in_dly[2];  
            data_in_dly[4]  <=  data_in_dly[3];  
        end
    end

    //--- gen sav/eav valid
    assign hs_in_pos = i_hs & (~hs_in_dly);
    assign hs_in_neg = (~i_hs) & hs_in_dly;

    always @(posedge i_clk or posedge i_rst) begin
        if (i_rst) begin
            sav_de  <=  1'b0;
        end else if(sav_cnt == 3'd3) begin
            sav_de  <=  1'b0;
        end else if(hs_in_pos) begin
            sav_de  <=  1'b1;
        end else begin
            sav_de  <=  sav_de;
        end
    end
    always @(posedge i_clk or posedge i_rst) begin
        if (i_rst) begin
            sav_cnt <=  3'd0;
        end else if(sav_cnt == 3'd3) begin
            sav_cnt <=  3'd0;
        end else if(sav_de) begin
            sav_cnt <=  sav_cnt + 3'd1;
        end else begin
            sav_cnt <=  sav_cnt;
        end
    end

    always @(posedge i_clk or posedge i_rst) begin
        if (i_rst) begin
            eav_de  <=  1'b0;
        end else if(eav_cnt == 3'd7) begin
            eav_de  <=  1'b0;
        end else if(hs_in_neg) begin
            eav_de  <=  1'b1;
        end else begin
            eav_de  <=  eav_de;
        end
    end
    always @(posedge i_clk or posedge i_rst) begin
        if (i_rst) begin
            eav_cnt <=  3'd0;
        end else if(eav_cnt == 3'd7) begin
            eav_cnt <=  3'd0;
        end else if(eav_de) begin
            eav_cnt <=  eav_cnt + 3'd1;
        end else begin
            eav_cnt <=  eav_cnt;
        end
    end


    //--- gen outputs
    always @(posedge i_clk or posedge i_rst) begin
        if (i_rst) begin
            o_bt1120_data   <=  20'd0;
        end else if(sav_de) begin
            case (sav_cnt)
                3'd0:   o_bt1120_data   <=  {10'h3ff, 10'h3ff}; 
                3'd1:   o_bt1120_data   <=  {10'h000, 10'h000}; 
                3'd2:   o_bt1120_data   <=  {10'h000, 10'h000};
                3'd3:   begin
                    if (vs_in_dly[3] == 1'b1) begin
                        o_bt1120_data <=  {8'h80,2'b00,8'h80,2'b00};
                    end else begin
                        o_bt1120_data <=  {8'hab,2'b00,8'hab,2'b00};
                    end
                end 
                default:  o_bt1120_data <=  {8'h80,2'b00,8'h10,2'b00};
            endcase
        end else if(eav_de && (eav_cnt > 3'd3)) begin
            case (eav_cnt)
                3'd4:   o_bt1120_data   <=  {10'h3ff, 10'h3ff}; 
                3'd5:   o_bt1120_data   <=  {10'h000, 10'h000}; 
                3'd6:   o_bt1120_data   <=  {10'h000, 10'h000}; 
                3'd7:   begin
                    if (vs_in_dly[3] == 1'b1) begin
                        o_bt1120_data <=  {8'h9d,2'b00,8'h9d,2'b00};
                    end else begin
                        o_bt1120_data <=  {8'hb6,2'b00,8'hb6,2'b00};
                    end
                end
                default: o_bt1120_data <=  {8'h80,2'b00,8'h10,2'b00};
            endcase
        end else if(de_in_dly[4] == 1'b1) begin
            o_bt1120_data   <=  data_in_dly[4];
        end else begin
            o_bt1120_data   <=  {8'h80,2'b00,8'h10,2'b00};
        end
    end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yifantan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值