📄 access.c
字号:
/***************************************************************************** * access.c : CD digital audio input module for vlc using libcdio ***************************************************************************** * Copyright (C) 2000, 2003, 2004, 2005 the VideoLAN team * $Id$ * * Authors: Rocky Bernstein <rocky@panix.com> * Laurent Aimar <fenrir@via.ecp.fr> * Gildas Bazin <gbazin@netcourrier.com> * * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#include "callback.h" /* FIXME - reorganize callback.h, cdda.h better */#include "cdda.h" /* private structures. Also #includes vlc things */#include "info.h" /* headers for meta info retrieval */#include "access.h"#include "vlc_keys.h"#include <vlc_interface.h>#include <cdio/cdio.h>#include <cdio/logging.h>#include <cdio/cd_types.h>/* #ifdef variables below are defined via config.h via #include vlc above. */#ifdef HAVE_SYS_TYPES_H#include <sys/types.h>#endif#ifdef HAVE_UNISTD_H# include <unistd.h>#endif/* FIXME: This variable is a hack. Would be nice to eliminate. */access_t *p_cdda_input = NULL;/***************************************************************************** * Local prototypes *****************************************************************************/static ssize_t CDDARead( access_t *, uint8_t *, size_t );static block_t *CDDAReadBlocks( access_t * p_access );static int CDDASeek( access_t * p_access, int64_t i_pos );static int CDDAControl( access_t *p_access, int i_query, va_list args );static int CDDAInit( access_t *p_access, cdda_data_t *p_cdda ) ;/**************************************************************************** * Private functions ****************************************************************************//* process messages that originate from libcdio. called by CDDAOpen*/static voidcdio_log_handler( cdio_log_level_t level, const char message[] ){ cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_sys; if( p_cdda == NULL ) return; switch( level ) { case CDIO_LOG_DEBUG: case CDIO_LOG_INFO: if (p_cdda->i_debug & INPUT_DBG_CDIO) msg_Dbg( p_cdda_input, "%s", message); break; case CDIO_LOG_WARN: msg_Warn( p_cdda_input, "%s", message); break; case CDIO_LOG_ERROR: case CDIO_LOG_ASSERT: msg_Err( p_cdda_input, "%s", message); break; default: msg_Warn( p_cdda_input, "%s\n%s %d", message, "the above message had unknown cdio log level", level); break; }}#ifdef HAVE_LIBCDDB/*! This routine is called by libcddb routines on error. called by CDDAOpen*/static voidcddb_log_handler( cddb_log_level_t level, const char message[] ){ cdda_data_t *p_cdda = (cdda_data_t *)p_cdda_input->p_sys; switch( level ) { case CDDB_LOG_DEBUG: case CDDB_LOG_INFO: if( !(p_cdda->i_debug & INPUT_DBG_CDDB) ) return; /* Fall through if to warn case */ default: cdio_log_handler( level, message ); break; }}#endif /*HAVE_LIBCDDB*//*! This routine is when vlc is not fully set up (before full initialization) or is not around (before finalization).*/static voiduninit_log_handler( cdio_log_level_t level, const char message[] ){ cdda_data_t *p_cdda = NULL; if( p_cdda_input ) p_cdda = (cdda_data_t *)p_cdda_input->p_sys; switch( level ) { case CDIO_LOG_DEBUG: case CDIO_LOG_INFO: if( !p_cdda || !(p_cdda->i_debug & (INPUT_DBG_CDIO|INPUT_DBG_CDDB)) ) return; /* Fall through if to warn case */ case CDIO_LOG_WARN: fprintf( stderr, "WARN: %s\n", message ); break; case CDIO_LOG_ERROR: fprintf( stderr, "ERROR: %s\n", message ); break; case CDIO_LOG_ASSERT: fprintf( stderr, "ASSERT ERROR: %s\n", message ); break; default: fprintf( stderr, "UNKNOWN ERROR: %s\n%s %d\n", message, "The above message had unknown cdio log level", level ); break; } /* gl_default_cdio_log_handler (level, message); */}/* Only used in audio control mode. Gets the current LSN from the CD-ROM drive. */static int64_t get_audio_position ( access_t *p_access ){ cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys; lsn_t i_offset;#if LIBCDIO_VERSION_NUM >= 73 if( p_cdda->b_audio_ctl ) { cdio_subchannel_t sub; CdIo_t *p_cdio = p_cdda->p_cdio; if( DRIVER_OP_SUCCESS == cdio_audio_read_subchannel(p_cdio, &sub) ) { if( (sub.audio_status != CDIO_MMC_READ_SUB_ST_PAUSED) && (sub.audio_status != CDIO_MMC_READ_SUB_ST_PLAY) ) return CDIO_INVALID_LSN; if( ! p_cdda->b_nav_mode ) { i_offset = cdio_msf_to_lba( (&sub.abs_addr) ); } else { i_offset = cdio_msf_to_lba( (&sub.rel_addr) ); } } else { i_offset = p_cdda->i_lsn; } } else { i_offset = p_cdda->i_lsn; }#else i_offset = p_cdda->i_lsn;#endif return i_offset;}/***************************************************************************** * CDDAReadBlocks: reads a group of blocks from the CD-DA and returns * an allocated pointer to the data. NULL is returned if no data * read. It is also possible if we haven't read a RIFF header in which * case one that we creaded during Open/Initialization is returned. *****************************************************************************/static block_t * CDDAReadBlocks( access_t * p_access ){ block_t *p_block; cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys; int i_blocks = p_cdda->i_blocks_per_read; dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_LSN), "called i_lsn: %d i_pos: %lld, size: %lld", p_cdda->i_lsn, p_access->info.i_pos, p_access->info.i_size ); /* Check end of file */ if( p_access->info.b_eof ) return NULL; if( !p_cdda->b_header ) { /* Return only the dummy RIFF header we created in Open/Init */ p_block = block_New( p_access, sizeof( WAVEHEADER ) ); memcpy( p_block->p_buffer, &p_cdda->waveheader, sizeof(WAVEHEADER) ); p_cdda->b_header = true; return p_block; } /* Check end of track */ while( p_cdda->i_lsn > cdio_get_track_last_lsn(p_cdda->p_cdio, p_cdda->i_track) ) { bool go_on; if( p_cdda->b_nav_mode ) go_on = p_cdda->i_lsn > p_cdda->last_disc_frame; else go_on = p_cdda->i_track >= p_cdda->i_first_track+p_cdda->i_titles-1 ; if( go_on ) { dbg_print( (INPUT_DBG_LSN), "EOF"); p_access->info.b_eof = true; return NULL; } p_access->info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_META; p_access->info.i_title++; p_cdda->i_track++; if( p_cdda-> b_nav_mode ) { char *psz_title = CDDAFormatTitle( p_access, p_cdda->i_track ); input_Control( p_cdda->p_input, INPUT_SET_NAME, psz_title ); free(psz_title); } else { p_access->info.i_size = p_cdda->p_title[p_access->info.i_title]->i_size; p_access->info.i_pos = 0; p_access->info.i_update |= INPUT_UPDATE_SIZE; } } /* Possibly adjust i_blocks so we don't read past the end of a track. */ if( p_cdda->i_lsn + i_blocks >= cdio_get_track_lsn(p_cdda->p_cdio, p_cdda->i_track+1) ) { i_blocks = cdio_get_track_lsn( p_cdda->p_cdio, p_cdda->i_track+1 ) - p_cdda->i_lsn; } /* Do the actual reading */ p_block = block_New( p_access, i_blocks * CDIO_CD_FRAMESIZE_RAW ); if( !p_block) { msg_Err( p_access, "cannot get a new block of size: %i", i_blocks * CDIO_CD_FRAMESIZE_RAW ); intf_UserFatal( p_access, false, _("CD reading failed"), _("VLC could not get a new block of size: %i."), i_blocks * CDIO_CD_FRAMESIZE_RAW ); return NULL; } {#if LIBCDIO_VERSION_NUM >= 72 driver_return_code_t rc = DRIVER_OP_SUCCESS; if( p_cdda->e_paranoia && p_cdda->paranoia ) { int i; for( i = 0; i < i_blocks; i++ ) { int16_t *p_readbuf = cdio_paranoia_read( p_cdda->paranoia, NULL ); char *psz_err = cdio_cddap_errors( p_cdda->paranoia_cd ); char *psz_mes = cdio_cddap_messages( p_cdda->paranoia_cd ); if( psz_mes || psz_err ) msg_Err( p_access, "%s%s\n", psz_mes ? psz_mes: "", psz_err ? psz_err: "" ); free( psz_err ); free( psz_mes ); if( !p_readbuf ) { msg_Err( p_access, "paranoia read error on frame %i\n", p_cdda->i_lsn+i ); } else memcpy( p_block->p_buffer + i * CDIO_CD_FRAMESIZE_RAW, p_readbuf, CDIO_CD_FRAMESIZE_RAW ); } } else { rc = cdio_read_audio_sectors( p_cdda->p_cdio, p_block->p_buffer, p_cdda->i_lsn, i_blocks );#else#define DRIVER_OP_SUCCESS 0 int rc; rc = cdio_read_audio_sectors( p_cdda->p_cdio, p_block->p_buffer, p_cdda->i_lsn, i_blocks);#endif } if( rc != DRIVER_OP_SUCCESS ) { msg_Err( p_access, "could not read %d sectors starting from %lu", i_blocks, (long unsigned int) p_cdda->i_lsn ); block_Release( p_block ); /* If we had problems above, assume the problem is with the first sector of the read and set to skip it. In the future libcdio may have cdparanoia support. */ p_cdda->i_lsn++; p_access->info.i_pos += CDIO_CD_FRAMESIZE_RAW; return NULL; } } p_cdda->i_lsn += i_blocks; p_access->info.i_pos += i_blocks * CDIO_CD_FRAMESIZE_RAW; return p_block;}/***************************************************************************** * CDDARead: Handler for audio control reads the CD-DA. *****************************************************************************/static ssize_tCDDARead( access_t * p_access, uint8_t *p_buffer, size_t i_len ){ cdda_data_t *p_cdda = (cdda_data_t *) p_access->p_sys; dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_LSN), "called lsn: %d pos: %lld, size: %lld", p_cdda->i_lsn, p_access->info.i_pos, p_access->info.i_size); /* Check end of file */ if( p_access->info.b_eof ) return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -