mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-17 09:43:59 +08:00
media fixes for v5.10-rc6
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+QmuaPwR3wnBdVwACF8+vY7k4RUFAl/A8mEACgkQCF8+vY7k 4RVMrBAAmWyCl5RUik6qlC3sCY136x1Bayojj8Hz5/m3Dt6W7+DSY90Lkra23h54 t4Y+V9Vjbtgk4rm27z/0CVFYUhzgtmEFnWHhahecnP+VjJ7JedS0LBW4vZ4BTzOl gzfJuXKeAyXOuVXRP5a/UQIlDtDbwkPIe6OL9ypZCV+Vnc35M5klQ/wpqJoq8BLp +5a6iFdBKofKCOy0s5MvreiCmP4P32QanVqR8tggkI5hYae4osd80AAgiICUppIZ G5h/KEZO9y5l0iZxQJwoHmL0dfdAgDkjYK/ipBOaTWvveYOKnHpWFcphqWbFFT/w FQ4YRDV6RLzdmTPJMr5X3rtujCGHC+POEDAUlLnFgif9q0sVFa+fwRjSvh2aEksM iB4uaD1dzQU+9+jVCHxTUDRKtC3uUtZBGG+ZzyubdhWVkynZcP3x+XPnHy1ens4T +pQgdpQFya4jCZeFbvuux9lyMgtmP96yEsM4OVRaEnMD2fFGjitYY7UxFwaG14Et t7WpkhO8yptASu9RteTwJswXURP2tivXNy+vmVlKRPKAHGAbic6Zb0TXMCsJiXGP rb+Uv24K3bvlNELw/7elOE+4G/lPyCe7NGCbTeHFLZcvldxCcIeTqcyjQdy1hS9R t7Ve5xkXi52eK4uo/0eMAdokTc4252N6Vq3n+XDj757EHgKuVQQ= =zCFd -----END PGP SIGNATURE----- Merge tag 'media/v5.10-3' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media Pull virtual digital TV driver fixes from Mauro Carvalho Chehab: "A series of fixes for the new virtual digital TV driver (vidtv), which is meant to help doing tests with the digital TV core and media userspace apps and libraries. They cover a series of issues I found on it, together with a few new things in order to make it easier to detect problems at the DVB core" * tag 'media/v5.10-3' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (36 commits) media: vidtv.rst: add kernel-doc markups media: vidtv.rst: update vidtv documentation media: vidtv: simplify EIT write function media: vidtv: simplify NIT write function media: vidtv: simplify SDT write function media: vidtv: cleanup PMT write table function media: vidtv: cleanup PAT write function media: vidtv: cleanup PSI table header function media: vidtv: cleanup PSI descriptor write function media: vidtv: simplify the crc writing logic media: vidtv: simplify PSI write function media: vidtv: add date to the current event media: vidtv: fix service_id at SDT table media: vidtv: fix service type media: vidtv: add a PID entry for the NIT table media: vidtv: properly fill EIT service_id media: vidtv: fix the network ID range media: vidtv: improve EIT data media: vidtv: cleanup null packet initialization logic media: vidtv: pre-initialize mux arrays ...
This commit is contained in:
commit
f594139d68
@ -149,11 +149,11 @@ vidtv_psi.[ch]
|
||||
Because the generator is implemented in a separate file, it can be
|
||||
reused elsewhere in the media subsystem.
|
||||
|
||||
Currently vidtv supports working with 3 PSI tables: PAT, PMT and
|
||||
SDT.
|
||||
Currently vidtv supports working with 5 PSI tables: PAT, PMT,
|
||||
SDT, NIT and EIT.
|
||||
|
||||
The specification for PAT and PMT can be found in *ISO 13818-1:
|
||||
Systems*, while the specification for the SDT can be found in *ETSI
|
||||
Systems*, while the specification for the SDT, NIT, EIT can be found in *ETSI
|
||||
EN 300 468: Specification for Service Information (SI) in DVB
|
||||
systems*.
|
||||
|
||||
@ -197,6 +197,8 @@ vidtv_channel.[ch]
|
||||
|
||||
#. Their programs will be concatenated to populate the PAT
|
||||
|
||||
#. Their events will be concatenated to populate the EIT
|
||||
|
||||
#. For each program in the PAT, a PMT section will be created
|
||||
|
||||
#. The PMT section for a channel will be assigned its streams.
|
||||
@ -256,6 +258,42 @@ Using dvb-fe-tool
|
||||
The first step to check whether the demod loaded successfully is to run::
|
||||
|
||||
$ 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
|
||||
|
||||
This should return what is currently set up at the demod struct, i.e.::
|
||||
|
||||
@ -314,7 +352,7 @@ For this, one should provide a configuration file known as a 'scan file',
|
||||
here's an example::
|
||||
|
||||
[Channel]
|
||||
FREQUENCY = 330000000
|
||||
FREQUENCY = 474000000
|
||||
MODULATION = QAM/AUTO
|
||||
SYMBOL_RATE = 6940000
|
||||
INNER_FEC = AUTO
|
||||
@ -335,6 +373,14 @@ You can browse scan tables online here: `dvb-scan-tables
|
||||
Assuming this channel is named 'channel.conf', you can then run::
|
||||
|
||||
$ 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
|
||||
|
||||
For more information on dvb-scan, check its documentation online here:
|
||||
`dvb-scan Documentation <https://www.linuxtv.org/wiki/index.php/Dvbscan>`_.
|
||||
@ -344,23 +390,38 @@ Using dvb-zap
|
||||
|
||||
dvbv5-zap is a command line tool that can be used to record MPEG-TS to disk. The
|
||||
typical use is to tune into a channel and put it into record mode. The example
|
||||
below - which is taken from the documentation - illustrates that::
|
||||
below - which is taken from the documentation - illustrates that\ [1]_::
|
||||
|
||||
$ dvbv5-zap -c dvb_channel.conf "trilhas sonoras" -r
|
||||
using demux '/dev/dvb/adapter0/demux0'
|
||||
$ dvbv5-zap -c dvb_channel.conf "beethoven" -o music.ts -P -t 10
|
||||
using demux 'dvb0.demux0'
|
||||
reading channels from file 'dvb_channel.conf'
|
||||
service has pid type 05: 204
|
||||
tuning to 573000000 Hz
|
||||
audio pid 104
|
||||
dvb_set_pesfilter 104
|
||||
Lock (0x1f) Quality= Good Signal= 100.00% C/N= -13.80dB UCB= 70 postBER= 3.14x10^-3 PER= 0
|
||||
DVR interface '/dev/dvb/adapter0/dvr0' can now be opened
|
||||
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
|
||||
|
||||
The channel can be watched by playing the contents of the DVR interface, with
|
||||
some player that recognizes the MPEG-TS format, such as *mplayer* or *vlc*.
|
||||
.. [1] In this example, it records 10 seconds with all program ID's stored
|
||||
at the music.ts file.
|
||||
|
||||
|
||||
The channel can be watched by playing the contents of the stream with some
|
||||
player that recognizes the MPEG-TS format, such as ``mplayer`` or ``vlc``.
|
||||
|
||||
By playing the contents of the stream one can visually inspect the workings of
|
||||
vidtv, e.g.::
|
||||
vidtv, e.g., to play a recorded TS file with::
|
||||
|
||||
$ mplayer music.ts
|
||||
|
||||
or, alternatively, running this command on one terminal::
|
||||
|
||||
$ dvbv5-zap -c dvb_channel.conf "beethoven" -P -r &
|
||||
|
||||
And, on a second terminal, playing the contents from DVR interface with::
|
||||
|
||||
$ mplayer /dev/dvb/adapter0/dvr0
|
||||
|
||||
@ -423,3 +484,30 @@ A nice addition is to simulate some noise when the signal quality is bad by:
|
||||
- Updating the error statistics accordingly (e.g. BER, etc).
|
||||
|
||||
- Simulating some noise in the encoded data.
|
||||
|
||||
Functions and structs used within vidtv
|
||||
---------------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_bridge.h
|
||||
|
||||
.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_channel.h
|
||||
|
||||
.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_demod.h
|
||||
|
||||
.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_encoder.h
|
||||
|
||||
.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_mux.h
|
||||
|
||||
.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_pes.h
|
||||
|
||||
.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_psi.h
|
||||
|
||||
.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_s302m.h
|
||||
|
||||
.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_ts.h
|
||||
|
||||
.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_tuner.h
|
||||
|
||||
.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_common.c
|
||||
|
||||
.. kernel-doc:: drivers/media/test-drivers/vidtv/vidtv_tuner.c
|
||||
|
@ -4,36 +4,43 @@
|
||||
* validate the existing APIs in the media subsystem. It can also aid
|
||||
* developers working on userspace applications.
|
||||
*
|
||||
* When this module is loaded, it will attempt to modprobe 'dvb_vidtv_tuner' and 'dvb_vidtv_demod'.
|
||||
* When this module is loaded, it will attempt to modprobe 'dvb_vidtv_tuner'
|
||||
* and 'dvb_vidtv_demod'.
|
||||
*
|
||||
* Copyright (C) 2020 Daniel W. S. Almeida
|
||||
*/
|
||||
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "vidtv_bridge.h"
|
||||
#include "vidtv_demod.h"
|
||||
#include "vidtv_tuner.h"
|
||||
#include "vidtv_ts.h"
|
||||
#include "vidtv_mux.h"
|
||||
#include "vidtv_common.h"
|
||||
#include "vidtv_demod.h"
|
||||
#include "vidtv_mux.h"
|
||||
#include "vidtv_ts.h"
|
||||
#include "vidtv_tuner.h"
|
||||
|
||||
//#define MUX_BUF_MAX_SZ
|
||||
//#define MUX_BUF_MIN_SZ
|
||||
#define MUX_BUF_MIN_SZ 90164
|
||||
#define MUX_BUF_MAX_SZ (MUX_BUF_MIN_SZ * 10)
|
||||
#define TUNER_DEFAULT_ADDR 0x68
|
||||
#define DEMOD_DEFAULT_ADDR 0x60
|
||||
#define VIDTV_DEFAULT_NETWORK_ID 0xff44
|
||||
#define VIDTV_DEFAULT_NETWORK_NAME "LinuxTV.org"
|
||||
#define VIDTV_DEFAULT_TS_ID 0x4081
|
||||
|
||||
/* LNBf fake parameters: ranges used by an Universal (extended) European LNBf */
|
||||
#define LNB_CUT_FREQUENCY 11700000
|
||||
#define LNB_LOW_FREQ 9750000
|
||||
#define LNB_HIGH_FREQ 10600000
|
||||
|
||||
/*
|
||||
* The LNBf fake parameters here are the ranges used by an
|
||||
* Universal (extended) European LNBf, which is likely the most common LNBf
|
||||
* found on Satellite digital TV system nowadays.
|
||||
*/
|
||||
#define LNB_CUT_FREQUENCY 11700000 /* high IF frequency */
|
||||
#define LNB_LOW_FREQ 9750000 /* low IF frequency */
|
||||
#define LNB_HIGH_FREQ 10600000 /* transition frequency */
|
||||
|
||||
static unsigned int drop_tslock_prob_on_low_snr;
|
||||
module_param(drop_tslock_prob_on_low_snr, uint, 0);
|
||||
@ -92,7 +99,8 @@ MODULE_PARM_DESC(si_period_msec, "How often to send SI packets. Default: 40ms");
|
||||
|
||||
static unsigned int pcr_period_msec = 40;
|
||||
module_param(pcr_period_msec, uint, 0);
|
||||
MODULE_PARM_DESC(pcr_period_msec, "How often to send PCR packets. Default: 40ms");
|
||||
MODULE_PARM_DESC(pcr_period_msec,
|
||||
"How often to send PCR packets. Default: 40ms");
|
||||
|
||||
static unsigned int mux_rate_kbytes_sec = 4096;
|
||||
module_param(mux_rate_kbytes_sec, uint, 0);
|
||||
@ -104,16 +112,14 @@ MODULE_PARM_DESC(pcr_pid, "PCR PID for all channels: defaults to 0x200");
|
||||
|
||||
static unsigned int mux_buf_sz_pkts;
|
||||
module_param(mux_buf_sz_pkts, uint, 0);
|
||||
MODULE_PARM_DESC(mux_buf_sz_pkts, "Size for the internal mux buffer in multiples of 188 bytes");
|
||||
|
||||
#define MUX_BUF_MIN_SZ 90164
|
||||
#define MUX_BUF_MAX_SZ (MUX_BUF_MIN_SZ * 10)
|
||||
MODULE_PARM_DESC(mux_buf_sz_pkts,
|
||||
"Size for the internal mux buffer in multiples of 188 bytes");
|
||||
|
||||
static u32 vidtv_bridge_mux_buf_sz_for_mux_rate(void)
|
||||
{
|
||||
u32 max_elapsed_time_msecs = VIDTV_MAX_SLEEP_USECS / USEC_PER_MSEC;
|
||||
u32 nbytes_expected;
|
||||
u32 mux_buf_sz = mux_buf_sz_pkts * TS_PACKET_LEN;
|
||||
u32 nbytes_expected;
|
||||
|
||||
nbytes_expected = mux_rate_kbytes_sec;
|
||||
nbytes_expected *= max_elapsed_time_msecs;
|
||||
@ -143,14 +149,12 @@ static bool vidtv_bridge_check_demod_lock(struct vidtv_dvb *dvb, u32 n)
|
||||
FE_HAS_LOCK);
|
||||
}
|
||||
|
||||
static void
|
||||
vidtv_bridge_on_new_pkts_avail(void *priv, u8 *buf, u32 npkts)
|
||||
/*
|
||||
* called on a separate thread by the mux when new packets become available
|
||||
*/
|
||||
static void vidtv_bridge_on_new_pkts_avail(void *priv, u8 *buf, u32 npkts)
|
||||
{
|
||||
/*
|
||||
* called on a separate thread by the mux when new packets become
|
||||
* available
|
||||
*/
|
||||
struct vidtv_dvb *dvb = (struct vidtv_dvb *)priv;
|
||||
struct vidtv_dvb *dvb = priv;
|
||||
|
||||
/* drop packets if we lose the lock */
|
||||
if (vidtv_bridge_check_demod_lock(dvb, 0))
|
||||
@ -159,7 +163,17 @@ vidtv_bridge_on_new_pkts_avail(void *priv, u8 *buf, u32 npkts)
|
||||
|
||||
static int vidtv_start_streaming(struct vidtv_dvb *dvb)
|
||||
{
|
||||
struct vidtv_mux_init_args mux_args = {0};
|
||||
struct vidtv_mux_init_args mux_args = {
|
||||
.mux_rate_kbytes_sec = mux_rate_kbytes_sec,
|
||||
.on_new_packets_available_cb = vidtv_bridge_on_new_pkts_avail,
|
||||
.pcr_period_usecs = pcr_period_msec * USEC_PER_MSEC,
|
||||
.si_period_usecs = si_period_msec * USEC_PER_MSEC,
|
||||
.pcr_pid = pcr_pid,
|
||||
.transport_stream_id = VIDTV_DEFAULT_TS_ID,
|
||||
.network_id = VIDTV_DEFAULT_NETWORK_ID,
|
||||
.network_name = VIDTV_DEFAULT_NETWORK_NAME,
|
||||
.priv = dvb,
|
||||
};
|
||||
struct device *dev = &dvb->pdev->dev;
|
||||
u32 mux_buf_sz;
|
||||
|
||||
@ -168,19 +182,17 @@ static int vidtv_start_streaming(struct vidtv_dvb *dvb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
mux_buf_sz = (mux_buf_sz_pkts) ? mux_buf_sz_pkts : vidtv_bridge_mux_buf_sz_for_mux_rate();
|
||||
if (mux_buf_sz_pkts)
|
||||
mux_buf_sz = mux_buf_sz_pkts;
|
||||
else
|
||||
mux_buf_sz = vidtv_bridge_mux_buf_sz_for_mux_rate();
|
||||
|
||||
mux_args.mux_rate_kbytes_sec = mux_rate_kbytes_sec;
|
||||
mux_args.on_new_packets_available_cb = vidtv_bridge_on_new_pkts_avail;
|
||||
mux_args.mux_buf_sz = mux_buf_sz;
|
||||
mux_args.pcr_period_usecs = pcr_period_msec * 1000;
|
||||
mux_args.si_period_usecs = si_period_msec * 1000;
|
||||
mux_args.pcr_pid = pcr_pid;
|
||||
mux_args.transport_stream_id = VIDTV_DEFAULT_TS_ID;
|
||||
mux_args.priv = dvb;
|
||||
mux_args.mux_buf_sz = mux_buf_sz;
|
||||
|
||||
dvb->streaming = true;
|
||||
dvb->mux = vidtv_mux_init(dvb->fe[0], dev, mux_args);
|
||||
dvb->mux = vidtv_mux_init(dvb->fe[0], dev, &mux_args);
|
||||
if (!dvb->mux)
|
||||
return -ENOMEM;
|
||||
vidtv_mux_start_thread(dvb->mux);
|
||||
|
||||
dev_dbg_ratelimited(dev, "Started streaming\n");
|
||||
@ -204,8 +216,8 @@ static int vidtv_start_feed(struct dvb_demux_feed *feed)
|
||||
{
|
||||
struct dvb_demux *demux = feed->demux;
|
||||
struct vidtv_dvb *dvb = demux->priv;
|
||||
int rc;
|
||||
int ret;
|
||||
int rc;
|
||||
|
||||
if (!demux->dmx.frontend)
|
||||
return -EINVAL;
|
||||
@ -243,9 +255,9 @@ static int vidtv_stop_feed(struct dvb_demux_feed *feed)
|
||||
|
||||
static struct dvb_frontend *vidtv_get_frontend_ptr(struct i2c_client *c)
|
||||
{
|
||||
/* the demod will set this when its probe function runs */
|
||||
struct vidtv_demod_state *state = i2c_get_clientdata(c);
|
||||
|
||||
/* the demod will set this when its probe function runs */
|
||||
return &state->frontend;
|
||||
}
|
||||
|
||||
@ -253,6 +265,11 @@ static int vidtv_master_xfer(struct i2c_adapter *i2c_adap,
|
||||
struct i2c_msg msgs[],
|
||||
int num)
|
||||
{
|
||||
/*
|
||||
* Right now, this virtual driver doesn't really send or receive
|
||||
* messages from I2C. A real driver will require an implementation
|
||||
* here.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -320,11 +337,10 @@ static int vidtv_bridge_dmxdev_init(struct vidtv_dvb *dvb)
|
||||
|
||||
static int vidtv_bridge_probe_demod(struct vidtv_dvb *dvb, u32 n)
|
||||
{
|
||||
struct vidtv_demod_config cfg = {};
|
||||
|
||||
cfg.drop_tslock_prob_on_low_snr = drop_tslock_prob_on_low_snr;
|
||||
cfg.recover_tslock_prob_on_good_snr = recover_tslock_prob_on_good_snr;
|
||||
|
||||
struct vidtv_demod_config cfg = {
|
||||
.drop_tslock_prob_on_low_snr = drop_tslock_prob_on_low_snr,
|
||||
.recover_tslock_prob_on_good_snr = recover_tslock_prob_on_good_snr,
|
||||
};
|
||||
dvb->i2c_client_demod[n] = dvb_module_probe("dvb_vidtv_demod",
|
||||
NULL,
|
||||
&dvb->i2c_adapter,
|
||||
@ -343,14 +359,14 @@ static int vidtv_bridge_probe_demod(struct vidtv_dvb *dvb, u32 n)
|
||||
|
||||
static int vidtv_bridge_probe_tuner(struct vidtv_dvb *dvb, u32 n)
|
||||
{
|
||||
struct vidtv_tuner_config cfg = {};
|
||||
struct vidtv_tuner_config cfg = {
|
||||
.fe = dvb->fe[n],
|
||||
.mock_power_up_delay_msec = mock_power_up_delay_msec,
|
||||
.mock_tune_delay_msec = mock_tune_delay_msec,
|
||||
};
|
||||
u32 freq;
|
||||
int i;
|
||||
|
||||
cfg.fe = dvb->fe[n];
|
||||
cfg.mock_power_up_delay_msec = mock_power_up_delay_msec;
|
||||
cfg.mock_tune_delay_msec = mock_tune_delay_msec;
|
||||
|
||||
/* TODO: check if the frequencies are at a valid range */
|
||||
|
||||
memcpy(cfg.vidtv_valid_dvb_t_freqs,
|
||||
@ -389,9 +405,7 @@ static int vidtv_bridge_probe_tuner(struct vidtv_dvb *dvb, u32 n)
|
||||
|
||||
static int vidtv_bridge_dvb_init(struct vidtv_dvb *dvb)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
int j;
|
||||
int ret, i, j;
|
||||
|
||||
ret = vidtv_bridge_i2c_register_adap(dvb);
|
||||
if (ret < 0)
|
||||
|
@ -20,9 +20,11 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <media/dmxdev.h>
|
||||
#include <media/dvb_demux.h>
|
||||
#include <media/dvb_frontend.h>
|
||||
|
||||
#include "vidtv_mux.h"
|
||||
|
||||
/**
|
||||
@ -32,7 +34,7 @@
|
||||
* @adapter: Represents a DTV adapter. See 'dvb_register_adapter'.
|
||||
* @demux: The demux used by the dvb_dmx_swfilter_packets() call.
|
||||
* @dmx_dev: Represents a demux device.
|
||||
* @dmx_frontend: The frontends associated with the demux.
|
||||
* @dmx_fe: The frontends associated with the demux.
|
||||
* @i2c_adapter: The i2c_adapter associated with the bridge driver.
|
||||
* @i2c_client_demod: The i2c_clients associated with the demodulator modules.
|
||||
* @i2c_client_tuner: The i2c_clients associated with the tuner modules.
|
||||
|
@ -9,6 +9,7 @@
|
||||
* When vidtv boots, it will create some hardcoded channels.
|
||||
* Their services will be concatenated to populate the SDT.
|
||||
* Their programs will be concatenated to populate the PAT
|
||||
* Their events will be concatenated to populate the EIT
|
||||
* For each program in the PAT, a PMT section will be created
|
||||
* The PMT section for a channel will be assigned its streams.
|
||||
* Every stream will have its corresponding encoder polled to produce TS packets
|
||||
@ -18,22 +19,22 @@
|
||||
* Copyright (C) 2020 Daniel W. S. Almeida
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "vidtv_channel.h"
|
||||
#include "vidtv_psi.h"
|
||||
#include "vidtv_common.h"
|
||||
#include "vidtv_encoder.h"
|
||||
#include "vidtv_mux.h"
|
||||
#include "vidtv_common.h"
|
||||
#include "vidtv_psi.h"
|
||||
#include "vidtv_s302m.h"
|
||||
|
||||
static void vidtv_channel_encoder_destroy(struct vidtv_encoder *e)
|
||||
{
|
||||
struct vidtv_encoder *curr = e;
|
||||
struct vidtv_encoder *tmp = NULL;
|
||||
struct vidtv_encoder *curr = e;
|
||||
|
||||
while (curr) {
|
||||
/* forward the call to the derived type */
|
||||
@ -44,55 +45,88 @@ static void vidtv_channel_encoder_destroy(struct vidtv_encoder *e)
|
||||
}
|
||||
|
||||
#define ENCODING_ISO8859_15 "\x0b"
|
||||
#define TS_NIT_PID 0x10
|
||||
|
||||
/*
|
||||
* init an audio only channel with a s302m encoder
|
||||
*/
|
||||
struct vidtv_channel
|
||||
*vidtv_channel_s302m_init(struct vidtv_channel *head, u16 transport_stream_id)
|
||||
{
|
||||
/*
|
||||
* init an audio only channel with a s302m encoder
|
||||
*/
|
||||
const __be32 s302m_fid = cpu_to_be32(VIDTV_S302M_FORMAT_IDENTIFIER);
|
||||
char *event_text = ENCODING_ISO8859_15 "Bagatelle No. 25 in A minor for solo piano, also known as F\xfcr Elise, composed by Ludwig van Beethoven";
|
||||
char *event_name = ENCODING_ISO8859_15 "Ludwig van Beethoven: F\xfcr Elise";
|
||||
struct vidtv_s302m_encoder_init_args encoder_args = {};
|
||||
char *iso_language_code = ENCODING_ISO8859_15 "eng";
|
||||
char *provider = ENCODING_ISO8859_15 "LinuxTV.org";
|
||||
char *name = ENCODING_ISO8859_15 "Beethoven";
|
||||
const u16 s302m_es_pid = 0x111; /* packet id for the ES */
|
||||
const u16 s302m_program_pid = 0x101; /* packet id for PMT*/
|
||||
const u16 s302m_service_id = 0x880;
|
||||
const u16 s302m_program_num = 0x880;
|
||||
const u16 s302m_program_pid = 0x101; /* packet id for PMT*/
|
||||
const u16 s302m_es_pid = 0x111; /* packet id for the ES */
|
||||
const __be32 s302m_fid = cpu_to_be32(VIDTV_S302M_FORMAT_IDENTIFIER);
|
||||
const u16 s302m_beethoven_event_id = 1;
|
||||
struct vidtv_channel *s302m;
|
||||
|
||||
char *name = ENCODING_ISO8859_15 "Beethoven";
|
||||
char *provider = ENCODING_ISO8859_15 "LinuxTV.org";
|
||||
|
||||
struct vidtv_channel *s302m = kzalloc(sizeof(*s302m), GFP_KERNEL);
|
||||
struct vidtv_s302m_encoder_init_args encoder_args = {};
|
||||
s302m = kzalloc(sizeof(*s302m), GFP_KERNEL);
|
||||
if (!s302m)
|
||||
return NULL;
|
||||
|
||||
s302m->name = kstrdup(name, GFP_KERNEL);
|
||||
if (!s302m->name)
|
||||
goto free_s302m;
|
||||
|
||||
s302m->service = vidtv_psi_sdt_service_init(NULL, s302m_service_id);
|
||||
s302m->service = vidtv_psi_sdt_service_init(NULL, s302m_service_id, false, true);
|
||||
if (!s302m->service)
|
||||
goto free_name;
|
||||
|
||||
s302m->service->descriptor = (struct vidtv_psi_desc *)
|
||||
vidtv_psi_service_desc_init(NULL,
|
||||
DIGITAL_TELEVISION_SERVICE,
|
||||
DIGITAL_RADIO_SOUND_SERVICE,
|
||||
name,
|
||||
provider);
|
||||
if (!s302m->service->descriptor)
|
||||
goto free_service;
|
||||
|
||||
s302m->transport_stream_id = transport_stream_id;
|
||||
|
||||
s302m->program = vidtv_psi_pat_program_init(NULL,
|
||||
s302m_service_id,
|
||||
s302m_program_pid);
|
||||
if (!s302m->program)
|
||||
goto free_service;
|
||||
|
||||
s302m->program_num = s302m_program_num;
|
||||
|
||||
s302m->streams = vidtv_psi_pmt_stream_init(NULL,
|
||||
STREAM_PRIVATE_DATA,
|
||||
s302m_es_pid);
|
||||
if (!s302m->streams)
|
||||
goto free_program;
|
||||
|
||||
s302m->streams->descriptor = (struct vidtv_psi_desc *)
|
||||
vidtv_psi_registration_desc_init(NULL,
|
||||
s302m_fid,
|
||||
NULL,
|
||||
0);
|
||||
if (!s302m->streams->descriptor)
|
||||
goto free_streams;
|
||||
|
||||
encoder_args.es_pid = s302m_es_pid;
|
||||
|
||||
s302m->encoders = vidtv_s302m_encoder_init(encoder_args);
|
||||
if (!s302m->encoders)
|
||||
goto free_streams;
|
||||
|
||||
s302m->events = vidtv_psi_eit_event_init(NULL, s302m_beethoven_event_id);
|
||||
if (!s302m->events)
|
||||
goto free_encoders;
|
||||
s302m->events->descriptor = (struct vidtv_psi_desc *)
|
||||
vidtv_psi_short_event_desc_init(NULL,
|
||||
iso_language_code,
|
||||
event_name,
|
||||
event_text);
|
||||
if (!s302m->events->descriptor)
|
||||
goto free_events;
|
||||
|
||||
if (head) {
|
||||
while (head->next)
|
||||
@ -102,6 +136,68 @@ struct vidtv_channel
|
||||
}
|
||||
|
||||
return s302m;
|
||||
|
||||
free_events:
|
||||
vidtv_psi_eit_event_destroy(s302m->events);
|
||||
free_encoders:
|
||||
vidtv_s302m_encoder_destroy(s302m->encoders);
|
||||
free_streams:
|
||||
vidtv_psi_pmt_stream_destroy(s302m->streams);
|
||||
free_program:
|
||||
vidtv_psi_pat_program_destroy(s302m->program);
|
||||
free_service:
|
||||
vidtv_psi_sdt_service_destroy(s302m->service);
|
||||
free_name:
|
||||
kfree(s302m->name);
|
||||
free_s302m:
|
||||
kfree(s302m);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct vidtv_psi_table_eit_event
|
||||
*vidtv_channel_eit_event_cat_into_new(struct vidtv_mux *m)
|
||||
{
|
||||
/* Concatenate the events */
|
||||
const struct vidtv_channel *cur_chnl = m->channels;
|
||||
struct vidtv_psi_table_eit_event *curr = NULL;
|
||||
struct vidtv_psi_table_eit_event *head = NULL;
|
||||
struct vidtv_psi_table_eit_event *tail = NULL;
|
||||
struct vidtv_psi_desc *desc = NULL;
|
||||
u16 event_id;
|
||||
|
||||
if (!cur_chnl)
|
||||
return NULL;
|
||||
|
||||
while (cur_chnl) {
|
||||
curr = cur_chnl->events;
|
||||
|
||||
if (!curr)
|
||||
dev_warn_ratelimited(m->dev,
|
||||
"No events found for channel %s\n",
|
||||
cur_chnl->name);
|
||||
|
||||
while (curr) {
|
||||
event_id = be16_to_cpu(curr->event_id);
|
||||
tail = vidtv_psi_eit_event_init(tail, event_id);
|
||||
if (!tail) {
|
||||
vidtv_psi_eit_event_destroy(head);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
desc = vidtv_psi_desc_clone(curr->descriptor);
|
||||
vidtv_psi_desc_assign(&tail->descriptor, desc);
|
||||
|
||||
if (!head)
|
||||
head = tail;
|
||||
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
cur_chnl = cur_chnl->next;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
static struct vidtv_psi_table_sdt_service
|
||||
@ -125,13 +221,21 @@ static struct vidtv_psi_table_sdt_service
|
||||
|
||||
if (!curr)
|
||||
dev_warn_ratelimited(m->dev,
|
||||
"No services found for channel %s\n", cur_chnl->name);
|
||||
"No services found for channel %s\n",
|
||||
cur_chnl->name);
|
||||
|
||||
while (curr) {
|
||||
service_id = be16_to_cpu(curr->service_id);
|
||||
tail = vidtv_psi_sdt_service_init(tail, service_id);
|
||||
tail = vidtv_psi_sdt_service_init(tail,
|
||||
service_id,
|
||||
curr->EIT_schedule,
|
||||
curr->EIT_present_following);
|
||||
if (!tail)
|
||||
goto free;
|
||||
|
||||
desc = vidtv_psi_desc_clone(curr->descriptor);
|
||||
if (!desc)
|
||||
goto free_tail;
|
||||
vidtv_psi_desc_assign(&tail->descriptor, desc);
|
||||
|
||||
if (!head)
|
||||
@ -144,6 +248,12 @@ static struct vidtv_psi_table_sdt_service
|
||||
}
|
||||
|
||||
return head;
|
||||
|
||||
free_tail:
|
||||
vidtv_psi_sdt_service_destroy(tail);
|
||||
free:
|
||||
vidtv_psi_sdt_service_destroy(head);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct vidtv_psi_table_pat_program*
|
||||
@ -174,6 +284,10 @@ vidtv_channel_pat_prog_cat_into_new(struct vidtv_mux *m)
|
||||
tail = vidtv_psi_pat_program_init(tail,
|
||||
serv_id,
|
||||
pid);
|
||||
if (!tail) {
|
||||
vidtv_psi_pat_program_destroy(head);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!head)
|
||||
head = tail;
|
||||
@ -183,30 +297,30 @@ vidtv_channel_pat_prog_cat_into_new(struct vidtv_mux *m)
|
||||
|
||||
cur_chnl = cur_chnl->next;
|
||||
}
|
||||
/* Add the NIT table */
|
||||
vidtv_psi_pat_program_init(tail, 0, TS_NIT_PID);
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Match channels to their respective PMT sections, then assign the
|
||||
* streams
|
||||
*/
|
||||
static void
|
||||
vidtv_channel_pmt_match_sections(struct vidtv_channel *channels,
|
||||
struct vidtv_psi_table_pmt **sections,
|
||||
u32 nsections)
|
||||
{
|
||||
/*
|
||||
* Match channels to their respective PMT sections, then assign the
|
||||
* streams
|
||||
*/
|
||||
struct vidtv_psi_table_pmt *curr_section = NULL;
|
||||
struct vidtv_channel *cur_chnl = channels;
|
||||
|
||||
struct vidtv_psi_table_pmt_stream *s = NULL;
|
||||
struct vidtv_psi_table_pmt_stream *head = NULL;
|
||||
struct vidtv_psi_table_pmt_stream *tail = NULL;
|
||||
|
||||
struct vidtv_psi_table_pmt_stream *s = NULL;
|
||||
struct vidtv_channel *cur_chnl = channels;
|
||||
struct vidtv_psi_desc *desc = NULL;
|
||||
u32 j;
|
||||
u16 curr_id;
|
||||
u16 e_pid; /* elementary stream pid */
|
||||
u16 curr_id;
|
||||
u32 j;
|
||||
|
||||
while (cur_chnl) {
|
||||
for (j = 0; j < nsections; ++j) {
|
||||
@ -232,7 +346,8 @@ vidtv_channel_pmt_match_sections(struct vidtv_channel *channels,
|
||||
head = tail;
|
||||
|
||||
desc = vidtv_psi_desc_clone(s->descriptor);
|
||||
vidtv_psi_desc_assign(&tail->descriptor, desc);
|
||||
vidtv_psi_desc_assign(&tail->descriptor,
|
||||
desc);
|
||||
|
||||
s = s->next;
|
||||
}
|
||||
@ -246,17 +361,103 @@ vidtv_channel_pmt_match_sections(struct vidtv_channel *channels,
|
||||
}
|
||||
}
|
||||
|
||||
void vidtv_channel_si_init(struct vidtv_mux *m)
|
||||
static void
|
||||
vidtv_channel_destroy_service_list(struct vidtv_psi_desc_service_list_entry *e)
|
||||
{
|
||||
struct vidtv_psi_desc_service_list_entry *tmp;
|
||||
|
||||
while (e) {
|
||||
tmp = e;
|
||||
e = e->next;
|
||||
kfree(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static struct vidtv_psi_desc_service_list_entry
|
||||
*vidtv_channel_build_service_list(struct vidtv_psi_table_sdt_service *s)
|
||||
{
|
||||
struct vidtv_psi_desc_service_list_entry *curr_e = NULL;
|
||||
struct vidtv_psi_desc_service_list_entry *head_e = NULL;
|
||||
struct vidtv_psi_desc_service_list_entry *prev_e = NULL;
|
||||
struct vidtv_psi_desc *desc = s->descriptor;
|
||||
struct vidtv_psi_desc_service *s_desc;
|
||||
|
||||
while (s) {
|
||||
while (desc) {
|
||||
if (s->descriptor->type != SERVICE_DESCRIPTOR)
|
||||
goto next_desc;
|
||||
|
||||
s_desc = (struct vidtv_psi_desc_service *)desc;
|
||||
|
||||
curr_e = kzalloc(sizeof(*curr_e), GFP_KERNEL);
|
||||
if (!curr_e) {
|
||||
vidtv_channel_destroy_service_list(head_e);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
curr_e->service_id = s->service_id;
|
||||
curr_e->service_type = s_desc->service_type;
|
||||
|
||||
if (!head_e)
|
||||
head_e = curr_e;
|
||||
if (prev_e)
|
||||
prev_e->next = curr_e;
|
||||
|
||||
prev_e = curr_e;
|
||||
|
||||
next_desc:
|
||||
desc = desc->next;
|
||||
}
|
||||
s = s->next;
|
||||
}
|
||||
return head_e;
|
||||
}
|
||||
|
||||
int vidtv_channel_si_init(struct vidtv_mux *m)
|
||||
{
|
||||
struct vidtv_psi_desc_service_list_entry *service_list = NULL;
|
||||
struct vidtv_psi_table_pat_program *programs = NULL;
|
||||
struct vidtv_psi_table_sdt_service *services = NULL;
|
||||
struct vidtv_psi_table_eit_event *events = NULL;
|
||||
|
||||
m->si.pat = vidtv_psi_pat_table_init(m->transport_stream_id);
|
||||
if (!m->si.pat)
|
||||
return -ENOMEM;
|
||||
|
||||
m->si.sdt = vidtv_psi_sdt_table_init(m->transport_stream_id);
|
||||
m->si.sdt = vidtv_psi_sdt_table_init(m->network_id,
|
||||
m->transport_stream_id);
|
||||
if (!m->si.sdt)
|
||||
goto free_pat;
|
||||
|
||||
programs = vidtv_channel_pat_prog_cat_into_new(m);
|
||||
if (!programs)
|
||||
goto free_sdt;
|
||||
services = vidtv_channel_sdt_serv_cat_into_new(m);
|
||||
if (!services)
|
||||
goto free_programs;
|
||||
|
||||
events = vidtv_channel_eit_event_cat_into_new(m);
|
||||
if (!events)
|
||||
goto free_services;
|
||||
|
||||
/* look for a service descriptor for every service */
|
||||
service_list = vidtv_channel_build_service_list(services);
|
||||
if (!service_list)
|
||||
goto free_events;
|
||||
|
||||
/* use these descriptors to build the NIT */
|
||||
m->si.nit = vidtv_psi_nit_table_init(m->network_id,
|
||||
m->transport_stream_id,
|
||||
m->network_name,
|
||||
service_list);
|
||||
if (!m->si.nit)
|
||||
goto free_service_list;
|
||||
|
||||
m->si.eit = vidtv_psi_eit_table_init(m->network_id,
|
||||
m->transport_stream_id,
|
||||
programs->service_id);
|
||||
if (!m->si.eit)
|
||||
goto free_nit;
|
||||
|
||||
/* assemble all programs and assign to PAT */
|
||||
vidtv_psi_pat_program_assign(m->si.pat, programs);
|
||||
@ -264,31 +465,65 @@ void vidtv_channel_si_init(struct vidtv_mux *m)
|
||||
/* assemble all services and assign to SDT */
|
||||
vidtv_psi_sdt_service_assign(m->si.sdt, services);
|
||||
|
||||
m->si.pmt_secs = vidtv_psi_pmt_create_sec_for_each_pat_entry(m->si.pat, m->pcr_pid);
|
||||
/* assemble all events and assign to EIT */
|
||||
vidtv_psi_eit_event_assign(m->si.eit, events);
|
||||
|
||||
m->si.pmt_secs = vidtv_psi_pmt_create_sec_for_each_pat_entry(m->si.pat,
|
||||
m->pcr_pid);
|
||||
if (!m->si.pmt_secs)
|
||||
goto free_eit;
|
||||
|
||||
vidtv_channel_pmt_match_sections(m->channels,
|
||||
m->si.pmt_secs,
|
||||
m->si.pat->programs);
|
||||
m->si.pat->num_pmt);
|
||||
|
||||
vidtv_channel_destroy_service_list(service_list);
|
||||
|
||||
return 0;
|
||||
|
||||
free_eit:
|
||||
vidtv_psi_eit_table_destroy(m->si.eit);
|
||||
free_nit:
|
||||
vidtv_psi_nit_table_destroy(m->si.nit);
|
||||
free_service_list:
|
||||
vidtv_channel_destroy_service_list(service_list);
|
||||
free_events:
|
||||
vidtv_psi_eit_event_destroy(events);
|
||||
free_services:
|
||||
vidtv_psi_sdt_service_destroy(services);
|
||||
free_programs:
|
||||
vidtv_psi_pat_program_destroy(programs);
|
||||
free_sdt:
|
||||
vidtv_psi_sdt_table_destroy(m->si.sdt);
|
||||
free_pat:
|
||||
vidtv_psi_pat_table_destroy(m->si.pat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vidtv_channel_si_destroy(struct vidtv_mux *m)
|
||||
{
|
||||
u32 i;
|
||||
u16 num_programs = m->si.pat->programs;
|
||||
|
||||
vidtv_psi_pat_table_destroy(m->si.pat);
|
||||
|
||||
for (i = 0; i < num_programs; ++i)
|
||||
for (i = 0; i < m->si.pat->num_pmt; ++i)
|
||||
vidtv_psi_pmt_table_destroy(m->si.pmt_secs[i]);
|
||||
|
||||
kfree(m->si.pmt_secs);
|
||||
vidtv_psi_sdt_table_destroy(m->si.sdt);
|
||||
vidtv_psi_nit_table_destroy(m->si.nit);
|
||||
vidtv_psi_eit_table_destroy(m->si.eit);
|
||||
}
|
||||
|
||||
void vidtv_channels_init(struct vidtv_mux *m)
|
||||
int vidtv_channels_init(struct vidtv_mux *m)
|
||||
{
|
||||
/* this is the place to add new 'channels' for vidtv */
|
||||
m->channels = vidtv_channel_s302m_init(NULL, m->transport_stream_id);
|
||||
|
||||
if (!m->channels)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vidtv_channels_destroy(struct vidtv_mux *m)
|
||||
@ -302,6 +537,7 @@ void vidtv_channels_destroy(struct vidtv_mux *m)
|
||||
vidtv_psi_pat_program_destroy(curr->program);
|
||||
vidtv_psi_pmt_stream_destroy(curr->streams);
|
||||
vidtv_channel_encoder_destroy(curr->encoders);
|
||||
vidtv_psi_eit_event_destroy(curr->events);
|
||||
|
||||
tmp = curr;
|
||||
curr = curr->next;
|
||||
|
@ -9,6 +9,7 @@
|
||||
* When vidtv boots, it will create some hardcoded channels.
|
||||
* Their services will be concatenated to populate the SDT.
|
||||
* Their programs will be concatenated to populate the PAT
|
||||
* Their events will be concatenated to populate the EIT
|
||||
* For each program in the PAT, a PMT section will be created
|
||||
* The PMT section for a channel will be assigned its streams.
|
||||
* Every stream will have its corresponding encoder polled to produce TS packets
|
||||
@ -22,9 +23,10 @@
|
||||
#define VIDTV_CHANNEL_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include "vidtv_psi.h"
|
||||
|
||||
#include "vidtv_encoder.h"
|
||||
#include "vidtv_mux.h"
|
||||
#include "vidtv_psi.h"
|
||||
|
||||
/**
|
||||
* struct vidtv_channel - A 'channel' abstraction
|
||||
@ -37,6 +39,7 @@
|
||||
* Every stream will have its corresponding encoder polled to produce TS packets
|
||||
* These packets may be interleaved by the mux and then delivered to the bridge
|
||||
*
|
||||
* @name: name of the channel
|
||||
* @transport_stream_id: a number to identify the TS, chosen at will.
|
||||
* @service: A _single_ service. Will be concatenated into the SDT.
|
||||
* @program_num: The link between PAT, PMT and SDT.
|
||||
@ -44,6 +47,7 @@
|
||||
* Will be concatenated into the PAT.
|
||||
* @streams: A stream loop used to populate the PMT section for 'program'
|
||||
* @encoders: A encoder loop. There must be one encoder for each stream.
|
||||
* @events: Optional event information. This will feed into the EIT.
|
||||
* @next: Optionally chain this channel.
|
||||
*/
|
||||
struct vidtv_channel {
|
||||
@ -54,6 +58,7 @@ struct vidtv_channel {
|
||||
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;
|
||||
};
|
||||
|
||||
@ -61,14 +66,14 @@ struct vidtv_channel {
|
||||
* vidtv_channel_si_init - Init the PSI tables from the channels in the mux
|
||||
* @m: The mux containing the channels.
|
||||
*/
|
||||
void vidtv_channel_si_init(struct vidtv_mux *m);
|
||||
int vidtv_channel_si_init(struct vidtv_mux *m);
|
||||
void vidtv_channel_si_destroy(struct vidtv_mux *m);
|
||||
|
||||
/**
|
||||
* vidtv_channels_init - Init hardcoded, fake 'channels'.
|
||||
* @m: The mux to store the channels into.
|
||||
*/
|
||||
void vidtv_channels_init(struct vidtv_mux *m);
|
||||
int vidtv_channels_init(struct vidtv_mux *m);
|
||||
struct vidtv_channel
|
||||
*vidtv_channel_s302m_init(struct vidtv_channel *head, u16 transport_stream_id);
|
||||
void vidtv_channels_destroy(struct vidtv_mux *m);
|
||||
|
@ -16,7 +16,6 @@
|
||||
#define CLOCK_UNIT_27MHZ 27000000
|
||||
#define VIDTV_SLEEP_USECS 10000
|
||||
#define VIDTV_MAX_SLEEP_USECS (2 * VIDTV_SLEEP_USECS)
|
||||
#define VIDTV_DEFAULT_TS_ID 0x744
|
||||
|
||||
u32 vidtv_memcpy(void *to,
|
||||
size_t to_offset,
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <media/dvb_frontend.h>
|
||||
|
||||
#include "vidtv_demod.h"
|
||||
@ -192,7 +193,6 @@ static void vidtv_demod_update_stats(struct dvb_frontend *fe)
|
||||
|
||||
c->cnr.stat[0].svalue = state->tuner_cnr;
|
||||
c->cnr.stat[0].svalue -= prandom_u32_max(state->tuner_cnr / 50);
|
||||
|
||||
}
|
||||
|
||||
static int vidtv_demod_read_status(struct dvb_frontend *fe,
|
||||
|
@ -12,6 +12,7 @@
|
||||
#define VIDTV_DEMOD_H
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
#include <media/dvb_frontend.h>
|
||||
|
||||
/**
|
||||
@ -19,6 +20,9 @@
|
||||
* modulation and fec_inner
|
||||
* @modulation: see enum fe_modulation
|
||||
* @fec: see enum fe_fec_rate
|
||||
* @cnr_ok: S/N threshold to consider the signal as OK. Below that, there's
|
||||
* a chance of losing sync.
|
||||
* @cnr_good: S/N threshold to consider the signal strong.
|
||||
*
|
||||
* This struct matches values for 'good' and 'ok' CNRs given the combination
|
||||
* of modulation and fec_inner in use. We might simulate some noise if the
|
||||
@ -52,13 +56,8 @@ struct vidtv_demod_config {
|
||||
* struct vidtv_demod_state - The demodulator state
|
||||
* @frontend: The frontend structure allocated by the demod.
|
||||
* @config: The config used to init the demod.
|
||||
* @poll_snr: The task responsible for periodically checking the simulated
|
||||
* signal quality, eventually dropping or reacquiring the TS lock.
|
||||
* @status: the demod status.
|
||||
* @cold_start: Whether the demod has not been init yet.
|
||||
* @poll_snr_thread_running: Whether the task responsible for periodically
|
||||
* checking the simulated signal quality is running.
|
||||
* @poll_snr_thread_restart: Whether we should restart the poll_snr task.
|
||||
* @tuner_cnr: current S/N ratio for the signal carrier
|
||||
*/
|
||||
struct vidtv_demod_state {
|
||||
struct dvb_frontend frontend;
|
||||
|
@ -28,7 +28,7 @@ struct vidtv_access_unit {
|
||||
struct vidtv_access_unit *next;
|
||||
};
|
||||
|
||||
/* Some musical notes, used by a tone generator */
|
||||
/* Some musical notes, used by a tone generator. Values are in Hz */
|
||||
enum musical_notes {
|
||||
NOTE_SILENT = 0,
|
||||
|
||||
@ -103,14 +103,16 @@ enum musical_notes {
|
||||
* @encoder_buf_sz: The encoder buffer size, in bytes
|
||||
* @encoder_buf_offset: Our byte position in the encoder buffer.
|
||||
* @sample_count: How many samples we have encoded in total.
|
||||
* @access_units: encoder payload units, used for clock references
|
||||
* @src_buf: The source of raw data to be encoded, encoder might set a
|
||||
* default if null.
|
||||
* @src_buf_sz: size of @src_buf.
|
||||
* @src_buf_offset: Our position in the source buffer.
|
||||
* @is_video_encoder: Whether this a video encoder (as opposed to audio)
|
||||
* @ctx: Encoder-specific state.
|
||||
* @stream_id: Examples: Audio streams (0xc0-0xdf), Video streams
|
||||
* (0xe0-0xef).
|
||||
* @es_id: The TS PID to use for the elementary stream in this encoder.
|
||||
* @es_pid: The TS PID to use for the elementary stream in this encoder.
|
||||
* @encode: Prepare enough AUs for the given amount of time.
|
||||
* @clear: Clear the encoder output.
|
||||
* @sync: Attempt to synchronize with this encoder.
|
||||
@ -131,9 +133,6 @@ struct vidtv_encoder {
|
||||
u32 encoder_buf_offset;
|
||||
|
||||
u64 sample_count;
|
||||
int last_duration;
|
||||
int note_offset;
|
||||
enum musical_notes last_tone;
|
||||
|
||||
struct vidtv_access_unit *access_units;
|
||||
|
||||
|
@ -12,23 +12,23 @@
|
||||
* Copyright (C) 2020 Daniel W. S. Almeida
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "vidtv_mux.h"
|
||||
#include "vidtv_ts.h"
|
||||
#include "vidtv_pes.h"
|
||||
#include "vidtv_encoder.h"
|
||||
#include "vidtv_channel.h"
|
||||
#include "vidtv_common.h"
|
||||
#include "vidtv_encoder.h"
|
||||
#include "vidtv_mux.h"
|
||||
#include "vidtv_pes.h"
|
||||
#include "vidtv_psi.h"
|
||||
#include "vidtv_ts.h"
|
||||
|
||||
static struct vidtv_mux_pid_ctx
|
||||
*vidtv_mux_get_pid_ctx(struct vidtv_mux *m, u16 pid)
|
||||
@ -47,33 +47,56 @@ static struct vidtv_mux_pid_ctx
|
||||
struct vidtv_mux_pid_ctx *ctx;
|
||||
|
||||
ctx = vidtv_mux_get_pid_ctx(m, pid);
|
||||
|
||||
if (ctx)
|
||||
goto end;
|
||||
return ctx;
|
||||
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
ctx->pid = pid;
|
||||
ctx->cc = 0;
|
||||
hash_add(m->pid_ctx, &ctx->h, pid);
|
||||
|
||||
end:
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void vidtv_mux_pid_ctx_init(struct vidtv_mux *m)
|
||||
static void vidtv_mux_pid_ctx_destroy(struct vidtv_mux *m)
|
||||
{
|
||||
struct vidtv_mux_pid_ctx *ctx;
|
||||
struct hlist_node *tmp;
|
||||
int bkt;
|
||||
|
||||
hash_for_each_safe(m->pid_ctx, bkt, tmp, ctx, h) {
|
||||
hash_del(&ctx->h);
|
||||
kfree(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static int vidtv_mux_pid_ctx_init(struct vidtv_mux *m)
|
||||
{
|
||||
struct vidtv_psi_table_pat_program *p = m->si.pat->program;
|
||||
u16 pid;
|
||||
|
||||
hash_init(m->pid_ctx);
|
||||
/* push the pcr pid ctx */
|
||||
vidtv_mux_create_pid_ctx_once(m, m->pcr_pid);
|
||||
/* push the null packet pid ctx */
|
||||
vidtv_mux_create_pid_ctx_once(m, TS_NULL_PACKET_PID);
|
||||
if (!vidtv_mux_create_pid_ctx_once(m, m->pcr_pid))
|
||||
return -ENOMEM;
|
||||
/* push the NULL packet pid ctx */
|
||||
if (!vidtv_mux_create_pid_ctx_once(m, TS_NULL_PACKET_PID))
|
||||
goto free;
|
||||
/* push the PAT pid ctx */
|
||||
vidtv_mux_create_pid_ctx_once(m, VIDTV_PAT_PID);
|
||||
if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_PAT_PID))
|
||||
goto free;
|
||||
/* push the SDT pid ctx */
|
||||
vidtv_mux_create_pid_ctx_once(m, VIDTV_SDT_PID);
|
||||
if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_SDT_PID))
|
||||
goto free;
|
||||
/* push the NIT pid ctx */
|
||||
if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_NIT_PID))
|
||||
goto free;
|
||||
/* push the EIT pid ctx */
|
||||
if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_EIT_PID))
|
||||
goto free;
|
||||
|
||||
/* add a ctx for all PMT sections */
|
||||
while (p) {
|
||||
@ -81,18 +104,12 @@ static void vidtv_mux_pid_ctx_init(struct vidtv_mux *m)
|
||||
vidtv_mux_create_pid_ctx_once(m, pid);
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void vidtv_mux_pid_ctx_destroy(struct vidtv_mux *m)
|
||||
{
|
||||
int bkt;
|
||||
struct vidtv_mux_pid_ctx *ctx;
|
||||
struct hlist_node *tmp;
|
||||
return 0;
|
||||
|
||||
hash_for_each_safe(m->pid_ctx, bkt, tmp, ctx, h) {
|
||||
hash_del(&ctx->h);
|
||||
kfree(ctx);
|
||||
}
|
||||
free:
|
||||
vidtv_mux_pid_ctx_destroy(m);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void vidtv_mux_update_clk(struct vidtv_mux *m)
|
||||
@ -112,32 +129,53 @@ static void vidtv_mux_update_clk(struct vidtv_mux *m)
|
||||
|
||||
static u32 vidtv_mux_push_si(struct vidtv_mux *m)
|
||||
{
|
||||
u32 initial_offset = m->mux_buf_offset;
|
||||
struct vidtv_psi_pat_write_args pat_args = {
|
||||
.buf = m->mux_buf,
|
||||
.buf_sz = m->mux_buf_sz,
|
||||
.pat = m->si.pat,
|
||||
};
|
||||
struct vidtv_psi_pmt_write_args pmt_args = {
|
||||
.buf = m->mux_buf,
|
||||
.buf_sz = m->mux_buf_sz,
|
||||
.pcr_pid = m->pcr_pid,
|
||||
};
|
||||
struct vidtv_psi_sdt_write_args sdt_args = {
|
||||
.buf = m->mux_buf,
|
||||
.buf_sz = m->mux_buf_sz,
|
||||
.sdt = m->si.sdt,
|
||||
};
|
||||
struct vidtv_psi_nit_write_args nit_args = {
|
||||
.buf = m->mux_buf,
|
||||
.buf_sz = m->mux_buf_sz,
|
||||
.nit = m->si.nit,
|
||||
|
||||
};
|
||||
struct vidtv_psi_eit_write_args eit_args = {
|
||||
.buf = m->mux_buf,
|
||||
.buf_sz = m->mux_buf_sz,
|
||||
.eit = m->si.eit,
|
||||
};
|
||||
u32 initial_offset = m->mux_buf_offset;
|
||||
struct vidtv_mux_pid_ctx *pat_ctx;
|
||||
struct vidtv_mux_pid_ctx *pmt_ctx;
|
||||
struct vidtv_mux_pid_ctx *sdt_ctx;
|
||||
|
||||
struct vidtv_psi_pat_write_args pat_args = {};
|
||||
struct vidtv_psi_pmt_write_args pmt_args = {};
|
||||
struct vidtv_psi_sdt_write_args sdt_args = {};
|
||||
|
||||
u32 nbytes; /* the number of bytes written by this function */
|
||||
struct vidtv_mux_pid_ctx *nit_ctx;
|
||||
struct vidtv_mux_pid_ctx *eit_ctx;
|
||||
u32 nbytes;
|
||||
u16 pmt_pid;
|
||||
u32 i;
|
||||
|
||||
pat_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_PAT_PID);
|
||||
sdt_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_SDT_PID);
|
||||
nit_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_NIT_PID);
|
||||
eit_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_EIT_PID);
|
||||
|
||||
pat_args.buf = m->mux_buf;
|
||||
pat_args.offset = m->mux_buf_offset;
|
||||
pat_args.pat = m->si.pat;
|
||||
pat_args.buf_sz = m->mux_buf_sz;
|
||||
pat_args.continuity_counter = &pat_ctx->cc;
|
||||
|
||||
m->mux_buf_offset += vidtv_psi_pat_write_into(pat_args);
|
||||
m->mux_buf_offset += vidtv_psi_pat_write_into(&pat_args);
|
||||
|
||||
for (i = 0; i < m->si.pat->programs; ++i) {
|
||||
for (i = 0; i < m->si.pat->num_pmt; ++i) {
|
||||
pmt_pid = vidtv_psi_pmt_get_pid(m->si.pmt_secs[i],
|
||||
m->si.pat);
|
||||
|
||||
@ -149,25 +187,29 @@ static u32 vidtv_mux_push_si(struct vidtv_mux *m)
|
||||
|
||||
pmt_ctx = vidtv_mux_get_pid_ctx(m, pmt_pid);
|
||||
|
||||
pmt_args.buf = m->mux_buf;
|
||||
pmt_args.offset = m->mux_buf_offset;
|
||||
pmt_args.pmt = m->si.pmt_secs[i];
|
||||
pmt_args.pid = pmt_pid;
|
||||
pmt_args.buf_sz = m->mux_buf_sz;
|
||||
pmt_args.continuity_counter = &pmt_ctx->cc;
|
||||
pmt_args.pcr_pid = m->pcr_pid;
|
||||
|
||||
/* write each section into buffer */
|
||||
m->mux_buf_offset += vidtv_psi_pmt_write_into(pmt_args);
|
||||
m->mux_buf_offset += vidtv_psi_pmt_write_into(&pmt_args);
|
||||
}
|
||||
|
||||
sdt_args.buf = m->mux_buf;
|
||||
sdt_args.offset = m->mux_buf_offset;
|
||||
sdt_args.sdt = m->si.sdt;
|
||||
sdt_args.buf_sz = m->mux_buf_sz;
|
||||
sdt_args.continuity_counter = &sdt_ctx->cc;
|
||||
|
||||
m->mux_buf_offset += vidtv_psi_sdt_write_into(sdt_args);
|
||||
m->mux_buf_offset += vidtv_psi_sdt_write_into(&sdt_args);
|
||||
|
||||
nit_args.offset = m->mux_buf_offset;
|
||||
nit_args.continuity_counter = &nit_ctx->cc;
|
||||
|
||||
m->mux_buf_offset += vidtv_psi_nit_write_into(&nit_args);
|
||||
|
||||
eit_args.offset = m->mux_buf_offset;
|
||||
eit_args.continuity_counter = &eit_ctx->cc;
|
||||
|
||||
m->mux_buf_offset += vidtv_psi_eit_write_into(&eit_args);
|
||||
|
||||
nbytes = m->mux_buf_offset - initial_offset;
|
||||
|
||||
@ -230,23 +272,29 @@ static bool vidtv_mux_should_push_si(struct vidtv_mux *m)
|
||||
static u32 vidtv_mux_packetize_access_units(struct vidtv_mux *m,
|
||||
struct vidtv_encoder *e)
|
||||
{
|
||||
u32 nbytes = 0;
|
||||
|
||||
struct pes_write_args args = {};
|
||||
u32 initial_offset = m->mux_buf_offset;
|
||||
struct pes_write_args args = {
|
||||
.dest_buf = m->mux_buf,
|
||||
.dest_buf_sz = m->mux_buf_sz,
|
||||
.pid = be16_to_cpu(e->es_pid),
|
||||
.encoder_id = e->id,
|
||||
.stream_id = be16_to_cpu(e->stream_id),
|
||||
.send_pts = true, /* forbidden value '01'... */
|
||||
.send_dts = false, /* ...for PTS_DTS flags */
|
||||
};
|
||||
struct vidtv_access_unit *au = e->access_units;
|
||||
|
||||
u32 initial_offset = m->mux_buf_offset;
|
||||
struct vidtv_mux_pid_ctx *pid_ctx;
|
||||
u32 nbytes = 0;
|
||||
u8 *buf = NULL;
|
||||
struct vidtv_mux_pid_ctx *pid_ctx = vidtv_mux_create_pid_ctx_once(m,
|
||||
be16_to_cpu(e->es_pid));
|
||||
|
||||
args.dest_buf = m->mux_buf;
|
||||
args.dest_buf_sz = m->mux_buf_sz;
|
||||
args.pid = be16_to_cpu(e->es_pid);
|
||||
args.encoder_id = e->id;
|
||||
/* see SMPTE 302M clause 6.4 */
|
||||
if (args.encoder_id == S302M) {
|
||||
args.send_dts = false;
|
||||
args.send_pts = true;
|
||||
}
|
||||
|
||||
pid_ctx = vidtv_mux_create_pid_ctx_once(m, be16_to_cpu(e->es_pid));
|
||||
args.continuity_counter = &pid_ctx->cc;
|
||||
args.stream_id = be16_to_cpu(e->stream_id);
|
||||
args.send_pts = true;
|
||||
|
||||
while (au) {
|
||||
buf = e->encoder_buf + au->offset;
|
||||
@ -256,7 +304,7 @@ static u32 vidtv_mux_packetize_access_units(struct vidtv_mux *m,
|
||||
args.pts = au->pts;
|
||||
args.pcr = m->timing.clk;
|
||||
|
||||
m->mux_buf_offset += vidtv_pes_write_into(args);
|
||||
m->mux_buf_offset += vidtv_pes_write_into(&args);
|
||||
|
||||
au = au->next;
|
||||
}
|
||||
@ -273,10 +321,10 @@ static u32 vidtv_mux_packetize_access_units(struct vidtv_mux *m,
|
||||
|
||||
static u32 vidtv_mux_poll_encoders(struct vidtv_mux *m)
|
||||
{
|
||||
u32 nbytes = 0;
|
||||
u32 au_nbytes;
|
||||
struct vidtv_channel *cur_chnl = m->channels;
|
||||
struct vidtv_encoder *e = NULL;
|
||||
u32 nbytes = 0;
|
||||
u32 au_nbytes;
|
||||
|
||||
while (cur_chnl) {
|
||||
e = cur_chnl->encoders;
|
||||
@ -300,18 +348,19 @@ static u32 vidtv_mux_poll_encoders(struct vidtv_mux *m)
|
||||
|
||||
static u32 vidtv_mux_pad_with_nulls(struct vidtv_mux *m, u32 npkts)
|
||||
{
|
||||
struct null_packet_write_args args = {};
|
||||
struct null_packet_write_args args = {
|
||||
.dest_buf = m->mux_buf,
|
||||
.buf_sz = m->mux_buf_sz,
|
||||
.dest_offset = m->mux_buf_offset,
|
||||
};
|
||||
u32 initial_offset = m->mux_buf_offset;
|
||||
u32 nbytes; /* the number of bytes written by this function */
|
||||
u32 i;
|
||||
struct vidtv_mux_pid_ctx *ctx;
|
||||
u32 nbytes;
|
||||
u32 i;
|
||||
|
||||
ctx = vidtv_mux_get_pid_ctx(m, TS_NULL_PACKET_PID);
|
||||
|
||||
args.dest_buf = m->mux_buf;
|
||||
args.buf_sz = m->mux_buf_sz;
|
||||
args.continuity_counter = &ctx->cc;
|
||||
args.dest_offset = m->mux_buf_offset;
|
||||
|
||||
for (i = 0; i < npkts; ++i) {
|
||||
m->mux_buf_offset += vidtv_ts_null_write_into(args);
|
||||
@ -343,9 +392,9 @@ static void vidtv_mux_tick(struct work_struct *work)
|
||||
struct vidtv_mux,
|
||||
mpeg_thread);
|
||||
struct dtv_frontend_properties *c = &m->fe->dtv_property_cache;
|
||||
u32 tot_bits = 0;
|
||||
u32 nbytes;
|
||||
u32 npkts;
|
||||
u32 tot_bits = 0;
|
||||
|
||||
while (m->streaming) {
|
||||
nbytes = 0;
|
||||
@ -427,40 +476,62 @@ void vidtv_mux_stop_thread(struct vidtv_mux *m)
|
||||
|
||||
struct vidtv_mux *vidtv_mux_init(struct dvb_frontend *fe,
|
||||
struct device *dev,
|
||||
struct vidtv_mux_init_args args)
|
||||
struct vidtv_mux_init_args *args)
|
||||
{
|
||||
struct vidtv_mux *m = kzalloc(sizeof(*m), GFP_KERNEL);
|
||||
struct vidtv_mux *m;
|
||||
|
||||
m = kzalloc(sizeof(*m), GFP_KERNEL);
|
||||
if (!m)
|
||||
return NULL;
|
||||
|
||||
m->dev = dev;
|
||||
m->fe = fe;
|
||||
m->timing.pcr_period_usecs = args.pcr_period_usecs;
|
||||
m->timing.si_period_usecs = args.si_period_usecs;
|
||||
m->timing.pcr_period_usecs = args->pcr_period_usecs;
|
||||
m->timing.si_period_usecs = args->si_period_usecs;
|
||||
|
||||
m->mux_rate_kbytes_sec = args.mux_rate_kbytes_sec;
|
||||
m->mux_rate_kbytes_sec = args->mux_rate_kbytes_sec;
|
||||
|
||||
m->on_new_packets_available_cb = args.on_new_packets_available_cb;
|
||||
m->on_new_packets_available_cb = args->on_new_packets_available_cb;
|
||||
|
||||
m->mux_buf = vzalloc(args.mux_buf_sz);
|
||||
m->mux_buf_sz = args.mux_buf_sz;
|
||||
m->mux_buf = vzalloc(args->mux_buf_sz);
|
||||
if (!m->mux_buf)
|
||||
goto free_mux;
|
||||
|
||||
m->pcr_pid = args.pcr_pid;
|
||||
m->transport_stream_id = args.transport_stream_id;
|
||||
m->priv = args.priv;
|
||||
m->mux_buf_sz = args->mux_buf_sz;
|
||||
|
||||
m->pcr_pid = args->pcr_pid;
|
||||
m->transport_stream_id = args->transport_stream_id;
|
||||
m->priv = args->priv;
|
||||
m->network_id = args->network_id;
|
||||
m->network_name = kstrdup(args->network_name, GFP_KERNEL);
|
||||
m->timing.current_jiffies = get_jiffies_64();
|
||||
|
||||
if (args.channels)
|
||||
m->channels = args.channels;
|
||||
if (args->channels)
|
||||
m->channels = args->channels;
|
||||
else
|
||||
vidtv_channels_init(m);
|
||||
if (vidtv_channels_init(m) < 0)
|
||||
goto free_mux_buf;
|
||||
|
||||
/* will alloc data for pmt_sections after initializing pat */
|
||||
vidtv_channel_si_init(m);
|
||||
if (vidtv_channel_si_init(m) < 0)
|
||||
goto free_channels;
|
||||
|
||||
INIT_WORK(&m->mpeg_thread, vidtv_mux_tick);
|
||||
|
||||
vidtv_mux_pid_ctx_init(m);
|
||||
if (vidtv_mux_pid_ctx_init(m) < 0)
|
||||
goto free_channel_si;
|
||||
|
||||
return m;
|
||||
|
||||
free_channel_si:
|
||||
vidtv_channel_si_destroy(m);
|
||||
free_channels:
|
||||
vidtv_channels_destroy(m);
|
||||
free_mux_buf:
|
||||
vfree(m->mux_buf);
|
||||
free_mux:
|
||||
kfree(m);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void vidtv_mux_destroy(struct vidtv_mux *m)
|
||||
@ -469,6 +540,7 @@ void vidtv_mux_destroy(struct vidtv_mux *m)
|
||||
vidtv_mux_pid_ctx_destroy(m);
|
||||
vidtv_channel_si_destroy(m);
|
||||
vidtv_channels_destroy(m);
|
||||
kfree(m->network_name);
|
||||
vfree(m->mux_buf);
|
||||
kfree(m);
|
||||
}
|
||||
|
@ -15,9 +15,10 @@
|
||||
#ifndef VIDTV_MUX_H
|
||||
#define VIDTV_MUX_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <media/dvb_frontend.h>
|
||||
|
||||
#include "vidtv_psi.h"
|
||||
@ -58,12 +59,16 @@ struct vidtv_mux_timing {
|
||||
* @pat: The PAT in use by the muxer.
|
||||
* @pmt_secs: The PMT sections in use by the muxer. One for each program in the PAT.
|
||||
* @sdt: The SDT in use by the muxer.
|
||||
* @nit: The NIT in use by the muxer.
|
||||
* @eit: the EIT in use by the muxer.
|
||||
*/
|
||||
struct vidtv_mux_si {
|
||||
/* the SI tables */
|
||||
struct vidtv_psi_table_pat *pat;
|
||||
struct vidtv_psi_table_pmt **pmt_secs; /* the PMT sections */
|
||||
struct vidtv_psi_table_sdt *sdt;
|
||||
struct vidtv_psi_table_nit *nit;
|
||||
struct vidtv_psi_table_eit *eit;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -82,8 +87,10 @@ struct vidtv_mux_pid_ctx {
|
||||
|
||||
/**
|
||||
* struct vidtv_mux - A muxer abstraction loosely based in libavcodec/mpegtsenc.c
|
||||
* @mux_rate_kbytes_sec: The bit rate for the TS, in kbytes.
|
||||
* @fe: The frontend structure allocated by the muxer.
|
||||
* @dev: pointer to struct device.
|
||||
* @timing: Keeps track of timing related information.
|
||||
* @mux_rate_kbytes_sec: The bit rate for the TS, in kbytes.
|
||||
* @pid_ctx: A hash table to keep track of per-PID metadata.
|
||||
* @on_new_packets_available_cb: A callback to inform of new TS packets ready.
|
||||
* @mux_buf: A pointer to a buffer for this muxer. TS packets are stored there
|
||||
@ -99,6 +106,8 @@ struct vidtv_mux_pid_ctx {
|
||||
* @pcr_pid: The TS PID used for the PSI packets. All channels will share the
|
||||
* same PCR.
|
||||
* @transport_stream_id: The transport stream ID
|
||||
* @network_id: The network ID
|
||||
* @network_name: The network name
|
||||
* @priv: Private data.
|
||||
*/
|
||||
struct vidtv_mux {
|
||||
@ -128,6 +137,8 @@ struct vidtv_mux {
|
||||
|
||||
u16 pcr_pid;
|
||||
u16 transport_stream_id;
|
||||
u16 network_id;
|
||||
char *network_name;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
@ -142,6 +153,8 @@ struct vidtv_mux {
|
||||
* same PCR.
|
||||
* @transport_stream_id: The transport stream ID
|
||||
* @channels: an optional list of channels to use
|
||||
* @network_id: The network ID
|
||||
* @network_name: The network name
|
||||
* @priv: Private data.
|
||||
*/
|
||||
struct vidtv_mux_init_args {
|
||||
@ -153,12 +166,14 @@ struct vidtv_mux_init_args {
|
||||
u16 pcr_pid;
|
||||
u16 transport_stream_id;
|
||||
struct vidtv_channel *channels;
|
||||
u16 network_id;
|
||||
char *network_name;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct vidtv_mux *vidtv_mux_init(struct dvb_frontend *fe,
|
||||
struct device *dev,
|
||||
struct vidtv_mux_init_args args);
|
||||
struct vidtv_mux_init_args *args);
|
||||
void vidtv_mux_destroy(struct vidtv_mux *m);
|
||||
|
||||
void vidtv_mux_start_thread(struct vidtv_mux *m);
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "vidtv_pes.h"
|
||||
#include "vidtv_common.h"
|
||||
@ -57,7 +56,7 @@ static u32 vidtv_pes_h_get_len(bool send_pts, bool send_dts)
|
||||
return len;
|
||||
}
|
||||
|
||||
static u32 vidtv_pes_write_header_stuffing(struct pes_header_write_args args)
|
||||
static u32 vidtv_pes_write_header_stuffing(struct pes_header_write_args *args)
|
||||
{
|
||||
/*
|
||||
* This is a fixed 8-bit value equal to '0xFF' that can be inserted
|
||||
@ -65,20 +64,20 @@ static u32 vidtv_pes_write_header_stuffing(struct pes_header_write_args args)
|
||||
* It is discarded by the decoder. No more than 32 stuffing bytes shall
|
||||
* be present in one PES packet header.
|
||||
*/
|
||||
if (args.n_pes_h_s_bytes > PES_HEADER_MAX_STUFFING_BYTES) {
|
||||
if (args->n_pes_h_s_bytes > PES_HEADER_MAX_STUFFING_BYTES) {
|
||||
pr_warn_ratelimited("More than %d stuffing bytes in PES packet header\n",
|
||||
PES_HEADER_MAX_STUFFING_BYTES);
|
||||
args.n_pes_h_s_bytes = PES_HEADER_MAX_STUFFING_BYTES;
|
||||
args->n_pes_h_s_bytes = PES_HEADER_MAX_STUFFING_BYTES;
|
||||
}
|
||||
|
||||
return vidtv_memset(args.dest_buf,
|
||||
args.dest_offset,
|
||||
args.dest_buf_sz,
|
||||
return vidtv_memset(args->dest_buf,
|
||||
args->dest_offset,
|
||||
args->dest_buf_sz,
|
||||
TS_FILL_BYTE,
|
||||
args.n_pes_h_s_bytes);
|
||||
args->n_pes_h_s_bytes);
|
||||
}
|
||||
|
||||
static u32 vidtv_pes_write_pts_dts(struct pes_header_write_args args)
|
||||
static u32 vidtv_pes_write_pts_dts(struct pes_header_write_args *args)
|
||||
{
|
||||
u32 nbytes = 0; /* the number of bytes written by this function */
|
||||
|
||||
@ -90,7 +89,7 @@ static u32 vidtv_pes_write_pts_dts(struct pes_header_write_args args)
|
||||
u64 mask2;
|
||||
u64 mask3;
|
||||
|
||||
if (!args.send_pts && args.send_dts)
|
||||
if (!args->send_pts && args->send_dts)
|
||||
return 0;
|
||||
|
||||
mask1 = GENMASK_ULL(32, 30);
|
||||
@ -98,80 +97,81 @@ static u32 vidtv_pes_write_pts_dts(struct pes_header_write_args args)
|
||||
mask3 = GENMASK_ULL(14, 0);
|
||||
|
||||
/* see ISO/IEC 13818-1 : 2000 p. 32 */
|
||||
if (args.send_pts && args.send_dts) {
|
||||
pts_dts.pts1 = (0x3 << 4) | ((args.pts & mask1) >> 29) | 0x1;
|
||||
pts_dts.pts2 = cpu_to_be16(((args.pts & mask2) >> 14) | 0x1);
|
||||
pts_dts.pts3 = cpu_to_be16(((args.pts & mask3) << 1) | 0x1);
|
||||
if (args->send_pts && args->send_dts) {
|
||||
pts_dts.pts1 = (0x3 << 4) | ((args->pts & mask1) >> 29) | 0x1;
|
||||
pts_dts.pts2 = cpu_to_be16(((args->pts & mask2) >> 14) | 0x1);
|
||||
pts_dts.pts3 = cpu_to_be16(((args->pts & mask3) << 1) | 0x1);
|
||||
|
||||
pts_dts.dts1 = (0x1 << 4) | ((args.dts & mask1) >> 29) | 0x1;
|
||||
pts_dts.dts2 = cpu_to_be16(((args.dts & mask2) >> 14) | 0x1);
|
||||
pts_dts.dts3 = cpu_to_be16(((args.dts & mask3) << 1) | 0x1);
|
||||
pts_dts.dts1 = (0x1 << 4) | ((args->dts & mask1) >> 29) | 0x1;
|
||||
pts_dts.dts2 = cpu_to_be16(((args->dts & mask2) >> 14) | 0x1);
|
||||
pts_dts.dts3 = cpu_to_be16(((args->dts & mask3) << 1) | 0x1);
|
||||
|
||||
op = &pts_dts;
|
||||
op_sz = sizeof(pts_dts);
|
||||
|
||||
} else if (args.send_pts) {
|
||||
pts.pts1 = (0x1 << 5) | ((args.pts & mask1) >> 29) | 0x1;
|
||||
pts.pts2 = cpu_to_be16(((args.pts & mask2) >> 14) | 0x1);
|
||||
pts.pts3 = cpu_to_be16(((args.pts & mask3) << 1) | 0x1);
|
||||
} else if (args->send_pts) {
|
||||
pts.pts1 = (0x1 << 5) | ((args->pts & mask1) >> 29) | 0x1;
|
||||
pts.pts2 = cpu_to_be16(((args->pts & mask2) >> 14) | 0x1);
|
||||
pts.pts3 = cpu_to_be16(((args->pts & mask3) << 1) | 0x1);
|
||||
|
||||
op = &pts;
|
||||
op_sz = sizeof(pts);
|
||||
}
|
||||
|
||||
/* copy PTS/DTS optional */
|
||||
nbytes += vidtv_memcpy(args.dest_buf,
|
||||
args.dest_offset + nbytes,
|
||||
args.dest_buf_sz,
|
||||
nbytes += vidtv_memcpy(args->dest_buf,
|
||||
args->dest_offset + nbytes,
|
||||
args->dest_buf_sz,
|
||||
op,
|
||||
op_sz);
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
static u32 vidtv_pes_write_h(struct pes_header_write_args args)
|
||||
static u32 vidtv_pes_write_h(struct pes_header_write_args *args)
|
||||
{
|
||||
u32 nbytes = 0; /* the number of bytes written by this function */
|
||||
|
||||
struct vidtv_mpeg_pes pes_header = {};
|
||||
struct vidtv_pes_optional pes_optional = {};
|
||||
struct pes_header_write_args pts_dts_args = args;
|
||||
u32 stream_id = (args.encoder_id == S302M) ? PRIVATE_STREAM_1_ID : args.stream_id;
|
||||
struct pes_header_write_args pts_dts_args;
|
||||
u32 stream_id = (args->encoder_id == S302M) ? PRIVATE_STREAM_1_ID : args->stream_id;
|
||||
u16 pes_opt_bitfield = 0x01 << 15;
|
||||
|
||||
pes_header.bitfield = cpu_to_be32((PES_START_CODE_PREFIX << 8) | stream_id);
|
||||
|
||||
pes_header.length = cpu_to_be16(vidtv_pes_op_get_len(args.send_pts,
|
||||
args.send_dts) +
|
||||
args.access_unit_len);
|
||||
pes_header.length = cpu_to_be16(vidtv_pes_op_get_len(args->send_pts,
|
||||
args->send_dts) +
|
||||
args->access_unit_len);
|
||||
|
||||
if (args.send_pts && args.send_dts)
|
||||
if (args->send_pts && args->send_dts)
|
||||
pes_opt_bitfield |= (0x3 << 6);
|
||||
else if (args.send_pts)
|
||||
else if (args->send_pts)
|
||||
pes_opt_bitfield |= (0x1 << 7);
|
||||
|
||||
pes_optional.bitfield = cpu_to_be16(pes_opt_bitfield);
|
||||
pes_optional.length = vidtv_pes_op_get_len(args.send_pts, args.send_dts) +
|
||||
args.n_pes_h_s_bytes -
|
||||
pes_optional.length = vidtv_pes_op_get_len(args->send_pts, args->send_dts) +
|
||||
args->n_pes_h_s_bytes -
|
||||
sizeof(struct vidtv_pes_optional);
|
||||
|
||||
/* copy header */
|
||||
nbytes += vidtv_memcpy(args.dest_buf,
|
||||
args.dest_offset + nbytes,
|
||||
args.dest_buf_sz,
|
||||
nbytes += vidtv_memcpy(args->dest_buf,
|
||||
args->dest_offset + nbytes,
|
||||
args->dest_buf_sz,
|
||||
&pes_header,
|
||||
sizeof(pes_header));
|
||||
|
||||
/* copy optional header bits */
|
||||
nbytes += vidtv_memcpy(args.dest_buf,
|
||||
args.dest_offset + nbytes,
|
||||
args.dest_buf_sz,
|
||||
nbytes += vidtv_memcpy(args->dest_buf,
|
||||
args->dest_offset + nbytes,
|
||||
args->dest_buf_sz,
|
||||
&pes_optional,
|
||||
sizeof(pes_optional));
|
||||
|
||||
/* copy the timing information */
|
||||
pts_dts_args.dest_offset = args.dest_offset + nbytes;
|
||||
nbytes += vidtv_pes_write_pts_dts(pts_dts_args);
|
||||
pts_dts_args = *args;
|
||||
pts_dts_args.dest_offset = args->dest_offset + nbytes;
|
||||
nbytes += vidtv_pes_write_pts_dts(&pts_dts_args);
|
||||
|
||||
/* write any PES header stuffing */
|
||||
nbytes += vidtv_pes_write_header_stuffing(args);
|
||||
@ -300,14 +300,31 @@ static u32 vidtv_pes_write_ts_h(struct pes_ts_header_write_args args,
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
u32 vidtv_pes_write_into(struct pes_write_args args)
|
||||
u32 vidtv_pes_write_into(struct pes_write_args *args)
|
||||
{
|
||||
u32 unaligned_bytes = (args.dest_offset % TS_PACKET_LEN);
|
||||
struct pes_ts_header_write_args ts_header_args = {};
|
||||
struct pes_header_write_args pes_header_args = {};
|
||||
u32 remaining_len = args.access_unit_len;
|
||||
u32 unaligned_bytes = (args->dest_offset % TS_PACKET_LEN);
|
||||
struct pes_ts_header_write_args ts_header_args = {
|
||||
.dest_buf = args->dest_buf,
|
||||
.dest_buf_sz = args->dest_buf_sz,
|
||||
.pid = args->pid,
|
||||
.pcr = args->pcr,
|
||||
.continuity_counter = args->continuity_counter,
|
||||
};
|
||||
struct pes_header_write_args pes_header_args = {
|
||||
.dest_buf = args->dest_buf,
|
||||
.dest_buf_sz = args->dest_buf_sz,
|
||||
.encoder_id = args->encoder_id,
|
||||
.send_pts = args->send_pts,
|
||||
.pts = args->pts,
|
||||
.send_dts = args->send_dts,
|
||||
.dts = args->dts,
|
||||
.stream_id = args->stream_id,
|
||||
.n_pes_h_s_bytes = args->n_pes_h_s_bytes,
|
||||
.access_unit_len = args->access_unit_len,
|
||||
};
|
||||
u32 remaining_len = args->access_unit_len;
|
||||
bool wrote_pes_header = false;
|
||||
u64 last_pcr = args.pcr;
|
||||
u64 last_pcr = args->pcr;
|
||||
bool need_pcr = true;
|
||||
u32 available_space;
|
||||
u32 payload_size;
|
||||
@ -318,25 +335,13 @@ u32 vidtv_pes_write_into(struct pes_write_args args)
|
||||
pr_warn_ratelimited("buffer is misaligned, while starting PES\n");
|
||||
|
||||
/* forcibly align and hope for the best */
|
||||
nbytes += vidtv_memset(args.dest_buf,
|
||||
args.dest_offset + nbytes,
|
||||
args.dest_buf_sz,
|
||||
nbytes += vidtv_memset(args->dest_buf,
|
||||
args->dest_offset + nbytes,
|
||||
args->dest_buf_sz,
|
||||
TS_FILL_BYTE,
|
||||
TS_PACKET_LEN - unaligned_bytes);
|
||||
}
|
||||
|
||||
if (args.send_dts && !args.send_pts) {
|
||||
pr_warn_ratelimited("forbidden value '01' for PTS_DTS flags\n");
|
||||
args.send_pts = true;
|
||||
args.pts = args.dts;
|
||||
}
|
||||
|
||||
/* see SMPTE 302M clause 6.4 */
|
||||
if (args.encoder_id == S302M) {
|
||||
args.send_dts = false;
|
||||
args.send_pts = true;
|
||||
}
|
||||
|
||||
while (remaining_len) {
|
||||
available_space = TS_PAYLOAD_LEN;
|
||||
/*
|
||||
@ -345,14 +350,14 @@ u32 vidtv_pes_write_into(struct pes_write_args args)
|
||||
* the space needed for the TS header _and_ for the PES header
|
||||
*/
|
||||
if (!wrote_pes_header)
|
||||
available_space -= vidtv_pes_h_get_len(args.send_pts,
|
||||
args.send_dts);
|
||||
available_space -= vidtv_pes_h_get_len(args->send_pts,
|
||||
args->send_dts);
|
||||
|
||||
/*
|
||||
* if the encoder has inserted stuffing bytes in the PES
|
||||
* header, account for them.
|
||||
*/
|
||||
available_space -= args.n_pes_h_s_bytes;
|
||||
available_space -= args->n_pes_h_s_bytes;
|
||||
|
||||
/* Take the extra adaptation into account if need to send PCR */
|
||||
if (need_pcr) {
|
||||
@ -387,14 +392,9 @@ u32 vidtv_pes_write_into(struct pes_write_args args)
|
||||
}
|
||||
|
||||
/* write ts header */
|
||||
ts_header_args.dest_buf = args.dest_buf;
|
||||
ts_header_args.dest_offset = args.dest_offset + nbytes;
|
||||
ts_header_args.dest_buf_sz = args.dest_buf_sz;
|
||||
ts_header_args.pid = args.pid;
|
||||
ts_header_args.pcr = args.pcr;
|
||||
ts_header_args.continuity_counter = args.continuity_counter;
|
||||
ts_header_args.wrote_pes_header = wrote_pes_header;
|
||||
ts_header_args.n_stuffing_bytes = stuff_bytes;
|
||||
ts_header_args.dest_offset = args->dest_offset + nbytes;
|
||||
ts_header_args.wrote_pes_header = wrote_pes_header;
|
||||
ts_header_args.n_stuffing_bytes = stuff_bytes;
|
||||
|
||||
nbytes += vidtv_pes_write_ts_h(ts_header_args, need_pcr,
|
||||
&last_pcr);
|
||||
@ -403,33 +403,20 @@ u32 vidtv_pes_write_into(struct pes_write_args args)
|
||||
|
||||
if (!wrote_pes_header) {
|
||||
/* write the PES header only once */
|
||||
pes_header_args.dest_buf = args.dest_buf;
|
||||
|
||||
pes_header_args.dest_offset = args.dest_offset +
|
||||
nbytes;
|
||||
|
||||
pes_header_args.dest_buf_sz = args.dest_buf_sz;
|
||||
pes_header_args.encoder_id = args.encoder_id;
|
||||
pes_header_args.send_pts = args.send_pts;
|
||||
pes_header_args.pts = args.pts;
|
||||
pes_header_args.send_dts = args.send_dts;
|
||||
pes_header_args.dts = args.dts;
|
||||
pes_header_args.stream_id = args.stream_id;
|
||||
pes_header_args.n_pes_h_s_bytes = args.n_pes_h_s_bytes;
|
||||
pes_header_args.access_unit_len = args.access_unit_len;
|
||||
|
||||
nbytes += vidtv_pes_write_h(pes_header_args);
|
||||
wrote_pes_header = true;
|
||||
pes_header_args.dest_offset = args->dest_offset +
|
||||
nbytes;
|
||||
nbytes += vidtv_pes_write_h(&pes_header_args);
|
||||
wrote_pes_header = true;
|
||||
}
|
||||
|
||||
/* write as much of the payload as we possibly can */
|
||||
nbytes += vidtv_memcpy(args.dest_buf,
|
||||
args.dest_offset + nbytes,
|
||||
args.dest_buf_sz,
|
||||
args.from,
|
||||
nbytes += vidtv_memcpy(args->dest_buf,
|
||||
args->dest_offset + nbytes,
|
||||
args->dest_buf_sz,
|
||||
args->from,
|
||||
payload_size);
|
||||
|
||||
args.from += payload_size;
|
||||
args->from += payload_size;
|
||||
|
||||
remaining_len -= payload_size;
|
||||
}
|
||||
|
@ -14,7 +14,6 @@
|
||||
#ifndef VIDTV_PES_H
|
||||
#define VIDTV_PES_H
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "vidtv_common.h"
|
||||
@ -114,8 +113,10 @@ struct pes_header_write_args {
|
||||
* @dest_buf_sz: The size of the dest_buffer
|
||||
* @pid: The PID to use for the TS packets.
|
||||
* @continuity_counter: Incremented on every new TS packet.
|
||||
* @n_pes_h_s_bytes: Padding bytes. Might be used by an encoder if needed, gets
|
||||
* @wrote_pes_header: Flag to indicate that the PES header was written
|
||||
* @n_stuffing_bytes: Padding bytes. Might be used by an encoder if needed, gets
|
||||
* discarded by the decoder.
|
||||
* @pcr: counter driven by a 27Mhz clock.
|
||||
*/
|
||||
struct pes_ts_header_write_args {
|
||||
void *dest_buf;
|
||||
@ -146,6 +147,7 @@ struct pes_ts_header_write_args {
|
||||
* @dts: DTS value to send.
|
||||
* @n_pes_h_s_bytes: Padding bytes. Might be used by an encoder if needed, gets
|
||||
* discarded by the decoder.
|
||||
* @pcr: counter driven by a 27Mhz clock.
|
||||
*/
|
||||
struct pes_write_args {
|
||||
void *dest_buf;
|
||||
@ -186,6 +188,6 @@ struct pes_write_args {
|
||||
* equal to the size of the access unit, since we need space for PES headers, TS headers
|
||||
* and padding bytes, if any.
|
||||
*/
|
||||
u32 vidtv_pes_write_into(struct pes_write_args args);
|
||||
u32 vidtv_pes_write_into(struct pes_write_args *args);
|
||||
|
||||
#endif // VIDTV_PES_H
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,10 +6,6 @@
|
||||
* technically be broken into one or more sections, we do not do this here,
|
||||
* hence 'table' and 'section' are interchangeable for vidtv.
|
||||
*
|
||||
* This code currently supports three tables: PAT, PMT and SDT. These are the
|
||||
* bare minimum to get userspace to recognize our MPEG transport stream. It can
|
||||
* be extended to support more PSI tables in the future.
|
||||
*
|
||||
* Copyright (C) 2020 Daniel W. S. Almeida
|
||||
*/
|
||||
|
||||
@ -17,7 +13,6 @@
|
||||
#define VIDTV_PSI_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
/*
|
||||
* all section lengths start immediately after the 'section_length' field
|
||||
@ -27,20 +22,28 @@
|
||||
#define PAT_LEN_UNTIL_LAST_SECTION_NUMBER 5
|
||||
#define PMT_LEN_UNTIL_PROGRAM_INFO_LENGTH 9
|
||||
#define SDT_LEN_UNTIL_RESERVED_FOR_FUTURE_USE 8
|
||||
#define NIT_LEN_UNTIL_NETWORK_DESCRIPTOR_LEN 7
|
||||
#define EIT_LEN_UNTIL_LAST_TABLE_ID 11
|
||||
#define MAX_SECTION_LEN 1021
|
||||
#define EIT_MAX_SECTION_LEN 4093 /* see ETSI 300 468 v.1.10.1 p. 26 */
|
||||
#define VIDTV_PAT_PID 0 /* mandated by the specs */
|
||||
#define VIDTV_SDT_PID 0x0011 /* mandated by the specs */
|
||||
#define VIDTV_NIT_PID 0x0010 /* mandated by the specs */
|
||||
#define VIDTV_EIT_PID 0x0012 /*mandated by the specs */
|
||||
|
||||
enum vidtv_psi_descriptors {
|
||||
REGISTRATION_DESCRIPTOR = 0x05, /* See ISO/IEC 13818-1 section 2.6.8 */
|
||||
NETWORK_NAME_DESCRIPTOR = 0x40, /* See ETSI EN 300 468 section 6.2.27 */
|
||||
SERVICE_LIST_DESCRIPTOR = 0x41, /* See ETSI EN 300 468 section 6.2.35 */
|
||||
SERVICE_DESCRIPTOR = 0x48, /* See ETSI EN 300 468 section 6.2.33 */
|
||||
SHORT_EVENT_DESCRIPTOR = 0x4d, /* See ETSI EN 300 468 section 6.2.37 */
|
||||
};
|
||||
|
||||
enum vidtv_psi_stream_types {
|
||||
STREAM_PRIVATE_DATA = 0x06, /* see ISO/IEC 13818-1 2000 p. 48 */
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* struct vidtv_psi_desc - A generic PSI descriptor type.
|
||||
* The descriptor length is an 8-bit field specifying the total number of bytes of the data portion
|
||||
* of the descriptor following the byte defining the value of this field.
|
||||
@ -52,7 +55,7 @@ struct vidtv_psi_desc {
|
||||
u8 data[];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
/*
|
||||
* struct vidtv_psi_desc_service - Service descriptor.
|
||||
* See ETSI EN 300 468 section 6.2.33.
|
||||
*/
|
||||
@ -68,7 +71,7 @@ struct vidtv_psi_desc_service {
|
||||
char *service_name;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
/*
|
||||
* struct vidtv_psi_desc_registration - A registration descriptor.
|
||||
* See ISO/IEC 13818-1 section 2.6.8
|
||||
*/
|
||||
@ -90,7 +93,56 @@ struct vidtv_psi_desc_registration {
|
||||
u8 additional_identification_info[];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
/*
|
||||
* struct vidtv_psi_desc_network_name - A network name descriptor
|
||||
* see ETSI EN 300 468 v1.15.1 section 6.2.27
|
||||
*/
|
||||
struct vidtv_psi_desc_network_name {
|
||||
struct vidtv_psi_desc *next;
|
||||
u8 type;
|
||||
u8 length;
|
||||
char *network_name;
|
||||
} __packed;
|
||||
|
||||
struct vidtv_psi_desc_service_list_entry {
|
||||
__be16 service_id;
|
||||
u8 service_type;
|
||||
struct vidtv_psi_desc_service_list_entry *next;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* struct vidtv_psi_desc_service_list - A service list descriptor
|
||||
* see ETSI EN 300 468 v1.15.1 section 6.2.35
|
||||
*/
|
||||
struct vidtv_psi_desc_service_list {
|
||||
struct vidtv_psi_desc *next;
|
||||
u8 type;
|
||||
u8 length;
|
||||
struct vidtv_psi_desc_service_list_entry *service_list;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* struct vidtv_psi_desc_short_event - A short event descriptor
|
||||
* see ETSI EN 300 468 v1.15.1 section 6.2.37
|
||||
*/
|
||||
struct vidtv_psi_desc_short_event {
|
||||
struct vidtv_psi_desc *next;
|
||||
u8 type;
|
||||
u8 length;
|
||||
char *iso_language_code;
|
||||
u8 event_name_len;
|
||||
char *event_name;
|
||||
u8 text_len;
|
||||
char *text;
|
||||
} __packed;
|
||||
|
||||
struct vidtv_psi_desc_short_event
|
||||
*vidtv_psi_short_event_desc_init(struct vidtv_psi_desc *head,
|
||||
char *iso_language_code,
|
||||
char *event_name,
|
||||
char *text);
|
||||
|
||||
/*
|
||||
* struct vidtv_psi_table_header - A header that is present for all PSI tables.
|
||||
*/
|
||||
struct vidtv_psi_table_header {
|
||||
@ -106,7 +158,7 @@ struct vidtv_psi_table_header {
|
||||
u8 last_section; /* last_section_number */
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
/*
|
||||
* struct vidtv_psi_table_pat_program - A single program in the PAT
|
||||
* See ISO/IEC 13818-1 : 2000 p.43
|
||||
*/
|
||||
@ -116,17 +168,18 @@ struct vidtv_psi_table_pat_program {
|
||||
struct vidtv_psi_table_pat_program *next;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
/*
|
||||
* struct vidtv_psi_table_pat - The Program Allocation Table (PAT)
|
||||
* See ISO/IEC 13818-1 : 2000 p.43
|
||||
*/
|
||||
struct vidtv_psi_table_pat {
|
||||
struct vidtv_psi_table_header header;
|
||||
u16 programs; /* Included by libdvbv5, not part of the table and not actually serialized */
|
||||
u16 num_pat;
|
||||
u16 num_pmt;
|
||||
struct vidtv_psi_table_pat_program *program;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
/*
|
||||
* struct vidtv_psi_table_sdt_service - Represents a service in the SDT.
|
||||
* see ETSI EN 300 468 v1.15.1 section 5.2.3.
|
||||
*/
|
||||
@ -140,7 +193,7 @@ struct vidtv_psi_table_sdt_service {
|
||||
struct vidtv_psi_table_sdt_service *next;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
/*
|
||||
* struct vidtv_psi_table_sdt - Represents the Service Description Table
|
||||
* see ETSI EN 300 468 v1.15.1 section 5.2.3.
|
||||
*/
|
||||
@ -152,7 +205,7 @@ struct vidtv_psi_table_sdt {
|
||||
struct vidtv_psi_table_sdt_service *service;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
/*
|
||||
* enum service_running_status - Status of a SDT service.
|
||||
* see ETSI EN 300 468 v1.15.1 section 5.2.3 table 6.
|
||||
*/
|
||||
@ -160,16 +213,17 @@ enum service_running_status {
|
||||
RUNNING = 0x4,
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* enum service_type - The type of a SDT service.
|
||||
* see ETSI EN 300 468 v1.15.1 section 6.2.33, table 81.
|
||||
*/
|
||||
enum service_type {
|
||||
/* see ETSI EN 300 468 v1.15.1 p. 77 */
|
||||
DIGITAL_TELEVISION_SERVICE = 0x1,
|
||||
DIGITAL_RADIO_SOUND_SERVICE = 0X2,
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* struct vidtv_psi_table_pmt_stream - A single stream in the PMT.
|
||||
* See ISO/IEC 13818-1 : 2000 p.46.
|
||||
*/
|
||||
@ -181,7 +235,7 @@ struct vidtv_psi_table_pmt_stream {
|
||||
struct vidtv_psi_table_pmt_stream *next;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
/*
|
||||
* struct vidtv_psi_table_pmt - The Program Map Table (PMT).
|
||||
* See ISO/IEC 13818-1 : 2000 p.46.
|
||||
*/
|
||||
@ -290,6 +344,13 @@ struct vidtv_psi_desc_registration
|
||||
u8 *additional_ident_info,
|
||||
u32 additional_info_len);
|
||||
|
||||
struct vidtv_psi_desc_network_name
|
||||
*vidtv_psi_network_name_desc_init(struct vidtv_psi_desc *head, char *network_name);
|
||||
|
||||
struct vidtv_psi_desc_service_list
|
||||
*vidtv_psi_service_list_desc_init(struct vidtv_psi_desc *head,
|
||||
struct vidtv_psi_desc_service_list_entry *entry);
|
||||
|
||||
struct vidtv_psi_table_pat_program
|
||||
*vidtv_psi_pat_program_init(struct vidtv_psi_table_pat_program *head,
|
||||
u16 service_id,
|
||||
@ -305,11 +366,14 @@ struct vidtv_psi_table_pat *vidtv_psi_pat_table_init(u16 transport_stream_id);
|
||||
struct vidtv_psi_table_pmt *vidtv_psi_pmt_table_init(u16 program_number,
|
||||
u16 pcr_pid);
|
||||
|
||||
struct vidtv_psi_table_sdt *vidtv_psi_sdt_table_init(u16 transport_stream_id);
|
||||
struct vidtv_psi_table_sdt *vidtv_psi_sdt_table_init(u16 network_id,
|
||||
u16 transport_stream_id);
|
||||
|
||||
struct vidtv_psi_table_sdt_service*
|
||||
vidtv_psi_sdt_service_init(struct vidtv_psi_table_sdt_service *head,
|
||||
u16 service_id);
|
||||
u16 service_id,
|
||||
bool eit_schedule,
|
||||
bool eit_present_following);
|
||||
|
||||
void
|
||||
vidtv_psi_desc_destroy(struct vidtv_psi_desc *desc);
|
||||
@ -413,7 +477,6 @@ struct vidtv_psi_desc *vidtv_psi_desc_clone(struct vidtv_psi_desc *desc);
|
||||
* vidtv_psi_create_sec_for_each_pat_entry - Create a PMT section for each
|
||||
* program found in the PAT
|
||||
* @pat: The PAT to look for programs.
|
||||
* @s: The stream loop (one or more streams)
|
||||
* @pcr_pid: packet ID for the PCR to be used for the program described in this
|
||||
* PMT section
|
||||
*/
|
||||
@ -492,7 +555,7 @@ struct vidtv_psi_pat_write_args {
|
||||
* equal to the size of the PAT, since more space is needed for TS headers during TS
|
||||
* encapsulation.
|
||||
*/
|
||||
u32 vidtv_psi_pat_write_into(struct vidtv_psi_pat_write_args args);
|
||||
u32 vidtv_psi_pat_write_into(struct vidtv_psi_pat_write_args *args);
|
||||
|
||||
/**
|
||||
* struct vidtv_psi_sdt_write_args - Arguments for writing a SDT table
|
||||
@ -524,16 +587,18 @@ struct vidtv_psi_sdt_write_args {
|
||||
* equal to the size of the SDT, since more space is needed for TS headers during TS
|
||||
* encapsulation.
|
||||
*/
|
||||
u32 vidtv_psi_sdt_write_into(struct vidtv_psi_sdt_write_args args);
|
||||
u32 vidtv_psi_sdt_write_into(struct vidtv_psi_sdt_write_args *args);
|
||||
|
||||
/**
|
||||
* struct vidtv_psi_pmt_write_args - Arguments for writing a PMT section
|
||||
* @buf: The destination buffer.
|
||||
* @offset: The offset into the destination buffer.
|
||||
* @pmt: A pointer to the PMT.
|
||||
* @pid: Program ID
|
||||
* @buf_sz: The size of the destination buffer.
|
||||
* @continuity_counter: A pointer to the CC. Incremented on every new packet.
|
||||
*
|
||||
* @pcr_pid: The TS PID used for the PSI packets. All channels will share the
|
||||
* same PCR.
|
||||
*/
|
||||
struct vidtv_psi_pmt_write_args {
|
||||
char *buf;
|
||||
@ -557,7 +622,7 @@ struct vidtv_psi_pmt_write_args {
|
||||
* equal to the size of the PMT section, since more space is needed for TS headers
|
||||
* during TS encapsulation.
|
||||
*/
|
||||
u32 vidtv_psi_pmt_write_into(struct vidtv_psi_pmt_write_args args);
|
||||
u32 vidtv_psi_pmt_write_into(struct vidtv_psi_pmt_write_args *args);
|
||||
|
||||
/**
|
||||
* vidtv_psi_find_pmt_sec - Finds the PMT section for 'program_num'
|
||||
@ -574,4 +639,171 @@ struct vidtv_psi_table_pmt *vidtv_psi_find_pmt_sec(struct vidtv_psi_table_pmt **
|
||||
u16 vidtv_psi_get_pat_program_pid(struct vidtv_psi_table_pat_program *p);
|
||||
u16 vidtv_psi_pmt_stream_get_elem_pid(struct vidtv_psi_table_pmt_stream *s);
|
||||
|
||||
/**
|
||||
* struct vidtv_psi_table_transport - A entry in the TS loop for the NIT and/or other tables.
|
||||
* See ETSI 300 468 section 5.2.1
|
||||
* @transport_id: The TS ID being described
|
||||
* @network_id: The network_id that contains the TS ID
|
||||
* @bitfield: Contains the descriptor loop length
|
||||
* @descriptor: A descriptor loop
|
||||
* @next: Pointer to the next entry
|
||||
*
|
||||
*/
|
||||
struct vidtv_psi_table_transport {
|
||||
__be16 transport_id;
|
||||
__be16 network_id;
|
||||
__be16 bitfield; /* desc_len: 12, reserved: 4 */
|
||||
struct vidtv_psi_desc *descriptor;
|
||||
struct vidtv_psi_table_transport *next;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct vidtv_psi_table_nit - A Network Information Table (NIT). See ETSI 300
|
||||
* 468 section 5.2.1
|
||||
* @header: A PSI table header
|
||||
* @bitfield: Contains the network descriptor length
|
||||
* @descriptor: A descriptor loop describing the network
|
||||
* @bitfield2: Contains the transport stream loop length
|
||||
* @transport: The transport stream loop
|
||||
*
|
||||
*/
|
||||
struct vidtv_psi_table_nit {
|
||||
struct vidtv_psi_table_header header;
|
||||
__be16 bitfield; /* network_desc_len: 12, reserved:4 */
|
||||
struct vidtv_psi_desc *descriptor;
|
||||
__be16 bitfield2; /* ts_loop_len: 12, reserved: 4 */
|
||||
struct vidtv_psi_table_transport *transport;
|
||||
} __packed;
|
||||
|
||||
struct vidtv_psi_table_nit
|
||||
*vidtv_psi_nit_table_init(u16 network_id,
|
||||
u16 transport_stream_id,
|
||||
char *network_name,
|
||||
struct vidtv_psi_desc_service_list_entry *service_list);
|
||||
|
||||
/**
|
||||
* struct vidtv_psi_nit_write_args - Arguments for writing a NIT section
|
||||
* @buf: The destination buffer.
|
||||
* @offset: The offset into the destination buffer.
|
||||
* @nit: A pointer to the NIT
|
||||
* @buf_sz: The size of the destination buffer.
|
||||
* @continuity_counter: A pointer to the CC. Incremented on every new packet.
|
||||
*
|
||||
*/
|
||||
struct vidtv_psi_nit_write_args {
|
||||
char *buf;
|
||||
u32 offset;
|
||||
struct vidtv_psi_table_nit *nit;
|
||||
u32 buf_sz;
|
||||
u8 *continuity_counter;
|
||||
};
|
||||
|
||||
/**
|
||||
* vidtv_psi_nit_write_into - Write NIT as MPEG-TS packets into a buffer.
|
||||
* @args: an instance of struct vidtv_psi_nit_write_args
|
||||
*
|
||||
* This function writes the MPEG TS packets for a NIT table into a buffer.
|
||||
* Calling code will usually generate the NIT via a call to its init function
|
||||
* and thus is responsible for freeing it.
|
||||
*
|
||||
* Return: The number of bytes written into the buffer. This is NOT
|
||||
* equal to the size of the NIT, since more space is needed for TS headers during TS
|
||||
* encapsulation.
|
||||
*/
|
||||
u32 vidtv_psi_nit_write_into(struct vidtv_psi_nit_write_args *args);
|
||||
|
||||
void vidtv_psi_nit_table_destroy(struct vidtv_psi_table_nit *nit);
|
||||
|
||||
/*
|
||||
* struct vidtv_psi_desc_short_event - A short event descriptor
|
||||
* see ETSI EN 300 468 v1.15.1 section 6.2.37
|
||||
*/
|
||||
struct vidtv_psi_table_eit_event {
|
||||
__be16 event_id;
|
||||
u8 start_time[5];
|
||||
u8 duration[3];
|
||||
__be16 bitfield; /* desc_length: 12, free_CA_mode: 1, running_status: 1 */
|
||||
struct vidtv_psi_desc *descriptor;
|
||||
struct vidtv_psi_table_eit_event *next;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* struct vidtv_psi_table_eit - A Event Information Table (EIT)
|
||||
* See ETSI 300 468 section 5.2.4
|
||||
*/
|
||||
struct vidtv_psi_table_eit {
|
||||
struct vidtv_psi_table_header header;
|
||||
__be16 transport_id;
|
||||
__be16 network_id;
|
||||
u8 last_segment;
|
||||
u8 last_table_id;
|
||||
struct vidtv_psi_table_eit_event *event;
|
||||
} __packed;
|
||||
|
||||
struct vidtv_psi_table_eit
|
||||
*vidtv_psi_eit_table_init(u16 network_id,
|
||||
u16 transport_stream_id,
|
||||
u16 service_id);
|
||||
|
||||
/**
|
||||
* struct vidtv_psi_eit_write_args - Arguments for writing an EIT section
|
||||
* @buf: The destination buffer.
|
||||
* @offset: The offset into the destination buffer.
|
||||
* @eit: A pointer to the EIT
|
||||
* @buf_sz: The size of the destination buffer.
|
||||
* @continuity_counter: A pointer to the CC. Incremented on every new packet.
|
||||
*
|
||||
*/
|
||||
struct vidtv_psi_eit_write_args {
|
||||
char *buf;
|
||||
u32 offset;
|
||||
struct vidtv_psi_table_eit *eit;
|
||||
u32 buf_sz;
|
||||
u8 *continuity_counter;
|
||||
};
|
||||
|
||||
/**
|
||||
* vidtv_psi_eit_write_into - Write EIT as MPEG-TS packets into a buffer.
|
||||
* @args: an instance of struct vidtv_psi_nit_write_args
|
||||
*
|
||||
* This function writes the MPEG TS packets for a EIT table into a buffer.
|
||||
* Calling code will usually generate the EIT via a call to its init function
|
||||
* and thus is responsible for freeing it.
|
||||
*
|
||||
* Return: The number of bytes written into the buffer. This is NOT
|
||||
* equal to the size of the EIT, since more space is needed for TS headers during TS
|
||||
* encapsulation.
|
||||
*/
|
||||
u32 vidtv_psi_eit_write_into(struct vidtv_psi_eit_write_args *args);
|
||||
|
||||
void vidtv_psi_eit_table_destroy(struct vidtv_psi_table_eit *eit);
|
||||
|
||||
/**
|
||||
* vidtv_psi_eit_table_update_sec_len - Recompute and update the EIT section length.
|
||||
* @eit: The EIT whose length is to be updated.
|
||||
*
|
||||
* This will traverse the table and accumulate the length of its components,
|
||||
* which is then used to replace the 'section_length' field.
|
||||
*
|
||||
* If section_length > EIT_MAX_SECTION_LEN, the operation fails.
|
||||
*/
|
||||
void vidtv_psi_eit_table_update_sec_len(struct vidtv_psi_table_eit *eit);
|
||||
|
||||
/**
|
||||
* vidtv_psi_eit_event_assign - Assigns the event loop to the EIT.
|
||||
* @eit: The EIT to assign to.
|
||||
* @e: The event loop
|
||||
*
|
||||
* This will free the previous event loop in the table.
|
||||
* This will assign ownership of the stream loop to the table, i.e. the table
|
||||
* will free this stream loop when a call to its destroy function is made.
|
||||
*/
|
||||
void vidtv_psi_eit_event_assign(struct vidtv_psi_table_eit *eit,
|
||||
struct vidtv_psi_table_eit_event *e);
|
||||
|
||||
struct vidtv_psi_table_eit_event
|
||||
*vidtv_psi_eit_event_init(struct vidtv_psi_table_eit_event *head, u16 event_id);
|
||||
|
||||
void vidtv_psi_eit_event_destroy(struct vidtv_psi_table_eit_event *e);
|
||||
|
||||
#endif // VIDTV_PSI_H
|
||||
|
@ -17,23 +17,22 @@
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s, %d: " fmt, __func__, __LINE__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fixp-arith.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/fixp-arith.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <linux/math64.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "vidtv_s302m.h"
|
||||
#include "vidtv_encoder.h"
|
||||
#include "vidtv_common.h"
|
||||
#include "vidtv_encoder.h"
|
||||
#include "vidtv_s302m.h"
|
||||
|
||||
#define S302M_SAMPLING_RATE_HZ 48000
|
||||
#define PES_PRIVATE_STREAM_1 0xbd /* PES: private_stream_1 */
|
||||
@ -79,8 +78,9 @@ struct tone_duration {
|
||||
int duration;
|
||||
};
|
||||
|
||||
#define COMPASS 120 /* beats per minute (Allegro) */
|
||||
static const struct tone_duration beethoven_5th_symphony[] = {
|
||||
#define COMPASS 100 /* beats per minute */
|
||||
static const struct tone_duration beethoven_fur_elise[] = {
|
||||
{ NOTE_SILENT, 512},
|
||||
{ NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128},
|
||||
{ NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_B_5, 128},
|
||||
{ NOTE_D_6, 128}, { NOTE_C_6, 128}, { NOTE_A_3, 128},
|
||||
@ -121,31 +121,36 @@ static const struct tone_duration beethoven_5th_symphony[] = {
|
||||
{ NOTE_E_5, 128}, { NOTE_D_5, 128}, { NOTE_A_3, 128},
|
||||
{ NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_E_4, 128},
|
||||
{ NOTE_D_5, 128}, { NOTE_C_5, 128}, { NOTE_E_3, 128},
|
||||
{ NOTE_E_4, 128}, { NOTE_E_5, 255}, { NOTE_E_6, 128},
|
||||
{ NOTE_E_5, 128}, { NOTE_E_6, 128}, { NOTE_E_5, 255},
|
||||
{ NOTE_E_4, 128}, { NOTE_E_5, 128}, { NOTE_E_5, 128},
|
||||
{ NOTE_E_6, 128}, { NOTE_E_5, 128}, { NOTE_E_6, 128},
|
||||
{ NOTE_E_5, 128}, { NOTE_E_5, 128}, { NOTE_DS_5, 128},
|
||||
{ NOTE_E_5, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128},
|
||||
{ NOTE_DS_5, 128}, { NOTE_E_5, 128}, { NOTE_DS_6, 128},
|
||||
{ NOTE_E_6, 128}, { NOTE_DS_5, 128}, { NOTE_E_5, 128},
|
||||
{ NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_DS_6, 128},
|
||||
{ NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128},
|
||||
{ NOTE_B_5, 128}, { NOTE_D_6, 128}, { NOTE_C_6, 128},
|
||||
{ NOTE_A_3, 128}, { NOTE_E_4, 128}, { NOTE_A_4, 128},
|
||||
{ NOTE_C_5, 128}, { NOTE_E_5, 128}, { NOTE_A_5, 128},
|
||||
{ NOTE_E_3, 128}, { NOTE_E_4, 128}, { NOTE_GS_4, 128},
|
||||
{ NOTE_E_5, 128}, { NOTE_GS_5, 128}, { NOTE_B_5, 128},
|
||||
{ NOTE_A_3, 128}, { NOTE_E_4, 128}, { NOTE_A_4, 128},
|
||||
{ NOTE_E_5, 128}, { NOTE_E_6, 128}, { NOTE_DS_6, 128},
|
||||
{ NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_B_5, 128},
|
||||
{ NOTE_D_6, 128}, { NOTE_C_6, 128}, { NOTE_A_3, 128},
|
||||
{ NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_C_5, 128},
|
||||
{ NOTE_E_5, 128}, { NOTE_A_5, 128}, { NOTE_E_3, 128},
|
||||
{ NOTE_E_4, 128}, { NOTE_GS_4, 128}, { NOTE_E_5, 128},
|
||||
{ NOTE_GS_5, 128}, { NOTE_B_5, 128}, { NOTE_A_3, 128},
|
||||
{ NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_E_5, 128},
|
||||
{ NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128},
|
||||
{ NOTE_B_5, 128}, { NOTE_D_6, 128}, { NOTE_C_6, 128},
|
||||
{ NOTE_A_3, 128}, { NOTE_E_4, 128}, { NOTE_A_4, 128},
|
||||
{ NOTE_C_5, 128}, { NOTE_E_5, 128}, { NOTE_A_5, 128},
|
||||
{ NOTE_E_3, 128}, { NOTE_E_4, 128}, { NOTE_GS_4, 128},
|
||||
{ NOTE_E_5, 128}, { NOTE_C_6, 128}, { NOTE_B_5, 128},
|
||||
{ NOTE_C_5, 255}, { NOTE_C_5, 255}, { NOTE_SILENT, 512},
|
||||
{ NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_B_5, 128},
|
||||
{ NOTE_D_6, 128}, { NOTE_C_6, 128}, { NOTE_A_3, 128},
|
||||
{ NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_C_5, 128},
|
||||
{ NOTE_E_5, 128}, { NOTE_A_5, 128}, { NOTE_E_3, 128},
|
||||
{ NOTE_E_4, 128}, { NOTE_GS_4, 128}, { NOTE_E_5, 128},
|
||||
{ NOTE_C_6, 128}, { NOTE_B_5, 128}, { NOTE_A_5, 512},
|
||||
{ NOTE_SILENT, 256},
|
||||
};
|
||||
|
||||
static struct vidtv_access_unit *vidtv_s302m_access_unit_init(struct vidtv_access_unit *head)
|
||||
{
|
||||
struct vidtv_access_unit *au = kzalloc(sizeof(*au), GFP_KERNEL);
|
||||
struct vidtv_access_unit *au;
|
||||
|
||||
au = kzalloc(sizeof(*au), GFP_KERNEL);
|
||||
if (!au)
|
||||
return NULL;
|
||||
|
||||
if (head) {
|
||||
while (head->next)
|
||||
@ -196,10 +201,10 @@ static void vidtv_s302m_alloc_au(struct vidtv_encoder *e)
|
||||
static void
|
||||
vidtv_s302m_compute_sample_count_from_video(struct vidtv_encoder *e)
|
||||
{
|
||||
struct vidtv_access_unit *au = e->access_units;
|
||||
struct vidtv_access_unit *sync_au = e->sync->access_units;
|
||||
u32 vau_duration_usecs;
|
||||
struct vidtv_access_unit *au = e->access_units;
|
||||
u32 sample_duration_usecs;
|
||||
u32 vau_duration_usecs;
|
||||
u32 s;
|
||||
|
||||
vau_duration_usecs = USEC_PER_SEC / e->sync->sampling_rate_hz;
|
||||
@ -230,36 +235,32 @@ static u16 vidtv_s302m_get_sample(struct vidtv_encoder *e)
|
||||
{
|
||||
u16 sample;
|
||||
int pos;
|
||||
struct vidtv_s302m_ctx *ctx = e->ctx;
|
||||
|
||||
if (!e->src_buf) {
|
||||
/*
|
||||
* Simple tone generator: play the tones at the
|
||||
* beethoven_5th_symphony array.
|
||||
* beethoven_fur_elise array.
|
||||
*/
|
||||
if (e->last_duration <= 0) {
|
||||
if (e->src_buf_offset >= ARRAY_SIZE(beethoven_5th_symphony))
|
||||
if (ctx->last_duration <= 0) {
|
||||
if (e->src_buf_offset >= ARRAY_SIZE(beethoven_fur_elise))
|
||||
e->src_buf_offset = 0;
|
||||
|
||||
e->last_tone = beethoven_5th_symphony[e->src_buf_offset].note;
|
||||
e->last_duration = beethoven_5th_symphony[e->src_buf_offset].duration * S302M_SAMPLING_RATE_HZ / COMPASS / 5;
|
||||
ctx->last_tone = beethoven_fur_elise[e->src_buf_offset].note;
|
||||
ctx->last_duration = beethoven_fur_elise[e->src_buf_offset].duration *
|
||||
S302M_SAMPLING_RATE_HZ / COMPASS / 5;
|
||||
e->src_buf_offset++;
|
||||
e->note_offset = 0;
|
||||
ctx->note_offset = 0;
|
||||
} else {
|
||||
e->last_duration--;
|
||||
ctx->last_duration--;
|
||||
}
|
||||
|
||||
/* Handle silent */
|
||||
if (!e->last_tone) {
|
||||
e->src_buf_offset = 0;
|
||||
/* Handle pause notes */
|
||||
if (!ctx->last_tone)
|
||||
return 0x8000;
|
||||
}
|
||||
|
||||
pos = (2 * PI * e->note_offset * e->last_tone / S302M_SAMPLING_RATE_HZ);
|
||||
|
||||
if (pos == 360)
|
||||
e->note_offset = 0;
|
||||
else
|
||||
e->note_offset++;
|
||||
pos = (2 * PI * ctx->note_offset * ctx->last_tone) / S302M_SAMPLING_RATE_HZ;
|
||||
ctx->note_offset++;
|
||||
|
||||
return (fixp_sin32(pos % (2 * PI)) >> 16) + 0x8000;
|
||||
}
|
||||
@ -289,9 +290,9 @@ static u16 vidtv_s302m_get_sample(struct vidtv_encoder *e)
|
||||
static u32 vidtv_s302m_write_frame(struct vidtv_encoder *e,
|
||||
u16 sample)
|
||||
{
|
||||
u32 nbytes = 0;
|
||||
struct vidtv_s302m_frame_16 f = {};
|
||||
struct vidtv_s302m_ctx *ctx = e->ctx;
|
||||
struct vidtv_s302m_frame_16 f = {};
|
||||
u32 nbytes = 0;
|
||||
|
||||
/* from ffmpeg: see s302enc.c */
|
||||
|
||||
@ -388,6 +389,8 @@ static void vidtv_s302m_write_frames(struct vidtv_encoder *e)
|
||||
|
||||
static void *vidtv_s302m_encode(struct vidtv_encoder *e)
|
||||
{
|
||||
struct vidtv_s302m_ctx *ctx = e->ctx;
|
||||
|
||||
/*
|
||||
* According to SMPTE 302M, an audio access unit is specified as those
|
||||
* AES3 words that are associated with a corresponding video frame.
|
||||
@ -401,8 +404,6 @@ static void *vidtv_s302m_encode(struct vidtv_encoder *e)
|
||||
* ffmpeg
|
||||
*/
|
||||
|
||||
struct vidtv_s302m_ctx *ctx = e->ctx;
|
||||
|
||||
vidtv_s302m_access_unit_destroy(e);
|
||||
vidtv_s302m_alloc_au(e);
|
||||
|
||||
@ -440,8 +441,13 @@ static u32 vidtv_s302m_clear(struct vidtv_encoder *e)
|
||||
struct vidtv_encoder
|
||||
*vidtv_s302m_encoder_init(struct vidtv_s302m_encoder_init_args args)
|
||||
{
|
||||
struct vidtv_encoder *e = kzalloc(sizeof(*e), GFP_KERNEL);
|
||||
u32 priv_sz = sizeof(struct vidtv_s302m_ctx);
|
||||
struct vidtv_s302m_ctx *ctx;
|
||||
struct vidtv_encoder *e;
|
||||
|
||||
e = kzalloc(sizeof(*e), GFP_KERNEL);
|
||||
if (!e)
|
||||
return NULL;
|
||||
|
||||
e->id = S302M;
|
||||
|
||||
@ -453,14 +459,19 @@ struct vidtv_encoder
|
||||
e->encoder_buf_offset = 0;
|
||||
|
||||
e->sample_count = 0;
|
||||
e->last_duration = 0;
|
||||
|
||||
e->src_buf = (args.src_buf) ? args.src_buf : NULL;
|
||||
e->src_buf_sz = (args.src_buf) ? args.src_buf_sz : 0;
|
||||
e->src_buf_offset = 0;
|
||||
|
||||
e->is_video_encoder = false;
|
||||
e->ctx = kzalloc(priv_sz, GFP_KERNEL);
|
||||
|
||||
ctx = kzalloc(priv_sz, GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
e->ctx = ctx;
|
||||
ctx->last_duration = 0;
|
||||
|
||||
e->encode = vidtv_s302m_encode;
|
||||
e->clear = vidtv_s302m_clear;
|
||||
|
@ -19,7 +19,6 @@
|
||||
#define VIDTV_S302M_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "vidtv_encoder.h"
|
||||
|
||||
@ -34,14 +33,20 @@
|
||||
* @enc: A pointer to the containing encoder structure.
|
||||
* @frame_index: The current frame in a block
|
||||
* @au_count: The total number of access units encoded up to now
|
||||
* @last_duration: Duration of the tone currently being played
|
||||
* @note_offset: Position at the music tone array
|
||||
* @last_tone: Tone currently being played
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* struct vidtv_smpte_s302m_es - s302m MPEG Elementary Stream header.
|
||||
*
|
||||
* See SMPTE 302M 2007 table 1.
|
||||
|
@ -9,14 +9,13 @@
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s, %d: " fmt, __func__, __LINE__
|
||||
|
||||
#include <linux/math64.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/math64.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "vidtv_ts.h"
|
||||
#include "vidtv_common.h"
|
||||
#include "vidtv_ts.h"
|
||||
|
||||
static u32 vidtv_ts_write_pcr_bits(u8 *to, u32 to_offset, u64 pcr)
|
||||
{
|
||||
|
@ -11,7 +11,6 @@
|
||||
#define VIDTV_TS_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#define TS_SYNC_BYTE 0x47
|
||||
#define TS_PACKET_LEN 188
|
||||
@ -54,7 +53,7 @@ struct vidtv_mpeg_ts {
|
||||
* @dest_offset: The byte offset into the buffer.
|
||||
* @pid: The TS PID for the PCR packets.
|
||||
* @buf_sz: The size of the buffer in bytes.
|
||||
* @countinuity_counter: The TS continuity_counter.
|
||||
* @continuity_counter: The TS continuity_counter.
|
||||
* @pcr: A sample from the system clock.
|
||||
*/
|
||||
struct pcr_write_args {
|
||||
@ -71,7 +70,7 @@ struct pcr_write_args {
|
||||
* @dest_buf: The buffer to write into.
|
||||
* @dest_offset: The byte offset into the buffer.
|
||||
* @buf_sz: The size of the buffer in bytes.
|
||||
* @countinuity_counter: The TS continuity_counter.
|
||||
* @continuity_counter: The TS continuity_counter.
|
||||
*/
|
||||
struct null_packet_write_args {
|
||||
void *dest_buf;
|
||||
|
@ -13,11 +13,12 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <media/dvb_frontend.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <media/dvb_frontend.h>
|
||||
|
||||
#include "vidtv_tuner.h"
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#define VIDTV_TUNER_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <media/dvb_frontend.h>
|
||||
|
||||
#define NUM_VALID_TUNER_FREQS 8
|
||||
|
Loading…
Reference in New Issue
Block a user