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 数据包的频率。默认值:40 毫秒。

pcr_period_msec

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

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:系统 中找到,而 SDT、NIT、EIT 的规范可以在 ETSI EN 300 468:DVB 系统中的服务信息 (SI) 规范 中找到。

严格来说不是必须的,但是使用真实的 TS 文件有助于调试 PSI 表。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:电视 - 将 AES3 数据映射到 MPEG-2 传输流

生成的 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,然后 modprobing 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

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

encoders

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

events

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

next

可以选择性地链接此频道。

描述

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

int vidtv_channel_si_init(struct vidtv_mux *m)

从多路复用器中的频道初始化 PSI 表

参数

struct vidtv_mux *m

包含频道的复用器。

int vidtv_channels_init(struct vidtv_mux *m)

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

参数

struct vidtv_mux *m

要将频道存储到的复用器。

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

请参阅 enum 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;
};

成员

frontend

解调器分配的前端结构。

config

用于初始化解调的配置。

status

解调状态。

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

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

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 数据包写入缓冲区。 调用代码通常会通过调用其 init 函数来生成 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 数据包写入缓冲区。 调用代码通常会通过调用其 init 函数来生成 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 数据包写入缓冲区。 调用代码通常会通过调用其 init 函数来生成 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

从指向 PMT 节的 PAT 中的 “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

bitfield

包含描述符循环长度

descriptor

描述符循环

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

成员

header

PSI 表头

bitfield

包含网络描述符长度

descriptor

描述网络的描述符循环

bitfield2

包含传输流循环长度

transport

传输流循环

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 数据包写入缓冲区。 调用代码通常会通过调用其 init 函数来生成 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 数据包写入缓冲区。 调用代码通常会通过调用其 init 函数来生成 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

调谐到频道时允许的最大频率偏移量 (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

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

config

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