9.2.3. vidtv: 虚拟数字电视驱动程序

作者:Daniel W. S. Almeida <dwlsalmeida@gmail.com>,2020 年 6 月。

9.2.3.1. 背景

Vidtv 是一个虚拟 DVB 驱动程序,旨在通过充当模板,为驱动程序编写者提供参考。它还验证现有的媒体 DVB API,从而帮助用户空间应用程序编写者。

目前,它由以下部分组成:

  • 一个虚假的调谐器驱动程序,如果所选频率与特定传输系统的有效频率表相差太远,它将报告不良的信号质量。

  • 一个虚假的解调器驱动程序,它会不断轮询调谐器返回的虚假信号质量,模拟一个可以根据 CNR 水平丢失/重新获得信号锁定的设备。

  • 一个虚假的桥接驱动程序,该模块负责 modprobing 虚假的调谐器和解调模块,并实现解复用逻辑。此模块在初始化时接收参数,这些参数将决定模拟的行为方式。

  • 负责编码有效 MPEG 传输流的代码,然后将其传递给桥接驱动程序。这个虚假的流包含一些硬编码内容。目前,我们有一个单一的、仅音频的频道,其中包含一个 MPEG 基本流,该基本流又包含一个 SMPTE 302m 编码的正弦波。请注意,选择此特定编码器是因为它是以 MPEG 传输流编码 PCM 音频数据的最简单方法。

9.2.3.2. 构建 vidtv

vidtv 是一个测试驱动程序,因此在编译内核时默认情况下 启用。

为了启用 vidtv 的编译

  • 启用 DVB_TEST_DRIVERS,然后

  • 启用 DVB_VIDTV

当编译为模块时,预期会生成以下 .ko 文件

  • dvb_vidtv_tuner.ko

  • dvb_vidtv_demod.ko

  • dvb_vidtv_bridge.ko

9.2.3.3. 运行 vidtv

当编译为模块时,运行

modprobe vidtv

就是这样!桥接驱动程序将在其自身初始化过程中初始化调谐器和解调器驱动程序。

默认情况下,它将接受以下频率

  • DVB-T/T2/C 的 474 MHz;

  • DVB-S/S2 的 11,362 GHz。

对于卫星系统,该驱动程序模拟一个通用的扩展 LNBf,其频率在 Ku 波段,范围从 10.7 GHz 到 12.75 GHz。

您可以选择性地为 vidtv 定义一些命令行参数。

9.2.3.4. vidtv 的命令行参数

下面是可以提供给 vidtv 的所有参数的列表

drop_tslock_prob_on_low_snr

如果信号质量差,则丢失 TS 锁定的概率。虚假解调器驱动程序可以使用此概率来最终在信号质量不佳时返回 0 状态。

recover_tslock_prob_on_good_snr

当信号改善时恢复 TS 锁定的概率。虚假解调器驱动程序可以使用此概率来最终在信号质量改善时/如果信号质量改善时返回 0x1f 状态。

mock_power_up_delay_msec

模拟上电延迟。默认值:0。

mock_tune_delay_msec

模拟调谐延迟。默认值:0。

vidtv_valid_dvb_t_freqs

要模拟的有效 DVB-T 频率,单位为 Hz。

vidtv_valid_dvb_c_freqs

要模拟的有效 DVB-C 频率,单位为 Hz。

vidtv_valid_dvb_s_freqs

要在 Ku 波段模拟的有效 DVB-S/S2 频率,单位为 kHz。

max_frequency_shift_hz,

调谐频道时允许的最大 HZ 偏移量。

si_period_msec

发送 SI 数据包的频率。默认值:40ms。

pcr_period_msec

发送 PCR 数据包的频率。默认值:40ms。

mux_rate_kbytes_sec

如果需要,尝试通过插入 TS 空数据包来保持此比特率。默认值:4096。

pcr_pid,

所有频道的 PCR PID。默认值:0x200。

mux_buf_sz_pkts,

复用缓冲区的大小,以 188 字节的倍数表示。

9.2.3.5. vidtv 内部结构

内核模块按以下方式拆分

vidtv_tuner.[ch]

实现一个虚假的调谐器 DVB 驱动程序。

vidtv_demod.[ch]

实现一个虚假的解调器 DVB 驱动程序。

vidtv_bridge.[ch]

实现一个桥接驱动程序。

MPEG 相关代码按以下方式拆分

vidtv_ts.[ch]

用于处理 MPEG TS 数据包的代码,例如 TS 标头、适配字段、PCR 数据包和 NULL 数据包。

vidtv_psi.[ch]

这是 PSI 生成器。PSI 数据包包含有关 MPEG 传输流的常规信息。需要 PSI 生成器,以便用户空间应用程序可以检索有关传输流的信息,并最终调谐到(虚拟)频道。

由于生成器是在单独的文件中实现的,因此可以在媒体子系统的其他地方重用它。

目前,vidtv 支持使用 5 个 PSI 表:PAT、PMT、SDT、NIT 和 EIT。

PAT 和 PMT 的规范可以在 ISO 13818-1: Systems 中找到,而 SDT、NIT、EIT 的规范可以在 ETSI EN 300 468: Specification for Service Information (SI) in DVB systems 中找到。

严格来说这不是必需的,但在调试 PSI 表时使用真实的 TS 文件会有所帮助。Vidtv 目前尝试复制在此文件中找到的 PSI 结构:TS1Globo.ts

可视化流结构的好方法是使用 DVBInspector

vidtv_pes.[ch]

实现 PES 逻辑,将编码器数据转换为 MPEG TS 数据包。然后,可以将这些数据包馈送到 TS 复用器,并最终馈送到用户空间。

vidtv_encoder.h

vidtv 编码器的接口。可以通过在此文件中实现调用来将新编码器添加到此驱动程序中。

vidtv_s302m.[ch]

实现 S302M 编码器,以便可以将 PCM 音频数据插入生成的 MPEG 传输流中。相关的规范可在线获取,名称为 SMPTE 302M-2007: Television - Mapping of AES3 Data into MPEG-2 Transport Stream

生成的 MPEG 基本流在附加了 S302M 注册描述符的私有流中传递。

这应能够将音频信号传递到用户空间,以便可以通过媒体软件对其进行解码和播放。ffmpeg 中相应的解码器位于“libavcodec/s302m.c”中,并且是实验性的。

vidtv_channel.[ch]

实现一个“频道”抽象。

当 vidtv 启动时,它将创建一些硬编码的频道

  1. 它们的服务将被连接起来以填充 SDT。

  2. 它们的节目将被连接起来以填充 PAT

  3. 它们的事件将被连接起来以填充 EIT

  4. 对于 PAT 中的每个节目,将创建一个 PMT 部分

  5. 频道的 PMT 部分将分配其流。

  6. 每个流都将在循环中轮询其对应的编码器,以生成 TS 数据包。这些数据包可以由复用器交织,然后传递到桥接器。

vidtv_mux.[ch]

