CVS: main/libmpdemux demux_ts.c,NONE,1.1 dvb_defaults.h,NONE,1.1 dvb_tune.c,NONE,1.1 dvbin.c,NONE,1.1 dvbin.h,NONE,1.1 Makefile,1.51,1.52 demuxer.c,1.135,1.136 demuxer.h,1.56,1.57 open.c,1.69,1.70 stream.c,1.51,1.52 stream.h,1.55,1.56video.c,1.36,1.37
Update of /cvsroot/mplayer/main/libmpdemux In directory mail:/var/tmp.root/cvs-serv15493/libmpdemux Modified Files: Makefile demuxer.c demuxer.h open.c stream.c stream.h video.c Added Files: demux_ts.c dvb_defaults.h dvb_tune.c dvbin.c dvbin.h Log Message: 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 <nsabbi@libero.it> some cleanups, ts demuxer fixes by me --- NEW FILE --- /* * 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: demux_ts.c,v 1.1 2003/03/16 20:13:27 arpi Exp $ * * 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 <stdio.h> #include <stdlib.h> #include <string.h> #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; i<NUM_CONSECUTIVE_TS_PACKETS; i++) { if (buf[i * TS_PACKET_SIZE] != 0x47) { mp_msg(MSGT_DEMUX, MSGL_DBG2, "GET_PACKET_SIZE, pos %d, char: %2x\n", i, buf[i * TS_PACKET_SIZE]); goto try_fec; } } return TS_PACKET_SIZE; try_fec: for(i=0; i<NUM_CONSECUTIVE_TS_PACKETS; i++) { if (buf[i * TS_FEC_PACKET_SIZE] != 0x47) return 0; } return TS_FEC_PACKET_SIZE; } int ts_check_file(demuxer_t * demuxer) { const int buf_size = (TS_FEC_PACKET_SIZE * NUM_CONSECUTIVE_TS_PACKETS); char buf[buf_size], c, done = 0; uint32_t _read, i=1; uint8_t size = 0; off_t pos = 0; mp_msg(MSGT_DEMUX, MSGL_V, "************Checking for TS************\n"); while(! done) { while(((c=stream_read_char(demuxer->stream)) != 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;i<NB_PID_MAX;i++) free(ts->pids[i]); return 0; } --- NEW FILE --- /* 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 --- NEW FILE --- /* 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 <stdio.h> #include <stdlib.h> #include <ctype.h> #include <sys/ioctl.h> #include <sys/poll.h> #include <unistd.h> #include <fcntl.h> #include <error.h> #include "config.h" #ifdef HAVE_DVB_HEAD #include <linux/dvb/dmx.h> #include <linux/dvb/frontend.h> 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 <ost/dmx.h> #include <ost/sec.h> #include <ost/frontend.h> 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)); } --- NEW FILE --- /* dvbstream (C) Dave Chapman <dave@dchapman.com> 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 <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <sys/ioctl.h> #include <sys/time.h> #include <sys/poll.h> #include <sys/stat.h> #include <resolv.h> #include <fcntl.h> #include <unistd.h> #include <signal.h> #include <values.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #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_DEMUX, MSGL_DBG2, "dvb_streaming_read(%u)\n", fd); while(pos < size) { ok = 0; tot = 0; //int m = min((size-pos), 188); m = size - pos; d = (int) (m / 188); r = m % 188; m = d * 188; m = (m ? m : r); pfds[0].fd = fd; pfds[0].events = POLLIN | POLLPRI; mp_msg(MSGT_DEMUX, MSGL_DBG2, "DEVICE: %d, DVR: %d, PIPE: %d <-> %d\n", fd, priv->dvr_fd, priv->input, priv->output); poll(pfds, 1, 500); if((rk = read(fd, &buffer[pos], m)) > 0) pos += rk; } return pos; } dvb_history_t *dvb_step_channel(dvb_priv_t *priv, int dir, dvb_history_t *h) { //int new_freq, new_srate, new_diseqc, new_tone, new_vpid, new_apid; //char new_pol; int new_current; dvb_channel_t *next; dvb_channels_list *list; if(priv == NULL) { mp_msg(MSGT_DEMUX, MSGL_ERR, "dvb_step_channel: PRIV NULL PTR, quit\n"); return 0; } list = priv->list; if(list == NULL) { mp_msg(MSGT_DEMUX, MSGL_ERR, "dvb_step_channel: LIST NULL PTR, quit\n"); return 0; } mp_msg(MSGT_DEMUX, MSGL_V, "DVB_STEP_CHANNEL dir %d\n", dir); if(dir == DVB_CHANNEL_HIGHER) { if(list->current == list->NUM_CHANNELS) return 0; new_current = list->current + 1; next = &(list->channels[new_current]); } else { if(list->current == 0) return 0; new_current = list->current - 1; next = &(list->channels[new_current]); } demux_stop(priv->demux_fd[0]); demux_stop(priv->demux_fd[1]); h->prev = list->current; h->next = new_current; list->current = new_current; return h; } extern char *get_path(char *); dvb_channels_list *list_ptr = NULL; int dvb_streaming_start(stream_t *stream) { int pids[MAX_CHANNELS]; int pestypes[MAX_CHANNELS]; int npids, i; char *filename, type[80]; unsigned long freq = 0; char pol = 0; unsigned long srate = 0; int diseqc = 0, old_diseqc = 0; int tone = -1; dvb_priv_t *priv; dvb_channel_t *channel = NULL; fe_spectral_inversion_t specInv = INVERSION_AUTO; fe_modulation_t modulation = CONSTELLATION_DEFAULT; fe_transmit_mode_t TransmissionMode = TRANSMISSION_MODE_DEFAULT; fe_bandwidth_t bandWidth = BANDWIDTH_DEFAULT; fe_guard_interval_t guardInterval = GUARD_INTERVAL_DEFAULT; fe_code_rate_t HP_CodeRate = HP_CODERATE_DEFAULT; stream->priv = (dvb_priv_t*) malloc(sizeof(dvb_priv_t)); if(stream->priv == NULL) return 0; priv = (dvb_priv_t*) stream->priv; if(!strncmp(dvbin_param_type, "CBL", 3)) strncpy(type, "CBL", 3); else if(!strncmp(dvbin_param_type, "TER", 3)) strncpy(type, "TER", 3); else strncpy(type, "SAT", 3); filename = get_path("channels.conf"); if(list_ptr == NULL) { if(filename) { if((list_ptr = dvb_get_channels(filename, type)) == NULL) mp_msg(MSGT_DEMUX, MSGL_WARN, "EMPTY CHANNELS LIST!\n"); else { priv->list = list_ptr; priv->list->current = 0; } } else { list_ptr = NULL; mp_msg(MSGT_DEMUX, MSGL_WARN, "NO CHANNELS FILE FOUND!\n"); } } mp_msg(MSGT_DEMUX, MSGL_INFO, "code taken from dvbstream for mplayer v0.4pre1 - (C) Dave Chapman 2001\n"); mp_msg(MSGT_DEMUX, MSGL_INFO, "Released under the GPL.\n"); mp_msg(MSGT_DEMUX, MSGL_INFO, "Latest version available from http://www.linuxstb.org/\n"); mp_msg(MSGT_DEMUX, MSGL_V, "ON: %d, CARD: %d, FREQ: %d, SRATE: %d, POL: %s, VID: %d, AID: %d\n", dvbin_param_on, dvbin_param_card, dvbin_param_freq, dvbin_param_srate, dvbin_param_pol, dvbin_param_vid, dvbin_param_aid); npids = 0; if((dvb_prev_next.next > -1) && (dvb_prev_next.prev > -1) && (list_ptr != NULL)) //We are after a channel stepping { list_ptr->current = dvb_prev_next.next; channel = &(list_ptr->channels[dvb_prev_next.next]); mp_msg(MSGT_DEMUX, MSGL_V, "PROGRAM NUMBER %d: name=%s, vid=%d, aid=%d, freq=%lu, srate=%lu, pol=%c, diseqc: %d, tone: %d\n", dvb_prev_next.next, channel->name, channel->vpid, channel->apid1, channel->freq, channel->srate, channel->pol, channel->diseqc, channel->tone); if((dvb_prev_next.prev >= 0) && (dvb_prev_next.prev < list_ptr->NUM_CHANNELS)) { dvb_channel_t *tmp = &(list_ptr->channels[dvb_prev_next.prev]); old_diseqc = tmp->diseqc; } } else if(list_ptr != NULL && strlen(dvbin_param_prog)) { i = 0; while((channel == NULL) && i < list_ptr->NUM_CHANNELS) { if(! strcmp(list_ptr->channels[i].name, dvbin_param_prog)) channel = &(list_ptr->channels[i]); i++; } if(channel != NULL) { list_ptr->current = i-1; mp_msg(MSGT_DEMUX, MSGL_V, "PROGRAM NUMBER %d: name=%s, vid=%d, aid=%d, freq=%lu, srate=%lu, pol=%c, diseqc: %d, tone: %d\n", i-1, channel->name, channel->vpid, channel->apid1, channel->freq, channel->srate, channel->pol, channel->diseqc, channel->tone); } } if(dvbin_param_vid > 0) { pids[npids] = priv->channel.vpid = dvbin_param_vid; } else if(channel != NULL) { pids[npids] = priv->channel.vpid = channel->vpid; } pestypes[npids] = DMX_PES_VIDEO; npids++; if(dvbin_param_aid > 0) { pids[npids] = priv->channel.apid1 = dvbin_param_aid; } else if(channel != NULL) { pids[npids] = priv->channel.vpid = channel->apid1; } pestypes[npids] = DMX_PES_AUDIO; npids++; if(dvbin_param_freq) freq = dvbin_param_freq * 1000UL; else if(channel != NULL) freq = channel->freq; if(dvbin_param_srate) srate = dvbin_param_srate * 1000UL; else if(channel != NULL) srate = channel->srate; if((1<= dvbin_param_diseqc) && (dvbin_param_diseqc <= 4)) diseqc = dvbin_param_diseqc; else if(channel != NULL) if(channel->diseqc != old_diseqc) diseqc = channel->diseqc; else diseqc = 0; else diseqc = 0; mp_msg(MSGT_DEMUX, MSGL_INFO, "DISEQC: %d\n", diseqc); if((dvbin_param_tone == 0) || (dvbin_param_tone == 1)) tone = dvbin_param_tone; else if(channel != NULL) tone = channel->tone; else tone = -1; if(! strcmp(dvbin_param_pol, "V")) pol = 'V'; else if(! strcmp(dvbin_param_pol, "H")) pol = 'H'; else if(channel != NULL) pol = channel->pol; else pol='V'; pol = toupper(pol); if(!strcmp(dvbin_param_inv, "INVERSION_ON")) specInv = INVERSION_ON; else if(!strcmp(dvbin_param_inv, "INVERSION_OFF")) specInv = INVERSION_OFF; else if(!strcmp(dvbin_param_inv, "INVERSION_AUTO")) specInv = INVERSION_AUTO; else if(channel != NULL) specInv = channel->inv; else specInv = INVERSION_AUTO; if(dvbin_param_mod) { switch(dvbin_param_mod) { case 16: modulation=QAM_16; break; case 32: modulation=QAM_32; break; case 64: modulation=QAM_64; break; case 128: modulation=QAM_128; break; case 256: modulation=QAM_256; break; default: mp_msg(MSGT_DEMUX, MSGL_ERR, "Invalid QAM rate: %s\n", dvbin_param_mod); modulation=CONSTELLATION_DEFAULT; } } else if(channel != NULL) modulation = channel->mod; else modulation=CONSTELLATION_DEFAULT; if(dvbin_param_gi) { switch(dvbin_param_gi) { case 32: guardInterval=GUARD_INTERVAL_1_32; break; case 16: guardInterval=GUARD_INTERVAL_1_16; break; case 8: guardInterval=GUARD_INTERVAL_1_8; break; case 4: guardInterval=GUARD_INTERVAL_1_4; break; default: mp_msg(MSGT_DEMUX, MSGL_ERR, "Invalid Guard Interval: %s\n", dvbin_param_gi); guardInterval=GUARD_INTERVAL_DEFAULT; } } else if(channel != NULL) guardInterval = channel->gi; else guardInterval=GUARD_INTERVAL_DEFAULT; if(dvbin_param_tm) { switch(dvbin_param_tm) { case 8: TransmissionMode=TRANSMISSION_MODE_8K; break; case 2: TransmissionMode=TRANSMISSION_MODE_2K; break; default: TransmissionMode=TRANSMISSION_MODE_DEFAULT; mp_msg(MSGT_DEMUX, MSGL_ERR, "Invalid Transmission Mode: %s\n", dvbin_param_tm); } } else if(channel != NULL) TransmissionMode = channel->trans; else TransmissionMode=TRANSMISSION_MODE_DEFAULT; if(dvbin_param_bw) { switch(dvbin_param_bw) { case 8: bandWidth=BANDWIDTH_8_MHZ; break; case 7: bandWidth=BANDWIDTH_7_MHZ; break; case 6: bandWidth=BANDWIDTH_6_MHZ; break; default: mp_msg(MSGT_DEMUX, MSGL_ERR, "Invalid DVB-T bandwidth: %s\n", dvbin_param_bw); bandWidth=BANDWIDTH_DEFAULT; } } else if(channel != NULL) bandWidth = channel->bw; else bandWidth=BANDWIDTH_DEFAULT; if(dvbin_param_cr) { switch(dvbin_param_cr) { case -1: HP_CodeRate=FEC_AUTO; break; case 12: HP_CodeRate=FEC_1_2; break; case 23: HP_CodeRate=FEC_2_3; break; case 34: HP_CodeRate=FEC_3_4; break; case 56: HP_CodeRate=FEC_5_6; break; case 78: HP_CodeRate=FEC_7_8; break; default: mp_msg(MSGT_DEMUX, MSGL_ERR, "Invalid Code Rate: %s\n", dvbin_param_cr); HP_CodeRate=HP_CODERATE_DEFAULT; } } else if(channel != NULL) HP_CodeRate = channel->cr; else HP_CodeRate=HP_CODERATE_DEFAULT; card = dvbin_param_card - 1; if((card < 0) || (card > 4)) card = 0; dvbin_param_on = 1; mp_msg(MSGT_DEMUX, MSGL_V, "CARD: %d, FREQ: %d, POL: %c, SRATE: %d, DISEQC: %d, TONE: %d, VPID: %d, APID: %d\n", card, freq, pol, srate, diseqc, tone, pids[0], pids[1]); priv->channel.freq = freq; priv->channel.srate = srate; priv->channel.diseqc = diseqc; priv->channel.pol = pol; 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; if(freq && pol && srate) if (! dvb_tune(priv, freq, pol, srate, diseqc, tone, specInv, modulation, guardInterval, TransmissionMode, bandWidth, HP_CodeRate)) return 0; for (i=0; i < npids; i++) { if((priv->demux_fd[i] = open(demuxdev[card], O_RDWR)) < 0) { mp_msg(MSGT_DEMUX, MSGL_ERR, "ERROR OPENING DEMUX %i: ", i); return -1; } } if((priv->dvr_fd = open(dvrdev[card], O_RDONLY| O_NONBLOCK)) < 0) { mp_msg(MSGT_DEMUX, MSGL_ERR, "DVR DEVICE: "); return -1; } /* Now we set the filters */ for (i=0; i< npids; i++) { set_ts_filt(priv->demux_fd[i], pids[i], pestypes[i]); //make_nonblock(fd[i]); } stream->fd = priv->dvr_fd; dvbin_is_active = 1; mp_msg(MSGT_DEMUX, MSGL_DBG2, "ESCO da dvb_streaming_start(s)\n"); return 1; } int dvbin_close(dvb_priv_t *priv) { //close(priv->dvr_fd); close(priv->demux_fd[0]); close(priv->demux_fd[1]); } --- NEW FILE --- #ifndef DVBIN_H #define DVBIN_H extern int dvbin_param_on; #ifdef HAVE_DVB_HEAD #include <linux/dvb/dmx.h> #include <linux/dvb/frontend.h> #else #include <ost/dmx.h> #include <ost/sec.h> #include <ost/frontend.h> #define fe_status_t FrontendStatus #define fe_spectral_inversion_t SpectralInversion #define fe_modulation_t Modulation #define fe_code_rate_t CodeRate #define fe_transmit_mode_t TransmitMode #define fe_guard_interval_t GuardInterval #define fe_bandwidth_t BandWidth #define fe_sec_voltage_t SecVoltage #define dmx_pes_filter_params dmxPesFilterParams #define dmx_sct_filter_params dmxSctFilterParams #define dmx_pes_type_t dmxPesType_t #endif #define DVB_CHANNEL_LOWER -1 #define DVB_CHANNEL_HIGHER 1 typedef struct { int next, prev; } dvb_history_t; typedef struct { char *name; int freq, srate, diseqc, tone; char pol; int vpid, apid1, apid2, tpid, dpid1, dpid2, progid, ca; fe_spectral_inversion_t inv; fe_modulation_t mod; fe_transmit_mode_t trans; fe_bandwidth_t bw; fe_guard_interval_t gi; fe_code_rate_t cr; } dvb_channel_t; typedef struct { uint16_t NUM_CHANNELS; uint16_t current; dvb_channel_t channels[512]; } dvb_channels_list; typedef struct { int fe_fd; int sec_fd; int demux_fd[3]; int dvr_fd; int input; int output; int discard; dvb_channel_t channel; dvb_channels_list *list; } dvb_priv_t; extern dvb_history_t *dvb_step_channel(dvb_priv_t*, int, dvb_history_t*); extern dvb_channels_list *dvb_get_channels(char *, const char *); extern dvb_history_t dvb_prev_next; #ifndef DVB_T_LOCATION #ifndef UK #warning No DVB-T country defined in dvb_defaults.h, defaulting to UK #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 #define HIERARCHY_DEFAULT HIERARCHY_NONE #define LP_CODERATE_DEFAULT (0) #endif Index: Makefile =================================================================== RCS file: /cvsroot/mplayer/main/libmpdemux/Makefile,v retrieving revision 1.51 retrieving revision 1.52 diff -u -r1.51 -r1.52 --- Makefile 3 Feb 2003 10:27:50 -0000 1.51 +++ Makefile 16 Mar 2003 20:13:27 -0000 1.52 @@ -3,7 +3,7 @@ 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 @@ -19,6 +19,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) Index: demuxer.c =================================================================== RCS file: /cvsroot/mplayer/main/libmpdemux/demuxer.c,v retrieving revision 1.135 retrieving revision 1.136 diff -u -r1.135 -r1.136 --- demuxer.c 16 Feb 2003 10:00:42 -0000 1.135 +++ demuxer.c 16 Mar 2003 20:13:27 -0000 1.136 @@ -134,6 +134,7 @@ 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 @@ 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_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 @@ #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 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 @@ 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 @@ 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 @@ 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 @@ 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) Index: demuxer.h =================================================================== RCS file: /cvsroot/mplayer/main/libmpdemux/demuxer.h,v retrieving revision 1.56 retrieving revision 1.57 diff -u -r1.56 -r1.57 --- demuxer.h 28 Jan 2003 00:12:23 -0000 1.56 +++ demuxer.h 16 Mar 2003 20:13:28 -0000 1.57 @@ -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 Index: open.c =================================================================== RCS file: /cvsroot/mplayer/main/libmpdemux/open.c,v retrieving revision 1.69 retrieving revision 1.70 diff -u -r1.69 -r1.70 --- open.c 5 Mar 2003 10:56:47 -0000 1.69 +++ open.c 16 Mar 2003 20:13:28 -0000 1.70 @@ -30,6 +30,8 @@ static URL_t* url; #endif +int dvbin_param_on=0; + int dvd_title=0; int dvd_chapter=1; int dvd_last_chapter=0; @@ -76,6 +78,12 @@ extern int stream_open_tv(stream_t *stream, tvi_handle_t *tvh); #endif +#ifdef HAS_DVBIN_SUPPORT +#include "dvbin.h" +#endif + + + #ifdef HAVE_CDDA stream_t* open_cdda(char* dev,char* track); #ifdef STREAMING @@ -477,6 +485,22 @@ return stream; } #endif + +#ifdef HAS_DVBIN_SUPPORT +if(dvbin_param_on == 1) +{ + stream = new_stream(-1, STREAMTYPE_DVB); + if (!stream) + return(NULL); + if (!dvb_streaming_start(stream)) + return NULL; + + return stream; +} +#endif + + + //============ Check for TV-input or multi-file input ==== if( (mf_support == 1) Index: stream.c =================================================================== RCS file: /cvsroot/mplayer/main/libmpdemux/stream.c,v retrieving revision 1.51 retrieving revision 1.52 diff -u -r1.51 -r1.52 --- stream.c 9 Feb 2003 20:18:22 -0000 1.51 +++ stream.c 16 Mar 2003 20:13:28 -0000 1.52 @@ -106,6 +106,15 @@ case STREAMTYPE_DS: len = demux_read_data((demux_stream_t*)s->priv,s->buffer,STREAM_BUFFER_SIZE); break; + +#ifdef HAS_DVBIN_SUPPORT + case STREAMTYPE_DVB: + len = dvb_streaming_read(s->fd, s->buffer, STREAM_BUFFER_SIZE, s->priv); + break; +#endif + + + default: len=0; } if(len<=0){ s->eof=1; s->buf_pos=s->buf_len=0; return 0; } @@ -309,6 +318,12 @@ close_cdda(s); break; #endif +#ifdef HAS_DVBIN_SUPPORT + case STREAMTYPE_DVB: + dvbin_close(s->priv); + break; +#endif + #ifdef USE_DVDREAD case STREAMTYPE_DVD: dvd_close(s->priv); Index: stream.h =================================================================== RCS file: /cvsroot/mplayer/main/libmpdemux/stream.h,v retrieving revision 1.55 retrieving revision 1.56 diff -u -r1.55 -r1.56 --- stream.h 4 Jan 2003 20:11:06 -0000 1.55 +++ stream.h 16 Mar 2003 20:13:28 -0000 1.56 @@ -18,6 +18,7 @@ #define STREAMTYPE_CDDA 10 // raw audio CD reader #define STREAMTYPE_SMB 11 // smb:// url, using libsmbclient (samba) #define STREAMTYPE_VCDBINCUE 12 // vcd directly from bin/cue files +#define STREAMTYPE_DVB 13 #define STREAM_BUFFER_SIZE 2048 Index: video.c =================================================================== RCS file: /cvsroot/mplayer/main/libmpdemux/video.c,v retrieving revision 1.36 retrieving revision 1.37 diff -u -r1.36 -r1.37 --- video.c 15 Mar 2003 21:07:45 -0000 1.36 +++ video.c 16 Mar 2003 20:13:28 -0000 1.37 @@ -134,6 +134,7 @@ // otherwise fall through to... #endif case DEMUXER_TYPE_PVA: + case DEMUXER_TYPE_MPEG_TS: case DEMUXER_TYPE_MPEG_ES: case DEMUXER_TYPE_MPEG_PS: { //mpeg_header_parser: @@ -270,7 +271,7 @@ *start=NULL; if(demuxer->file_format==DEMUXER_TYPE_MPEG_ES || demuxer->file_format==DEMUXER_TYPE_MPEG_PS - || demuxer->file_format==DEMUXER_TYPE_PVA + || demuxer->file_format==DEMUXER_TYPE_PVA || demuxer->file_format==DEMUXER_TYPE_MPEG_TS #ifdef STREAMING_LIVE_DOT_COM || (demuxer->file_format==DEMUXER_TYPE_RTP && demux_is_mpeg_rtp_stream(demuxer)) #endif @@ -422,6 +423,7 @@ } if(demuxer->file_format==DEMUXER_TYPE_MPEG_PS || + demuxer->file_format==DEMUXER_TYPE_MPEG_TS || demuxer->file_format==DEMUXER_TYPE_MPEG_ES){ // if(pts>0.0001) printf("\r!!! pts: %5.3f [%d] (%5.3f) \n",pts,picture_coding_type,i_pts);
participants (1)
-
Arpi of Ize