TMDS视频编解码算法

因为使用的是DDR进行传输,即双倍频率采样,故时钟只用是并行数据数据的5倍,而不是10倍。

TMDS算法流程:

视频编码TMDS算法流程实现:

`timescale 1 ps / 1ps
//DVI编码通常用于视频传输,将并行数据转换为适合串行传输的格式。
module dvi_encoder (
  input            clkin,    // pixel clock input
  input            rstin,    // async. reset input (active high)
  input      [7:0] din,      // data inputs: expect registered
  input            c0,       // c0 input
  input            c1,       // c1 input;c0 和 c1 用于指示视频的**水平同步(HSYNC)和垂直同步(VSYNC)**信号。
  input            de,       // de input
  output reg [9:0] dout      // data outputs
);


// Counting number of 1s and 0s for each incoming pixel
// component. Pipe line the result.
// Register Data Input so it matches the pipe lined adder
// output

reg [3:0] n1d; //number of 1s in din
reg [7:0] din_q;

//计算像素数据中"1"的个数
always @ (posedge clkin) begin
  n1d <=#1 din[0] + din[1] + din[2] + din[3] + din[4] + din[5] + din[6] + din[7];

  din_q <=#1 din;
end

///
// Stage 1: 8 bit -> 9 bit
// Refer to DVI 1.0 Specification, page 29, Figure 3-5
///
wire decision1;

//decision1 为真,表示需要反转数据。
assign decision1 = (n1d > 4'h4) | ((n1d == 4'h4) & (din_q[0] == 1'b0));

wire [8:0] q_m;
assign q_m[0] = din_q[0];
assign q_m[1] = (decision1) ? (q_m[0] ^~ din_q[1]) : (q_m[0] ^ din_q[1]);
assign q_m[2] = (decision1) ? (q_m[1] ^~ din_q[2]) : (q_m[1] ^ din_q[2]);
assign q_m[3] = (decision1) ? (q_m[2] ^~ din_q[3]) : (q_m[2] ^ din_q[3]);
assign q_m[4] = (decision1) ? (q_m[3] ^~ din_q[4]) : (q_m[3] ^ din_q[4]);
assign q_m[5] = (decision1) ? (q_m[4] ^~ din_q[5]) : (q_m[4] ^ din_q[5]);
assign q_m[6] = (decision1) ? (q_m[5] ^~ din_q[6]) : (q_m[5] ^ din_q[6]);
assign q_m[7] = (decision1) ? (q_m[6] ^~ din_q[7]) : (q_m[6] ^ din_q[7]);
assign q_m[8] = (decision1) ? 1'b0 : 1'b1;   //第9位 q_m[8] 用于指示数据是否被反转,0是数据被反转

/
// Stage 2: 9 bit -> 10 bit
// Refer to DVI 1.0 Specification, page 29, Figure 3-5
/
//计算1和0的个数
reg [3:0] n1q_m, n0q_m; // number of 1s and 0s for q_m
always @ (posedge clkin) begin
  n1q_m  <=#1 q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7];
  n0q_m  <=#1 4'h8 - (q_m[0] + q_m[1] + q_m[2] + q_m[3] + q_m[4] + q_m[5] + q_m[6] + q_m[7]);
end

//控制令牌(Control Tokens),用于在视频的消隐期(Blanking Period)传输同步信息。
//这些控制令牌是10位的固定编码值,用于表示视频的**水平同步(HSYNC)和垂直同步(VSYNC)**信号
parameter CTRLTOKEN0 = 10'b1101010100;
parameter CTRLTOKEN1 = 10'b0010101011;
parameter CTRLTOKEN2 = 10'b0101010100;
parameter CTRLTOKEN3 = 10'b1010101011;

/*
差异计数器(Disparity Counter):
    在TMDS编码中,差异计数器用于跟踪当前信号的直流偏差(DC Disparity)。
    直流偏差是指信号中"1"和"0"的数量之差。
    通过调整编码方式(如反转数据),差异计数器可以帮助实现直流平衡,减少信号的直流分量。
    最高位是符号位(MSB is the sign bit):
差异计数器的最高位(MSB)表示偏差的方向:
    如果最高位为 0,表示偏差为负(即"0"的数量多于"1")。
    如果最高位为 1,表示偏差为正(即"1"的数量多于"0")。
    其余位表示偏差的大小。
*/
reg [4:0] cnt; //disparity counter, MSB is the sign bit
wire decision2, decision3;

assign decision2 = (cnt == 5'h0) | (n1q_m == n0q_m);  //1和0的数量相等
/
// [(cnt > 0) and (N1q_m > N0q_m)] or [(cnt < 0) and (N0q_m > N1q_m)]
/
assign decision3 = (~cnt[4] & (n1q_m > n0q_m)) | (cnt[4] & (n0q_m > n1q_m));
                  //即cnt[4]=0                    cnt[4]=1


// pipe line alignment

reg       de_q, de_reg;
reg       c0_q, c1_q;
reg       c0_reg, c1_reg;
reg [8:0] q_m_reg;

always @ (posedge clkin) begin
  de_q    <=#1 de;
  de_reg  <=#1 de_q;
  
  c0_q    <=#1 c0;
  c0_reg  <=#1 c0_q;
  
  c1_q    <=#1 c1;
  c1_reg  <=#1 c1_q;

  q_m_reg <=#1 q_m;
end

///
// 10-bit out
// disparity counter
///
always @ (posedge clkin or posedge rstin) begin
  if(rstin) begin
    dout <= 10'h0;
    cnt <= 5'h0;
  end else begin
    if (de_reg) begin
      if(decision2) begin
        dout[9]   <=#1 ~q_m_reg[8]; 
        dout[8]   <=#1 q_m_reg[8]; 
        dout[7:0] <=#1 (q_m_reg[8]) ? q_m_reg[7:0] : ~q_m_reg[7:0];

        cnt <=#1 (~q_m_reg[8]) ? (cnt + n0q_m - n1q_m) : (cnt + n1q_m - n0q_m);  //第一个cnt代表当前cnt值,后面两个cnt代表上一次执行时的值
      end else begin
        if(decision3) begin
          dout[9]   <=#1 1'b1;
          dout[8]   <=#1 q_m_reg[8];
          dout[7:0] <=#1 ~q_m_reg[7:0];

          cnt <=#1 cnt + {q_m_reg[8], 1'b0} + (n0q_m - n1q_m);
        end else begin
          dout[9]   <=#1 1'b0;
          dout[8]   <=#1 q_m_reg[8];
          dout[7:0] <=#1 q_m_reg[7:0];

          cnt <=#1 cnt - {~q_m_reg[8], 1'b0} + (n1q_m - n0q_m);
        end
      end
    end else begin
      case ({c1_reg, c0_reg})  //进入消隐期
        2'b00:   dout <=#1 CTRLTOKEN0;
        2'b01:   dout <=#1 CTRLTOKEN1;
        2'b10:   dout <=#1 CTRLTOKEN2;
        default: dout <=#1 CTRLTOKEN3;
      endcase

      cnt <=#1 5'h0;
    end
  end
end
  
endmodule 

解码:使用xilinx原语serdes进行并转串,serdes分为master和slave模式,其中的master使用的是8bit数据,另外带两个bit的扩展位放在了slave中。

参考:正点原子

相关推荐
FPGA狂飙32 分钟前
快速傅里叶变换(FFT):从数学公式到5G信号,揭开数字世界的“频率密码”
fpga开发·信号处理·verilog·fpga·vivado
科技小E1 小时前
低延迟,高互动:EasyRTC的全场景实时通信解决方案
网络协议·小程序·音视频·webrtc·p2p·智能硬件·视频监控
IT技术分享社区5 小时前
电脑软件:推荐一款非常强大的视频音频转换剪辑工具FFmpeg Batch AV Converter V3.12
ffmpeg·音视频·batch·剪辑工具
猿大师播放器5 小时前
猿大师播放器:交通水利、公安消防Web端Vue网页播放20路RTSP H.265 1080P监控视频流
vue.js·chrome·音视频·web·h.265·rtsp
Java搬砖组长10 小时前
抖音视频如何下载保存去水印
音视频
余~~1853816280012 小时前
短视频矩阵系统源码开发/矩阵系统OEM搭建
线性代数·矩阵·音视频
HHUCESTA12 小时前
FPGA 常用的片上缓存方式
缓存·fpga开发
szxinmai主板定制专家12 小时前
基于全志T536+FPGA+AI的智能服务机器人解决方案
大数据·运维·人工智能·fpga开发·机器人·边缘计算
宇宙无敌花心大萝卜18 小时前
一种简单的快速批量视频抽取固定间隔帧截图的操作方法
ffmpeg·音视频·视频