实现一个 MPEG TS 复用器,它松散地基于“libavcodec/mpegtsenc.c”中的 ffmpeg 实现

复用器运行一个循环,该循环负责

  1. 记录自上次迭代以来经过的时间量。

  2. 轮询编码器以获取 ‘elapsed_time’ 值得的数据。

  3. 如果需要,插入 PSI 和/或 PCR 数据包。

  4. 如果需要,用 NULL 数据包填充结果流,以维持选择的比特率。

  5. 将生成的 TS 数据包传递给桥接驱动程序,以便将其传递给解复用器。

9.2.3.6. 使用 v4l-utils 测试 vidtv

使用 v4l-utils 中的工具是测试和检查 vidtv 输出的好方法。它托管在这里:v4l-utils 文档

从其网页

The v4l-utils are a series of packages for handling media devices.

It is hosted at http://git.linuxtv.org/v4l-utils.git, and packaged
on most distributions.

It provides a series of libraries and utilities to be used to
control several aspect of the media boards.

首先安装 v4l-utils,然后加载 vidtv 模块

modprobe dvb_vidtv_bridge

如果驱动程序正常,它应该加载并且其探测代码将运行。这将拉入调谐器和解调驱动程序。

9.2.3.6.1. 使用 dvb-fe-tool

检查解调器是否成功加载的第一步是运行

$ dvb-fe-tool
Device Dummy demod for DVB-T/T2/C/S/S2 (/dev/dvb/adapter0/frontend0) capabilities:
    CAN_FEC_1_2
    CAN_FEC_2_3
    CAN_FEC_3_4
    CAN_FEC_4_5
    CAN_FEC_5_6
    CAN_FEC_6_7
    CAN_FEC_7_8
    CAN_FEC_8_9
    CAN_FEC_AUTO
    CAN_GUARD_INTERVAL_AUTO
    CAN_HIERARCHY_AUTO
    CAN_INVERSION_AUTO
    CAN_QAM_16
    CAN_QAM_32
    CAN_QAM_64
    CAN_QAM_128
    CAN_QAM_256
    CAN_QAM_AUTO
    CAN_QPSK
    CAN_TRANSMISSION_MODE_AUTO
DVB API Version 5.11, Current v5 delivery system: DVBC/ANNEX_A
Supported delivery systems:
    DVBT
    DVBT2
    [DVBC/ANNEX_A]
    DVBS
    DVBS2
Frequency range for the current standard:
From:            51.0 MHz
To:              2.15 GHz
Step:            62.5 kHz
Tolerance:       29.5 MHz
Symbol rate ranges for the current standard:
From:            1.00 MBauds
To:              45.0 MBauds

这应该返回当前在解调器结构中设置的内容,即

