SDI音频加嵌技术详解
一、概述
SDI音频加嵌是将音频数据嵌入到SDI视频流的水平消隐期间的过程。这是广播和专业视频制作中的关键技术。
二、SDI音频加嵌系统架构
1. 系统框图
┌─────────────┐ ┌──────────────┐ ┌──────────────┐ ┌─────────────┐
│ 音频输入 │───▶│ 音频处理与 │───▶│ ANC数据包 │───▶│ SDI视频 │
│ 模块 │ │ 格式化 │ │ 生成器 │ │ 混合器 │
└─────────────┘ └──────────────┘ └──────────────┘ └─────────────┘
│ │ │
┌─────────────┐ | | ┌─────────────┐
│ 视频输入 │────────────────────────────────────────────┤ SDI输出 │
│ 模块 │ │ │
└─────────────┘ └─────────────┘
三、Verilog实现SDI音频加嵌
1. 顶层加嵌模块
module sdi_audio_embed (
input wire clk_74mhz, // 74.25/74.176 MHz SDI时钟
input wire clk_audio, // 音频时钟
input wire rst_n,
// 视频输入
input wire [9:0] video_data_in,
input wire video_data_valid,
input wire [1:0] video_standard, // 00-SD, 01-HD, 10-3G
// 音频输入
input wire [15:0] audio_ch1_data,
input wire [15:0] audio_ch2_data,
input wire [15:0] audio_ch3_data,
input wire [15:0] audio_ch4_data,
input wire audio_data_valid,
// 控制信号
input wire [3:0] audio_channel_enable,
input wire embed_enable,
// 输出
output reg [9:0] sdi_data_out,
output reg sdi_data_valid,
output reg [3:0] audio_embedded_status
);
// 内部信号
wire [9:0] anc_packet_data;
wire anc_packet_valid;
wire [9:0] video_data_delayed;
wire in_hblank;
wire [10:0] line_number;
wire [10:0] pixel_count;
// 视频时序检测
video_timing_detector u_timing_detector (
.clk(clk_74mhz),
.rst_n(rst_n),
.video_data(video_data_in),
.data_valid(video_data_valid),
.video_standard(video_standard),
.in_hblank(in_hblank),
.line_number(line_number),
.pixel_count(pixel_count),
.hblank_start(hblank_start),
.hblank_end(hblank_end)
);
// 音频数据处理
audio_data_processor u_audio_processor (
.clk_audio(clk_audio),
.clk_video(clk_74mhz),
.rst_n(rst_n),
.audio_ch1_data(audio_ch1_data),
.audio_ch2_data(audio_ch2_data),
.audio_ch3_data(audio_ch3_data),
.audio_ch4_data(audio_ch4_data),
.audio_data_valid(audio_data_valid),
.audio_channel_enable(audio_channel_enable),
.processed_audio_data(processed_audio_data),
.processed_audio_valid(processed_audio_valid),
.audio_group(audio_group)
);
// ANC数据包生成
anc_packet_generator u_anc_generator (
.clk(clk_74mhz),
.rst_n(rst_n),
.audio_data(processed_audio_data),
.audio_valid(processed_audio_valid),
.audio_group(audio_group),
.line_number(line_number),
.video_standard(video_standard),
.anc_packet_data(anc_packet_data),
.anc_packet_valid(anc_packet_valid),
.packet_ready(packet_ready)
);
// SDI数据混合器
sdi_data_mixer u_data_mixer (
.clk(clk_74mhz),
.rst_n(rst_n),
.video_data_in(video_data_in),
.video_data_valid(video_data_valid),
.anc_packet_data(anc_packet_data),
.anc_packet_valid(anc_packet_valid),
.in_hblank(in_hblank),
.embed_enable(embed_enable),
.sdi_data_out(sdi_data_out),
.sdi_data_valid(sdi_data_valid)
);
// 状态监控
always @(posedge clk_74mhz or negedge rst_n) begin
if (!rst_n) begin
audio_embedded_status <= 4'b0000;
end else begin
audio_embedded_status <= audio_channel_enable & {4{embed_enable}};
end
end
endmodule
2. 视频时序检测模块
module video_timing_detector (
input wire clk,
input wire rst_n,
input wire [9:0] video_data,
input wire data_valid,
input wire [1:0] video_standard,
output reg in_hblank,
output reg [10:0] line_number,
output reg [10:0] pixel_count,
output reg hblank_start,
output reg hblank_end
);
// 视频标准参数
localparam [10:0]
HD_ACTIVE_PIXELS = 11'd1920,
HD_HBLANK_START = 11'd1920,
HD_HBLANK_END = 11'd2200,
HD_TOTAL_LINES = 11'd1125;
reg [10:0] vcounter;
reg [9:0] prev_video_data;
wire sav_detected, eav_detected;
// SAV/EAV检测
assign sav_detected = (prev_video_data == 10'h3FF) && (video_data == 10'h000) &&
data_valid;
assign eav_detected = (prev_video_data == 10'h3FF) && (video_data == 10'h000) &&
data_valid;
// 像素计数器
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
pixel_count <= 11'd0;
vcounter <= 11'd0;
line_number <= 11'd0;
in_hblank <= 1'b0;
prev_video_data <= 10'd0;
end else if (data_valid) begin
prev_video_data <= video_data;
if (sav_detected) begin
pixel_count <= 11'd0;
in_hblank <= 1'b0;
hblank_start <= 1'b0;
hblank_end <= 1'b1;
end else if (eav_detected) begin
pixel_count <= 11'd0;
in_hblank <= 1'b1;
hblank_start <= 1'b1;
hblank_end <= 1'b0;
vcounter <= vcounter + 11'd1;
if (vcounter == HD_TOTAL_LINES - 11'd1) begin
vcounter <= 11'd0;
end
line_number <= vcounter;
end else begin
pixel_count <= pixel_count + 11'd1;
hblank_start <= 1'b0;
hblank_end <= 1'b0;
// 水平消隐期检测
case (video_standard)
2'b01: begin // HD
if (pixel_count == HD_HBLANK_START) begin
in_hblank <= 1'b1;
end else if (pixel_count == HD_HBLANK_END) begin
in_hblank <= 1'b0;
end
end
// 其他视频标准...
endcase
end
end
end
endmodule
3. 音频数据处理模块
module audio_data_processor (
input wire clk_audio,
input wire clk_video,
input wire rst_n,
// 音频输入
input wire [15:0] audio_ch1_data,
input wire [15:0] audio_ch2_data,
input wire [15:0] audio_ch3_data,
input wire [15:0] audio_ch4_data,
input wire audio_data_valid,
input wire [3:0] audio_channel_enable,
// 处理后的输出
output reg [191:0] processed_audio_data, // 4通道×24-bit×2样本
output reg processed_audio_valid,
output reg [1:0] audio_group
);
// 音频FIFO
reg [67:0] audio_fifo_in; // 4×16-bit + 4-bit有效
wire [67:0] audio_fifo_out;
reg audio_wr_en, audio_rd_en;
wire audio_fifo_full, audio_fifo_empty;
// 音频样本缓冲区
reg [23:0] audio_samples[0:7]; // 4通道×2样本
reg [2:0] sample_count;
reg [7:0] audio_control_bits;
// 16-bit转24-bit扩展
function [23:0] extend_16_to_24;
input [15:0] audio_16bit;
begin
extend_16_to_24 = {audio_16bit[15], audio_16bit[15:0], 7'b0};
end
endfunction
// 音频FIFO写逻辑
always @(posedge clk_audio or negedge rst_n) begin
if (!rst_n) begin
audio_wr_en <= 1'b0;
audio_fifo_in <= 68'd0;
end else if (audio_data_valid) begin
audio_fifo_in[15:0] <= extend_16_to_24(audio_ch1_data);
audio_fifo_in[39:16] <= extend_16_to_24(audio_ch2_data);
audio_fifo_in[63:40] <= extend_16_to_24(audio_ch3_data);
audio_fifo_in[87:64] <= extend_16_to_24(audio_ch4_data);
audio_fifo_in[91:88] <= audio_channel_enable;
audio_wr_en <= 1'b1;
end else begin
audio_wr_en <= 1'b0;
end
end
// 异步FIFO实例
async_fifo #(
.DATA_WIDTH(92),
.FIFO_DEPTH(512)
) u_audio_fifo (
.wr_clk(clk_audio),
.rd_clk(clk_video),
.rst_n(rst_n),
.wr_en(audio_wr_en),
.rd_en(audio_rd_en),
.data_in(audio_fifo_in),
.data_out(audio_fifo_out),
.full(audio_fifo_full),
.empty(audio_fifo_empty)
);
// 音频数据处理状态机
reg [2:0] audio_state;
localparam [2:0]
AUDIO_IDLE = 3'd0,
AUDIO_READ = 3'd1,
AUDIO_PROCESS = 3'd2,
AUDIO_OUTPUT = 3'd3;
always @(posedge clk_video or negedge rst_n) begin
if (!rst_n) begin
audio_state <= AUDIO_IDLE;
processed_audio_valid <= 1'b0;
sample_count <= 3'd0;
audio_rd_en <= 1'b0;
end else begin
case (audio_state)
AUDIO_IDLE: begin
processed_audio_valid <= 1'b0;
if (!audio_fifo_empty) begin
audio_rd_en <= 1'b1;
audio_state <= AUDIO_READ;
end
end
AUDIO_READ: begin
audio_rd_en <= 1'b0;
// 存储音频样本
audio_samples[0] <= audio_fifo_out[23:0]; // CH1
audio_samples[1] <= audio_fifo_out[47:24]; // CH2
audio_samples[2] <= audio_fifo_out[71:48]; // CH3
audio_samples[3] <= audio_fifo_out[95:72]; // CH4
audio_state <= AUDIO_PROCESS;
end
AUDIO_PROCESS: begin
// 生成控制位 (V, U, C, P)
audio_control_bits <= 8'b11110000; // V=1, U=1, C=1, P=0
// 打包音频数据
processed_audio_data[23:0] <= audio_samples[0]; // 样本1
processed_audio_data[47:24] <= audio_samples[1]; // 样本2
processed_audio_data[71:48] <= audio_samples[2]; // 样本3
processed_audio_data[95:72] <= audio_samples[3]; // 样本4
processed_audio_data[119:96] <= audio_samples[4]; // 样本5 (如果有)
processed_audio_data[143:120] <= audio_samples[5]; // 样本6
processed_audio_data[167:144] <= audio_samples[6]; // 样本7
processed_audio_data[191:168] <= audio_samples[7]; // 样本8
audio_state <= AUDIO_OUTPUT;
end
AUDIO_OUTPUT: begin
processed_audio_valid <= 1'b1;
audio_state <= AUDIO_IDLE;
audio_group <= audio_group + 2'd1; // 轮换音频组
end
endcase
end
end
endmodule
4. ANC数据包生成器
module anc_packet_generator (
input wire clk,
input wire rst_n,
input wire [191:0] audio_data,
input wire audio_valid,
input wire [1:0] audio_group,
input wire [10:0] line_number,
input wire [1:0] video_standard,
output reg [9:0] anc_packet_data,
output reg anc_packet_valid,
output reg packet_ready
);
// ANC包状态机
reg [3:0] packet_state;
reg [7:0] data_counter;
reg [9:0] crc_register;
reg [191:0] audio_data_latched;
// ANC包定义
localparam [7:0]
AUDIO_DID = 8'h5F, // 音频数据包DID
AUDIO_SDID = 8'h60; // 音频数据包SDID
localparam [9:0]
ANC_PREFIX = 10'h000,
ANC_PREFIX_INV = 10'h3FF;
// CRC计算函数
function [9:0] compute_crc;
input [9:0] data;
input [9:0] current_crc;
reg [9:0] new_crc;
begin
new_crc = current_crc;
for (int i = 0; i < 10; i = i + 1) begin
if (data[i] ^ new_crc[9]) begin
new_crc = {new_crc[8:0], 1'b0} ^ 10'h23;
end else begin
new_crc = {new_crc[8:0], 1'b0};
end
end
compute_crc = new_crc;
end
endfunction
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
packet_state <= 4'd0;
anc_packet_valid <= 1'b0;
packet_ready <= 1'b1;
crc_register <= 10'd0;
data_counter <= 8'd0;
end else begin
anc_packet_valid <= 1'b0;
case (packet_state)
4'd0: begin // 等待音频数据
if (audio_valid && packet_ready) begin
audio_data_latched <= audio_data;
packet_ready <= 1'b0;
packet_state <= 4'd1;
data_counter <= 8'd0;
crc_register <= 10'd0;
end
end
4'd1: begin // ANC前缀
anc_packet_data <= ANC_PREFIX;
anc_packet_valid <= 1'b1;
packet_state <= 4'd2;
end
4'd2: begin // ANC前缀取反
anc_packet_data <= ANC_PREFIX_INV;
anc_packet_valid <= 1'b1;
packet_state <= 4'd3;
end
4'd3: begin // 数据ID (DID)
anc_packet_data <= {2'b00, AUDIO_DID};
crc_register <= compute_crc({2'b00, AUDIO_DID}, crc_register);
anc_packet_valid <= 1'b1;
packet_state <= 4'd4;
end
4'd4: begin // 数据块号 (DBN)
anc_packet_data <= {2'b00, 8'h00}; // 数据块号
crc_register <= compute_crc({2'b00, 8'h00}, crc_register);
anc_packet_valid <= 1'b1;
packet_state <= 4'd5;
end
4'd5: begin // 数据计数 (DC)
anc_packet_data <= {2'b00, 8'd23}; // 23个数据字
crc_register <= compute_crc({2'b00, 8'd23}, crc_register);
anc_packet_valid <= 1'b1;
packet_state <= 4'd6;
end
// 音频数据字段 (24个字)
4'd6: begin
if (data_counter < 8'd24) begin
anc_packet_data <= audio_data_latched[data_counter*8 +: 8];
crc_register <= compute_crc(audio_data_latched[data_counter*8 +: 8], crc_register);
anc_packet_valid <= 1'b1;
data_counter <= data_counter + 8'd1;
end else begin
packet_state <= 4'd7;
end
end
4'd7: begin // CRC校验和
anc_packet_data <= crc_register;
anc_packet_valid <= 1'b1;
packet_state <= 4'd0;
packet_ready <= 1'b1;
end
endcase
end
end
endmodule
5. SDI数据混合器
module sdi_data_mixer (
input wire clk,
input wire rst_n,
input wire [9:0] video_data_in,
input wire video_data_valid,
input wire [9:0] anc_packet_data,
input wire anc_packet_valid,
input wire in_hblank,
input wire embed_enable,
output reg [9:0] sdi_data_out,
output reg sdi_data_valid
);
reg [9:0] video_pipeline[0:2];
reg packet_insert_active;
reg [4:0] packet_insert_counter;
// 视频数据流水线
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
video_pipeline[0] <= 10'd0;
video_pipeline[1] <= 10'd0;
video_pipeline[2] <= 10'd0;
packet_insert_active <= 1'b0;
packet_insert_counter <= 5'd0;
sdi_data_valid <= 1'b0;
end else if (video_data_valid) begin
// 视频数据流水线
video_pipeline[0] <= video_data_in;
video_pipeline[1] <= video_pipeline[0];
video_pipeline[2] <= video_pipeline[1];
sdi_data_valid <= 1'b1;
if (embed_enable && in_hblank) begin
// 在消隐期插入ANC包
if (anc_packet_valid && !packet_insert_active) begin
packet_insert_active <= 1'b1;
packet_insert_counter <= 5'd0;
sdi_data_out <= anc_packet_data;
end else if (packet_insert_active) begin
sdi_data_out <= anc_packet_data;
packet_insert_counter <= packet_insert_counter + 5'd1;
// 假设ANC包长度为32个10-bit字
if (packet_insert_counter == 5'd31) begin
packet_insert_active <= 1'b0;
end
end else begin
sdi_data_out <= video_pipeline[2];
end
end else begin
// 非消隐期或禁用加嵌,直接输出视频
sdi_data_out <= video_pipeline[2];
packet_insert_active <= 1'b0;
end
end else begin
sdi_data_valid <= 1'b0;
end
end
endmodule
6. 配置和控制寄存器
module sdi_audio_embed_registers (
input wire clk,
input wire rst_n,
input wire [7:0] reg_addr,
input wire [31:0] reg_data_in,
input wire reg_write,
output reg [31:0] reg_data_out,
// 控制信号输出
output reg [3:0] audio_channel_enable,
output reg embed_enable,
output reg [1:0] audio_sample_rate,
output reg [7:0] audio_delay
);
// 寄存器定义
localparam [7:0]
REG_CONTROL = 8'h00,
REG_CH_ENABLE = 8'h04,
REG_SAMPLE_RATE = 8'h08,
REG_AUDIO_DELAY = 8'h0C;
// 控制寄存器
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
embed_enable <= 1'b0;
audio_channel_enable <= 4'b0000;
audio_sample_rate <= 2'b00; // 48kHz
audio_delay <= 8'd0;
reg_data_out <= 32'd0;
end else if (reg_write) begin
case (reg_addr)
REG_CONTROL: begin
embed_enable <= reg_data_in[0];
end
REG_CH_ENABLE: begin
audio_channel_enable <= reg_data_in[3:0];
end
REG_SAMPLE_RATE: begin
audio_sample_rate <= reg_data_in[1:0];
end
REG_AUDIO_DELAY: begin
audio_delay <= reg_data_in[7:0];
end
endcase
end
// 寄存器读取
case (reg_addr)
REG_CONTROL: reg_data_out <= {31'd0, embed_enable};
REG_CH_ENABLE: reg_data_out <= {28'd0, audio_channel_enable};
REG_SAMPLE_RATE: reg_data_out <= {30'd0, audio_sample_rate};
REG_AUDIO_DELAY: reg_data_out <= {24'd0, audio_delay};
default: reg_data_out <= 32'd0;
endcase
end
endmodule
四、关键特性
1. 支持的音频格式
-
4通道/8通道音频嵌入
-
16-bit/24-bit音频精度
-
48kHz采样率支持
-
可配置的音频延迟
2. 视频标准支持
-
HD-SDI (1.5 Gbps)
-
3G-SDI (2.97 Gbps)
-
6G-SDI/12G-SDI (可选)
3. 性能特点
-
低延迟音频处理
-
精确的时序控制
-
可配置的音频通道映射
-
完整的错误检测和处理
这种SDI音频加嵌实现广泛应用于广播设备、视频切换台、音频嵌入器和专业视频制作系统中。
1156

被折叠的 条评论
为什么被折叠?



