Index: stream/dvbin.h =================================================================== --- stream/dvbin.h (revision 31961) +++ stream/dvbin.h (working copy) @@ -97,6 +97,57 @@ #define TUNER_CBL 3 #define TUNER_ATSC 4 +// MPEG TS video/audio stream types +#define STREAM_VIDEO_MPEG1 0x01 +#define STREAM_VIDEO_MPEG2 0x02 +#define STREAM_VIDEO_MPEG4 0x10 +#define STREAM_VIDEO_VC1 0xEA +#define STREAM_VIDEO_H264 0x1B +#define STREAM_AUDIO_MPEG1 0x03 +#define STREAM_AUDIO_MP3 0x04 +#define STREAM_AUDIO_AC3 0x81 +#define STREAM_AUDIO_AAC 0x0F +#define STREAM_AUDIO_DTS 0x8A +#define STREAM_AUDIO_DDPLUS 0x06 +#define STREAM_AUDIO_PCM 0x80 +#define STREAM_AUDIO_EAC3 0x87 +#define STREAM_AUDIO_MPEG4AAC 0x11 +#define STREAM_AUDIO_MPEG2AAC 0xf0 + +#define DVB_MAX_PROGRAMS 32 +#define DVB_MAX_STREAMS 8 + +// PAT table struct +typedef struct { + uint16_t version; + uint16_t ts_pid; + uint16_t nit_pid; + uint8_t section; + uint8_t last_section; + + uint16_t num_programs; + struct { + uint16_t program; + uint16_t pid; + } programs[DVB_MAX_PROGRAMS]; +} dvb_pat_t; + +// PMT table struct +typedef struct { + uint16_t version; + uint16_t program; + uint16_t pcr_pid; + uint8_t section; + uint8_t last_section; + + uint16_t num_streams; + struct { + uint16_t pid; + uint8_t type; + char lang[4]; + } streams[DVB_MAX_STREAMS]; +} dvb_pmt_t; + int dvb_step_channel(stream_t *, int); int dvb_set_channel(stream_t *, int, int); dvb_config_t *dvb_get_config(void); Index: stream/stream_dvb.c =================================================================== --- stream/stream_dvb.c (revision 31961) +++ stream/stream_dvb.c (working copy) @@ -47,7 +47,7 @@ #include "path.h" #include "libavutil/avstring.h" -#include "dvbin.h" +#include "dvb_tune.h" #define MAX_CHANNELS 8 @@ -131,7 +131,7 @@ const char *cbl_conf = "%d:%255[^:]:%d:%255[^:]:%255[^:]:%255[^:]:%255[^:]\n"; const char *sat_conf = "%d:%c:%d:%d:%255[^:]:%255[^:]\n"; 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 *atsc_conf = "%d:%255[^:]:%255[^:]:%255[^:]:%d\n"; mp_msg(MSGT_DEMUX, MSGL_V, "CONFIG_READ FILE: %s, type: %d\n", filename, type); if((f=fopen(filename, "r"))==NULL) @@ -198,10 +198,10 @@ else if(type == TUNER_ATSC) { fields = sscanf(&line[k], atsc_conf, - &ptr->freq, mod, vpid_str, apid_str); + &ptr->freq, mod, vpid_str, apid_str, &ptr->progid); mp_msg(MSGT_DEMUX, MSGL_V, - "ATSC, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d\n", - list->NUM_CHANNELS, fields, ptr->name, ptr->freq); + "ATSC, NUM: %d, NUM_FIELDS: %d, NAME: %s, FREQ: %d, MOD: %s, PIDS: %s:%s, PROG: %d\n", + list->NUM_CHANNELS, fields, ptr->name, ptr->freq, mod, vpid_str, apid_str, ptr->progid); } #endif else //SATELLITE @@ -554,6 +554,16 @@ priv->last_freq = channel->freq; priv->is_on = 1; + // Discover pids by service program id + if (channel->pids[0] < 0 && channel->progid > 0) { + i = dvb_discover_pids(card, channel->progid, priv->timeout, &channel->pids[0], &channel->pids[1]); + if (i <= 0) { + mp_msg(MSGT_DEMUX, MSGL_ERR, "dvb_set_channel: UNABLE TO DISCOVER PIDS, card: %d, progid: %d, EXIT\n", card, channel->progid); + return 0; + } + channel->pids_cnt = i; + } + //sets demux filters and restart the stream for(i = 0; i < channel->pids_cnt; i++) { Index: stream/dvb_tune.c =================================================================== --- stream/dvb_tune.c (revision 31961) +++ stream/dvb_tune.c (working copy) @@ -440,3 +440,251 @@ return ris == 0; } + +static inline uint16_t dvb_get_section_length(uint8_t *ptr) +{ + return ((ptr[1] & 0x0F) << 8) | ptr[2]; +} + +static inline uint16_t dvb_get_descriptor_length(uint8_t *ptr) +{ + return (ptr[0] & 0x03) << 8 | ptr[1]; +} + +static int dvb_parse_pat(uint8_t *bufptr, int bufsize, dvb_pat_t *pat) +{ + int slen, end, base; + + if (bufsize < 11 || bufptr[0] != 0) { + return 0; + } + + // Section length + slen = dvb_get_section_length(&bufptr[0]); + end = slen + 2; + if (end >= bufsize) { + return 0; + } + + // Current next indicator + if ((bufptr[5] & 0x01) == 0) { + return 0; + } + + // Parse section header + memset(pat, 0, sizeof(dvb_pat_t)); + pat->nit_pid = 0; + pat->ts_pid = bufptr[3] << 8 | bufptr[4]; + pat->version = (bufptr[5] & 0x3e) >> 1; + pat->section = bufptr[6]; + pat->last_section = bufptr[7]; + + // Point to the beginning of the descriptor + base = 8; + + while (base + 3 < end - 3 && pat->num_programs < DVB_MAX_PROGRAMS) { + pat->programs[pat->num_programs].program = bufptr[base] << 8 | bufptr[base + 1]; + pat->programs[pat->num_programs].pid = (bufptr[base + 2] & 0x1f) << 8 | bufptr[base + 3]; + // Advance with record size + base += 4; + + mp_msg(MSGT_DEMUX, MSGL_V, "dvb_parse_pat: program: %d, pid: %d\n", + pat->programs[pat->num_programs].program, + pat->programs[pat->num_programs].pid); + pat->num_programs++; + } + + return pat->num_programs > 0; +} + +static int dvb_parse_pmt(uint8_t *bufptr, int bufsize, dvb_pmt_t *pmt) +{ + int slen, end, plen, dlen, base; + + if (bufsize < 11 || bufptr[0] != 2) { + return 0; + } + + // Section length + slen = dvb_get_section_length(&bufptr[0]); + end = slen + 2; + if (end >= bufsize) { + return 0; + } + // Do not include CRC field, end points to the first byte of the CRC32 field + end -= 3; + + // Parse section header + memset(pmt, 0, sizeof(dvb_pmt_t)); + pmt->program = bufptr[3] << 8 | bufptr[base + 4]; + pmt->version = (bufptr[5] & 0x3e) >> 1; + pmt->section = bufptr[6]; + pmt->last_section = bufptr[7]; + pmt->pcr_pid = (bufptr[8] & 0x1f) << 8 | (bufptr[9]); + + // Program info length + plen = dvb_get_descriptor_length(&bufptr[10]); + base = 11; + + // Parse program descriptors + while (plen > 0) { + int tlen = bufptr[base + 2]; + + if (tlen > plen - 2) { + return 0; + } + plen -= tlen + 2; + base += tlen + 2; + } + + while (base + 5 < end && pmt->num_streams < DVB_MAX_STREAMS) { + pmt->streams[pmt->num_streams].type = bufptr[base + 1]; + pmt->streams[pmt->num_streams].pid = (bufptr[base + 2] & 0x1f) << 8 | bufptr[base + 3]; + + // ES descriptors length + dlen = dvb_get_descriptor_length(&bufptr[base + 4]); + base += 5; + + if (base + dlen >= end) { + return 0; + } + + while (dlen > 0) { + int tag = bufptr[base + 1]; + int tlen = bufptr[base + 2]; + + if (tlen > dlen - 2) { + return 0; + } + switch (tag) { + case 0x0a: // ISO language descriptor + if (tlen >= 4) { + pmt->streams[pmt->num_streams].lang[0] = bufptr[base + 3]; + pmt->streams[pmt->num_streams].lang[1] = bufptr[base + 4]; + pmt->streams[pmt->num_streams].lang[2] = bufptr[base + 5]; + } + break; + } + + dlen -= tlen + 2; + base += tlen + 2; + } + + mp_msg(MSGT_DEMUX, MSGL_V, "dvb_parse_pmt: type: 0x%x, pid: %d, lang: %s\n", + pmt->streams[pmt->num_streams].type, + pmt->streams[pmt->num_streams].pid, + pmt->streams[pmt->num_streams].lang); + pmt->num_streams++; + } + + return pmt->num_streams > 0; +} + +static int dvb_get_psi_table(int card, int pid, int section, int timeout, void *table) +{ + int n, fd; + char path[64]; + uint8_t buf[4096]; + struct pollfd pfds[1]; + struct dmx_sct_filter_params params; + + snprintf(path, sizeof(path), "/dev/dvb/adapter%d/demux0", card); + fd = open(path, O_RDWR | O_NONBLOCK); + if (fd < 0) { + return 0; + } + + memset(¶ms, 0, sizeof(params)); + params.pid = pid; + params.filter.filter[0] = section; + params.filter.mask[0] = 0xff; + params.flags = DMX_IMMEDIATE_START; + + if (ioctl(fd, DMX_SET_FILTER, ¶ms) < 0) { + close(fd); + return 0; + } + + // Parse one section + pfds[0].fd = fd; + pfds[0].events = POLLIN | POLLPRI; + if (poll(pfds, 1, timeout * 1000) <= 0) { + close(fd); + return 0; + } + n = read(fd, buf, sizeof(buf)); + close(fd); + + switch (section) { + case 0: + return dvb_parse_pat(buf, n, (dvb_pat_t*) table); + + case 2: + return dvb_parse_pmt(buf, n, (dvb_pmt_t*) table); + } + return 0; +} + +int dvb_discover_pids(int card, int program, int timeout, int *apid, int *vpid) +{ + int i, ts_pid = -1; + dvb_pat_t pat; + dvb_pmt_t pmt; + + // Read PAT table + if (!dvb_get_psi_table(card, 0, 0, timeout, &pat)) { + return 0; + } + + // Find required PID in the PMT list + for (i = 0; i < pat.num_programs; i++) { + if (program == pat.programs[i].program) { + ts_pid = pat.programs[i].pid; + break; + } + } + if (ts_pid < 0) { + return 0; + } + + // Read PMT table + if (!dvb_get_psi_table(card, ts_pid, 2, timeout, &pmt)) { + return 0; + } + + *apid = *vpid = 0; + + // Find stream pids and types + for (i = 0; i < pmt.num_streams; i++) { + switch (pmt.streams[i].type) { + case STREAM_AUDIO_AC3: + case STREAM_AUDIO_AAC: + case STREAM_AUDIO_DTS: + case STREAM_AUDIO_MP3: + case STREAM_AUDIO_MPEG1: + case STREAM_AUDIO_PCM: + case STREAM_AUDIO_EAC3: + case STREAM_AUDIO_MPEG4AAC: + case STREAM_AUDIO_MPEG2AAC: + if (*apid <= 0) { + *apid = pmt.streams[i].pid; + } + break; + + case STREAM_VIDEO_MPEG1: + case STREAM_VIDEO_MPEG2: + case STREAM_VIDEO_MPEG4: + case STREAM_VIDEO_VC1: + case STREAM_VIDEO_H264: + if (*vpid <= 0) { + *vpid = pmt.streams[i].pid; + } + break; + } + } + + mp_msg(MSGT_DEMUX, MSGL_INFO, "dvb_discover_pids: card: %d, progid: %d, apid: %d, vpid: %d\n", card, program, *apid, *vpid); + + return *apid > 0 && *vpid > 0 ? 2 : *apid > 0 || *vpid > 0 ? 1 : 0; +} + Index: stream/dvb_tune.h =================================================================== --- stream/dvb_tune.h (revision 31961) +++ stream/dvb_tune.h (working copy) @@ -33,5 +33,6 @@ fe_transmit_mode_t TransmissionMode, fe_bandwidth_t bandWidth, fe_code_rate_t HP_CodeRate, fe_code_rate_t LP_CodeRate, fe_hierarchy_t hier, int timeout); - +int dvb_discover_pids(int card, int program, int timeout, + int *apid, int *vpid); #endif /* MPLAYER_DVB_TUNE_H */