static const struct dvb_frontend_ops vidtv_demod_ops = {
        .delsys = {
                SYS_DVBT,
                SYS_DVBT2,
                SYS_DVBC_ANNEX_A,
                SYS_DVBS,
                SYS_DVBS2,
        },

        .info = {
                .name                   = "Dummy demod for DVB-T/T2/C/S/S2",
                .frequency_min_hz       = 51 * MHz,
                .frequency_max_hz       = 2150 * MHz,
                .frequency_stepsize_hz  = 62500,
                .frequency_tolerance_hz = 29500 * kHz,
                .symbol_rate_min        = 1000000,
                .symbol_rate_max        = 45000000,

                .caps = FE_CAN_FEC_1_2 |
                        FE_CAN_FEC_2_3 |
                        FE_CAN_FEC_3_4 |
                        FE_CAN_FEC_4_5 |
                        FE_CAN_FEC_5_6 |
                        FE_CAN_FEC_6_7 |
                        FE_CAN_FEC_7_8 |
                        FE_CAN_FEC_8_9 |
                        FE_CAN_QAM_16 |
                        FE_CAN_QAM_64 |
                        FE_CAN_QAM_32 |
                        FE_CAN_QAM_128 |
                        FE_CAN_QAM_256 |
                        FE_CAN_QAM_AUTO |
                        FE_CAN_QPSK |
                        FE_CAN_FEC_AUTO |
                        FE_CAN_INVERSION_AUTO |
                        FE_CAN_TRANSMISSION_MODE_AUTO |
                        FE_CAN_GUARD_INTERVAL_AUTO |
                        FE_CAN_HIERARCHY_AUTO,
        }

        ....

有关 dvb-fe-tools 的更多信息,请在此处查看其在线文档:dvb-fe-tool 文档

9.2.3.6.2. 使用 dvb-scan

为了调谐到一个频道并读取 PSI 表,我们可以使用 dvb-scan。

为此,应提供一个名为“扫描文件”的配置文件,这是一个示例

[Channel]
FREQUENCY = 474000000
MODULATION = QAM/AUTO
SYMBOL_RATE = 6940000
INNER_FEC = AUTO
DELIVERY_SYSTEM = DVBC/ANNEX_A

注意

参数取决于您正在测试的视频标准。

注意

Vidtv 是一个伪驱动程序,并且不会验证扫描文件中的太多信息。对于 DVB-T/DVB-T2,仅指定“FREQUENCY”和“DELIVERY_SYSTEM”应该足够了。但是,对于 DVB-S/DVB-C,您还应该提供“SYMBOL_RATE”。

您可以在此处在线浏览扫描表:dvb-scan-tables

假设此频道名为“channel.conf”,则可以运行

$ dvbv5-scan channel.conf
dvbv5-scan ~/vidtv.conf
ERROR    command BANDWIDTH_HZ (5) not found during retrieve
Cannot calc frequency shift. Either bandwidth/symbol-rate is unavailable (yet).
Scanning frequency #1 330000000
    (0x00) Signal= -68.00dBm
Scanning frequency #2 474000000
Lock   (0x1f) Signal= -34.45dBm C/N= 33.74dB UCB= 0
Service Beethoven, provider LinuxTV.org: digital television

有关 dvb-scan 的更多信息,请在此处查看其在线文档:dvb-scan 文档

9.2.3.6.3. 使用 dvb-zap

dvbv5-zap 是一个命令行工具,可用于将 MPEG-TS 记录到磁盘。典型的用法是调谐到一个频道并将其置于记录模式。下面的示例(摘自文档)说明了这一点[1]

$ dvbv5-zap -c dvb_channel.conf "beethoven" -o music.ts -P -t 10
using demux 'dvb0.demux0'
reading channels from file 'dvb_channel.conf'
tuning to 474000000 Hz
pass all PID's to TS
dvb_set_pesfilter 8192
dvb_dev_set_bufsize: buffer set to 6160384
Lock   (0x1f) Quality= Good Signal= -34.66dBm C/N= 33.41dB UCB= 0 postBER= 0 preBER= 1.05x10^-3 PER= 0
Lock   (0x1f) Quality= Good Signal= -34.57dBm C/N= 33.46dB UCB= 0 postBER= 0 preBER= 1.05x10^-3 PER= 0
Record to file 'music.ts' started
received 24587768 bytes (2401 Kbytes/sec)
Lock   (0x1f) Quality= Good Signal= -34.42dBm C/N= 33.89dB UCB= 0 postBER= 0 preBER= 2.44x10^-3 PER= 0

可以通过使用一些识别 MPEG-TS 格式的播放器(例如 mplayervlc)播放流的内容来观看频道。

通过播放流的内容,可以直观地检查 vidtv 的工作原理,例如,使用以下命令播放记录的 TS 文件

$ mplayer music.ts

或者,在某个终端上运行此命令

$ dvbv5-zap -c dvb_channel.conf "beethoven" -P -r &

并且,在第二个终端上,使用以下命令从 DVR 接口播放内容

$ mplayer /dev/dvb/adapter0/dvr0

有关 dvb-zap 的更多信息,请在此处查看其在线文档:dvb-zap 文档。另请参阅:zap

9.2.3.7. vidtv 中仍可改进的内容

9.2.3.7.1. 添加 debugfs 集成

虽然前端驱动程序通过 .read_status 调用提供 DVBv5 统计信息,但一个不错的补充是通过 debugfs 向用户空间提供其他统计信息,debugfs 是一个易于使用的、基于 RAM 的文件系统,专门为调试目的而设计。

此逻辑将在单独的文件中实现,以免污染前端驱动程序。这些统计信息是特定于驱动程序的,并且在测试期间可能很有用。

Siano 驱动程序是使用 debugfs 向用户空间传递特定于驱动程序的统计信息的一个示例,可以将其用作参考。

为了方便起见,应通过 Kconfig 选项进一步启用和禁用此功能。

9.2.3.7.2. 添加测试视频的方法

目前,vidtv 只能编码 PCM 音频。如果能够实现 MPEG-2 视频编码的精简版本,以便我们也可以测试视频,那就太好了。首先要研究的是ISO 13818-2:信息技术 — 移动图像和相关音频信息的通用编码 — 第 2 部分:视频,它涵盖了 MPEG 传输流中压缩视频的编码。

这可能会选择使用 Video4Linux2 测试模式生成器 v4l2-tpg,它位于

drivers/media/common/v4l2-tpg/

9.2.3.7.3. 添加白噪声模拟

vidtv 调谐器已经具有用于识别所选频率是否与有效频率表相距太远的代码。目前,这意味着解调器最终可能会失去对信号的锁定,因为调谐器会报告信号质量不佳。

一个不错的补充是在信号质量不佳时通过以下方式模拟一些噪声

  • 随机丢弃一些 TS 数据包。如果更新了连续性计数器,但没有将数据包传递给解复用器,则这将触发连续性错误。

  • 相应地更新错误统计信息(例如 BER 等)。

  • 在编码数据中模拟一些噪声。

9.2.3.8. vidtv 中使用的函数和结构

struct vidtv_dvb

Vidtv 桥接状态

定义:

struct vidtv_dvb {
    struct platform_device *pdev;
    struct dvb_frontend *fe[NUM_FE];
    struct dvb_adapter adapter;
    struct dvb_demux demux;
    struct dmxdev dmx_dev;
    struct dmx_frontend dmx_fe[NUM_FE];
    struct i2c_adapter i2c_adapter;
    struct i2c_client *i2c_client_demod[NUM_FE];
    struct i2c_client *i2c_client_tuner[NUM_FE];
    u32 nfeeds;
    struct mutex feed_lock;
    bool streaming;
    struct vidtv_mux *mux;
#ifdef CONFIG_MEDIA_CONTROLLER_DVB;
    struct media_device mdev;
#endif ;
};

成员

pdev

平台设备。在探测桥接时获取。

fe

前端。在探测解调器模块时获取。

adapter

表示 DTV 适配器。请参阅“dvb_register_adapter”。

demux

dvb_dmx_swfilter_packets() 调用使用的解复用器。

dmx_dev

表示解复用器设备。

dmx_fe

与解复用器关联的前端。

i2c_adapter

与桥接驱动程序关联的 i2c_adapter。

i2c_client_demod

与解调器模块关联的 i2c_clients。

i2c_client_tuner

与调谐器模块关联的 i2c_clients。

nfeeds

活动的馈送数量。

feed_lock

保护对启动/停止流逻辑/数据的访问。

streaming

我们现在是否正在流式传输。

mux

负责将 MPEG TS 数据包传递到桥接的抽象。

mdev

用于媒体控制器支持的 media_device 结构。

struct vidtv_channel

“频道”抽象

定义:

struct vidtv_channel {
    char *name;
    u16 transport_stream_id;
    struct vidtv_psi_table_sdt_service *service;
    u16 program_num;
    struct vidtv_psi_table_pat_program *program;
    struct vidtv_psi_table_pmt_stream *streams;
    struct vidtv_encoder *encoders;
    struct vidtv_psi_table_eit_event *events;
    struct vidtv_channel *next;
};

成员

name

频道名称

transport_stream_id

用于识别 TS 的数字,随意选择。

service

一个单个服务。将连接到 SDT。

program_num

PAT、PMT 和 SDT 之间的链接。

program

一个单个程序,其中一个或多个流与之关联。将连接到 PAT。

streams

用于填充“程序”的 PMT 部分的流循环

encoders

编码器循环。每个流必须有一个编码器。

events

可选事件信息。这将馈送到 EIT。

next

可选地链接此频道。

描述

当 vidtv 启动时,它将创建一些硬编码的频道。它们的服务将被连接起来以填充 SDT。它们的程序将被连接起来以填充 PAT 对于 PAT 中的每个程序,将创建一个 PMT 部分频道的 PMT 部分将分配其流。将轮询每个流的相应编码器以生成 TS 数据包这些数据包可能会被 mux 交错,然后传递到桥接

int vidtv_channel_si_init(struct vidtv_mux *m)

从 mux 中的频道初始化 PSI 表

参数

struct vidtv_mux *m

包含频道的 mux。

int vidtv_channels_init(struct vidtv_mux *m)

初始化硬编码的伪“频道”。

参数

struct vidtv_mux *m

将频道存储到的 mux。

struct vidtv_demod_cnr_to_qual_s

将 CNR 值映射到给定的调制和 fec_inner 组合

定义:

struct vidtv_demod_cnr_to_qual_s {
    u32 modulation;
    u32 fec;
    u32 cnr_ok;
    u32 cnr_good;
};

成员

modulation

请参阅 enum fe_modulation

fec

请参阅枚举 fe_fec_rate

cnr_ok

信噪比阈值,用于判断信号是否正常。低于该阈值,可能会失去同步。

cnr_good

信噪比阈值,用于判断信号是否强。

描述

此结构体匹配给定调制方式和 fec_inner 组合的“good”和“ok” CNR 值。如果信号质量不太好,我们可能会模拟一些噪声。

这些值取自 libdvbv5。

struct vidtv_demod_config

用于初始化解调器的配置

定义:

struct vidtv_demod_config {
    u8 drop_tslock_prob_on_low_snr;
    u8 recover_tslock_prob_on_good_snr;
};

成员

drop_tslock_prob_on_low_snr

由于低信噪比而导致丢失锁定的概率

recover_tslock_prob_on_good_snr

当信号改善时恢复的概率

描述

用于初始化解调器模块的配置,通常由桥接驱动程序填充。对于 vidtv,这在探测解调器模块之前由 vidtv_bridge 填充。

struct vidtv_demod_state

解调器状态

定义:

struct vidtv_demod_state {
    struct dvb_frontend frontend;
    struct vidtv_demod_config config;
    enum fe_status status;
    u16 tuner_cnr;
};

成员

前端

由解调器分配的前端结构。

配置

用于初始化解调器的配置。

状态

解调器状态。

tuner_cnr

信号载波的当前信噪比

struct vidtv_encoder

一个通用的编码器类型。

定义:

struct vidtv_encoder {
    enum vidtv_encoder_id id;
    char *name;
    u8 *encoder_buf;
    u32 encoder_buf_sz;
    u32 encoder_buf_offset;
    u64 sample_count;
    struct vidtv_access_unit *access_units;
    void *src_buf;
    u32 src_buf_sz;
    u32 src_buf_offset;
    bool is_video_encoder;
    void *ctx;
    __be16 stream_id;
    __be16 es_pid;
    void *(*encode)(struct vidtv_encoder *e);
    u32 (*clear)(struct vidtv_encoder *e);
    struct vidtv_encoder *sync;
    u32 sampling_rate_hz;
    void (*last_sample_cb)(u32 sample_no);
    void (*destroy)(struct vidtv_encoder *e);
    struct vidtv_encoder *next;
};

成员

id

以便在需要时可以转换为具体的实现。

name

通常与流名称相同。

encoder_buf

用于访问单元的编码器内部缓冲区。

encoder_buf_sz

编码器缓冲区大小,以字节为单位

encoder_buf_offset

我们在编码器缓冲区中的字节位置。

sample_count

我们总共编码了多少个样本。

access_units

编码器有效负载单元,用于时钟参考

src_buf

要编码的原始数据的来源,如果为空,编码器可能会设置默认值。

src_buf_sz

src_buf 的大小。

src_buf_offset

我们在源缓冲区中的位置。

is_video_encoder

是否为视频编码器(与音频相对)

ctx

特定于编码器的状态。

stream_id

示例:音频流 (0xc0-0xdf),视频流 (0xe0-0xef)。

es_pid

用于此编码器中基本流的 TS PID。

encode

为给定的时间量准备足够的 AU。

clear

清除编码器输出。

sync

尝试与此编码器同步。

sampling_rate_hz

使用的采样率(或帧率,如果为视频)。

last_sample_cb

当编码器数据耗尽时调用。这样源可以以零碎的方式读取数据,而不是必须一次性提供所有数据。

destroy

销毁此编码器,释放已分配的资源。

next

链中的下一个

struct vidtv_mux_timing

与计时相关的信息

定义:

struct vidtv_mux_timing {
    u64 start_jiffies;
    u64 current_jiffies;
    u64 past_jiffies;
    u64 clk;
    u64 pcr_period_usecs;
    u64 si_period_usecs;
};

成员

start_jiffies

当我们启动复用线程时“jiffies”的值。

current_jiffies

当前迭代的“jiffies”值。

past_jiffies

过去迭代的“jiffies”值。

clk

我们将从中驱动 PCR 的 27Mhz 时钟。在每次迭代中按比例更新。

pcr_period_usecs

我们应该发送 PCR 数据包的频率。

si_period_usecs

我们应该发送 PSI 数据包的频率。

描述

这用于决定何时应发送 PCR 或 PSI 数据包。这也将为时钟提供存储空间,该时钟用于计算 PCR 的值。

struct vidtv_mux_si

存储 PSI 上下文。

定义:

struct vidtv_mux_si {
    struct vidtv_psi_table_pat *pat;
    struct vidtv_psi_table_pmt **pmt_secs;
    struct vidtv_psi_table_sdt *sdt;
    struct vidtv_psi_table_nit *nit;
    struct vidtv_psi_table_eit *eit;
};

成员

pat

复用器正在使用的 PAT。

pmt_secs

复用器正在使用的 PMT 段。PAT 中的每个程序一个。

sdt

复用器正在使用的 SDT。

nit

复用器正在使用的 NIT。

eit

复用器正在使用的 EIT。

描述

这用于存储复用器正在使用的 PAT、PMT 段和 SDT。

复用器通过查看 vidtv_channel 中的硬编码通道来获取这些,然后定期为它们发送 TS 数据包>

struct vidtv_mux_pid_ctx

存储给定 TS PID 的上下文。

定义:

struct vidtv_mux_pid_ctx {
    u16 pid;
    u8 cc;
    struct hlist_node h;
};

成员

pid

TS PID。

cc

此 PID 的连续性计数器。它在每个 TS 数据包上递增,并在 0xf0 处回绕。如果解码器注意到此计数器突然跳跃,这将触发不连续状态。

h

这嵌入在哈希表中,映射 pid -> vidtv_mux_pid_ctx

struct vidtv_mux

一个大致基于 libavcodec/mpegtsenc.c 的复用器抽象

定义:

struct vidtv_mux {
    struct dvb_frontend *fe;
    struct device *dev;
    struct vidtv_mux_timing timing;
    u32 mux_rate_kbytes_sec;
    unsigned long pid_ctx[1 << ((3) - 1)];
    void (*on_new_packets_available_cb)(void *priv, u8 *buf, u32 npackets);
    u8 *mux_buf;
    u32 mux_buf_sz;
    u32 mux_buf_offset;
    struct vidtv_channel  *channels;
    struct vidtv_mux_si si;
    u64 num_streamed_pcr;
    u64 num_streamed_si;
    struct work_struct mpeg_thread;
    bool streaming;
    u16 pcr_pid;
    u16 transport_stream_id;
    u16 network_id;
    char *network_name;
    void *priv;
};

成员

fe

由复用器分配的前端结构。

dev

指向 struct device 的指针。

timing

跟踪与计时相关的信息。

mux_rate_kbytes_sec

TS 的比特率,以 kbytes 为单位。

pid_ctx

一个哈希表,用于跟踪每个 PID 的元数据。

on_new_packets_available_cb

一个回调,用于通知新的 TS 数据包已准备就绪。

mux_buf

指向此复用器缓冲区的指针。TS 数据包存储在那里,然后传递给桥接驱动程序。

mux_buf_sz

“mux_buf”的大小。

mux_buf_offset

“mux_buf”中的当前偏移量。

channels

与此复用器关联的通道。

si

跟踪 PSI 上下文。

num_streamed_pcr

已流式传输的 PCR 数据包数。

num_streamed_si

已流式传输的 PSI 数据包数。

mpeg_thread

负责复用器循环的线程。

streaming

“mpeg_thread”是否正在运行。

pcr_pid

用于 PSI 数据包的 TS PID。所有通道将共享相同的 PCR。

transport_stream_id

传输流 ID

network_id

网络 ID

network_name

网络名称

priv

私有数据。

struct vidtv_mux_init_args

用于初始化复用器的参数。

定义:

struct vidtv_mux_init_args {
    u32 mux_rate_kbytes_sec;
    void (*on_new_packets_available_cb)(void *priv, u8 *buf, u32 npackets);
    u32 mux_buf_sz;
    u64 pcr_period_usecs;
    u64 si_period_usecs;
    u16 pcr_pid;
    u16 transport_stream_id;
    struct vidtv_channel *channels;
    u16 network_id;
    char *network_name;
    void *priv;
};

成员

mux_rate_kbytes_sec

TS 的比特率,以 kbytes 为单位。

on_new_packets_available_cb

一个回调,用于通知新的 TS 数据包已准备就绪。

mux_buf_sz

“mux_buf”的大小。

pcr_period_usecs

我们应该发送 PCR 数据包的频率。

si_period_usecs

我们应该发送 PSI 数据包的频率。

pcr_pid

用于 PSI 数据包的 TS PID。所有通道将共享相同的 PCR。

transport_stream_id

传输流 ID

channels

要使用的可选通道列表

network_id

网络 ID

network_name

网络名称

priv

私有数据。

struct pes_header_write_args

用于写入 PES 标头的参数。

定义:

struct pes_header_write_args {
    void *dest_buf;
    u32 dest_offset;
    u32 dest_buf_sz;
    u32 encoder_id;
    bool send_pts;
    u64 pts;
    bool send_dts;
    u64 dts;
    u16 stream_id;
    u32 n_pes_h_s_bytes;
    u32 access_unit_len;
};

成员

dest_buf

要写入的缓冲区。

dest_offset

在 dest_buffer 中开始写入的位置。

dest_buf_sz

dest_buffer 的大小

encoder_id

编码器 ID(请参阅 vidtv_encoder.h)

send_pts

我们应该发送 PTS 吗?

pts

要发送的 PTS 值。

send_dts

我们应该发送 DTS 吗?

dts

要发送的 DTS 值。

stream_id

要使用的流 ID。示例:音频流 (0xc0-0xdf),视频流 (0xe0-0xef)。

n_pes_h_s_bytes

填充字节。如果需要,编码器可能会使用,解码器会丢弃。

access_unit_len

一个访问单元的大小(包括它可能需要的任何标头)

struct pes_ts_header_write_args

用于写入 TS 标头的参数。

定义:

struct pes_ts_header_write_args {
    void *dest_buf;
    u32 dest_offset;
    u32 dest_buf_sz;
    u16 pid;
    u8 *continuity_counter;
    bool wrote_pes_header;
    u32 n_stuffing_bytes;
    u64 pcr;
};

成员

dest_buf

要写入的缓冲区。

dest_offset

在 dest_buffer 中开始写入的位置。

dest_buf_sz

dest_buffer 的大小

pid

用于 TS 数据包的 PID。

continuity_counter

在每个新的 TS 数据包上递增。

wrote_pes_header

指示 PES 标头已写入的标志

n_stuffing_bytes

填充字节。如果需要,编码器可能会使用,解码器会丢弃。

pcr

由 27Mhz 时钟驱动的计数器。

struct pes_write_args

数据包化器的参数。

定义:

struct pes_write_args {
    void *dest_buf;
    void *from;
    u32 access_unit_len;
    u32 dest_offset;
    u32 dest_buf_sz;
    u16 pid;
    u32 encoder_id;
    u8 *continuity_counter;
    u16 stream_id;
    bool send_pts;
    u64 pts;
    bool send_dts;
    u64 dts;
    u32 n_pes_h_s_bytes;
    u64 pcr;
};

成员

dest_buf

要写入的缓冲区。

from

指向包含一个访问单元的编码器缓冲区的指针。

access_unit_len

一个访问单元的大小(包括它可能需要的任何标头)

dest_offset

在 dest_buffer 中开始写入的位置。

dest_buf_sz

dest_buffer 的大小

pid

用于 TS 数据包的 PID。

encoder_id

编码器 ID(请参阅 vidtv_encoder.h)

continuity_counter

在每个新的 TS 数据包上递增。

stream_id

要使用的流 ID。示例:音频流 (0xc0-0xdf),视频流 (0xe0-0xef)。

send_pts

我们应该发送 PTS 吗?

pts

要发送的 PTS 值。

send_dts

我们应该发送 DTS 吗?

dts

要发送的 DTS 值。

n_pes_h_s_bytes

填充字节。如果需要,编码器可能会使用,解码器会丢弃。

pcr

由 27Mhz 时钟驱动的计数器。

u32 vidtv_pes_write_into(struct pes_write_args *args)

将 PES 数据包作为 MPEG-TS 数据包写入缓冲区。

参数

struct pes_write_args *args

写入时要使用的参数

描述

此函数将来自编码器的访问单元的 ES 数据转换为 MPEG TS 数据包。它首先使用 PES 标头封装它,然后将其拆分为 TS 数据包。

然后将数据写入由“args.buf”指向的缓冲区

返回

写入缓冲区的字节数。这通常不等于访问单元的大小,因为我们需要 PES 标头、TS 标头和填充字节(如果有)的空间。

struct psi_write_args

PSI 数据包化器的参数。

定义:

struct psi_write_args {
    void *dest_buf;
    void *from;
    size_t len;
    u32 dest_offset;
    u16 pid;
    bool new_psi_section;
    u8 *continuity_counter;
    bool is_crc;
    u32 dest_buf_sz;
    u32 *crc;
};

成员

dest_buf

要写入的缓冲区。

from

要复制的 PSI 数据。

len

要写入多少。

dest_offset

在 dest_buffer 中开始写入的位置。

pid

TS 数据包 ID。

new_psi_section

在开始表段时设置。

continuity_counter

在每个新数据包上递增。

is_crc

在末尾写入 CRC 时设置。

dest_buf_sz

dest_buffer 的大小

crc

用于存储此块的 crc 的指针

struct desc_write_args

为了写入描述符而使用的参数。

定义:

struct desc_write_args {
    void *dest_buf;
    u32 dest_offset;
    struct vidtv_psi_desc *desc;
    u16 pid;
    u8 *continuity_counter;
    u32 dest_buf_sz;
    u32 *crc;
};

成员

dest_buf

要写入的缓冲区。

dest_offset

在 dest_buffer 中开始写入的位置。

desc

指向描述符的指针

pid

TS 数据包 ID。

continuity_counter

在每个新数据包上递增。

dest_buf_sz

dest_buffer 的大小

crc

用于存储此块的 crc 的指针

struct crc32_write_args

为了在 PSI 表的末尾写入 CRC 而使用的参数。

定义:

struct crc32_write_args {
    void *dest_buf;
    u32 dest_offset;
    __be32 crc;
    u16 pid;
    u8 *continuity_counter;
    u32 dest_buf_sz;
};

成员

dest_buf

要写入的缓冲区。

dest_offset

在 dest_buffer 中开始写入的位置。

crc

要写入的 CRC 值

pid

TS 数据包 ID。

continuity_counter

在每个新数据包上递增。

dest_buf_sz

dest_buffer 的大小

struct header_write_args

用于写入通用表头的参数,按顺序排列

定义:

struct header_write_args {
    void *dest_buf;
    u32 dest_offset;
    struct vidtv_psi_table_header *h;
    u16 pid;
    u8 *continuity_counter;
    u32 dest_buf_sz;
    u32 *crc;
};

成员

dest_buf

要写入的缓冲区。

dest_offset

在 dest_buffer 中开始写入的位置。

h

指向表头的指针。

pid

TS 数据包 ID。

continuity_counter

在每个新数据包上递增。

dest_buf_sz

dest_buffer 的大小

crc

用于存储此块的 crc 的指针

void vidtv_psi_sdt_service_assign(struct vidtv_psi_table_sdt *sdt, struct vidtv_psi_table_sdt_service *service)

将服务循环分配给SDT。

参数

struct vidtv_psi_table_sdt *sdt

要分配到的SDT。

struct vidtv_psi_table_sdt_service *service

服务循环(一个或多个服务)

描述

这将释放表中之前的服务循环。这会将服务循环的所有权分配给表,即当调用其销毁函数时,该表将释放此服务循环。

void vidtv_psi_desc_assign(struct vidtv_psi_desc **to, struct vidtv_psi_desc *desc)

在某个点分配描述符循环

参数

struct vidtv_psi_desc **to

将此描述符循环分配到哪里

struct vidtv_psi_desc *desc

将被分配的描述符循环。

描述

这将释放'to'中的循环(如果存在)。

void vidtv_pmt_desc_assign(struct vidtv_psi_table_pmt *pmt, struct vidtv_psi_desc **to, struct vidtv_psi_desc *desc)

在PMT部分中的某个点分配描述符循环。

参数

struct vidtv_psi_table_pmt *pmt

将包含描述符循环的PMT部分

struct vidtv_psi_desc **to

将此描述符循环分配到PMT中的位置

struct vidtv_psi_desc *desc

将被分配的描述符循环。

描述

这将释放'to'中的循环(如果存在)。这会将循环的所有权分配给表,即当调用其销毁函数时,该表将释放此循环。

void vidtv_sdt_desc_assign(struct vidtv_psi_table_sdt *sdt, struct vidtv_psi_desc **to, struct vidtv_psi_desc *desc)

在SDT的某个点分配描述符循环。

参数

struct vidtv_psi_table_sdt *sdt

将包含描述符循环的SDT

struct vidtv_psi_desc **to

将此描述符循环分配到PMT中的位置

struct vidtv_psi_desc *desc

将被分配的描述符循环。

描述

这将释放'to'中的循环(如果存在)。这会将循环的所有权分配给表,即当调用其销毁函数时,该表将释放此循环。

void vidtv_psi_pat_program_assign(struct vidtv_psi_table_pat *pat, struct vidtv_psi_table_pat_program *p)

将程序循环分配给PAT。

参数

struct vidtv_psi_table_pat *pat

要分配到的PAT。

struct vidtv_psi_table_pat_program *p

程序循环(一个或多个程序)

描述

这将释放表中之前的程序循环。这会将程序循环的所有权分配给表,即当调用其销毁函数时,该表将释放此程序循环。

void vidtv_psi_pmt_stream_assign(struct vidtv_psi_table_pmt *pmt, struct vidtv_psi_table_pmt_stream *s)

将流循环分配给PAT。

参数

struct vidtv_psi_table_pmt *pmt

要分配到的PMT。

struct vidtv_psi_table_pmt_stream *s

流循环(一个或多个流)

描述

这将释放表中之前的流循环。这会将流循环的所有权分配给表,即当调用其销毁函数时,该表将释放此流循环。

struct vidtv_psi_table_pmt **vidtv_psi_pmt_create_sec_for_each_pat_entry(struct vidtv_psi_table_pat *pat, u16 pcr_pid)

为PAT中找到的每个程序创建一个PMT部分

参数

struct vidtv_psi_table_pat *pat

要查找程序的PAT。

u16 pcr_pid

此PMT部分中描述的程序要使用的PCR的包ID

u16 vidtv_psi_pmt_get_pid(struct vidtv_psi_table_pmt *section, struct vidtv_psi_table_pat *pat)

获取PMT部分的TS PID。

参数

struct vidtv_psi_table_pmt *section

我们要检索其PID的PMT部分。

struct vidtv_psi_table_pat *pat

要查找的PAT表。

返回

“section”的TS PID

void vidtv_psi_pat_table_update_sec_len(struct vidtv_psi_table_pat *pat)

重新计算并更新PAT节的长度。

参数

struct vidtv_psi_table_pat *pat

要更新其长度的PAT。

描述

这将遍历表并累积其组件的长度,然后将其用于替换“section_length”字段。

如果section_length > MAX_SECTION_LEN,则操作失败。

void vidtv_psi_pmt_table_update_sec_len(struct vidtv_psi_table_pmt *pmt)

重新计算并更新PMT节的长度。

参数

struct vidtv_psi_table_pmt *pmt

要更新其长度的PMT。

描述

这将遍历表并累积其组件的长度,然后将其用于替换“section_length”字段。

如果section_length > MAX_SECTION_LEN,则操作失败。

void vidtv_psi_sdt_table_update_sec_len(struct vidtv_psi_table_sdt *sdt)

重新计算并更新SDT节的长度。

参数

struct vidtv_psi_table_sdt *sdt

要更新其长度的SDT。

描述

这将遍历表并累积其组件的长度,然后将其用于替换“section_length”字段。

如果section_length > MAX_SECTION_LEN,则操作失败。

struct vidtv_psi_pat_write_args

用于写入PAT表的参数

定义:

struct vidtv_psi_pat_write_args {
    char *buf;
    u32 offset;
    struct vidtv_psi_table_pat *pat;
    u32 buf_sz;
    u8 *continuity_counter;
};

成员

buf

目标缓冲区。

offset

目标缓冲区中的偏移量。

pat

指向PAT的指针。

buf_sz

目标缓冲区的大小。

continuity_counter

指向CC的指针。在每个新数据包上递增。

u32 vidtv_psi_pat_write_into(struct vidtv_psi_pat_write_args *args)

将 PAT 作为 MPEG-TS 数据包写入缓冲区。

参数

struct vidtv_psi_pat_write_args *args

struct vidtv_psi_pat_write_args 的一个实例

描述

此函数将 PAT 表的 MPEG TS 数据包写入缓冲区。调用代码通常会通过调用其初始化函数来生成 PAT,因此负责释放它。

返回

写入缓冲区的字节数。这不等于 PAT 的大小,因为在 TS 封装期间需要更多空间用于 TS 标头。

struct vidtv_psi_sdt_write_args

用于写入 SDT 表的参数

定义:

struct vidtv_psi_sdt_write_args {
    char *buf;
    u32 offset;
    struct vidtv_psi_table_sdt *sdt;
    u32 buf_sz;
    u8 *continuity_counter;
};

成员

buf

目标缓冲区。

offset

目标缓冲区中的偏移量。

sdt

指向 SDT 的指针。

buf_sz

目标缓冲区的大小。

continuity_counter

指向CC的指针。在每个新数据包上递增。

u32 vidtv_psi_sdt_write_into(struct vidtv_psi_sdt_write_args *args)

将 SDT 作为 MPEG-TS 数据包写入缓冲区。

参数

struct vidtv_psi_sdt_write_args *args

struct vidtv_psi_sdt_write_args 的一个实例

描述

此函数将 SDT 表的 MPEG TS 数据包写入缓冲区。调用代码通常会通过调用其初始化函数来生成 SDT,因此负责释放它。

返回

写入缓冲区的字节数。这不等于 SDT 的大小,因为在 TS 封装期间需要更多空间用于 TS 标头。

struct vidtv_psi_pmt_write_args

用于写入 PMT 段的参数

定义:

struct vidtv_psi_pmt_write_args {
    char *buf;
    u32 offset;
    struct vidtv_psi_table_pmt *pmt;
    u16 pid;
    u32 buf_sz;
    u8 *continuity_counter;
    u16 pcr_pid;
};

成员

buf

目标缓冲区。

offset

目标缓冲区中的偏移量。

pmt

指向 PMT 的指针。

pid

节目 ID

buf_sz

目标缓冲区的大小。

continuity_counter

指向CC的指针。在每个新数据包上递增。

pcr_pid

用于 PSI 数据包的 TS PID。所有通道将共享相同的 PCR。

u32 vidtv_psi_pmt_write_into(struct vidtv_psi_pmt_write_args *args)

将 PMT 作为 MPEG-TS 数据包写入缓冲区。

参数

struct vidtv_psi_pmt_write_args *args

struct vidtv_psi_pmt_write_args 的一个实例

描述

此函数将 PMT 段的 MPEG TS 数据包写入缓冲区。调用代码通常会通过调用其初始化函数来生成 PMT 段,因此负责释放它。

返回

写入缓冲区的字节数。这不等于 PMT 段的大小,因为在 TS 封装期间需要更多空间用于 TS 标头。

struct vidtv_psi_table_pmt *vidtv_psi_find_pmt_sec(struct vidtv_psi_table_pmt **pmt_sections, u16 nsections, u16 program_num)

查找 ‘program_num’ 的 PMT 段

参数

struct vidtv_psi_table_pmt **pmt_sections

要查找的段。

u16 nsections

段的数量。

u16 program_num

来自 PAT 的指向 PMT 段的 'program_num'。

返回

指向 PMT 的指针(如果找到),否则为 NULL。

struct vidtv_psi_table_transport

NIT 和/或其他表的 TS 循环中的一个条目。参见 ETSI 300 468 第 5.2.1 节

定义:

struct vidtv_psi_table_transport {
    __be16 transport_id;
    __be16 network_id;
    __be16 bitfield;
    struct vidtv_psi_desc *descriptor;
    struct vidtv_psi_table_transport *next;
};

成员

transport_id

正在描述的 TS ID

network_id

包含 TS ID 的 network_id

位域

包含描述符循环长度

描述符

描述符循环

next

指向下一个条目的指针

struct vidtv_psi_table_nit

网络信息表 (NIT)。参见 ETSI 300 468 第 5.2.1 节

定义:

struct vidtv_psi_table_nit {
    struct vidtv_psi_table_header header;
    __be16 bitfield;
    struct vidtv_psi_desc *descriptor;
    __be16 bitfield2;
    struct vidtv_psi_table_transport *transport;
};

成员

标头

PSI 表标头

位域

包含网络描述符长度

描述符

描述网络的描述符循环

位域2

包含传输流循环长度

传输

传输流循环

struct vidtv_psi_nit_write_args

用于写入 NIT 段的参数

定义:

struct vidtv_psi_nit_write_args {
    char *buf;
    u32 offset;
    struct vidtv_psi_table_nit *nit;
    u32 buf_sz;
    u8 *continuity_counter;
};

成员

buf

目标缓冲区。

offset

目标缓冲区中的偏移量。

nit

指向 NIT 的指针

buf_sz

目标缓冲区的大小。

continuity_counter

指向CC的指针。在每个新数据包上递增。

u32 vidtv_psi_nit_write_into(struct vidtv_psi_nit_write_args *args)

将 NIT 作为 MPEG-TS 数据包写入缓冲区。

参数

struct vidtv_psi_nit_write_args *args

struct vidtv_psi_nit_write_args 的一个实例

描述

此函数将 NIT 表的 MPEG TS 数据包写入缓冲区。调用代码通常会通过调用其初始化函数来生成 NIT,因此负责释放它。

返回

写入缓冲区的字节数。这不等于 NIT 的大小,因为在 TS 封装期间需要更多空间用于 TS 标头。

struct vidtv_psi_eit_write_args

用于写入 EIT 段的参数

定义:

struct vidtv_psi_eit_write_args {
    char *buf;
    u32 offset;
    struct vidtv_psi_table_eit *eit;
    u32 buf_sz;
    u8 *continuity_counter;
};

成员

buf

目标缓冲区。

offset

目标缓冲区中的偏移量。

eit

指向 EIT 的指针

buf_sz

目标缓冲区的大小。

continuity_counter

指向CC的指针。在每个新数据包上递增。

u32 vidtv_psi_eit_write_into(struct vidtv_psi_eit_write_args *args)

将 EIT 作为 MPEG-TS 数据包写入缓冲区。

参数

struct vidtv_psi_eit_write_args *args

struct vidtv_psi_nit_write_args 的一个实例

描述

此函数将 EIT 表的 MPEG TS 数据包写入缓冲区。调用代码通常会通过调用其初始化函数来生成 EIT,因此负责释放它。

返回

写入缓冲区的字节数。这不等于 EIT 的大小,因为在 TS 封装期间需要更多空间用于 TS 标头。

void vidtv_psi_eit_table_update_sec_len(struct vidtv_psi_table_eit *eit)

重新计算并更新 EIT 段长度。

参数

struct vidtv_psi_table_eit *eit

要更新长度的 EIT。

描述

这将遍历表并累积其组件的长度,然后将其用于替换“section_length”字段。

如果 section_length > EIT_MAX_SECTION_LEN,则操作失败。

void vidtv_psi_eit_event_assign(struct vidtv_psi_table_eit *eit, struct vidtv_psi_table_eit_event *e)

将事件循环分配给 EIT。

参数

struct vidtv_psi_table_eit *eit

要分配到的 EIT。

struct vidtv_psi_table_eit_event *e

事件循环

描述

这将释放表中以前的事件循环。这会将流循环的所有权分配给表,即,当调用其销毁函数时,该表将释放此流循环。

struct vidtv_s302m_ctx

s302m 编码器上下文。

定义:

struct vidtv_s302m_ctx {
    struct vidtv_encoder *enc;
    u32 frame_index;
    u32 au_count;
    int last_duration;
    unsigned int note_offset;
    enum musical_notes last_tone;
};

成员

enc

指向包含的编码器结构的指针。

frame_index

块中的当前帧

au_count

到目前为止编码的访问单元总数

last_duration

当前播放的音调的持续时间

note_offset

音乐音调数组中的位置

last_tone

当前播放的音调

struct vidtv_s302m_encoder_init_args

s302m 编码器的参数。

定义:

struct vidtv_s302m_encoder_init_args {
    char *name;
    void *src_buf;
    u32 src_buf_sz;
    u16 es_pid;
    struct vidtv_encoder *sync;
    void (*last_sample_cb)(u32 sample_no);
    struct vidtv_encoder *head;
};

成员

name

用于标识此特定实例的名称

src_buf

源缓冲区,如果此项为 NULL,编码器将默认为正弦波。

src_buf_sz

源缓冲区的大小。

es_pid

要使用的 MPEG 基本流 PID。

sync

尝试将音频与此视频编码器同步(如果不是 NULL)。

last_sample_cb

当编码器用完数据时调用的回调。

head

添加到此链

struct pcr_write_args

pcr_write_into 函数的参数。

定义:

struct pcr_write_args {
    void *dest_buf;
    u32 dest_offset;
    u16 pid;
    u32 buf_sz;
    u8 *continuity_counter;
    u64 pcr;
};

成员

dest_buf

要写入的缓冲区。

dest_offset

缓冲区中的字节偏移量。

pid

PCR 数据包的 TS PID。

buf_sz

缓冲区的字节大小。

continuity_counter

TS continuity_counter。

pcr

来自系统时钟的采样。

struct null_packet_write_args

null_write_into 函数的参数

定义:

struct null_packet_write_args {
    void *dest_buf;
    u32 dest_offset;
    u32 buf_sz;
    u8 *continuity_counter;
};

成员

dest_buf

要写入的缓冲区。

dest_offset

缓冲区中的字节偏移量。

buf_sz

缓冲区的字节大小。

continuity_counter

TS continuity_counter。

u32 vidtv_ts_null_write_into(struct null_packet_write_args args)

将 TS 空包写入缓冲区。

参数

struct null_packet_write_args args

写入时使用的参数。

描述

此函数将一个空包写入缓冲区。通常用于填充 TS 流。

返回

写入缓冲区的字节数。

u32 vidtv_ts_pcr_write_into(struct pcr_write_args args)

将 PCR 包写入缓冲区。

参数

struct pcr_write_args args

写入时使用的参数。

描述

此函数将 PCR 包写入缓冲区。用于同步编码器和解码器之间的时钟。

返回

写入缓冲区的字节数。

struct vidtv_tuner_config

用于初始化调谐器的配置。

定义:

struct vidtv_tuner_config {
    struct dvb_frontend *fe;
    u32 mock_power_up_delay_msec;
    u32 mock_tune_delay_msec;
    u32 vidtv_valid_dvb_t_freqs[NUM_VALID_TUNER_FREQS];
    u32 vidtv_valid_dvb_c_freqs[NUM_VALID_TUNER_FREQS];
    u32 vidtv_valid_dvb_s_freqs[NUM_VALID_TUNER_FREQS];
    u8 max_frequency_shift_hz;
};

成员

fe

指向由 vidtv_demod 分配的 dvb_frontend 结构的指针。

mock_power_up_delay_msec

模拟上电延迟。

mock_tune_delay_msec

模拟调谐延迟。

vidtv_valid_dvb_t_freqs

要模拟的有效 DVB-T 频率。

vidtv_valid_dvb_c_freqs

要模拟的有效 DVB-C 频率。

vidtv_valid_dvb_s_freqs

要模拟的有效 DVB-S 频率。

max_frequency_shift_hz

调谐频道时允许的最大频率偏移量 (以赫兹为单位)

描述

用于初始化调谐器模块的配置,通常由桥接驱动程序填充。对于 vidtv,此配置在探测调谐器模块之前由 vidtv_bridge 填充。

u32 vidtv_memcpy(void *to, size_t to_offset, size_t to_size, const void *from, size_t len)

MPEG-TS 生成器使用的包装例程,以避免超出输出缓冲区。

参数

void *to

将复制 MPEG-TS 包的起始元素。

size_t to_offset

要填充的 to 缓冲区的起始位置。

size_t to_size

to 缓冲区的大小。

const void *from

要复制的缓冲区的起始元素。

size_t len

要从 from 缓冲区复制到 to**+ **to_offset 缓冲区的元素数量。

注意

真实的数字电视解调驱动程序不应有 memcpy 包装器。我们在这里使用它,因为在内核空间中模拟 MPEG-TS 生成需要一些额外的注意。

返回

返回写入的字节数

u32 vidtv_memset(void *to, size_t to_offset, size_t to_size, const int c, size_t len)

MPEG-TS 生成器使用的包装例程,以避免超出输出缓冲区。

参数

void *to

要设置的起始元素

size_t to_offset

要填充的 to 缓冲区的起始位置。

size_t to_size

to 缓冲区的大小。

const int c

将内存设置为的值。

size_t len

要从 from 缓冲区复制到 to**+ **to_offset 缓冲区的元素数量。

注意

真实的数字电视解调驱动程序不应有 memset 包装器。我们在这里使用它,因为在内核空间中模拟 MPEG-TS 生成需要一些额外的注意。

返回

返回写入的字节数

struct vidtv_tuner_hardware_state

模拟调谐器硬件状态

定义:

struct vidtv_tuner_hardware_state {
    bool asleep;
    u32 lock_status;
    u32 if_frequency;
    u32 tuned_frequency;
    u32 bandwidth;
};

成员

asleep

调谐器是否处于睡眠状态,即是否调用了 _sleep() 或 _suspend()。

lock_status

调谐器是否已成功锁定到请求的频率。

if_frequency

调谐器的中频。为了模拟而硬编码。

tuned_frequency

实际调谐频率。

bandwidth

实际带宽。

描述

此结构旨在模拟调谐器硬件的状态,就像我们有物理调谐器硬件一样。

struct vidtv_tuner_dev

调谐器结构

定义:

struct vidtv_tuner_dev {
    struct dvb_frontend *fe;
    struct vidtv_tuner_hardware_state hw_state;
    struct vidtv_tuner_config config;
};

成员

fe

指向由 vidtv_demod 分配的 dvb_frontend 结构的指针

hw_state

一个结构,用于模拟调谐器的硬件状态,就像我们有物理调谐器硬件一样。

配置

用于启动调谐器模块的配置,通常由桥接驱动程序填充。对于 vidtv,此配置在探测调谐器模块之前由 vidtv_bridge 填充。