📄 linux_dvb.c
字号:
/***************************************************************************** * linux_dvb.c : functions to control a DVB card under Linux with v4l2 ***************************************************************************** * Copyright (C) 1998-2005 the VideoLAN team * * Authors: Damien Lucas <nitrox@via.ecp.fr> * Johan Bilien <jobi@via.ecp.fr> * Jean-Paul Saman <jpsaman _at_ videolan _dot_ org> * Christopher Ross <chris@tebibyte.org> * Christophe Massiot <massiot@via.ecp.fr> * * 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, USA. *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <vlc_access.h>#include <sys/ioctl.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <time.h>#include <unistd.h>#include <sys/stat.h>#include <sys/poll.h>/* DVB Card Drivers */#include <linux/dvb/version.h>#include <linux/dvb/dmx.h>#include <linux/dvb/frontend.h>#include <linux/dvb/ca.h>/* Include dvbpsi headers */#ifdef HAVE_DVBPSI_DR_H# include <dvbpsi/dvbpsi.h># include <dvbpsi/descriptor.h># include <dvbpsi/pat.h># include <dvbpsi/pmt.h># include <dvbpsi/dr.h># include <dvbpsi/psi.h>#else# include "dvbpsi.h"# include "descriptor.h"# include "tables/pat.h"# include "tables/pmt.h"# include "descriptors/dr.h"# include "psi.h"#endif#ifdef ENABLE_HTTPD# include "vlc_httpd.h"#endif#include "dvb.h"/* * Frontends */struct frontend_t{ fe_status_t i_last_status; struct dvb_frontend_info info;};#define FRONTEND_LOCK_TIMEOUT 10000000 /* 10 s *//* Local prototypes */static int FrontendInfo( access_t * );static int FrontendSetQPSK( access_t * );static int FrontendSetQAM( access_t * );static int FrontendSetOFDM( access_t * );static int FrontendSetATSC( access_t * );/***************************************************************************** * FrontendOpen : Determine frontend device information and capabilities *****************************************************************************/int FrontendOpen( access_t *p_access ){ access_sys_t *p_sys = p_access->p_sys; frontend_t * p_frontend; unsigned int i_adapter, i_device; bool b_probe; char frontend[128]; i_adapter = var_GetInteger( p_access, "dvb-adapter" ); i_device = var_GetInteger( p_access, "dvb-device" ); b_probe = var_GetBool( p_access, "dvb-probe" ); if( snprintf( frontend, sizeof(frontend), FRONTEND, i_adapter, i_device ) >= (int)sizeof(frontend) ) { msg_Err( p_access, "snprintf() truncated string for FRONTEND" ); frontend[sizeof(frontend) - 1] = '\0'; } p_sys->p_frontend = p_frontend = malloc( sizeof(frontend_t) ); if( !p_frontend ) return VLC_ENOMEM; msg_Dbg( p_access, "Opening device %s", frontend ); if( (p_sys->i_frontend_handle = open(frontend, O_RDWR | O_NONBLOCK)) < 0 ) { msg_Err( p_access, "FrontEndOpen: opening device failed (%m)" ); free( p_frontend ); return VLC_EGENERIC; } if( b_probe ) { const char * psz_expected = NULL; const char * psz_real; if( FrontendInfo( p_access ) < 0 ) { close( p_sys->i_frontend_handle ); free( p_frontend ); return VLC_EGENERIC; } switch( p_frontend->info.type ) { case FE_OFDM: psz_real = "DVB-T"; break; case FE_QAM: psz_real = "DVB-C"; break; case FE_QPSK: psz_real = "DVB-S"; break; case FE_ATSC: psz_real = "ATSC"; break; default: psz_real = "unknown"; } /* Sanity checks */ if( (!strncmp( p_access->psz_access, "qpsk", 4 ) || !strncmp( p_access->psz_access, "dvb-s", 5 ) || !strncmp( p_access->psz_access, "satellite", 9 ) ) && (p_frontend->info.type != FE_QPSK) ) { psz_expected = "DVB-S"; } if( (!strncmp( p_access->psz_access, "cable", 5 ) || !strncmp( p_access->psz_access, "dvb-c", 5 ) ) && (p_frontend->info.type != FE_QAM) ) { psz_expected = "DVB-C"; } if( (!strncmp( p_access->psz_access, "terrestrial", 11 ) || !strncmp( p_access->psz_access, "dvb-t", 5 ) ) && (p_frontend->info.type != FE_OFDM) ) { psz_expected = "DVB-T"; } if( (!strncmp( p_access->psz_access, "usdigital", 9 ) || !strncmp( p_access->psz_access, "atsc", 4 ) ) && (p_frontend->info.type != FE_ATSC) ) { psz_expected = "ATSC"; } if( psz_expected != NULL ) { msg_Err( p_access, "the user asked for %s, and the tuner is %s", psz_expected, psz_real ); close( p_sys->i_frontend_handle ); free( p_frontend ); return VLC_EGENERIC; } } else /* no frontend probing is done so use default border values. */ { msg_Dbg( p_access, "using default values for frontend info" ); msg_Dbg( p_access, "method of access is %s", p_access->psz_access ); p_frontend->info.type = FE_QPSK; if( !strncmp( p_access->psz_access, "qpsk", 4 ) || !strncmp( p_access->psz_access, "dvb-s", 5 ) ) p_frontend->info.type = FE_QPSK; else if( !strncmp( p_access->psz_access, "cable", 5 ) || !strncmp( p_access->psz_access, "dvb-c", 5 ) ) p_frontend->info.type = FE_QAM; else if( !strncmp( p_access->psz_access, "terrestrial", 11 ) || !strncmp( p_access->psz_access, "dvb-t", 5 ) ) p_frontend->info.type = FE_OFDM; else if( !strncmp( p_access->psz_access, "usdigital", 9 ) || !strncmp( p_access->psz_access, "atsc", 4 ) ) p_frontend->info.type = FE_ATSC; } return VLC_SUCCESS;}/***************************************************************************** * FrontendClose : Close the frontend *****************************************************************************/void FrontendClose( access_t *p_access ){ access_sys_t *p_sys = p_access->p_sys; if( p_sys->p_frontend ) { close( p_sys->i_frontend_handle ); free( p_sys->p_frontend ); p_sys->p_frontend = NULL; }}/***************************************************************************** * FrontendSet : Tune ! *****************************************************************************/int FrontendSet( access_t *p_access ){ access_sys_t *p_sys = p_access->p_sys; switch( p_sys->p_frontend->info.type ) { /* DVB-S */ case FE_QPSK: if( FrontendSetQPSK( p_access ) < 0 ) { msg_Err( p_access, "DVB-S: tuning failed" ); return VLC_EGENERIC; } break; /* DVB-C */ case FE_QAM: if( FrontendSetQAM( p_access ) < 0 ) { msg_Err( p_access, "DVB-C: tuning failed" ); return VLC_EGENERIC; } break; /* DVB-T */ case FE_OFDM: if( FrontendSetOFDM( p_access ) < 0 ) { msg_Err( p_access, "DVB-T: tuning failed" ); return VLC_EGENERIC; } break; /* ATSC */ case FE_ATSC: if( FrontendSetATSC( p_access ) < 0 ) { msg_Err( p_access, "ATSC: tuning failed" ); return VLC_EGENERIC; } break; default: msg_Err( p_access, "Could not determine frontend type on %s", p_sys->p_frontend->info.name ); return VLC_EGENERIC; } p_sys->p_frontend->i_last_status = 0; p_sys->i_frontend_timeout = mdate() + FRONTEND_LOCK_TIMEOUT; return VLC_SUCCESS;}/***************************************************************************** * FrontendPoll : Poll for frontend events *****************************************************************************/void FrontendPoll( access_t *p_access ){ access_sys_t *p_sys = p_access->p_sys; frontend_t * p_frontend = p_sys->p_frontend; struct dvb_frontend_event event; fe_status_t i_status, i_diff; for( ;; ) { int i_ret = ioctl( p_sys->i_frontend_handle, FE_GET_EVENT, &event ); if( i_ret < 0 ) { if( errno == EWOULDBLOCK ) return; /* no more events */ msg_Err( p_access, "reading frontend event failed (%d): %m", i_ret ); return; } i_status = event.status; i_diff = i_status ^ p_frontend->i_last_status; p_frontend->i_last_status = i_status; {#define IF_UP( x ) \ } \ if ( i_diff & (x) ) \ { \ if ( i_status & (x) ) IF_UP( FE_HAS_SIGNAL ) msg_Dbg( p_access, "frontend has acquired signal" ); else msg_Dbg( p_access, "frontend has lost signal" ); IF_UP( FE_HAS_CARRIER ) msg_Dbg( p_access, "frontend has acquired carrier" ); else msg_Dbg( p_access, "frontend has lost carrier" ); IF_UP( FE_HAS_VITERBI ) msg_Dbg( p_access, "frontend has acquired stable FEC" ); else msg_Dbg( p_access, "frontend has lost FEC" ); IF_UP( FE_HAS_SYNC ) msg_Dbg( p_access, "frontend has acquired sync" ); else msg_Dbg( p_access, "frontend has lost sync" ); IF_UP( FE_HAS_LOCK ) { int32_t i_value = 0; msg_Dbg( p_access, "frontend has acquired lock" ); p_sys->i_frontend_timeout = 0; /* Read some statistics */ if( ioctl( p_sys->i_frontend_handle, FE_READ_BER, &i_value ) >= 0 ) msg_Dbg( p_access, "- Bit error rate: %d", i_value ); if( ioctl( p_sys->i_frontend_handle, FE_READ_SIGNAL_STRENGTH, &i_value ) >= 0 ) msg_Dbg( p_access, "- Signal strength: %d", i_value ); if( ioctl( p_sys->i_frontend_handle, FE_READ_SNR, &i_value ) >= 0 ) msg_Dbg( p_access, "- SNR: %d", i_value ); } else { msg_Dbg( p_access, "frontend has lost lock" ); p_sys->i_frontend_timeout = mdate() + FRONTEND_LOCK_TIMEOUT; } IF_UP( FE_REINIT ) { /* The frontend was reinited. */ msg_Warn( p_access, "reiniting frontend"); FrontendSet( p_access ); } }#undef IF_UP }}#ifdef ENABLE_HTTPD
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -