mirror of https://github.com/mpv-player/mpv
stream_dvb: Also demux PMT if possible, reactivate TPID parsing.
If VDR-channel-config is used, we know the service_id. Using that, PMT can be extracted from PAT (code for that inspired by szap-s2 again). For this, we need to demux PAT with a special filter-setup, and once PMT was found it can be added to the PID-list. PMT is only resolved the first time one tunes to a channel, then stored in the channel-list in memory. With PMT available, ffmpeg can safely decode the teletext-pids.
This commit is contained in:
parent
ef463aa103
commit
f309ecebe5
|
@ -187,6 +187,74 @@ int dvb_set_ts_filt(dvb_priv_t *priv, int fd, uint16_t pid, dmx_pes_type_t pesty
|
|||
return 1;
|
||||
}
|
||||
|
||||
int dvb_get_pmt_pid(dvb_priv_t *priv, int card, int service_id) {
|
||||
/* We need special filters on the demux,
|
||||
so open one locally, and close also here. */
|
||||
char demux_dev[32];
|
||||
sprintf(demux_dev, "/dev/dvb/adapter%d/demux0", card);
|
||||
|
||||
struct dmx_sct_filter_params fparams;
|
||||
|
||||
memset(&fparams, 0, sizeof(fparams));
|
||||
fparams.pid = 0;
|
||||
fparams.filter.filter[0] = 0x00;
|
||||
fparams.filter.mask[0] = 0xff;
|
||||
fparams.timeout = 0;
|
||||
fparams.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;
|
||||
|
||||
int pat_fd;
|
||||
if ((pat_fd = open(demux_dev, O_RDWR)) < 0) {
|
||||
MP_ERR(priv, "Opening PAT DEMUX failed, error: %d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl(pat_fd, DMX_SET_FILTER, &fparams) == -1) {
|
||||
MP_ERR(priv, "ioctl DMX_SET_FILTER failed, error: %d", errno);
|
||||
close(pat_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bytes_read;
|
||||
int section_length;
|
||||
unsigned char buft[4096];
|
||||
unsigned char *bufptr = buft;
|
||||
|
||||
int pmt_pid = -1;
|
||||
|
||||
bool pat_read = false;
|
||||
while (!pat_read) {
|
||||
if (((bytes_read = read(pat_fd, bufptr, sizeof(buft))) < 0) && errno == EOVERFLOW)
|
||||
bytes_read = read(pat_fd, bufptr, sizeof(buft));
|
||||
if (bytes_read < 0) {
|
||||
MP_ERR(priv, "PAT: read_sections: read error: %d", errno);
|
||||
close(pat_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
section_length = ((bufptr[1] & 0x0f) << 8) | bufptr[2];
|
||||
if (bytes_read != section_length + 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bufptr += 8;
|
||||
section_length -= 8;
|
||||
|
||||
/* assumes one section contains the whole pat */
|
||||
pat_read = true;
|
||||
while (section_length > 0) {
|
||||
int this_service_id = (bufptr[0] << 8) | bufptr[1];
|
||||
if (this_service_id == service_id) {
|
||||
pmt_pid = ((bufptr[2] & 0x1f) << 8) | bufptr[3];
|
||||
section_length = 0;
|
||||
}
|
||||
bufptr += 4;
|
||||
section_length -= 4;
|
||||
}
|
||||
}
|
||||
close(pat_fd);
|
||||
|
||||
return pmt_pid;
|
||||
}
|
||||
|
||||
int dvb_demux_stop(int fd)
|
||||
{
|
||||
|
|
|
@ -27,6 +27,7 @@ int dvb_get_tuner_type(int fe_fd, struct mp_log *log);
|
|||
int dvb_open_devices(dvb_priv_t *priv, int n, int demux_cnt);
|
||||
int dvb_fix_demuxes(dvb_priv_t *priv, int cnt);
|
||||
int dvb_set_ts_filt(dvb_priv_t *priv, int fd, uint16_t pid, dmx_pes_type_t pestype);
|
||||
int dvb_get_pmt_pid(dvb_priv_t *priv, int card, int service_id);
|
||||
int dvb_demux_stop(int fd);
|
||||
int dvb_demux_start(int fd);
|
||||
int dvb_tune(dvb_priv_t *priv, int freq, char pol, int srate, int diseqc,
|
||||
|
|
|
@ -65,6 +65,7 @@ typedef struct {
|
|||
int tpid, dpid1, dpid2, progid, ca, pids[DMX_FILTER_SIZE], pids_cnt;
|
||||
bool is_dvb_s2;
|
||||
int stream_id;
|
||||
int service_id;
|
||||
fe_spectral_inversion_t inv;
|
||||
fe_modulation_t mod;
|
||||
fe_transmit_mode_t trans;
|
||||
|
|
|
@ -214,7 +214,7 @@ static dvb_channels_list *dvb_get_channels(struct mp_log *log, char *filename, i
|
|||
const char *ter_conf = "%d:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]\n";
|
||||
const char *atsc_conf = "%d:%255[^:]:%255[^:]:%255[^:]\n";
|
||||
|
||||
const char *vdr_conf = "%d:%255[^:]:%255[^:]:%d:%255[^:]:%255[^:]:%255[^:]:%*255[^:]:%*d:%*d:%*d:%*d\n%n";
|
||||
const char *vdr_conf = "%d:%255[^:]:%255[^:]:%d:%255[^:]:%255[^:]:%255[^:]:%*255[^:]:%d:%*d:%*d:%*d\n%n";
|
||||
|
||||
mp_verbose(log, "CONFIG_READ FILE: %s, type: %d\n", filename, type);
|
||||
if((f=fopen(filename, "r"))==NULL)
|
||||
|
@ -267,13 +267,14 @@ static dvb_channels_list *dvb_get_channels(struct mp_log *log, char *filename, i
|
|||
ptr->pids_cnt = 0;
|
||||
ptr->freq = 0;
|
||||
ptr->is_dvb_s2 = false;
|
||||
ptr->service_id = -1;
|
||||
ptr->stream_id = NO_STREAM_ID_FILTER;
|
||||
ptr->inv = INVERSION_AUTO;
|
||||
|
||||
// Check if VDR-type channels.conf-line - then full line is consumed by the scan.
|
||||
int num_chars = 0;
|
||||
fields = sscanf(&line[k], vdr_conf,
|
||||
&ptr->freq, vdr_par_str, vdr_loc_str, &ptr->srate, vpid_str, apid_str, tpid_str, &num_chars);
|
||||
&ptr->freq, vdr_par_str, vdr_loc_str, &ptr->srate, vpid_str, apid_str, tpid_str, &ptr->service_id, &num_chars);
|
||||
|
||||
if (num_chars == strlen(&line[k])) {
|
||||
// It's a VDR-style config line.
|
||||
|
@ -302,9 +303,9 @@ static dvb_channels_list *dvb_get_channels(struct mp_log *log, char *filename, i
|
|||
}
|
||||
}
|
||||
|
||||
mp_verbose(log, "SAT, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d, SRATE: %d, POL: %c, DISEQC: %d, S2: %s, StreamID: %d",
|
||||
mp_verbose(log, "SAT, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d, SRATE: %d, POL: %c, DISEQC: %d, S2: %s, StreamID: %d, SID: %d",
|
||||
list->NUM_CHANNELS, fields, ptr->name, ptr->freq, ptr->srate, ptr->pol, ptr->diseqc,
|
||||
ptr->is_dvb_s2 ? "yes" : "no", ptr->stream_id);
|
||||
ptr->is_dvb_s2 ? "yes" : "no", ptr->stream_id, ptr->service_id);
|
||||
} else {
|
||||
mp_verbose(log, "VDR, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d, SRATE: %d",
|
||||
list->NUM_CHANNELS, fields, ptr->name, ptr->freq, ptr->srate);
|
||||
|
@ -355,12 +356,14 @@ static dvb_channels_list *dvb_get_channels(struct mp_log *log, char *filename, i
|
|||
if (parse_pid_string(log, apid_str, ptr)) {
|
||||
fields++;
|
||||
}
|
||||
/*
|
||||
// FIXME: Teletext PID excluded for now, seems misdetected as mp3.
|
||||
if (parse_pid_string(log, tpid_str, ptr)) {
|
||||
fields++;
|
||||
/* If we do not know the service_id, PMT can not be extracted.
|
||||
Teletext decoding will fail without PMT. */
|
||||
if (ptr->service_id != -1) {
|
||||
if (parse_pid_string(log, tpid_str, ptr)) {
|
||||
fields++;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
if((fields < 2) || (ptr->pids_cnt <= 0) || (ptr->freq == 0) || (strlen(ptr->name) == 0))
|
||||
continue;
|
||||
|
@ -383,6 +386,15 @@ static dvb_channels_list *dvb_get_channels(struct mp_log *log, char *filename, i
|
|||
ptr->pids[ptr->pids_cnt] = 0; //PID 0 is the PAT
|
||||
ptr->pids_cnt++;
|
||||
}
|
||||
|
||||
if (ptr->service_id != -1) {
|
||||
/* We have the PMT-PID in addition.
|
||||
This will be found later, when we tune to the channel.
|
||||
Push back here to create the additional demux. */
|
||||
ptr->pids[ptr->pids_cnt] = -1; // Placeholder.
|
||||
ptr->pids_cnt++;
|
||||
}
|
||||
|
||||
mp_verbose(log, " PIDS: ");
|
||||
for(cnt = 0; cnt < ptr->pids_cnt; cnt++)
|
||||
mp_verbose(log, " %d ", ptr->pids[cnt]);
|
||||
|
@ -663,13 +675,32 @@ int dvb_set_channel(stream_t *stream, int card, int n)
|
|||
|
||||
priv->last_freq = channel->freq;
|
||||
priv->is_on = 1;
|
||||
|
||||
if (channel->service_id != -1) {
|
||||
/* We need the PMT-PID in addition.
|
||||
If it has not yet beem resolved, do it now. */
|
||||
for (i = 0; i < channel->pids_cnt; i++) {
|
||||
if (channel->pids[i] == -1) {
|
||||
MP_VERBOSE(stream, "DVB_SET_CHANNEL: PMT-PID for service %d not resolved yet, parsing PAT...\n", channel->service_id);
|
||||
int pmt_pid = dvb_get_pmt_pid(priv, card, channel->service_id);
|
||||
MP_VERBOSE(stream, "DVB_SET_CHANNEL: Found PMT-PID: %d\n", pmt_pid);
|
||||
channel->pids[i] = pmt_pid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//sets demux filters and restart the stream
|
||||
// sets demux filters and restart the stream
|
||||
for(i = 0; i < channel->pids_cnt; i++)
|
||||
{
|
||||
if (!dvb_set_ts_filt(priv,priv->demux_fds[i], channel->pids[i], DMX_PES_OTHER))
|
||||
return 0;
|
||||
if (channel->pids[i] == -1) {
|
||||
// In case PMT was not resolved, skip it here.
|
||||
MP_ERR(stream, "DVB_SET_CHANNEL: PMT-PID not found, teletext-decoding may fail.\n");
|
||||
} else {
|
||||
if (!dvb_set_ts_filt(priv,priv->demux_fds[i], channel->pids[i], DMX_PES_OTHER))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue