From 5c49cd8e07ca0f676f759bfb8e1e4a94636e2af6 Mon Sep 17 00:00:00 2001 From: arpi Date: Sun, 16 Mar 2003 20:13:28 +0000 Subject: this is a combo patch that: 1) adds an experimental TS demuxer to mplayer 2) adds an input (streaming) interface from DVB cards. It compiles and runs with the following versions of the drivers: dvb-kernel (HEAD) (with stock kernel 2.4.20) and 0.9.4 (with kernel 2.4.18) patch by Nico some cleanups, ts demuxer fixes by me git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@9611 b3059339-0415-0410-9bf9-f77b7e298cf2 --- libmpdemux/Makefile | 11 +- libmpdemux/demux_ts.c | 903 ++++++++++++++++++++++++++++++++++++++++++++++ libmpdemux/demuxer.c | 25 +- libmpdemux/demuxer.h | 3 +- libmpdemux/dvb_defaults.h | 89 +++++ libmpdemux/dvb_tune.c | 803 +++++++++++++++++++++++++++++++++++++++++ libmpdemux/dvbin.c | 684 +++++++++++++++++++++++++++++++++++ libmpdemux/dvbin.h | 102 ++++++ libmpdemux/open.c | 24 ++ libmpdemux/stream.c | 15 + libmpdemux/stream.h | 1 + libmpdemux/video.c | 4 +- 12 files changed, 2660 insertions(+), 4 deletions(-) create mode 100644 libmpdemux/demux_ts.c create mode 100644 libmpdemux/dvb_defaults.h create mode 100644 libmpdemux/dvb_tune.c create mode 100644 libmpdemux/dvbin.c create mode 100644 libmpdemux/dvbin.h (limited to 'libmpdemux') diff --git a/libmpdemux/Makefile b/libmpdemux/Makefile index 42d2ca21cf..a1ce08ffe7 100644 --- a/libmpdemux/Makefile +++ b/libmpdemux/Makefile @@ -3,7 +3,7 @@ LIBNAME = libmpdemux.a include ../config.mak -SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c cue_read.c extension.c demux_gif.c +SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c cue_read.c extension.c demux_gif.c demux_ts.c ifeq ($(XMMS_PLUGINS),yes) SRCS += demux_xmms.c endif @@ -20,6 +20,15 @@ SRCS += rtp.c endif endif +DVBIN = yes +ifeq ($(DVBIN),yes) +SRCS += dvbin.c +SRCS += dvb_tune.c +endif + + + + OBJS = $(SRCS:.c=.o) OBJS += $(CPLUSPLUSSRCS:.cpp=.o) INCLUDE = -I../loader $(CSS_INC) $(EXTRA_INC) diff --git a/libmpdemux/demux_ts.c b/libmpdemux/demux_ts.c new file mode 100644 index 0000000000..a718a17da7 --- /dev/null +++ b/libmpdemux/demux_ts.c @@ -0,0 +1,903 @@ +/* + * Copyright (C) 2000-2002 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id$ + * + * Demultiplexer for MPEG2 Transport Streams. + * + * For the purposes of playing video, we make some assumptions about the + * kinds of TS we have to process. The most important simplification is to + * assume that the TS contains a single program (SPTS) because this then + * allows significant simplifications to be made in processing PATs. + + + + /* + * WARNING: Quite a hack was required in order to get files by MultiDec played back correctly. + * If it breaks anything else, just comment out the "#define DEMUX_PVA_MULTIDEC_HACK" below + * and it will not be compiled in. + * + * Feedback is appreciated. + * + * written by Matteo Giani + */ + + +/* + * MPEG2 transport stream (aka DVB) demux + * Copyright (c) 2002 Fabrice Bellard. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" + +#include "stream.h" +#include "demuxer.h" +#include "stheader.h" + +#include "bswap.h" + + +typedef struct { + off_t offset; + long size; + uint8_t type; + uint8_t is_packet_start; + float pts; + uint8_t packet_size; +} ts_payload_t; + + +typedef struct { + float last_audio_pts; + float last_video_pts; + uint8_t just_synced; + uint8_t synced_stream_id; + char *buffer; + int buffer_size; + int buffer_offset; + int packet_size; +} ts_priv_t; + +#define TS_FEC_PACKET_SIZE 204 +#define TS_PACKET_SIZE 188 +#define NB_PID_MAX 8192 + +#define MAX_HEADER_SIZE 6 /* enough for PES header + length */ +#define MAX_PROBE_SIZE 1000000 +#define NUM_CONSECUTIVE_TS_PACKETS 5 + + +enum MpegTSState { + MPEGTS_HEADER = 0, + MPEGTS_PESHEADER_FILL, + MPEGTS_PESHEADER_FLAGS, + MPEGTS_PESHEADER_SIZE, + MPEGTS_PESHEADER_READ, + MPEGTS_PAYLOAD, + MPEGTS_SKIP, +}; + + +int ts_fastparse = 0; + +typedef enum +{ + UNKNOWN = -1, + VIDEO_MPEG2 = 0x10000002, + AUDIO_MP2 = 0x50, + AUDIO_A52 = 0x2000, + AUDIO_LPCM_BE = 0x2000000, + SPU_DVD = 0x3000000, + SPU_DVB = 0x3000001, +} es_stream_type_t; + +typedef struct MpegTSStream // IT'S AN ES +{ + int pid; + enum MpegTSState state; + int last_cc; /* last cc code (-1 if first packet) */ + /* used to get the format */ + int header_size; + int payload_size; + int pes_header_size; + //AVStream *st; + es_stream_type_t type; + unsigned char header[MAX_HEADER_SIZE]; + char *pes_buffer; + int offset; + float pts; + float last_pts; +} MpegTSStream; + + +typedef struct MpegTSContext { + int raw_packet_size; /* raw packet size, including FEC if present */ + MpegTSStream *pids[NB_PID_MAX]; + demuxer_t *demuxer; +} MpegTSContext; + + +typedef struct { + int size; + unsigned char *start; + es_stream_type_t type; + float pts; + int pid; +} ES_info_t; + +MpegTSContext ts; + +//FILE *outfile; + + +static uint8_t get_packet_size(const unsigned char *buf, int size) +{ + int i; + + if (size < (TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS)) + return 0; + + for(i=0; istream)) != 0x47) + && (i < MAX_PROBE_SIZE) + && ! demuxer->stream->eof + ) i++; + + if(c != 0x47) + { + mp_msg(MSGT_DEMUX, MSGL_V, "NOT A TS FILE1\n"); + done = 1; + continue; + } + + pos = stream_tell(demuxer->stream) - 1; + buf[0] = c; + _read = stream_read(demuxer->stream, &buf[1], buf_size-1); + + if(_read < buf_size-1) + { + mp_msg(MSGT_DEMUX, MSGL_V, "COULDN'T READ ENOUGH DATA, EXITING TS_CHECK\n"); + stream_reset(demuxer->stream); + return 0; + } + + size = get_packet_size(buf, buf_size); + if(size) + done = 1; + } + + mp_msg(MSGT_DEMUX, MSGL_V, "TRIED UP TO POSITION %u, FUOND %x, packet_size= %d\n", i, c, size); + stream_seek(demuxer->stream, pos); + return size; +} + + + + + +demuxer_t *demux_open_ts(demuxer_t * demuxer) +{ + uint8_t packet_size; + //demuxer_t *vd, *ad; + //stream_t *s; + sh_video_t *sh_video; + sh_audio_t *sh_audio; + ts_priv_t * priv; + int i; + + + mp_msg(MSGT_DEMUX, MSGL_V, "DEMUX OPEN, AUDIO_ID: %d, VIDEO_ID: %d, SUBTITLE_ID: %d,\n", + demuxer->audio->id, demuxer->video->id, demuxer->sub->id); + + for(i=0; i < 8192; i++) + ts.pids[i] = NULL; + + demuxer->type= DEMUXER_TYPE_MPEG_TS; + + stream_reset(demuxer->stream); + stream_seek(demuxer->stream, 0); + + packet_size = ts_check_file(demuxer); + if(!packet_size) + return NULL; + + priv = malloc(sizeof(ts_priv_t)); + priv->last_video_pts=-1; + priv->last_audio_pts=-1; + priv->packet_size = packet_size; + demuxer->priv = priv; + + if(demuxer->stream->type != STREAMTYPE_FILE) demuxer->seekable=0; + else demuxer->seekable = 1; + + + sh_video = new_sh_video(demuxer, 0); + sh_video->ds = demuxer->video; + demuxer->video->sh = sh_video; + + + + sh_audio = new_sh_audio(demuxer, 0); + sh_audio->ds = demuxer->audio; + demuxer->audio->sh = sh_audio; + + + mp_msg(MSGT_DEMUXER,MSGL_INFO, "Opened TS demuxer..."); + + if(! ts_fastparse) + ts_detect_streams(demuxer); + + + /* + demuxer->movi_start = 0; + demuxer->movi_end = demuxer->stream->end_pos; + */ + + + /* + s= new_ds_stream(demuxer->video); + return demux_open_stream(s, DEMUXER_TYPE_MPEG_ES, demuxer->audio->id, demuxer->video->id, demuxer->sub->id, NULL); + */ + + stream_seek(demuxer->stream, 0); //IF IT'S FROM A PIPE IT WILL FAIL, BUT WHO CARES? + return demuxer; +} + + + +void ts_detect_streams(demuxer_t *demuxer) +{ + int video_found = 0, audio_found = 0; + off_t pos=0; + ES_info_t es; + int *apid, *vpid, *spid; + unsigned char tmp[TS_FEC_PACKET_SIZE]; + sh_video_t *sh_video = demuxer->video->sh; + sh_audio_t *sh_audio = demuxer->audio->sh; + + apid = &(demuxer->audio->id); + vpid = &(demuxer->video->id); + spid = &(demuxer->sub->id); + + + mp_msg(MSGT_DEMUXER, MSGL_INFO, "PROBING UP TO %u\n", MAX_PROBE_SIZE); + while(pos <= MAX_PROBE_SIZE) + { + if(ts_parse(demuxer, &es, tmp)) + { + mp_msg(MSGT_DEMUXER, MSGL_V, "TYPE: %x, PID: %d\n", es.type, es.pid); + if(es.type == VIDEO_MPEG2) + { + sh_video->format = VIDEO_MPEG2; //MPEG2 video + if(*vpid == -1) + *vpid = es.pid; + video_found = 1; + } + + if(es.type == AUDIO_MP2) + { + sh_audio->format = AUDIO_MP2; //MPEG1L2 audio + if(*apid == -1) + *apid = es.pid; + audio_found = 1; + } + + if(es.type == AUDIO_A52) + { + sh_audio->format = AUDIO_MP2; //MPEG1L2 audio + if(*apid == -1) + *apid = es.pid; + audio_found = 1; + } + + pos = stream_tell(demuxer->stream); + if(video_found && audio_found) + break; + } + } + + if(video_found) + mp_msg(MSGT_DEMUXER, MSGL_INFO, "VIDEO MPEG2..."); + else + { + *vpid = -2; //WE DIDN'T MATCH ANY VIDEO STREAM, SO WE FORCE THE DEMUXER TO IGNORE VIDEO + mp_msg(MSGT_DEMUXER, MSGL_INFO, "NO VIDEO!\n"); + } + + if(sh_audio->format == AUDIO_MP2) + mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO MP2\n"); + else if(sh_audio->format == AUDIO_A52) + mp_msg(MSGT_DEMUXER, MSGL_INFO, "AUDIO A52\n"); + else + { + *apid = -2; //WE DIDN'T MATCH ANY AUDIO STREAM, SO WE FORCE THE DEMUXER TO IGNORE AUDIO + mp_msg(MSGT_DEMUXER, MSGL_INFO, "NO AUDIO!\n"); + } +} + + +void demux_close_ts(demuxer_t * demuxer) +{ + if(demuxer->priv) + { + free(demuxer->priv); + demuxer->priv=NULL; + } +} + + + + +//MpegTSStream *tss, const unsigned char *buf, int buf_size, int is_start, ES_info_t *es +static int pes_parse2(MpegTSStream *tss, unsigned char *buf, uint16_t packet_len, int is_start, ES_info_t *es) +{ + unsigned char *p; + uint32_t header_len; + int64_t pts; + uint32_t stream_id; + uint32_t pkt_len; + + mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2(%X, %X, %d, %d, ): \n", tss, buf, packet_len, is_start); + + if(packet_len == 0) + { + mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2(,PACKET_LEN = 0, EXIT\n"); + return 0; + } + + if(packet_len > 184) + { + mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2, BUFFER LEN IS TOO BIG: %d, EXIT\n", packet_len); + return 0; + } + + + p = buf; + pkt_len = packet_len; + + if(! is_start) + { + tss->pts = tss->last_pts; + es->start = p; + es->size = packet_len; + return es->size; + } + + /* we should have a PES packet here */ + + if (p[0] || p[1] || (p[2] != 1)) + { + mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: error HEADER %02x %02x %02x (should be 0x000001) \n", p[0], p[1], p[2]); + return 0 ; + } + + packet_len -= 6; + + tss->payload_size = p[4] << 8 | p[5]; + if (tss->payload_size == 0) + tss->payload_size = 65536; + + stream_id = p[3]; + + if(packet_len==0) + return 0; + + //mp_msg(MSGT_DEMUX, MSGL_V, "pes_parse2: packet stream id: %.2X (%d) len: %d (%x)\n", stream_id, stream_id, packet_len, packet_len); + + if (p[7] & 0x80) + { /* pts avail */ + pts = (int64_t)(p[9] & 0x0E) << 29 ; + pts |= p[10] << 22 ; + pts |= (p[11] & 0xFE) << 14 ; + pts |= p[12] << 7 ; + pts |= (p[13] & 0xFE) >> 1 ; + + tss->pts = tss->last_pts = pts / 90000.0f; + } + else + tss->pts = tss->last_pts; + + header_len = p[8]; + + /* sometimes corruption on header_len causes segfault in memcpy below */ + if (header_len + 9 > pkt_len) + { + mp_msg(MSGT_DEMUX, MSGL_DBG2, "demux_ts: illegal value for PES_header_data_length (0x%02x)\n", header_len); + return 0; + } + + p += header_len + 9; + packet_len -= header_len + 3; + + if (stream_id == 0xbd) + { + int track, spu_id; + + mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: audio buf = %02X %02X %02X %02X %02X %02X %02X %02X\n", + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + + track = p[0] & 0x0F; /* hack : ac3 track */ + /* + * we check the descriptor tag first because some stations + * do not include any of the ac3 header info in their audio tracks + * these "raw" streams may begin with a byte that looks like a stream type. + */ + if( //(m->descriptor_tag == 0x81) || /* ac3 - raw */ + (p[0] == 0x0B && p[1] == 0x77)) /* ac3 - syncword */ + { + es->start = p; + es->size = packet_len; + tss->type = AUDIO_A52; + return es->size; + } + else if (//m->descriptor_tag == 0x06 && + p[0] == 0x20 && p[1] == 0x00) + { + /* DVBSUB */ + long payload_len = ((buf[4] << 8) | buf[5]) - header_len - 3; + es->start = p; + es->size = packet_len; + tss->type = SPU_DVB + payload_len; + + return es->size; + } + else if ((p[0] & 0xE0) == 0x20) + { + spu_id = (p[0] & 0x1f); + es->start = p+1; + es->size = packet_len-1; + tss->type = SPU_DVD + spu_id; + return es->size; + } + else if ((p[0] & 0xF0) == 0x80) + { + es->start = p+4; + es->size = packet_len - 4; + tss->type = AUDIO_A52; // + track; + return es->size; + } + else if ((p[0]&0xf0) == 0xa0) + { + int pcm_offset; + + for (pcm_offset=0; ++pcm_offset < packet_len-1 ; ) + { + if (p[pcm_offset] == 0x01 && p[pcm_offset+1] == 0x80) + { /* START */ + pcm_offset += 2; + break; + } + } + + es->start = p + pcm_offset; + es->size = packet_len - pcm_offset; + tss->type = AUDIO_LPCM_BE; // + track; + return es->size; + } + } + else if ((stream_id >= 0xbc) && ((stream_id & 0xf0) == 0xe0)) + { + es->start = p; + es->size = packet_len; + tss->type = VIDEO_MPEG2; + return es->size; + } + else if ((stream_id & 0xe0) == 0xc0) + { + int track; + track = stream_id & 0x1f; + es->start = p; + es->size = packet_len; + tss->type = AUDIO_MP2; // + track; + return es->size; + } + else + { + mp_msg(MSGT_DEMUX, MSGL_DBG2, "pes_parse2: unknown packet, id: %x\n", stream_id); + } + + return 0; +} + + + + +int ts_sync(demuxer_t *demuxer) +{ + uint8_t c=0; + + mp_msg(MSGT_DEMUX, MSGL_DBG2, "TS_SYNC \n"); + + while(((c=stream_read_char(demuxer->stream)) != 0x47) && ! demuxer->stream->eof); + + if(c == 0x47) + return c; + else + return 0; +} + + + + + + +// 0 = EOF or no stream found +// 1 = successfully read a packet +int ts_parse(demuxer_t * demuxer , ES_info_t *es, unsigned char *packet) +{ + MpegTSStream *tss; + uint8_t done = 0; + ts_priv_t *priv = demuxer->priv; + uint16_t buf_size, is_start; + int len, pid, cc, cc_ok, afc; + unsigned char *p; + + while(! done) + { + if(! ts_sync(demuxer)) + { + mp_msg(MSGT_DEMUX, MSGL_V, "TS_FILL_BUFFER: COULDN'T SYNC\n"); + return 0; + } + + len = stream_read(demuxer->stream, &packet[1], priv->packet_size-1); + if (len != priv->packet_size-1) + return 0; + + + + pid = ((packet[1] & 0x1f) << 8) | packet[2]; + tss = ts.pids[pid]; //an ES stream + if(tss == NULL) + { + /* if no pid found, then add a pid context */ + tss = malloc(sizeof(MpegTSStream)); + if (!tss) + continue; + memset(tss, 0, sizeof(MpegTSStream)); + ts.pids[pid] = tss; + tss->pid = pid; + tss->last_cc = -1; + tss->type = UNKNOWN; + mp_msg(MSGT_DEMUX, MSGL_DBG2, "new TS pid=%u\n", pid); + } + + cc = (packet[3] & 0xf); + cc_ok = (tss->last_cc < 0) || ((((tss->last_cc + 1) & 0x0f) == cc)); + if(! cc_ok) + { + mp_msg(MSGT_DEMUX, MSGL_V, "ts_parse: CCCheck NOT OK: %d -> %d\n", tss->last_cc, cc); + } + tss->last_cc = cc; + + + + /* skip adaptation field */ + afc = (packet[3] >> 4) & 3; + p = packet + 4; + if (afc == 0) /* reserved value */ + continue; + if (afc == 2) /* adaptation field only */ + continue; + if (afc == 3) + { + /* skip adapation field */ + p += p[0] + 1; + } + /* if past the end of packet, ignore */ + if (p >= packet + TS_PACKET_SIZE) + continue; + + // PES CONTENT STARTS HERE + + buf_size = TS_PACKET_SIZE - (p - packet); + + is_start = packet[1] & 0x40; + if((len = pes_parse2(tss, p, buf_size, is_start, es))) + { + tss->offset += es->size; + es->pid = tss->pid; + es->pts = tss->pts; + es->type = tss->type; + + mp_msg(MSGT_DEMUX, MSGL_DBG2, "ts_parse, type=%X, start=%X, len=%d\n", tss->type, es->start, es->size); + + return len; + } + } + + return 0; +} + + +int demux_ts_fill_buffer(demuxer_t * demuxer) +{ + ES_info_t es; + demux_packet_t *dp; + int len; + unsigned char packet[TS_FEC_PACKET_SIZE]; + int *apid, *vpid, *spid; + + apid = &(demuxer->audio->id); + vpid = &(demuxer->video->id); + spid = &(demuxer->sub->id); + + while(len = ts_parse(demuxer, &es, packet)) + { + mp_msg(MSGT_DEMUX, MSGL_V, "NEW_FILL_BUFFER, NEW_ADD_PACKET(%x, %d) type: %x, PTS: %f\n", es.start, es.size, es.type, es.pts); + + if(es.type == VIDEO_MPEG2) + { + if(ts_fastparse) + { + if(*vpid == -2) + continue; + + if(*vpid == -1) + *vpid = es.pid; + } + + if(*vpid != es.pid) + continue; + + dp = new_demux_packet(es.size); + if(! dp || ! dp->buffer) + { + fprintf(stderr, "fill_buffer, NEW_ADD_PACKET(%d) FAILED\n", es.size); + continue; + } + memcpy(dp->buffer, es.start, es.size); + dp->pts = es.pts; + dp->flags = 0; + dp->pos = stream_tell(demuxer->stream); + ds_add_packet(demuxer->video, dp); + mp_msg(MSGT_DEMUX, MSGL_V, "VIDEO pts=%f\n", es.pts); + return len; + } + + if((es.type == AUDIO_MP2) || (es.type == AUDIO_A52)) + { + if(ts_fastparse) + { + if(*apid == -2) + continue; + + if(*apid == -1) + *apid = es.pid; + } + + if(*apid != es.pid) + continue; + + dp = new_demux_packet(es.size); + if(! dp || ! dp->buffer) + { + fprintf(stderr, "fill_buffer, NEW_ADD_PACKET(%d) FAILED\n", es.size); + continue; + } + memcpy(dp->buffer, es.start, es.size); + dp->flags = 0; + dp->pts = es.pts; + dp->pos = stream_tell(demuxer->stream); + ds_add_packet(demuxer->audio, dp); + mp_msg(MSGT_DEMUX, MSGL_V, "AUDIO pts=%f\r\n", es.pts); + return len; + } + + mp_msg(MSGT_DEMUX, MSGL_V, "SKIP--------\n"); + } +} + + + + +int stringent_ts_sync(demuxer_t *demuxer) +{ + ts_priv_t *priv = demuxer->priv; + uint8_t c = 0, done = 0, i, buf[TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS]; + off_t pos; + + mp_msg(MSGT_DEMUX, MSGL_DBG2, "STRINGENT_TS_SYNC packet_size: %d\n", priv->packet_size); + + + if(! demuxer->seekable) + return 0; + + + while(! done) + { + while(((c=stream_read_char(demuxer->stream)) != 0x47) && !demuxer->stream->eof); + + if(c != 0x47) + { + stream_reset(demuxer->stream); + return 0; + } + + pos = stream_tell(demuxer->stream); + if(pos < 1) + pos = 1; + mp_msg(MSGT_DEMUX, MSGL_DBG2, "dopo il while, pos=%u\n", pos); + + done = 1; + buf[0] = c; + stream_read(demuxer->stream, &buf[1], (priv->packet_size * NUM_CONSECUTIVE_TS_PACKETS) - 1); + for(i = 0; i < 5; i++) + { + if (buf[i * priv->packet_size] != 0x47) + done = 0; + mp_msg(MSGT_DEMUX, MSGL_DBG2, "i: %d, char: %x\n", i, buf[i * priv->packet_size]); + } + + if(done) + stream_seek(demuxer->stream, pos); + else + stream_seek(demuxer->stream, pos); + } + //stream_seek(demuxer->stream, pos+1); + mp_msg(MSGT_DEMUX, MSGL_DBG2, "STRINGENT_TS_SYNC, STREAM_POS: %lu\n", stream_tell(demuxer->stream)); + return 0x47; +} + + +extern void resync_audio_stream(sh_audio_t *); + + +int demux_seek_ts(demuxer_t * demuxer, float rel_seek_secs, int flags) +{ + int total_bitrate=0; + off_t dest_offset; + ts_priv_t * priv = demuxer->priv; + int a_bps, v_bps; + demux_stream_t *d_audio=demuxer->audio; + demux_stream_t *d_video=demuxer->video; + sh_audio_t *sh_audio=d_audio->sh; + sh_video_t *sh_video=d_video->sh; + + + /* + * Compute absolute offset inside the stream. Approximate total bitrate with sum of bitrates + * reported by the audio and video codecs. The seek is not accurate because, just like + * with MPEG streams, the bitrate is not constant. Moreover, we do not take into account + * the overhead caused by PVA and PES headers. + * If the calculated absolute offset is negative, seek to the beginning of the file. + */ + + + if(demuxer->audio->id != -2) + { + a_bps = ((sh_audio_t *)demuxer->audio->sh)->i_bps; + total_bitrate += a_bps; + } + + if(demuxer->video->id != -2) + { + v_bps = ((sh_video_t *)demuxer->video->sh)->i_bps; + total_bitrate += v_bps; + } + + if(! total_bitrate) + { + mp_msg(MSGT_DEMUX, MSGL_V, "SEEK_TS, couldn't determine bitrate, no seek\n"); + return 0; + } + + dest_offset = stream_tell(demuxer->stream) + rel_seek_secs*total_bitrate; + if(dest_offset < 0) dest_offset = 0; + + mp_msg(MSGT_DEMUX, MSGL_V, "SEEK TO: %f, BITRATE: %lu, FINAL_POS: %u \n", rel_seek_secs, total_bitrate, dest_offset); + + stream_seek(demuxer->stream, dest_offset); + + /*if(!ts_sync(demuxer)) + { + mp_msg(MSGT_DEMUX, MSGL_V, "demux_ts: Couldn't seek!\n"); + return 0; + } + */ + + ds_fill_buffer(d_video); + if(sh_audio) + { + ds_fill_buffer(d_audio); + resync_audio_stream(sh_audio); + } + + + /* + * Reset the PTS info inside the ts_priv_t structure. This way we don't deliver + * data with the wrong PTSs (the ones we had before seeking). + * + */ + + + priv->last_video_pts=-1; + priv->last_audio_pts=-1; + + return 1; +} + + + + + +static int mpegts_read_close(MpegTSContext *ts) +{ + int i; + for(i=0;ipids[i]); + return 0; +} + + + diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c index 49aaf92692..65fd2df5a6 100644 --- a/libmpdemux/demuxer.c +++ b/libmpdemux/demuxer.c @@ -134,6 +134,7 @@ extern void demux_close_pva(demuxer_t* demuxer); extern void demux_close_smjpeg(demuxer_t* demuxer); extern void demux_close_xmms(demuxer_t* demuxer); extern void demux_close_gif(demuxer_t* demuxer); +extern void demux_close_ts(demuxer_t* demuxer); #ifdef USE_TV #include "tv.h" @@ -204,6 +205,8 @@ void free_demuxer(demuxer_t *demuxer){ case DEMUXER_TYPE_GIF: demux_close_gif(demuxer); break; #endif + case DEMUXER_TYPE_MPEG_TS: + demux_close_ts(demuxer); break; } // free streams: @@ -282,6 +285,7 @@ int demux_audio_fill_buffer(demux_stream_t *ds); int demux_pva_fill_buffer(demuxer_t *demux); int demux_xmms_fill_buffer(demuxer_t *demux,demux_stream_t *ds); int demux_gif_fill_buffer(demuxer_t *demux); +int demux_ts_fill_buffer(demuxer_t *demux); extern int demux_demuxers_fill_buffer(demuxer_t *demux,demux_stream_t *ds); extern int demux_ogg_fill_buffer(demuxer_t *d); @@ -334,6 +338,7 @@ int demux_fill_buffer(demuxer_t *demux,demux_stream_t *ds){ #ifdef HAVE_GIF case DEMUXER_TYPE_GIF: return demux_gif_fill_buffer(demux); #endif + case DEMUXER_TYPE_MPEG_TS: return demux_ts_fill_buffer(demux); } return 0; } @@ -560,6 +565,7 @@ extern int bmp_check_file(demuxer_t *demuxer); extern int demux_xmms_open(demuxer_t* demuxer); extern int gif_check_file(demuxer_t *demuxer); extern int demux_open_gif(demuxer_t* demuxer); +extern int ts_check_file(demuxer_t * demuxer); extern demuxer_t* init_avi_with_ogg(demuxer_t* demuxer); @@ -817,6 +823,17 @@ if(file_format == DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_PVA){ demuxer=NULL; } } +//=============== Try to open as MPEG-TS file: ================= +if(file_format == DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_MPEG_TS){ + demuxer=new_demuxer(stream,DEMUXER_TYPE_MPEG_TS,audio_id,video_id,dvdsub_id); + if(ts_check_file(demuxer)) { + mp_msg(MSGT_DEMUXER,MSGL_INFO,MSGTR_Detected_XXX_FileFormat,"TS"); + file_format=DEMUXER_TYPE_MPEG_TS; + } else { + free_demuxer(demuxer); + demuxer=NULL; + } +} //=============== Try to open as MPEG-PS file: ================= if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_MPEG_PS){ int pes=1; @@ -1127,6 +1144,10 @@ switch(file_format){ break; } #endif + case DEMUXER_TYPE_MPEG_TS: { + demux_open_ts(demuxer); + break; + } } // switch(file_format) pts_from_bps=0; // !!! return demuxer; @@ -1195,6 +1216,7 @@ int demux_seek_nuv(demuxer_t *demuxer,float rel_seek_secs,int flags); void demux_seek_mov(demuxer_t *demuxer,float pts,int flags); int demux_seek_real(demuxer_t *demuxer,float rel_seek_secs,int flags); int demux_seek_pva(demuxer_t *demuxer,float rel_seek_secs,int flags); +int demux_seek_ts(demuxer_t *demuxer,float rel_seek_secs,int flags); #ifdef HAVE_LIBDV095 int demux_seek_rawdv(demuxer_t *demuxer, float pts, int flags); @@ -1294,7 +1316,8 @@ switch(demuxer->file_format){ case DEMUXER_TYPE_XMMS: demux_xmms_seek(demuxer,rel_seek_secs,flags); break; #endif - + case DEMUXER_TYPE_MPEG_TS: + demux_seek_ts(demuxer,rel_seek_secs,flags); break; } // switch(demuxer->file_format) diff --git a/libmpdemux/demuxer.h b/libmpdemux/demuxer.h index 0b211f30d5..2138e68a8d 100644 --- a/libmpdemux/demuxer.h +++ b/libmpdemux/demuxer.h @@ -37,11 +37,12 @@ #define DEMUXER_TYPE_RAWVIDEO 26 #define DEMUXER_TYPE_MPEG4_ES 27 #define DEMUXER_TYPE_GIF 28 +#define DEMUXER_TYPE_MPEG_TS 29 // This should always match the higest demuxer type number. // Unless you want to disallow users to force the demuxer to some types #define DEMUXER_TYPE_MIN 0 -#define DEMUXER_TYPE_MAX 28 +#define DEMUXER_TYPE_MAX 29 #define DEMUXER_TYPE_DEMUXERS (1<<16) // A virtual demuxer type for the network code diff --git a/libmpdemux/dvb_defaults.h b/libmpdemux/dvb_defaults.h new file mode 100644 index 0000000000..0f56c1e8e5 --- /dev/null +++ b/libmpdemux/dvb_defaults.h @@ -0,0 +1,89 @@ +/* dvb_defaults.h + + Provided by Tomi Ollila + + Copyright (C) Dave Chapman 2002 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + Or, point your browser to http://www.gnu.org/copyleft/gpl.html + +*/ + +#ifndef _DVB_DEFAULTS_H +#define _DVB_DEFAULTS_H + +/* DVB-S */ + +// With a diseqc system you may need different values per LNB. I hope +// no-one ever asks for that :-) + +#define SLOF (11700*1000UL) +#define LOF1 (9750*1000UL) +#define LOF2 (10600*1000UL) + + + +#ifdef FINLAND + /* FINLAND settings 1 */ + #define DVB_T_LOCATION "Suomessa" + #define BANDWIDTH_DEFAULT BANDWIDTH_8_MHZ + #define HP_CODERATE_DEFAULT FEC_2_3 + #define CONSTELLATION_DEFAULT QAM_64 + #define TRANSMISSION_MODE_DEFAULT TRANSMISSION_MODE_8K + #define GUARD_INTERVAL_DEFAULT GUARD_INTERVAL_1_8 + #define HIERARCHY_DEFAULT HIERARCHY_NONE +#endif + + +#ifdef FINLAND2 + /* FINLAND settings 2 (someone verify there is such environment) */ + #define DVB_T_LOCATION "Suomessa II" + #define BANDWIDTH_DEFAULT BANDWIDTH_8_MHZ + #define HP_CODERATE_DEFAULT FEC_1_2 + #define CONSTELLATION_DEFAULT QAM_64 + #define TRANSMISSION_MODE_DEFAULT TRANSMISSION_MODE_2K + #define GUARD_INTERVAL_DEFAULT GUARD_INTERVAL_1_8 + #define HIERARCHY_DEFAULT HIERARCHY_NONE +#endif + +#if defined (UK) && defined (HP_CODERATE_DEFAULT) + #error Multible countries defined +#endif + + + +#ifndef DVB_T_LOCATION + #ifndef UK + #warning No DVB-T country defined in dvb_defaults.h + #warning defaulting to UK + #warning Ignore this if using Satellite or Cable + #endif + + /* UNITED KINGDOM settings */ + #define DVB_T_LOCATION "in United Kingdom" + #define BANDWIDTH_DEFAULT BANDWIDTH_8_MHZ + #define HP_CODERATE_DEFAULT FEC_2_3 + #define CONSTELLATION_DEFAULT QAM_64 + #define TRANSMISSION_MODE_DEFAULT TRANSMISSION_MODE_2K + #define GUARD_INTERVAL_DEFAULT GUARD_INTERVAL_1_32 + #define HIERARCHY_DEFAULT HIERARCHY_NONE +#endif + + +#if HIERARCHY_DEFAULT == HIERARCHY_NONE && !defined (LP_CODERATE_DEFAULT) + #define LP_CODERATE_DEFAULT (0) /* unused if HIERARCHY_NONE */ +#endif + +#endif diff --git a/libmpdemux/dvb_tune.c b/libmpdemux/dvb_tune.c new file mode 100644 index 0000000000..147976c22f --- /dev/null +++ b/libmpdemux/dvb_tune.c @@ -0,0 +1,803 @@ +/* dvbtune - tune.c + + Copyright (C) Dave Chapman 2001,2002 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + Or, point your browser to http://www.gnu.org/copyleft/gpl.html + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" + +#ifdef HAVE_DVB_HEAD + #include + #include + char* frontenddev[4]={"/dev/dvb/adapter0/frontend0","/dev/dvb/adapter1/frontend0","/dev/dvb/adapter2/frontend0","/dev/dvb/adapter3/frontend0"}; + char* dvrdev[4]={"/dev/dvb/adapter0/dvr0","/dev/dvb/adapter1/dvr0","/dev/dvb/adapter2/dvr0","/dev/dvb/adapter3/dvr0"}; + char* demuxdev[4]={"/dev/dvb/adapter0/demux0","/dev/dvb/adapter1/demux0","/dev/dvb/adapter2/demux0","/dev/dvb/adapter3/demux0"}; + char* secdev[4]={"","","",""}; //UNUSED, ONLY FOR UNIFORMITY +#else + #include + #include + #include + char* frontenddev[4]={"/dev/ost/frontend0","/dev/ost/frontend1","/dev/ost/frontend2","/dev/ost/frontend3"}; + char* dvrdev[4]={"/dev/ost/dvr0","/dev/ost/dvr1","/dev/ost/dvr2","/dev/ost/dvr3"}; + char* secdev[4]={"/dev/ost/sec0","/dev/ost/sec1","/dev/ost/sec2","/dev/ost/sec3"}; + char* demuxdev[4]={"/dev/ost/demux0","/dev/ost/demux1","/dev/ost/demux2","/dev/ost/demux3"}; +#endif + +#include "dvbin.h" +#include "dvb_defaults.h" +#include "../mp_msg.h" + + +extern int card; + +int open_fe(int* fd_frontend, int* fd_sec) +{ + if((*fd_frontend = open(frontenddev[card], O_RDWR)) < 0) + { + perror("ERROR IN OPENING FRONTEND DEVICE: "); + return -1; + } +#ifdef HAVE_DVB_HEAD + fd_sec=0; +#else + if (fd_sec != 0) + { + if((*fd_sec = open(secdev[card], O_RDWR)) < 0) + { + perror("ERROR IN OPENING SEC DEVICE: "); + return -1; + } + } +#endif + return 1; +} + + + +int set_ts_filt(int fd, uint16_t pid, dmx_pes_type_t pestype) +{ + int i; + struct dmx_pes_filter_params pesFilterParams; + + pesFilterParams.pid = pid; + pesFilterParams.input = DMX_IN_FRONTEND; + pesFilterParams.output = DMX_OUT_TS_TAP; +#ifdef HAVE_DVB_HEAD + pesFilterParams.pes_type = pestype; +#else + pesFilterParams.pesType = pestype; +#endif + + //pesFilterParams.pesType = pestype; + + pesFilterParams.flags = DMX_IMMEDIATE_START; + + if ((i = ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams)) < 0) + { + mp_msg(MSGT_DEMUX, MSGL_DBG2, "ERROR IN SETTING DMX_FILTER %i: ", pid); + } + + mp_msg(MSGT_DEMUX, MSGL_V, "SET PES FILTER ON PID %d, RESULT: %d\n", pid, i ); + return 1; +} + + +int demux_stop(int fd) +{ + int i; + i = ioctl(fd, DMX_STOP); + + mp_msg(MSGT_DEMUX, MSGL_DBG2, "STOPPING FD: %d, RESULT: %d\n", fd, i); + + return (i==0); +} + + + +void make_nonblock(int f) +{ + int oldflags; + + if ((oldflags=fcntl(f, F_GETFL, 0)) < 0) + { + perror("ERROR IN F_GETFL"); + } + + oldflags|=O_NONBLOCK; + if (fcntl(f, F_SETFL, oldflags) < 0) + { + perror("F_SETFL"); + } +} + + +static int tune_it(int fd_frontend, int fd_sec, unsigned int freq, unsigned int srate, char pol, int tone, + fe_spectral_inversion_t specInv, unsigned int diseqc, fe_modulation_t modulation, fe_code_rate_t HP_CodeRate, + fe_transmit_mode_t TransmissionMode, fe_guard_interval_t guardInterval, fe_bandwidth_t bandwidth); + + +//int dvb_tune(dvb_priv_t *priv, int freq, char pol, int srate, int diseqc, int tone) +dvb_tune(dvb_priv_t *priv, int freq, char pol, int srate, int diseqc, int tone, + fe_spectral_inversion_t specInv, fe_modulation_t modulation, fe_guard_interval_t guardInterval, + fe_transmit_mode_t TransmissionMode, fe_bandwidth_t bandWidth, fe_code_rate_t HP_CodeRate) +{ + mp_msg(MSGT_DEMUX, MSGL_DBG2, "dvb_tune con Freq: %lu, pol: %c, srate: %lu, diseqc %d, tone %d\n", freq, pol, srate, diseqc, tone); + /* INPUT: frequency, polarization, srate */ + if(freq > 100000000) + { + if(open_fe(&(priv->fe_fd), 0)) + { + //tune_it(fd_frontend, 0, freq, 0, 0, tone, specInv, diseqc,modulation,HP_CodeRate,TransmissionMode,guardInterval,bandWidth); + tune_it(priv->fe_fd, 0, freq, 0, 0, tone, specInv, diseqc, modulation, HP_CodeRate, TransmissionMode, guardInterval, bandWidth); + + close(priv->fe_fd); + } + else + return 0; + } + else if ((freq != 0) && (pol != 0) && (srate != 0)) + { + if (open_fe(&(priv->fe_fd), &(priv->sec_fd))) + { + tune_it(priv->fe_fd, priv->sec_fd, freq, srate, pol, tone, specInv, diseqc, modulation, HP_CodeRate, TransmissionMode, guardInterval, bandWidth); + close(priv->fe_fd); + close(priv->sec_fd); + } + else + return 0; + } + + priv->channel.freq = freq; + priv->channel.srate = srate; + priv->channel.pol = pol; + priv->channel.diseqc = diseqc; + priv->channel.tone = tone; + priv->channel.inv = specInv; + priv->channel.mod = modulation; + priv->channel.gi = guardInterval; + priv->channel.trans = TransmissionMode; + priv->channel.bw = bandWidth; + priv->channel.cr = HP_CodeRate; + + return 1; +} + + + + + +#ifndef HAVE_DVB_HEAD +static int OSTSelftest(int fd) +{ + int ans; + + if ((ans = ioctl(fd, FE_SELFTEST,0) < 0)) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "FE SELF TEST: "); + return -1; + } + + return 0; +} + +static int OSTSetPowerState(int fd, uint32_t state) +{ + int ans; + + if ((ans = ioctl(fd,FE_SET_POWER_STATE,state) < 0)) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "OST SET POWER STATE: "); + return -1; + } + + return 0; +} + +static int OSTGetPowerState(int fd, uint32_t *state) +{ + int ans; + + if ((ans = ioctl(fd,FE_GET_POWER_STATE,state) < 0)) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "OST GET POWER STATE: "); + return -1; + } + + switch(*state) + { + case FE_POWER_ON: + mp_msg(MSGT_DEMUX, MSGL_V, "POWER ON (%d)\n",*state); + break; + case FE_POWER_STANDBY: + mp_msg(MSGT_DEMUX, MSGL_V, "POWER STANDBY (%d)\n",*state); + break; + case FE_POWER_SUSPEND: + mp_msg(MSGT_DEMUX, MSGL_V, "POWER SUSPEND (%d)\n",*state); + break; + case FE_POWER_OFF: + mp_msg(MSGT_DEMUX, MSGL_V, "POWER OFF (%d)\n",*state); + break; + default: + mp_msg(MSGT_DEMUX, MSGL_V, "unknown (%d)\n",*state); + break; + } + + return 0; +} + + +static int SecGetStatus (int fd, struct secStatus *state) +{ + int ans; + + if ((ans = ioctl(fd, SEC_GET_STATUS, state) < 0)) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, ("SEC GET STATUS: ")); + return -1; + } + + switch (state->busMode) + { + case SEC_BUS_IDLE: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC BUS MODE: IDLE (%d)\n",state->busMode); + break; + case SEC_BUS_BUSY: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC BUS MODE: BUSY (%d)\n",state->busMode); + break; + case SEC_BUS_OFF: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC BUS MODE: OFF (%d)\n",state->busMode); + break; + case SEC_BUS_OVERLOAD: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC BUS MODE: OVERLOAD (%d)\n",state->busMode); + break; + default: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC BUS MODE: unknown (%d)\n",state->busMode); + break; + } + + switch (state->selVolt) + { + case SEC_VOLTAGE_OFF: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: OFF (%d)\n",state->selVolt); + break; + case SEC_VOLTAGE_LT: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: LT (%d)\n",state->selVolt); + break; + case SEC_VOLTAGE_13: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: 13 (%d)\n",state->selVolt); + break; + case SEC_VOLTAGE_13_5: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: 13.5 (%d)\n",state->selVolt); + break; + case SEC_VOLTAGE_18: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: 18 (%d)\n",state->selVolt); + break; + case SEC_VOLTAGE_18_5: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: 18.5 (%d)\n",state->selVolt); + break; + default: + mp_msg(MSGT_DEMUX, MSGL_V, "SEC VOLTAGE: unknown (%d)\n",state->selVolt); + break; + } + + mp_msg(MSGT_DEMUX, MSGL_V, "SEC CONT TONE: %s\n", (state->contTone == SEC_TONE_ON ? "ON" : "OFF")); + return 0; +} + +#endif + +static void print_status(fe_status_t festatus) +{ + mp_msg(MSGT_DEMUX, MSGL_V, "FE_STATUS:"); + if (festatus & FE_HAS_SIGNAL) mp_msg(MSGT_DEMUX, MSGL_V," FE_HAS_SIGNAL"); +#ifdef HAVE_DVB_HEAD + if (festatus & FE_TIMEDOUT) mp_msg(MSGT_DEMUX, MSGL_V, " FE_TIMEDOUT"); +#else + if (festatus & FE_HAS_POWER) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_POWER"); + if (festatus & FE_SPECTRUM_INV) mp_msg(MSGT_DEMUX, MSGL_V, " FE_SPECTRUM_INV"); + if (festatus & FE_TUNER_HAS_LOCK) mp_msg(MSGT_DEMUX, MSGL_V, " FE_TUNER_HAS_LOCK"); +#endif + if (festatus & FE_HAS_LOCK) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_LOCK"); + if (festatus & FE_HAS_CARRIER) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_CARRIER"); + if (festatus & FE_HAS_VITERBI) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_VITERBI"); + if (festatus & FE_HAS_SYNC) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_SYNC"); + mp_msg(MSGT_DEMUX, MSGL_V, "\n"); +} + + +#ifdef HAVE_DVB_HEAD +static int check_status(int fd_frontend,struct dvb_frontend_parameters* feparams,int tone) +{ + int i,res; + int32_t strength; + fe_status_t festatus; + struct dvb_frontend_event event; + struct dvb_frontend_info fe_info; + struct pollfd pfd[1]; + + if (ioctl(fd_frontend,FE_SET_FRONTEND,feparams) < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR tuning channel\n"); + return -1; + } + + pfd[0].fd = fd_frontend; + pfd[0].events = POLLIN; + + event.status=0; + while (((event.status & FE_TIMEDOUT)==0) && ((event.status & FE_HAS_LOCK)==0)) + { + mp_msg(MSGT_DEMUX, MSGL_V, "polling....\n"); + if (poll(pfd,1,10000)) + { + if (pfd[0].revents & POLLIN) + { + mp_msg(MSGT_DEMUX, MSGL_V, "Getting frontend event\n"); + if ( ioctl(fd_frontend, FE_GET_EVENT, &event) < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "FE_GET_EVENT"); + return -1; + } + } + print_status(event.status); + } + } + + if (event.status & FE_HAS_LOCK) + { + switch(fe_info.type) + { + case FE_OFDM: + mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",event.parameters.frequency); + break; + case FE_QPSK: + mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",(unsigned int)((event.parameters.frequency)+(tone==SEC_TONE_OFF ? LOF1 : LOF2))); + mp_msg(MSGT_DEMUX, MSGL_V, " SymbolRate: %d\n",event.parameters.u.qpsk.symbol_rate); + mp_msg(MSGT_DEMUX, MSGL_V, " FEC_inner: %d\n",event.parameters.u.qpsk.fec_inner); + mp_msg(MSGT_DEMUX, MSGL_V, "\n"); + break; + case FE_QAM: + mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",event.parameters.frequency); + mp_msg(MSGT_DEMUX, MSGL_V, " SymbolRate: %d\n",event.parameters.u.qpsk.symbol_rate); + mp_msg(MSGT_DEMUX, MSGL_V, " FEC_inner: %d\n",event.parameters.u.qpsk.fec_inner); + break; + default: + break; + } + + strength=0; + ioctl(fd_frontend,FE_READ_BER,&strength); + mp_msg(MSGT_DEMUX, MSGL_V, "Bit error rate: %d\n",strength); + + strength=0; + ioctl(fd_frontend,FE_READ_SIGNAL_STRENGTH,&strength); + mp_msg(MSGT_DEMUX, MSGL_V, "Signal strength: %d\n",strength); + + strength=0; + ioctl(fd_frontend,FE_READ_SNR,&strength); + mp_msg(MSGT_DEMUX, MSGL_V, "SNR: %d\n",strength); + + festatus=0; + ioctl(fd_frontend,FE_READ_STATUS,&festatus); + print_status(festatus); + } + else + { + mp_msg(MSGT_DEMUX, MSGL_V, "Not able to lock to the signal on the given frequency\n"); + return -1; + } + return 0; +} + +#else + +static int check_status(int fd_frontend,FrontendParameters* feparams,int tone) +{ + int i,res; + int32_t strength; + fe_status_t festatus; + FrontendEvent event; + FrontendInfo fe_info; + struct pollfd pfd[1]; + + i = 0; res = -1; + while ((i < 3) && (res < 0)) + { + if (ioctl(fd_frontend,FE_SET_FRONTEND,feparams) < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR tuning channel\n"); + return -1; + } + + pfd[0].fd = fd_frontend; + pfd[0].events = POLLIN; + + if (poll(pfd,1,10000)) + { + if (pfd[0].revents & POLLIN) + { + mp_msg(MSGT_DEMUX, MSGL_V, "Getting frontend event\n"); + if ( ioctl(fd_frontend, FE_GET_EVENT, &event) < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "FE_GET_EVENT"); + return -1; + } + mp_msg(MSGT_DEMUX, MSGL_V, "Received "); + switch(event.type) + { + case FE_UNEXPECTED_EV: + mp_msg(MSGT_DEMUX, MSGL_V, "unexpected event\n"); + res = -1; + break; + + case FE_FAILURE_EV: + mp_msg(MSGT_DEMUX, MSGL_V, "failure event\n"); + res = -1; + break; + + case FE_COMPLETION_EV: + mp_msg(MSGT_DEMUX, MSGL_V, "completion event\n"); + res = 0; + break; + } + } + i++; + } + } + + if (res > 0) + switch (event.type) + { + case FE_UNEXPECTED_EV: mp_msg(MSGT_DEMUX, MSGL_V, "FE_UNEXPECTED_EV\n"); + break; + case FE_COMPLETION_EV: mp_msg(MSGT_DEMUX, MSGL_V, "FE_COMPLETION_EV\n"); + break; + case FE_FAILURE_EV: mp_msg(MSGT_DEMUX, MSGL_V, "FE_FAILURE_EV\n"); + break; + } + + if (event.type == FE_COMPLETION_EV) + { + switch(fe_info.type) + { + case FE_OFDM: + mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",event.u.completionEvent.Frequency); + break; + + case FE_QPSK: + mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",(unsigned int)((event.u.completionEvent.Frequency)+(tone==SEC_TONE_OFF ? LOF1 : LOF2))); + mp_msg(MSGT_DEMUX, MSGL_V, " SymbolRate: %d\n",event.u.completionEvent.u.qpsk.SymbolRate); + mp_msg(MSGT_DEMUX, MSGL_V, " FEC_inner: %d\n",event.u.completionEvent.u.qpsk.FEC_inner); + mp_msg(MSGT_DEMUX, MSGL_V, "\n"); + break; + + case FE_QAM: + mp_msg(MSGT_DEMUX, MSGL_V, "Event: Frequency: %d\n",event.u.completionEvent.Frequency); + mp_msg(MSGT_DEMUX, MSGL_V, " SymbolRate: %d\n",event.u.completionEvent.u.qpsk.SymbolRate); + mp_msg(MSGT_DEMUX, MSGL_V, " FEC_inner: %d\n",event.u.completionEvent.u.qpsk.FEC_inner); + break; + + default: + break; + } + + strength=0; + ioctl(fd_frontend,FE_READ_BER,&strength); + mp_msg(MSGT_DEMUX, MSGL_V, "Bit error rate: %d\n",strength); + + strength=0; + ioctl(fd_frontend,FE_READ_SIGNAL_STRENGTH,&strength); + mp_msg(MSGT_DEMUX, MSGL_V, "Signal strength: %d\n",strength); + + strength=0; + ioctl(fd_frontend,FE_READ_SNR,&strength); + mp_msg(MSGT_DEMUX, MSGL_V, "SNR: %d\n",strength); + + festatus=0; + ioctl(fd_frontend,FE_READ_STATUS,&festatus); + + mp_msg(MSGT_DEMUX, MSGL_V, "FE_STATUS:"); + if (festatus & FE_HAS_POWER) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_POWER"); + if (festatus & FE_HAS_SIGNAL) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_SIGNAL"); + if (festatus & FE_SPECTRUM_INV) mp_msg(MSGT_DEMUX, MSGL_V, " FE_SPECTRUM_INV"); + if (festatus & FE_HAS_LOCK) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_LOCK"); + if (festatus & FE_HAS_CARRIER) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_CARRIER"); + if (festatus & FE_HAS_VITERBI) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_VITERBI"); + if (festatus & FE_HAS_SYNC) mp_msg(MSGT_DEMUX, MSGL_V, " FE_HAS_SYNC"); + if (festatus & FE_TUNER_HAS_LOCK) mp_msg(MSGT_DEMUX, MSGL_V, " FE_TUNER_HAS_LOCK"); + mp_msg(MSGT_DEMUX, MSGL_V, "\n"); + } + else + { + mp_msg(MSGT_DEMUX, MSGL_V, "Not able to lock to the signal on the given frequency\n"); + return -1; + } + return 0; +} +#endif + +#ifdef HAVE_DVB_HEAD + +struct diseqc_cmd { + struct dvb_diseqc_master_cmd cmd; + uint32_t wait; +}; + +static void diseqc_send_msg(int fd, fe_sec_voltage_t v, struct diseqc_cmd *cmd, + fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b) +{ + ioctl(fd, FE_SET_TONE, SEC_TONE_OFF); + ioctl(fd, FE_SET_VOLTAGE, v); + usleep(15 * 1000); + ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &cmd->cmd); + usleep(cmd->wait * 1000); + usleep(15 * 1000); + ioctl(fd, FE_DISEQC_SEND_BURST, b); + usleep(15 * 1000); + ioctl(fd, FE_SET_TONE, t); +} + + + + +/* digital satellite equipment control, + * specification is available from http://www.eutelsat.com/ + */ +static int head_diseqc(int secfd, int sat_no, int pol, int hi_lo) +{ + struct diseqc_cmd cmd = { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 }; + + /* param: high nibble: reset bits, low nibble set bits, + * bits are: option, position, polarizaion, band + */ + cmd.cmd.msg[3] = + 0xf0 | (((sat_no * 4) & 0x0f) | (hi_lo ? 1 : 0) | (pol ? 0 : 2)); + + diseqc_send_msg(secfd, pol ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18, + &cmd, hi_lo ? SEC_TONE_ON : SEC_TONE_OFF, + (sat_no / 4) % 2 ? SEC_MINI_B : SEC_MINI_A); + + return 1; +} + +#endif + + +static int tune_it(int fd_frontend, int fd_sec, unsigned int freq, unsigned int srate, char pol, int tone, + fe_spectral_inversion_t specInv, unsigned int diseqc, fe_modulation_t modulation, fe_code_rate_t HP_CodeRate, + fe_transmit_mode_t TransmissionMode, fe_guard_interval_t guardInterval, fe_bandwidth_t bandwidth) +{ + int res; +#ifdef HAVE_DVB_HEAD + struct dvb_frontend_parameters feparams; + struct dvb_frontend_info fe_info; + fe_sec_voltage_t voltage; +#else + FrontendParameters feparams; + FrontendInfo fe_info; + secVoltage voltage; + struct secStatus sec_state; +#endif + + + mp_msg(MSGT_DEMUX, MSGL_V, "TUNE_IT, fd_frontend %d, fd_sec %d, freq %lu, srate %lu, pol %c, tone %i, specInv, diseqc %u, fe_modulation_t modulation,fe_code_rate_t HP_CodeRate, fe_transmit_mode_t TransmissionMode,fe_guard_interval_t guardInterval, fe_bandwidth_t bandwidth\n", + fd_frontend, fd_sec, freq, srate, pol, tone, diseqc); + + + if ( (res = ioctl(fd_frontend,FE_GET_INFO, &fe_info) < 0)) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "FE_GET_INFO: "); + return -1; + } + + +#ifdef HAVE_DVB_HEAD + mp_msg(MSGT_DEMUX, MSGL_V, "Using DVB card \"%s\"\n",fe_info.name); +#endif + + switch(fe_info.type) + { + case FE_OFDM: +#ifdef HAVE_DVB_HEAD + if (freq < 1000000) freq*=1000UL; + feparams.frequency=freq; + feparams.inversion=INVERSION_OFF; + feparams.u.ofdm.bandwidth=bandwidth; + feparams.u.ofdm.code_rate_HP=HP_CodeRate; + feparams.u.ofdm.code_rate_LP=LP_CODERATE_DEFAULT; + feparams.u.ofdm.constellation=modulation; + feparams.u.ofdm.transmission_mode=TransmissionMode; + feparams.u.ofdm.guard_interval=guardInterval; + feparams.u.ofdm.hierarchy_information=HIERARCHY_DEFAULT; +#else + if (freq < 1000000) freq*=1000UL; + feparams.Frequency=freq; + feparams.Inversion=INVERSION_OFF; + feparams.u.ofdm.bandWidth=bandwidth; + feparams.u.ofdm.HP_CodeRate=HP_CodeRate; + feparams.u.ofdm.LP_CodeRate=LP_CODERATE_DEFAULT; + feparams.u.ofdm.Constellation=modulation; + feparams.u.ofdm.TransmissionMode=TransmissionMode; + feparams.u.ofdm.guardInterval=guardInterval; + feparams.u.ofdm.HierarchyInformation=HIERARCHY_DEFAULT; +#endif + mp_msg(MSGT_DEMUX, MSGL_V, "tuning DVB-T (%s) to %d Hz\n",DVB_T_LOCATION,freq); + break; + case FE_QPSK: +#ifdef HAVE_DVB_HEAD + mp_msg(MSGT_DEMUX, MSGL_V, "tuning DVB-S to L-Band:%d, Pol:%c Srate=%d, 22kHz=%s\n",feparams.frequency,pol,srate,tone == SEC_TONE_ON ? "on" : "off"); +#else + mp_msg(MSGT_DEMUX, MSGL_V, "tuning DVB-S to L-Band:%d, Pol:%c Srate=%d, 22kHz=%s\n",feparams.Frequency,pol,srate,tone == SEC_TONE_ON ? "on" : "off"); +#endif + if ((pol=='h') || (pol=='H')) + { + voltage = SEC_VOLTAGE_18; + } + else + { + voltage = SEC_VOLTAGE_13; + } +#ifdef HAVE_DVB_HEAD + if (ioctl(fd_frontend,FE_SET_VOLTAGE,voltage) < 0) + { +#else + if (ioctl(fd_sec,SEC_SET_VOLTAGE,voltage) < 0) + { +#endif + mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR setting voltage\n"); + } + + if (freq > 2200000) + { + // this must be an absolute frequency + if (freq < SLOF) + { +#ifdef HAVE_DVB_HEAD + feparams.frequency=(freq-LOF1); +#else + feparams.Frequency=(freq-LOF1); +#endif + if (tone < 0) tone = SEC_TONE_OFF; + } + else + { +#ifdef HAVE_DVB_HEAD + feparams.frequency=(freq-LOF2); +#else + feparams.Frequency=(freq-LOF2); +#endif + if (tone < 0) tone = SEC_TONE_ON; + } + } + else + { + // this is an L-Band frequency +#ifdef HAVE_DVB_HEAD + feparams.frequency=freq; +#else + feparams.Frequency=freq; +#endif + } + +#ifdef HAVE_DVB_HEAD + feparams.inversion=specInv; + feparams.u.qpsk.symbol_rate=srate; + feparams.u.qpsk.fec_inner=FEC_AUTO; +#else + feparams.Inversion=specInv; + feparams.u.qpsk.SymbolRate=srate; + feparams.u.qpsk.FEC_inner=FEC_AUTO; +#endif + +#ifdef HAVE_DVB_HEAD + if (ioctl(fd_frontend, FE_SET_TONE,tone) < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR setting tone\n"); + } +#else + if (ioctl(fd_sec, SEC_SET_TONE,tone) < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR setting tone\n"); + } +#endif + +#ifdef HAVE_DVB_HEAD + //#warning DISEQC is unimplemented for HAVE_DVB_HEAD + if(diseqc > 0) + { + int ipol = (pol == 'V' ? 1 : 0); + int hiband = (freq >= SLOF); + + if(head_diseqc(fd_frontend, diseqc-1, ipol, hiband)) + { + mp_msg(MSGT_DEMUX, MSGL_V, "DISEQC SETTING SUCCEDED\n"); + } + else + { + mp_msg(MSGT_DEMUX, MSGL_V, "DISEQC SETTING FAILED\n"); + } + } +#else + if (diseqc > 0) + { + struct secCommand scmd; + struct secCmdSequence scmds; + + scmds.continuousTone = tone; + scmds.voltage = voltage; + /* + scmds.miniCommand = toneBurst ? SEC_MINI_B : SEC_MINI_A; + */ + scmds.miniCommand = SEC_MINI_NONE; + + scmd.type = 0; + scmds.numCommands = 1; + scmds.commands = &scmd; + + scmd.u.diseqc.addr = 0x10; + scmd.u.diseqc.cmd = 0x38; + scmd.u.diseqc.numParams = 1; + scmd.u.diseqc.params[0] = 0xf0 | + (((diseqc - 1) << 2) & 0x0c) | + (voltage==SEC_VOLTAGE_18 ? 0x02 : 0) | + (tone==SEC_TONE_ON ? 0x01 : 0); + + if (ioctl(fd_sec,SEC_SEND_SEQUENCE,&scmds) < 0) + { + mp_msg(MSGT_DEMUX, MSGL_ERR, "Error sending DisEqC"); + return -1; + } + } +#endif + break; + case FE_QAM: + mp_msg(MSGT_DEMUX, MSGL_V, "tuning DVB-C to %d, srate=%d\n",freq,srate); +#ifdef HAVE_DVB_HEAD + feparams.frequency=freq; + feparams.inversion=INVERSION_OFF; + feparams.u.qam.symbol_rate = srate; + feparams.u.qam.fec_inner = FEC_AUTO; + feparams.u.qam.modulation = QAM_64; +#else + feparams.Frequency=freq; + feparams.Inversion=INVERSION_OFF; + feparams.u.qam.SymbolRate = srate; + feparams.u.qam.FEC_inner = FEC_AUTO; + feparams.u.qam.QAM = QAM_64; +#endif + break; + default: + mp_msg(MSGT_DEMUX, MSGL_V, "Unknown FE type. Aborting\n"); + exit(-1); + } + usleep(100000); + +#ifndef HAVE_DVB_HEAD + if (fd_sec) SecGetStatus(fd_sec, &sec_state); +#endif + + return(check_status(fd_frontend,&feparams,tone)); +} diff --git a/libmpdemux/dvbin.c b/libmpdemux/dvbin.c new file mode 100644 index 0000000000..d845b64e32 --- /dev/null +++ b/libmpdemux/dvbin.c @@ -0,0 +1,684 @@ +/* + +dvbstream +(C) Dave Chapman 2001, 2002. + +The latest version can be found at http://www.linuxstb.org/dvbstream + +Copyright notice: + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +// Linux includes: +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" + +// DVB includes: + +#include "stream.h" +#include "demuxer.h" + +#include "../cfgparser.h" + +#include "dvbin.h" +#include "dvb_defaults.h" + +extern int video_id, audio_id, demuxer_type; + + +#define MAX_CHANNELS 8 + + +#define min(a, b) ((a) <= (b) ? (a) : (b)) + +int dvbin_param_card, dvbin_param_freq, dvbin_param_srate, dvbin_param_diseqc = 0, + dvbin_param_tone = -1, dvbin_param_vid, dvbin_param_aid, dvbin_is_active = 0; +int dvbin_param_mod, dvbin_param_gi, dvbin_param_tm, dvbin_param_bw, dvbin_param_cr; +char *dvbin_param_pol = "", *dvbin_param_inv="INVERSION_AUTO", + *dvbin_param_type="SAT ", + *dvbin_param_prog = " "; +dvb_history_t dvb_prev_next; + +struct config dvbin_opts_conf[] = { + {"on", &dvbin_param_on, CONF_TYPE_INT, 0, 0, 1, NULL}, + {"type", &dvbin_param_type, CONF_TYPE_STRING, 0, 0, 1, NULL}, + {"card", &dvbin_param_card, CONF_TYPE_INT, CONF_RANGE, 1, 4, NULL}, + {"freq", &dvbin_param_freq, CONF_TYPE_INT, 0, 0, 1, NULL}, + {"pol", &dvbin_param_pol, CONF_TYPE_STRING, 0, 0, 0, NULL}, + {"srate", &dvbin_param_srate, CONF_TYPE_INT, 0, 0, 1, NULL}, + {"diseqc", &dvbin_param_diseqc, CONF_TYPE_INT, CONF_RANGE, 1, 4, NULL}, + {"tone", &dvbin_param_tone, CONF_TYPE_INT, 0, 0, 1, NULL}, + {"vid", &dvbin_param_vid, CONF_TYPE_INT, 0, 0, 1, NULL}, + {"aid", &dvbin_param_aid, CONF_TYPE_INT, 0, 0, 1, NULL}, + {"prog", &dvbin_param_prog, CONF_TYPE_STRING, 0, 0, 0, NULL}, + {"inv", &dvbin_param_inv, CONF_TYPE_STRING, 0, 0, 0, NULL}, + {"mod", &dvbin_param_mod, CONF_TYPE_INT, 0, 0, 1, NULL}, + {"gi", &dvbin_param_gi, CONF_TYPE_INT, 0, 0, 1, NULL}, + {"tm", &dvbin_param_tm, CONF_TYPE_INT, 0, 0, 1, NULL}, + {"bw", &dvbin_param_bw, CONF_TYPE_INT, 0, 0, 1, NULL}, + {"cr", &dvbin_param_cr, CONF_TYPE_INT, 0, 0, 1, NULL}, + {NULL, NULL, 0, 0, 0, 0, NULL} +}; + + +int card=0; + +extern int open_fe(int* fd_frontend, int* fd_sec); +extern int set_ts_filt(int fd, uint16_t pid, dmx_pes_type_t pestype); +extern int demux_stop(int fd); +extern void make_nonblock(int f); +extern int dvb_tune(dvb_priv_t *priv, int freq, char pol, int srate, int diseqc, int tone, + fe_spectral_inversion_t specInv, fe_modulation_t modulation, fe_guard_interval_t guardInterval, + fe_transmit_mode_t TransmissionMode, fe_bandwidth_t bandWidth, fe_code_rate_t HP_CodeRate); +extern char *frontenddev[4], *dvrdev[4], *secdev[4], *demuxdev[4]; + + +dvb_channels_list *dvb_get_channels(char *filename, const char *type) +{ + dvb_channels_list *list; + FILE *f; + uint8_t line[128]; + int fields, row_count; + dvb_channel_t *ptr; + char *tmp_lcr, *tmp_hier, *inv, *bw, *cr, *mod, *transm, *gi; + //const char *cbl_conf = "%a[^:]:%d:%c:%d:%a[^:]:%a[^:]:%d:%d\n"; + const char *sat_conf = "%a[^:]:%d:%c:%d:%d:%d:%d:%d:%d:%d\n"; + const char *ter_conf = "%a[^:]:%d:%a[^:]:%a[^:]:%a[^:]:%a[^:]:%a[^:]:%a[^:]:%a[^:]:%a[^:]:%d:%d\n"; + + list = malloc(sizeof(dvb_channels_list)); + if(list == NULL) + { + mp_msg(MSGT_DEMUX, MSGL_V, "DVB_GET_CHANNELS: couldn't malloc enough memory\n"); + return NULL; + } + + mp_msg(MSGT_DEMUX, MSGL_V, "CONFIG_READ FILE: %s, type: %s\n", filename, type); + if((f=fopen(filename, "r"))==NULL) + { + mp_msg(MSGT_DEMUX, MSGL_FATAL, "CAN'T READ CONFIG FILE %s\n", filename); + return NULL; + } + + list->NUM_CHANNELS = 0; + row_count = 0; + while(! feof(f) && row_count < 512) + { + if( fgets(line, 128, f) == NULL ) continue; + + if(line[0] == '#') + continue; //comment line + + ptr = &(list->channels[ list->NUM_CHANNELS ]); + + if(! strcmp(type, "TER")) + { + fields = sscanf(line, ter_conf, + &ptr->name, &ptr->freq, &inv, &bw, &cr, tmp_lcr, &mod, + &transm, &gi, &tmp_hier, &ptr->vpid, &ptr->apid1); + + if(! strcmp(inv, "INVERSION_ON")) + ptr->inv = INVERSION_ON; + else if(! strcmp(inv, "INVERSION_OFF")) + ptr->inv = INVERSION_OFF; + else + ptr->inv = INVERSION_AUTO; + + if(! strcmp(bw, "BANDWIDTH_6_MHZ")) + ptr->bw = BANDWIDTH_6_MHZ; + else if(! strcmp(bw, "BANDWIDTH_7_MHZ")) + ptr->bw = BANDWIDTH_7_MHZ; + else if(! strcmp(bw, "BANDWIDTH_8_MHZ")) + ptr->bw = BANDWIDTH_8_MHZ; + + + if(! strcmp(cr, "FEC_1_2")) + ptr->cr =FEC_1_2; + else if(! strcmp(cr, "FEC_2_3")) + ptr->cr =FEC_2_3; + else if(! strcmp(cr, "FEC_3_4")) + ptr->cr =FEC_3_4; +#ifdef HAVE_DVB_HEAD + else if(! strcmp(cr, "FEC_4_5")) + ptr->cr =FEC_4_5; + else if(! strcmp(cr, "FEC_6_7")) + ptr->cr =FEC_6_7; + else if(! strcmp(cr, "FEC_8_9")) + ptr->cr =FEC_8_9; +#endif + else if(! strcmp(cr, "FEC_5_6")) + ptr->cr =FEC_5_6; + else if(! strcmp(cr, "FEC_7_8")) + ptr->cr =FEC_7_8; + else if(! strcmp(cr, "FEC_NONE")) + ptr->cr =FEC_NONE; + else ptr->cr =FEC_AUTO; + + if(! strcmp(mod, "QAM_128")) + ptr->mod = QAM_128; + else if(! strcmp(mod, "QAM_256")) + ptr->mod = QAM_256; + else if(! strcmp(mod, "QAM_64")) + ptr->mod = QAM_64; + else if(! strcmp(mod, "QAM_32")) + ptr->mod = QAM_32; + else if(! strcmp(mod, "QAM_16")) + ptr->mod = QAM_16; + else ptr->mod = QPSK; + + + if(! strcmp(transm, "TRANSMISSION_MODE_2K")) + ptr->trans = TRANSMISSION_MODE_2K; + else if(! strcmp(transm, "TRANSMISSION_MODE_8K")) + ptr->trans = TRANSMISSION_MODE_8K; + + if(! strcmp(gi, "GUARD_INTERVAL_1_32")) + ptr->gi = GUARD_INTERVAL_1_32; + else if(! strcmp(gi, "GUARD_INTERVAL_1_16")) + ptr->gi = GUARD_INTERVAL_1_16; + else if(! strcmp(gi, "GUARD_INTERVAL_1_8")) + ptr->gi = GUARD_INTERVAL_1_8; + else ptr->gi = GUARD_INTERVAL_1_4; + + + } + /* + else if(! strcmp(type, "CBL")) + { + fields = sscanf(line, cbl_conf, + &ptr->name, &ptr->freq, &ptr->inv, &ptr->qam, + &ptr->fec, &ptr->mod, &ptr->vpid, &ptr->apid1); + + + } + */ + else //SATELLITE + { + fields = sscanf(line, sat_conf, + &ptr->name, &ptr->freq, &ptr->pol, &ptr->diseqc, &ptr->srate, &ptr->vpid, &ptr->apid1, + &ptr->tpid, &ptr->ca, &ptr->progid); + ptr->pol = toupper(ptr->pol); + ptr->freq *= 1000UL; + ptr->srate *= 1000UL; + ptr->tone = -1; + mp_msg(MSGT_DEMUX, MSGL_V, + "NUM_FIELDS: %d, NAME: %s, FREQ: %d, SRATE: %d, POL: %c, DISEQC: %d, TONE: %d, VPID: %d, APID1: %d, APID2: %d, TPID: %d, PROGID: %d, NUM: %d\n", + fields, ptr->name, ptr->freq, ptr->srate, ptr->pol, ptr->diseqc, ptr->tone, ptr->vpid, ptr->apid1, ptr->apid2, ptr->tpid, ptr->progid, list->NUM_CHANNELS); + } + + list->NUM_CHANNELS++; + row_count++; + } + + fclose(f); + return list; +} + + +static long getmsec() +{ + struct timeval tv; + gettimeofday(&tv, (struct timezone*) NULL); + return(tv.tv_sec%1000000)*1000 + tv.tv_usec/1000; +} + + + +int dvb_streaming_read(int fd, char *buffer, unsigned int size, dvb_priv_t *priv) +{ + struct pollfd pfds[1]; + uint32_t ok = 0, pos = 0, tot = 0, rk, d, r, m; + + mp_msg(MSGT_D