Beispiel #1
0
static int seek(stream_t *s, int64_t newpos)
{
    cdda_priv *p = (cdda_priv *)s->priv;
    int sec;
    int current_track = 0, seeked_track = 0;
    int seek_to_track = 0;
    int i;

    sec = newpos / CDIO_CD_FRAMESIZE_RAW;
    if (newpos < 0 || sec > p->end_sector) {
        p->sector = p->end_sector + 1;
        return 0;
    }

    for (i = 0; i < p->cd->tracks; i++) {
        if (p->sector >= p->cd->disc_toc[i].dwStartSector
            && p->sector < p->cd->disc_toc[i + 1].dwStartSector)
            current_track = i;
        if (sec >= p->cd->disc_toc[i].dwStartSector
            && sec < p->cd->disc_toc[i + 1].dwStartSector)
        {
            seeked_track = i;
            seek_to_track = sec == p->cd->disc_toc[i].dwStartSector;
        }
    }
    if (current_track != seeked_track && !seek_to_track)
        print_track_info(s, seeked_track + 1);

    p->sector = sec;

    paranoia_seek(p->cdp, sec, SEEK_SET);
    return 1;
}
Beispiel #2
0
static int
cda_seek_sample (DB_fileinfo_t *_info, int sample)
{
    trace("cda_seek_sample %d\n", sample);
    cdda_info_t *info = (cdda_info_t *)_info;
    const int sector = sample * SAMPLESIZE / SECTORSIZE + info->first_sector;
    const int offset = sample * SAMPLESIZE % SECTORSIZE;

#if USE_PARANOIA
    if (info->paranoia) {
        paranoia_seek(info->paranoia, sector, SEEK_SET);
    }
#endif
    info->current_sector = sector;
    const char *p_readbuf = read_sector(info);
    if (!p_readbuf) {
        return -1;
    }

    info->tail = (char *)p_readbuf + offset;
    info->tail_length = SECTORSIZE - offset;
    _info->readpos = (float)sample / _info->fmt.samplerate;

    return 0;
}
Beispiel #3
0
int CdParanoia::seek(long sector, int mode)
{
    #ifdef CDIOPARANOIA_FOUND
    return paranoia ? cdio_paranoia_seek(paranoia, sector, mode) : -1;
    #else
    return paranoia ? paranoia_seek(paranoia, sector, mode) : -1;
    #endif
}
Beispiel #4
0
int CDDAParanoia::paranoiaSeek(long sector, int mode) {
  if (paranoia) {
    mutex.lock();
    long pos = paranoia_seek(paranoia, sector, mode);
    mutex.unlock();
    return pos;
  }
  return -1;
}
Beispiel #5
0
static int seek(stream_t* s,off_t newpos) {
  cdda_priv* p = (cdda_priv*)s->priv;
  cd_track_t *cd_track;
  int sec;
  int current_track=0, seeked_track=0;
  int seek_to_track = 0;
  int i;

  s->pos = newpos;
  sec = s->pos/CD_FRAMESIZE_RAW;
  if (s->pos < 0 || sec > p->end_sector) {
    s->eof = 1;
    return 0;
  }

//printf("pos: %d, sec: %d ## %d\n", (int)s->pos, (int)sec, CD_FRAMESIZE_RAW);
//printf("sector: %d  new: %d\n", p->sector, sec );

  for(i=0;i<p->cd->tracks;i++){
//        printf("trk #%d: %d .. %d\n",i,p->cd->disc_toc[i].dwStartSector,p->cd->disc_toc[i+1].dwStartSector);
	if( p->sector>=p->cd->disc_toc[i].dwStartSector && p->sector<p->cd->disc_toc[i+1].dwStartSector ) {
		current_track = i;
	}
	if( sec>=p->cd->disc_toc[i].dwStartSector && sec<p->cd->disc_toc[i+1].dwStartSector ) {
		seeked_track = i;
		seek_to_track = sec == p->cd->disc_toc[i].dwStartSector;
	}
  }
//printf("current: %d, seeked: %d\n", current_track, seeked_track);
	if (current_track != seeked_track && !seek_to_track) {
//printf("Track %d, sector=%d\n", seeked_track, sec);
		  cd_track = cd_info_get_track(p->cd_info, seeked_track+1);
		  if( cd_track!=NULL ) {
			  mp_msg(MSGT_SEEK, MSGL_INFO, "\n%s\n", cd_track->name);
			  mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_CDDA_TRACK=%d\n", cd_track->track_nb);
		  }

	}
#if 0
  if(sec < p->start_sector)
    sec = p->start_sector;
  else if(sec > p->end_sector)
    sec = p->end_sector;
#endif

  p->sector = sec;
//  s->pos = sec*CD_FRAMESIZE_RAW;

//printf("seek: %d, sec: %d\n", (int)s->pos, sec);
  paranoia_seek(p->cdp,sec,SEEK_SET);
  return 1;
}
Beispiel #6
0
    ParanoiaStream(cdrom_drive *cdt, int first_sector, int last_sector)
	: m_drive(cdt),
	  m_paranoia(paranoia_init(cdt)),
	  m_first_sector(first_sector),
	  m_last_sector(last_sector),
	  m_sector(first_sector-1),
	  m_data(NULL),
	  m_skip(2352)
    {
	sm_speed = 64;
	cdda_speed_set(cdt, 64);

	TRACE << "Read starting\n";
	paranoia_modeset(m_paranoia, 
			 PARANOIA_MODE_FULL - PARANOIA_MODE_NEVERSKIP);
	paranoia_seek(m_paranoia, first_sector, SEEK_SET);
    }
		int RipAttempt() {
			for ( i_cursor = i_first_lsn; i_cursor <= i_last_lsn; ) {
				for ( int i = 0; i < NUM_TRIES; i++) {
					paranoia_seek(p, i_cursor, SEEK_SET);
					for ( int j = 0; j < NUM_SECTORS && j <= (i_last_lsn - i_cursor); j++ ) {
						/* read a sector */
						int16_t *p_readbuf = cdio_paranoia_read(p, NULL);
						int16_t *buf_pointer;
						psz_err = cdio_cddap_errors(d);
						psz_mes = cdio_cddap_messages(d);
						if (psz_mes || psz_err)
							printf("%s%s\n", psz_mes ? psz_mes: "", psz_err ? psz_err: "");
						if (psz_err) free(psz_err);
						if (psz_mes) free(psz_mes);
						if( !p_readbuf ) {
							printf("paranoia read error. Stopping.\n");
							break;
						} else {
							/* Transport data to actual buffer */
							if ( i == 0 ) {
								for ( buf_pointer = p_readbuf, counter = (CDIO_CD_FRAMESIZE_RAW/2)*j; buf_pointer != NULL && counter < (CDIO_CD_FRAMESIZE_RAW/2)*(j+1); buf_pointer++, counter++ ) {
									readbuf[counter] = *buf_pointer;
								}
							} else {
								for ( buf_pointer = p_readbuf, counter = (CDIO_CD_FRAMESIZE_RAW/2)*j; buf_pointer != NULL && counter < (CDIO_CD_FRAMESIZE_RAW/2)*(j+1); buf_pointer++, counter++ ) {
									readbuf2[counter] = *buf_pointer;
								}
							}
						}
						num_samples = counter;
					}
				}
				failed = false;
				for (int i = 0; i < num_samples ; i++) {
					if (readbuf[i] != readbuf2[i]) {
						failed = true;
					}
				}
				if (!failed) {
					i_cursor += NUM_SECTORS;
					written_samples = WriteToFile();
					if (written_samples != num_samples) return 1;
				}
			}
			return 0;
		}
/*
 * Class:     org_tritonus_lowlevel_cdda_cdparanoia_Cdparanoia
 * Method:    prepareTrack
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL
Java_org_tritonus_lowlevel_cdda_cdparanoia_Cdparanoia_prepareTrack
(JNIEnv* env, jobject obj, jint nTrack)
{
	handle_t*	handle;
	cdrom_drive*	cdrom;
	cdrom_paranoia*	paranoia;
	int		nFirstSector;
	
	if (debug_flag) { fprintf(debug_file, "Java_org_tritonus_lowlevel_cdda_cdparanoia_Cdparanoia_prepareTrack(): begin\n"); }
	handle = getHandle(env, obj);
	cdrom = handle->drive;
	paranoia = handle->paranoia;

	nFirstSector = cdda_track_firstsector(cdrom, nTrack);
	// TODO: check return value
	paranoia_seek(paranoia, nFirstSector, SEEK_SET);
	if (debug_flag) { fprintf(debug_file, "Java_org_tritonus_lowlevel_cdda_cdparanoia_Cdparanoia_prepareTrack(): end\n"); }
	return 0;
}
Beispiel #9
0
unsigned ParanoiaStream::Seek(uint64_t pos)
{
    if (pos == Tell())
	return 0;

    uint64_t current = Tell();
    TRACE << "Tell()=" << current/2352 << ":" << current%2352
	  << " pos=" << pos/2352 << ":" << pos%2352 << ", seeking\n";

    m_sector = (int)(m_first_sector + pos/2352);
    m_skip = (unsigned int)(pos % 2352);

    assert(pos == Tell());

    TRACE << "Seeking to sector " << m_sector << "\n";

    paranoia_seek(m_paranoia, m_sector, SEEK_SET);

    m_data = NULL;
    return 0;
}
Beispiel #10
0
static int
cda_init (DB_fileinfo_t *_info, DB_playItem_t *it)
{
    deadbeef->pl_lock();
    const char *uri = deadbeef->pl_find_meta(it, ":URI");
    const char *nr = uri ? strchr(uri, '#') : NULL;
    if (!nr || nr == uri) {
        deadbeef->pl_unlock();
        trace ("cdda: bad name: %s\n", uri);
        return -1;
    }

    trace ("cdda: init %s\n", uri);
    const int track_nr = atoi(nr+1);
    const size_t device_length = nr - uri;
    char device[device_length+1];
    strncpy(device, uri, device_length);
    device[device_length] = '\0';
    deadbeef->pl_unlock();

    cdda_info_t *info = (cdda_info_t *)_info;
    info->cdio = cdio_open(device, DRIVER_UNKNOWN);
    if  (!info->cdio) {
        trace ("cdda: Could not open CD device\n");
        return -1;
    }

    const int need_bitrate = info->hints & DDB_DECODER_HINT_NEED_BITRATE;
    const int drive_speed = deadbeef->conf_get_int("cdda.drive_speed", 2);
    cdio_set_speed(info->cdio, need_bitrate && drive_speed < 5 ? 1<<drive_speed : -1);

    cddb_disc_t *disc = create_disc(info->cdio);
    if (!disc) {
        return -1;
    }

    const unsigned long discid = cddb_disc_get_discid(disc);
    cddb_disc_destroy(disc);

    deadbeef->pl_lock();
    const char *discid_hex = deadbeef->pl_find_meta(it, CDDB_DISCID_TAG);
    const unsigned long trk_discid = discid_hex ? strtoul(discid_hex, NULL, 16) : 0;
    deadbeef->pl_unlock();
    if (trk_discid != discid) {
        trace ("cdda: the track belongs to another disc (%x vs %x), skipped\n", trk_discid, discid);
        return -1;
    }

    if (cdio_get_track_format(info->cdio, track_nr) != TRACK_FORMAT_AUDIO) {
        trace ("cdda: Not an audio track (%d)\n", track_nr);
        return -1;
    }

    info->first_sector = cdio_get_track_lsn(info->cdio, track_nr);
    info->current_sector = info->first_sector;
    info->last_sector = info->first_sector + cdio_get_track_sec_count(info->cdio, track_nr) - 1;
    trace("cdio nchannels (should always be 2 for an audio track): %d\n", cdio_get_track_channels (info->cdio, track_nr));
    if (info->first_sector == CDIO_INVALID_LSN || info->last_sector <= info->first_sector) {
        trace ("cdda: invalid track\n");
        return -1;
    }

#if USE_PARANOIA
    if (cdio_get_driver_id(info->cdio) != DRIVER_NRG) {
        info->cdrom = cdda_identify(device, CDDA_MESSAGE_FORGETIT, NULL);
        if (info->cdrom) {
            cdda_open(info->cdrom);
            info->paranoia = paranoia_init(info->cdrom);
        }
        if (!info->paranoia) {
            trace ("cdda: cannot re-open %s for paranoia\n", device);
            return -1;
        }
        const int no_paranoia = need_bitrate || !deadbeef->conf_get_int("cdda.paranoia", 0);
        if (no_paranoia) {
            paranoia_cachemodel_size(info->paranoia, 100);
        }
        paranoia_modeset(info->paranoia, no_paranoia ? PARANOIA_MODE_DISABLE : PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP);
        paranoia_seek(info->paranoia, info->first_sector, SEEK_SET);
    }
#endif
    return 0;
}
static GstBuffer *
gst_cd_paranoia_src_read_sector (GstAudioCdSrc * audiocdsrc, gint sector)
{
  GstCdParanoiaSrc *src = GST_CD_PARANOIA_SRC (audiocdsrc);
  GstBuffer *buf;
  gboolean do_serialize;
  gint16 *cdda_buf;

#if 0
  /* Do we really need to output this? (tpm) */
  /* Due to possible autocorrections of start sectors of audio tracks on 
   * multisession cds, we can maybe not compute the correct discid.
   * So issue a warning.
   * See cdparanoia/interface/common-interface.c:FixupTOC */
  if (src->d && src->d->cd_extra) {
    g_message
        ("DiscID on multisession discs might be broken. Use at own risk.");
  }
#endif

  if (src->next_sector == -1 || src->next_sector != sector) {
    if (paranoia_seek (src->p, sector, SEEK_SET) == -1)
      goto seek_failed;

    GST_DEBUG_OBJECT (src, "successfully seeked to sector %d", sector);
    src->next_sector = sector;
  }

  do_serialize =
      gst_cd_paranoia_src_signal_is_being_watched (src, TRANSPORT_ERROR) ||
      gst_cd_paranoia_src_signal_is_being_watched (src, UNCORRECTED_ERROR);

  if (do_serialize) {
    GST_LOG_OBJECT (src, "Signal handlers connected, serialising access");
    g_mutex_lock (&cur_cb_mutex);
    GST_LOG_OBJECT (src, "Got lock");
    cur_cb_source = src;

    cdda_buf = paranoia_read (src->p, gst_cd_paranoia_paranoia_callback);

    cur_cb_source = NULL;
    GST_LOG_OBJECT (src, "Releasing lock");
    g_mutex_unlock (&cur_cb_mutex);
  } else {
    cdda_buf = paranoia_read (src->p, gst_cd_paranoia_dummy_callback);
  }

  if (cdda_buf == NULL)
    goto read_failed;

  buf = gst_buffer_new_and_alloc (CD_FRAMESIZE_RAW);
  gst_buffer_fill (buf, 0, cdda_buf, CD_FRAMESIZE_RAW);

  /* cdda base class will take care of timestamping etc. */
  ++src->next_sector;

  return buf;

  /* ERRORS */
seek_failed:
  {
    GST_WARNING_OBJECT (src, "seek to sector %d failed!", sector);
    GST_ELEMENT_ERROR (src, RESOURCE, SEEK,
        (_("Could not seek CD.")),
        ("paranoia_seek to %d failed: %s", sector, g_strerror (errno)));
    return NULL;
  }
read_failed:
  {
    GST_WARNING_OBJECT (src, "read at sector %d failed!", sector);
    GST_ELEMENT_ERROR (src, RESOURCE, READ,
        (_("Could not read CD.")),
        ("paranoia_read at %d failed: %s", sector, g_strerror (errno)));
    return NULL;
  }
}
Beispiel #12
0
static int open_cdda(stream_t *st, int m)
{
    cdda_priv *priv = st->priv;
    cdda_priv *p = priv;
    int mode = p->paranoia_mode;
    int offset = p->toc_offset;
    cdrom_drive_t *cdd = NULL;
    int last_track;

    if (m != STREAM_READ) {
        return STREAM_UNSUPPORTED;
    }

    if (!p->device) {
        if (cdrom_device)
            p->device = talloc_strdup(NULL, cdrom_device);
        else
            p->device = talloc_strdup(NULL, DEFAULT_CDROM_DEVICE);
    }

#if defined(__NetBSD__)
    cdd = cdda_identify_scsi(p->device, p->device, 0, NULL);
#else
    cdd = cdda_identify(p->device, 0, NULL);
#endif

    if (!cdd) {
        MP_ERR(st, "Can't open CDDA device.\n");
        return STREAM_ERROR;
    }

    cdda_verbose_set(cdd, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);

    if (p->sector_size)
        cdd->nsectors = p->sector_size;

    if (cdda_open(cdd) != 0) {
        MP_ERR(st, "Can't open disc.\n");
        cdda_close(cdd);
        return STREAM_ERROR;
    }

    priv = malloc(sizeof(cdda_priv));
    memset(priv, 0, sizeof(cdda_priv));
    priv->cd = cdd;

    if (p->toc_bias)
        offset -= cdda_track_firstsector(cdd, 1);

    if (offset) {
        for (int n = 0; n < cdd->tracks + 1; n++)
            cdd->disc_toc[n].dwStartSector += offset;
    }

    if (p->speed > 0)
        cdda_speed_set(cdd, p->speed);

    last_track = cdda_tracks(cdd);
    if (p->span[0] > last_track)
        p->span[0] = last_track;
    if (p->span[1] < p->span[0])
        p->span[1] = p->span[0];
    if (p->span[1] > last_track)
        p->span[1] = last_track;
    if (p->span[0])
        priv->start_sector = cdda_track_firstsector(cdd, p->span[0]);
    else
        priv->start_sector = cdda_disc_firstsector(cdd);

    if (p->span[1])
        priv->end_sector = cdda_track_lastsector(cdd, p->span[1]);
    else
        priv->end_sector = cdda_disc_lastsector(cdd);

    priv->cdp = paranoia_init(cdd);
    if (priv->cdp == NULL) {
        cdda_close(cdd);
        free(priv);
        return STREAM_ERROR;
    }

    if (mode == 0)
        mode = PARANOIA_MODE_DISABLE;
    else if (mode == 1)
        mode = PARANOIA_MODE_OVERLAP;
    else
        mode = PARANOIA_MODE_FULL;

    if (p->no_skip)
        mode |= PARANOIA_MODE_NEVERSKIP;
    else
        mode &= ~PARANOIA_MODE_NEVERSKIP;

    if (p->search_overlap > 0)
        mode |= PARANOIA_MODE_OVERLAP;
    else if (p->search_overlap == 0)
        mode &= ~PARANOIA_MODE_OVERLAP;

    paranoia_modeset(priv->cdp, mode);

    if (p->search_overlap > 0)
        paranoia_overlapset(priv->cdp, p->search_overlap);

    paranoia_seek(priv->cdp, priv->start_sector, SEEK_SET);
    priv->sector = priv->start_sector;

    st->priv = priv;
    st->start_pos = priv->start_sector * CDIO_CD_FRAMESIZE_RAW;
    st->end_pos = (priv->end_sector + 1) * CDIO_CD_FRAMESIZE_RAW;
    st->sector_size = CDIO_CD_FRAMESIZE_RAW;

    st->fill_buffer = fill_buffer;
    st->seek = seek;
    st->control = control;
    st->close = close_cdda;

    st->demuxer = "rawaudio";

    print_cdtext(st, 0);

    return STREAM_OK;
}
Beispiel #13
0
int CdParanoia::seek(long sector, int mode)
{
    return paranoia ? paranoia_seek(paranoia, sector, mode) : -1;
}
Beispiel #14
0
int main(int argc,char *argv[]){
  int toc_bias=0;
  int toc_offset=0;
  int sample_offset=0;
  int force_cdrom_endian=-1;
  int force_cdrom_sectors=-1;
  int force_cdrom_overlap=-1;
  char *force_cdrom_device=NULL;
  char *force_generic_device=NULL;
  char *force_cooked_device=NULL;
  int force_cdrom_speed=0;
  int max_retries=20;
  char *span=NULL;
  int output_type=1; /* 0=raw, 1=wav, 2=aifc */
  int output_endian=0; /* -1=host, 0=little, 1=big */
  int query_only=0;
  int batch=0,i;
  int run_cache_test=0;

  char *logfile_name=NULL;
  char *reportfile_name=NULL;
  int logfile_open=0;
  int reportfile_open=0;

  /* full paranoia, but allow skipping */
  int paranoia_mode=PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP; 

  char *info_file=NULL;
  int out;

  int search=0;
  int c,long_option_index;

  atexit(cleanup);

  while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){
    switch(c){
    case 'B':
      batch=1;
      break;
    case 'c':
      force_cdrom_endian=0;
      break;
    case 'C':
      force_cdrom_endian=1;
      break;
    case 'n':
      force_cdrom_sectors=atoi(optarg);
      break;
    case 'o':
      force_cdrom_overlap=atoi(optarg);
      break;
    case 'd':
      if(force_cdrom_device)free(force_cdrom_device);
      force_cdrom_device=copystring(optarg);
      break;
    case 'g':
      if(force_cooked_device){
	report("-g option incompatable with -k\n");
	exit(1);
      }
      force_cooked_device=NULL;
      if(force_generic_device)free(force_generic_device);
      force_generic_device=copystring(optarg);
      break;
    case 'k':
      if(force_generic_device || force_cdrom_device){
	report("-k option incompatable with -d and -g\n");
	exit(1);
      }
      if(force_cooked_device)free(force_cooked_device);
      force_cooked_device=copystring(optarg);
      break;
    case 'S':
      force_cdrom_speed=atoi(optarg);
      break;
    case 'p':
      output_type=0;
      output_endian=-1;
      break;
    case 'r':
      output_type=0;
      output_endian=0;
      break;
    case 'R':
      output_type=0;
      output_endian=1;
      break;
    case 'w':
      output_type=1;
      output_endian=0;
      break;
    case 'a':
      output_type=2;
      output_endian=1;
      break;
    case 'f':
      output_type=3;
      output_endian=1;
      break;
    case 'v':
      verbose=CDDA_MESSAGE_PRINTIT;
      quiet=0;
      break;
    case 's':
      search=1;
      break;
    case 'q':
      verbose=CDDA_MESSAGE_FORGETIT;
      quiet=1;
      break;
    case 'e':
      callscript=1;
      fprintf(stderr,"Sending all callbacks to stderr for wrapper script\n");
      break;
    case 'V':
      fprintf(stderr,VERSION);
      fprintf(stderr,"\n");
      exit(0);
      break;
    case 'Q':
      query_only=1;
      break;
    case 'h':
      usage(stdout);
      exit(0);
    case 'Z':
      paranoia_mode=PARANOIA_MODE_DISABLE; 
      break;
    case 'A':
      run_cache_test=1;
      query_only=1;
      reportfile_open=1;
      verbose=CDDA_MESSAGE_PRINTIT;
      break;
    case 'z':
      if (optarg) {
        max_retries = atoi (optarg);
        paranoia_mode&=~PARANOIA_MODE_NEVERSKIP;
      } else {
        paranoia_mode|=PARANOIA_MODE_NEVERSKIP;
      }
      break;
    case 'Y':
      paranoia_mode|=PARANOIA_MODE_OVERLAP; /* cdda2wav style overlap 
						check only */
      paranoia_mode&=~PARANOIA_MODE_VERIFY;
      break;
    case 'X':
      /*paranoia_mode&=~(PARANOIA_MODE_SCRATCH|PARANOIA_MODE_REPAIR);*/
      abort_on_skip=1;
      break;
    case 'W':
      paranoia_mode&=~PARANOIA_MODE_REPAIR;
      break;
    case 'F':
      paranoia_mode&=~(PARANOIA_MODE_FRAGMENT);
      break;
    case 'i':
      if(info_file)free(info_file);
      info_file=copystring(info_file);
      break;
    case 'T':
      toc_bias=-1;
      break;
    case 't':
      toc_offset=atoi(optarg);
      break;
    case 'l':
      if(logfile_name)free(logfile_name);
      logfile_name=NULL;
      if(optarg)
	logfile_name=strdup(optarg);
      logfile_open=1;
      break;
    case 'L':
      if(reportfile_name)free(reportfile_name);
      reportfile_name=NULL;
      if(optarg)
	reportfile_name=strdup(optarg);
      reportfile_open=1;
      break;
    case 'O':
      sample_offset=atoi(optarg);
      break;
    default:
      usage(stderr);
      exit(1);
    }
  }

  if(logfile_open){
    if(logfile_name==NULL)
      logfile_name=strdup("cdparanoia.log");
    if(!strcmp(logfile_name,"-")){
      logfile=stdout;
      logfile_open=0;
    }else{
      logfile=fopen(logfile_name,"w");
      if(logfile==NULL){
	report("Cannot open log summary file %s: %s",logfile_name,
	       strerror(errno));
	exit(1);
      }
    }
  }
  if(reportfile_open){
    if(reportfile_name==NULL)
      reportfile_name=strdup("cdparanoia.log");
    if(!strcmp(reportfile_name,"-")){
      reportfile=stdout;
      reportfile_open=0;
    }else{
      if(logfile_name && !strcmp(reportfile_name,logfile_name)){
	reportfile=logfile;
	reportfile_open=0;
      }else{
	reportfile=fopen(reportfile_name,"w");
	if(reportfile==NULL){
	  report("Cannot open debug log file %s: %s",reportfile_name,
		 strerror(errno));
	  exit(1);
	}
      }
    }
  }
    
  if(logfile){
    /* log command line and version */
    int i;
    for (i = 0; i < argc; i++) 
      fprintf(logfile,"%s ",argv[i]);
    fprintf(logfile,"\n");

    if(reportfile!=logfile){
      fprintf(logfile,VERSION);
      fprintf(logfile,"\n");
      fprintf(logfile,"Using cdda library version: %s\n",cdda_version());
      fprintf(logfile,"Using paranoia library version: %s\n",paranoia_version());
    }
    fflush(logfile);
  }

  if(reportfile && reportfile!=logfile){
    /* log command line */
    int i;
    for (i = 0; i < argc; i++) 
      fprintf(reportfile,"%s ",argv[i]);
    fprintf(reportfile,"\n");
    fflush(reportfile);
  }

  if(optind>=argc && !query_only){
    if(batch)
      span=NULL;
    else{
      /* D'oh.  No span. Fetch me a brain, Igor. */
      usage(stderr);
      exit(1);
    }
  }else
    span=copystring(argv[optind]);

  report(VERSION);
  if(verbose){
    report("Using cdda library version: %s",cdda_version());
    report("Using paranoia library version: %s",paranoia_version());
  }

  /* Query the cdrom/disc; we may need to override some settings */

  if(force_cooked_device){
    d=cdda_identify_cooked(force_cooked_device,verbose,NULL);
  }else if(force_generic_device)
    d=cdda_identify_scsi(force_generic_device,force_cdrom_device,verbose,NULL);
  else
    if(force_cdrom_device)
      d=cdda_identify(force_cdrom_device,verbose,NULL);
    else
      if(search)
	d=cdda_find_a_cdrom(verbose,NULL);
      else{
	/* does the /dev/cdrom link exist? */
	struct stat s;
	if(lstat("/dev/cdrom",&s)){
	  /* no link.  Search anyway */
	  d=cdda_find_a_cdrom(verbose,NULL);
	}else{
	  d=cdda_identify("/dev/cdrom",verbose,NULL);
	  if(d==NULL  && !verbose){
	    verbose=1;
	    report("\n/dev/cdrom exists but isn't accessible.  By default,\n"
		   "cdparanoia stops searching for an accessible drive here.\n"
		   "Consider using -sv to force a more complete autosense\n"
		   "of the machine.\n\nMore information about /dev/cdrom:");

	    d=cdda_identify("/dev/cdrom",CDDA_MESSAGE_PRINTIT,NULL);
	    report("\n");
	    exit(1);
	  }else
	    report(" ");
	}
      }

  if(!d){
    if(!verbose)
      report("\nUnable to open cdrom drive; -v will give more information.");
    exit(1);
  }
  
  if(verbose)
    cdda_verbose_set(d,CDDA_MESSAGE_PRINTIT,CDDA_MESSAGE_PRINTIT);
  else
    cdda_verbose_set(d,CDDA_MESSAGE_PRINTIT,CDDA_MESSAGE_FORGETIT);

  /* possibly force hand on endianness of drive, sector request size */
  if(force_cdrom_endian!=-1){
    d->bigendianp=force_cdrom_endian;
    switch(force_cdrom_endian){
    case 0:
      report("Forcing CDROM sense to little-endian; ignoring preset and autosense");
      break;
    case 1:
      report("Forcing CDROM sense to big-endian; ignoring preset and autosense");
      break;
    }
  }
  if(force_cdrom_sectors!=-1){
    if(force_cdrom_sectors<0 || force_cdrom_sectors>100){
      report("Default sector read size must be 1<= n <= 100\n");
      cdda_close(d);
      d=NULL;
      exit(1);
    }
    report("Forcing default to read %d sectors; "
	   "ignoring preset and autosense",force_cdrom_sectors);
    d->nsectors=force_cdrom_sectors;
    d->bigbuff=force_cdrom_sectors*CD_FRAMESIZE_RAW;
  }
  if(force_cdrom_overlap!=-1){
    if(force_cdrom_overlap<0 || force_cdrom_overlap>75){
      report("Search overlap sectors must be 0<= n <=75\n");
      cdda_close(d);
      d=NULL;
      exit(1);
    }
    report("Forcing search overlap to %d sectors; "
	   "ignoring autosense",force_cdrom_overlap);
  }

  switch(cdda_open(d)){
  case -2:case -3:case -4:case -5:
    report("\nUnable to open disc.  Is there an audio CD in the drive?");
    exit(1);
  case -6:
    report("\ncdparanoia could not find a way to read audio from this drive.");
    exit(1);
  case 0:
    break;
  default:
    report("\nUnable to open disc.");
    exit(1);
  }

  if(force_cdrom_speed==0)force_cdrom_speed=-1;
  if(force_cdrom_speed!=-1){
    report("\nAttempting to set speed to %dx... ",force_cdrom_speed);
  }else{
    if(verbose)
      report("\nAttempting to set cdrom to full speed... ");
  }

  if(cdda_speed_set(d,force_cdrom_speed)){
    if(verbose || force_cdrom_speed!=-1)
      report("\tCDROM speed set FAILED. Continuing anyway...");
  }else{
    if(verbose)
      report("\tdrive returned OK.");
  }
  
  if(run_cache_test){
    int warn=analyze_cache(d, stderr, reportfile, force_cdrom_speed);
    
    if(warn==0){
      reportC("\nDrive tests OK with Paranoia.\n\n");
      return 0;
    }

    if(warn==1)
      reportC("\nWARNING! PARANOIA MAY NOT BE TRUSTWORTHY WITH THIS DRIVE!\n"
	      "\nThe Paranoia library may not model this CDROM drive's cache"
	      "\ncorrectly according to this analysis run. Analysis is not"
	      "\nalways accurate (it can be fooled by machine load or random"
	      "\nkernel latencies), but if a failed result happens more often"
	      "\nthan one time in twenty on an unloaded machine, please mail"
	      "\nthe %s file produced by this failed analysis to"
	      "\[email protected] to assist developers in extending"
	      "\nParanoia to handle this CDROM properly.\n\n",reportfile_name);
    return 1;
  }


  /* Dump the TOC */
  if(query_only || verbose)display_toc(d);
  if(query_only)exit(0);

  /* bias the disc.  A hack.  Of course. */
  /* we may need to read before or past user area; this is never
     default, and we do it because the [allegedly informed] user told
     us to */
  if(sample_offset){
    toc_offset+=sample_offset/588;
    sample_offset%=588;
    if(sample_offset<0){
      sample_offset+=588;
      toc_offset--;
    }
  }

  if(toc_bias){
    toc_offset=-cdda_track_firstsector(d,1);
  }
  for(i=0;i<d->tracks+1;i++)
    d->disc_toc[i].dwStartSector+=toc_offset;


  if(d->nsectors==1){
    report("WARNING: The autosensed/selected sectors per read value is\n"
	   "         one sector, making it very unlikely Paranoia can \n"
	   "         work.\n\n"
	   "         Attempting to continue...\n\n");
  }

  /* parse the span, set up begin and end sectors */

  {
    long first_sector;
    long last_sector;
    long batch_first;
    long batch_last;
    int batch_track;

    if(span){
      /* look for the hyphen */ 
      char *span2=strchr(span,'-');
      if(strrchr(span,'-')!=span2){
	report("Error parsing span argument");
	cdda_close(d);
	d=NULL;
	exit(1);
      }
      
      if(span2!=NULL){
	*span2='\0';
	span2++;
      }
      
      first_sector=parse_offset(d,span,-1);
      if(first_sector==-1)
	last_sector=parse_offset(d,span2,cdda_disc_firstsector(d));
      else
	last_sector=parse_offset(d,span2,first_sector);
      
      if(first_sector==-1){
	if(last_sector==-1){
	  report("Error parsing span argument");
	  cdda_close(d);
	  d=NULL;
	  exit(1);
	}else{
	  first_sector=cdda_disc_firstsector(d);
	}
      }else{
	if(last_sector==-1){
	  if(span2){ /* There was a hyphen */
	    last_sector=cdda_disc_lastsector(d);
	  }else{
	    last_sector=
	      cdda_track_lastsector(d,cdda_sector_gettrack(d,first_sector));
	  }
	}
      }
    }else{
      first_sector=cdda_disc_firstsector(d);
      last_sector=cdda_disc_lastsector(d);
    }

    {
      int track1=cdda_sector_gettrack(d,first_sector);
      int track2=cdda_sector_gettrack(d,last_sector);
      long off1=first_sector-cdda_track_firstsector(d,track1);
      long off2=last_sector-cdda_track_firstsector(d,track2);
      int i;

      for(i=track1;i<=track2;i++)
	if(!cdda_track_audiop(d,i)){
	  report("Selected span contains non audio tracks.  Aborting.\n\n");
	  exit(1);
	}

      report("Ripping from sector %7ld (track %2d [%d:%02d.%02d])\n"
	     "\t  to sector %7ld (track %2d [%d:%02d.%02d])\n",first_sector,
	     track1,(int)(off1/(60*75)),(int)((off1/75)%60),(int)(off1%75),
	     last_sector,
	     track2,(int)(off2/(60*75)),(int)((off2/75)%60),(int)(off2%75));
      
    }

    {
      long cursor;
      int16_t offset_buffer[1176];
      int offset_buffer_used=0;
      int offset_skip=sample_offset*4;

      p=paranoia_init(d);
      paranoia_modeset(p,paranoia_mode);
      if(force_cdrom_overlap!=-1)paranoia_overlapset(p,force_cdrom_overlap);

      if(verbose)
        cdda_verbose_set(d,CDDA_MESSAGE_LOGIT,CDDA_MESSAGE_LOGIT);
      else
        cdda_verbose_set(d,CDDA_MESSAGE_FORGETIT,CDDA_MESSAGE_FORGETIT);

      paranoia_seek(p,cursor=first_sector,SEEK_SET);      

      /* this is probably a good idea in general */
      seteuid(getuid());
      setegid(getgid());

      /* we'll need to be able to read one sector past user data if we
	 have a sample offset in order to pick up the last bytes.  We
	 need to set the disc length forward here so that the libs are
	 willing to read past, assuming that works on the hardware, of
	 course */
      if(sample_offset)
	d->disc_toc[d->tracks].dwStartSector++;

      while(cursor<=last_sector){
	char outfile_name[256];
	if(batch){
	  batch_first=cursor;
	  batch_last=
	    cdda_track_lastsector(d,batch_track=
				  cdda_sector_gettrack(d,cursor));
	  if(batch_last>last_sector)batch_last=last_sector;
	}else{
	  batch_first=first_sector;
	  batch_last=last_sector;
	  batch_track=-1;
	}
	
	callbegin=batch_first;
	callend=batch_last;
	
	/* argv[optind] is the span, argv[optind+1] (if exists) is outfile */
	
	if(optind+1<argc){
	  if(!strcmp(argv[optind+1],"-")){
	    out=dup(fileno(stdout));
	    if(batch)report("Are you sure you wanted 'batch' "
			    "(-B) output with stdout?");
	    report("outputting to stdout\n");
	    if(logfile){
	      fprintf(logfile,"outputting to stdout\n");
	      fflush(logfile);
	    }
	    outfile_name[0]='\0';
	  }else{
	    char path[256];

	    char *post=strrchr(argv[optind+1],'/');
	    int pos=(post?post-argv[optind+1]+1:0);
	    char *file=argv[optind+1]+pos;
	    
	    path[0]='\0';

	    if(pos)
	      strncat(path,argv[optind+1],pos>256?256:pos);

	    if(batch)
	      snprintf(outfile_name,246,"%strack%02d.%s",path,batch_track,file);
	    else
	      snprintf(outfile_name,246,"%s%s",path,file);

	    if(file[0]=='\0'){
	      switch(output_type){
	      case 0: /* raw */
		strcat(outfile_name,"cdda.raw");
		break;
	      case 1:
		strcat(outfile_name,"cdda.wav");
		break;
	      case 2:
		strcat(outfile_name,"cdda.aifc");
		break;
	      case 3:
		strcat(outfile_name,"cdda.aiff");
		break;
	      }
	    }
	    
	    out=open(outfile_name,O_RDWR|O_CREAT|O_TRUNC,0666);
	    if(out==-1){
	      report("Cannot open specified output file %s: %s",outfile_name,
		      strerror(errno));
	      cdda_close(d);
	      d=NULL;
	      exit(1);
	    }
	    report("outputting to %s\n",outfile_name);
	    if(logfile){
	      fprintf(logfile,"outputting to %s\n",outfile_name);
	      fflush(logfile);
	    }
	  }
	}else{
	  /* default */
	  if(batch)
	    sprintf(outfile_name,"track%02d.",batch_track);
	  else
	    outfile_name[0]='\0';
	  
	  switch(output_type){
	  case 0: /* raw */
	    strcat(outfile_name,"cdda.raw");
	    break;
	  case 1:
	    strcat(outfile_name,"cdda.wav");
	    break;
	  case 2:
	    strcat(outfile_name,"cdda.aifc");
	    break;
	  case 3:
	    strcat(outfile_name,"cdda.aiff");
	    break;
	  }
	  
	  out=open(outfile_name,O_RDWR|O_CREAT|O_TRUNC,0666);
	  if(out==-1){
	    report("Cannot open default output file %s: %s",outfile_name,
		    strerror(errno));
	    cdda_close(d);
	    d=NULL;
	    exit(1);
	  }
	  report("outputting to %s\n",outfile_name);
	  if(logfile){
	    fprintf(logfile,"outputting to %s\n",outfile_name);
	    fflush(logfile);
	  }
	}
	
	switch(output_type){
	case 0: /* raw */
	  break;
	case 1: /* wav */
	  WriteWav(out,(batch_last-batch_first+1)*CD_FRAMESIZE_RAW);
	  break;
	case 2: /* aifc */
	  WriteAifc(out,(batch_last-batch_first+1)*CD_FRAMESIZE_RAW);
	  break;
	case 3: /* aiff */
	  WriteAiff(out,(batch_last-batch_first+1)*CD_FRAMESIZE_RAW);
	  break;
	}
	
	/* Off we go! */

	if(offset_buffer_used){
	  /* partial sector from previous batch read */
	  cursor++;
	  if(buffering_write(out,
			     ((char *)offset_buffer)+offset_buffer_used,
			     CD_FRAMESIZE_RAW-offset_buffer_used)){
	    report("Error writing output: %s",strerror(errno));
	    exit(1);
	  }
	}
	
	skipped_flag=0;
	while(cursor<=batch_last){
	  /* read a sector */
	  int16_t *readbuf=paranoia_read_limited(p,callback,max_retries);
	  char *err=cdda_errors(d);
	  char *mes=cdda_messages(d);

	  if(mes || err)
	    fprintf(stderr,"\r                               "
		    "                                           \r%s%s\n",
		    mes?mes:"",err?err:"");
	  
	  if(err)free(err);
	  if(mes)free(mes);
	  if(readbuf==NULL){
	    if(errno==EBADF || errno==ENOMEDIUM){
	      report("\nparanoia_read: CDROM drive unavailable, bailing.\n");
	      exit(1);
	    }
	    skipped_flag=1;
	    report("\nparanoia_read: Unrecoverable error, bailing.\n");
	    break;
	  }
	  if(skipped_flag && abort_on_skip){
	    cursor=batch_last+1;
	    break;
	  }

	  skipped_flag=0;
	  cursor++;
	  
	  if(output_endian!=bigendianp()){
	    int i;
	    for(i=0;i<CD_FRAMESIZE_RAW/2;i++)readbuf[i]=swap16(readbuf[i]);
	  }
	  
	  callback(cursor*(CD_FRAMEWORDS)-1,-2);

	  if(buffering_write(out,((char *)readbuf)+offset_skip,
			     CD_FRAMESIZE_RAW-offset_skip)){
	    report("Error writing output: %s",strerror(errno));
	    exit(1);
	  }
	  offset_skip=0;
	  
	  if(output_endian!=bigendianp()){
	    int i;
	    for(i=0;i<CD_FRAMESIZE_RAW/2;i++)readbuf[i]=swap16(readbuf[i]);
	  }

	  /* One last bit of silliness to deal with sample offsets */
	  if(sample_offset && cursor>batch_last){
	    int i;
	    /* read a sector and output the partial offset.  Save the
               rest for the next batch iteration */
	    readbuf=paranoia_read_limited(p,callback,max_retries);
	    err=cdda_errors(d);mes=cdda_messages(d);

	    if(mes || err)
	      fprintf(stderr,"\r                               "
		      "                                           \r%s%s\n",
		      mes?mes:"",err?err:"");
	  
	    if(err)free(err);if(mes)free(mes);
	    if(readbuf==NULL){
	      skipped_flag=1;
	      report("\nparanoia_read: Unrecoverable error reading through "
		     "sample_offset shift\n\tat end of track, bailing.\n");
	      break;
	    }
	    if(skipped_flag && abort_on_skip)break;
	    skipped_flag=0;
	    /* do not move the cursor */
	  
	    if(output_endian!=bigendianp())
	      for(i=0;i<CD_FRAMESIZE_RAW/2;i++)
		offset_buffer[i]=swap16(readbuf[i]);
	    else
	      memcpy(offset_buffer,readbuf,CD_FRAMESIZE_RAW);
	    offset_buffer_used=sample_offset*4;
	  
	    callback(cursor*(CD_FRAMEWORDS),-2);

	    if(buffering_write(out,(char *)offset_buffer,
			       offset_buffer_used)){
	      report("Error writing output: %s",strerror(errno));
	      exit(1);
	    }
	  }
	}
	callback(cursor*(CD_FRAMESIZE_RAW/2)-1,-1);
	buffering_close(out);
	if(skipped_flag){
	  /* remove the file */
	  report("\nRemoving aborted file: %s",outfile_name);
	  unlink(outfile_name);
	  /* make the cursor correct if we have another track */
	  if(batch_track!=-1){
	    batch_track++;
	    cursor=cdda_track_firstsector(d,batch_track);
	    paranoia_seek(p,cursor,SEEK_SET);      
	    offset_skip=sample_offset*4;
	    offset_buffer_used=0;
	  }
	}
	report("\n");
      }

      paranoia_free(p);
      p=NULL;
    }
  }

  report("Done.\n\n");
  
  cdda_close(d);
  d=NULL;
  if(logfile_open)
    fclose(logfile);
  if(reportfile_open)
    fclose(reportfile);
  return 0;
}
Beispiel #15
0
static int open_cdda(stream_t *st,int m, void* opts, int* file_format) {
  struct cdda_params* p = (struct cdda_params*)opts;
  int mode = p->paranoia_mode;
  int offset = p->toc_offset;
#ifndef HAVE_LIBCDIO
  cdrom_drive* cdd = NULL;
#else
  cdrom_drive_t* cdd = NULL;
#endif
  cdda_priv* priv;
  cd_info_t *cd_info,*cddb_info = NULL;
  unsigned int audiolen=0;
  int last_track;
  int i;
  char *xmcd_file = NULL;

  if(m != STREAM_READ) {
    m_struct_free(&stream_opts,opts);
    return STREAM_UNSUPORTED;
  }

  if(!p->device) {
    if (cdrom_device)
      p->device = strdup(cdrom_device);
    else
      p->device = strdup(DEFAULT_CDROM_DEVICE);
  }

#ifdef HAVE_CDDB
  // cdd_identify returns -1 if it cannot read the TOC,
  // in which case there is no point in calling cddb_resolve
  if(cdd_identify(p->device) >= 0 && strncmp(st->url,"cddb",4) == 0) {
    i = cddb_resolve(p->device, &xmcd_file);
    if(i == 0) {
      cddb_info = cddb_parse_xmcd(xmcd_file);
      free(xmcd_file);
    }
  }
#endif
  
#ifndef HAVE_LIBCDIO
  if(p->generic_dev)
    cdd = cdda_identify_scsi(p->generic_dev,p->device,0,NULL);
  else
#endif
#if defined(__NetBSD__)
    cdd = cdda_identify_scsi(p->device,p->device,0,NULL);
#else
    cdd = cdda_identify(p->device,0,NULL);
#endif

  if(!cdd) {
    mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_MPDEMUX_CDDA_CantOpenCDDADevice);
    m_struct_free(&stream_opts,opts);
    free(cddb_info);
    return STREAM_ERROR;
  }

  cdda_verbose_set(cdd, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT);

  if(p->sector_size) {
    cdd->nsectors = p->sector_size;
#ifndef HAVE_LIBCDIO
    cdd->bigbuff = p->sector_size * CD_FRAMESIZE_RAW;
#endif
  }

  if(cdda_open(cdd) != 0) {
    mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_MPDEMUX_CDDA_CantOpenDisc);
    cdda_close(cdd);
    m_struct_free(&stream_opts,opts);
    free(cddb_info);
    return STREAM_ERROR;
  }

  cd_info = cd_info_new();
  mp_msg(MSGT_OPEN,MSGL_INFO,MSGTR_MPDEMUX_CDDA_AudioCDFoundWithNTracks,cdda_tracks(cdd));
  for(i=0;i<cdd->tracks;i++) {
	  char track_name[80];
	  long sec=cdda_track_firstsector(cdd,i+1);
	  long off=cdda_track_lastsector(cdd,i+1)-sec+1;

	  sprintf(track_name, "Track %d", i+1);
	  cd_info_add_track(cd_info, track_name, i+1, (unsigned int)(off/(60*75)), (unsigned int)((off/75)%60), (unsigned int)(off%75), sec, off );
	  audiolen += off;
  }
  cd_info->min  = (unsigned int)(audiolen/(60*75));
  cd_info->sec  = (unsigned int)((audiolen/75)%60);
  cd_info->msec = (unsigned int)(audiolen%75);

  priv = malloc(sizeof(cdda_priv));
  memset(priv, 0, sizeof(cdda_priv));
  priv->cd = cdd;
  priv->cd_info = cd_info;

  if(p->toc_bias)
    offset -= cdda_track_firstsector(cdd,1);

  if(offset) {
    int i;
    for(i = 0 ; i < cdd->tracks + 1 ; i++)
      cdd->disc_toc[i].dwStartSector += offset;
  }

  if(p->speed)
    cdda_speed_set(cdd,p->speed);

  last_track = cdda_tracks(cdd);
  if (p->span.start > last_track) p->span.start = last_track;
  if (p->span.end < p->span.start) p->span.end = p->span.start;
  if (p->span.end > last_track) p->span.end = last_track;
  if(p->span.start)
    priv->start_sector = cdda_track_firstsector(cdd,p->span.start);
  else
    priv->start_sector = cdda_disc_firstsector(cdd);

  if(p->span.end) {
    priv->end_sector = cdda_track_lastsector(cdd,p->span.end);
  } else
    priv->end_sector = cdda_disc_lastsector(cdd);

  priv->cdp = paranoia_init(cdd);
  if(priv->cdp == NULL) {
    cdda_close(cdd);
    free(priv);
    cd_info_free(cd_info);
    m_struct_free(&stream_opts,opts);
    free(cddb_info);
    return STREAM_ERROR;
  }

  if(mode == 0)
    mode = PARANOIA_MODE_DISABLE;
  else if(mode == 1)
    mode = PARANOIA_MODE_OVERLAP;
  else
    mode = PARANOIA_MODE_FULL;
  
  if(p->no_skip)
    mode |= PARANOIA_MODE_NEVERSKIP;
#ifndef HAVE_LIBCDIO
  paranoia_modeset(cdd, mode);

  if(p->search_overlap >= 0)
    paranoia_overlapset(cdd,p->search_overlap);
#else
  paranoia_modeset(priv->cdp, mode);

  if(p->search_overlap >= 0)
    paranoia_overlapset(priv->cdp,p->search_overlap);
#endif

  paranoia_seek(priv->cdp,priv->start_sector,SEEK_SET);
  priv->sector = priv->start_sector;

#ifdef HAVE_CDDB
  if(cddb_info) {
    cd_info_free(cd_info);
    priv->cd_info = cddb_info;
    cd_info_debug( cddb_info );
  }
#endif

  st->priv = priv;
  st->start_pos = priv->start_sector*CD_FRAMESIZE_RAW;
  st->end_pos = priv->end_sector*CD_FRAMESIZE_RAW;
  st->type = STREAMTYPE_CDDA;
  st->sector_size = CD_FRAMESIZE_RAW;

  st->fill_buffer = fill_buffer;
  st->seek = seek;
  st->close = close_cdda;

  *file_format = DEMUXER_TYPE_RAWAUDIO;

  m_struct_free(&stream_opts,opts);

  return STREAM_OK;
}
int
main(int argc,char *argv[])
{
  int   toc_bias             =  0;
  int   force_cdrom_endian   = -1;
  int   output_type          =  1; /* 0=raw, 1=wav, 2=aifc */
  int   output_endian        =  0; /* -1=host, 0=little, 1=big */
  int   query_only           =  0;
  int   batch                =  0;
  int   run_cache_test       =  0;
  long int force_cdrom_overlap  = -1;
  long int force_cdrom_sectors  = -1;
  long int force_cdrom_speed    =  0;
  long int force_overread       =  0;
  long int sample_offset        =  0;
  long int test_flags           =  0;
  long int toc_offset           =  0;
  long int max_retries          = 20;

  char *logfile_name=NULL;
  char *reportfile_name=NULL;

  /* full paranoia, but allow skipping */
  int paranoia_mode=PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP;

  int out;

  int c,long_option_index;

  atexit(cleanup);

  while((c=getopt_long(argc,argv,optstring,options,&long_option_index))!=EOF){
    switch(c){
    case 'a':
      output_type=2;
      output_endian=1;
      break;
    case 'B':
      batch=1;
      break;
    case 'c':
      force_cdrom_endian=0;
      break;
    case 'C':
      force_cdrom_endian=1;
      break;
    case 'e':
      callscript=1;
      fprintf(stderr,
              "Sending all callback output to stderr for wrapper script\n");
      break;
    case 'f':
      output_type=3;
      output_endian=1;
      break;
    case 'F':
      paranoia_mode&=~(PARANOIA_MODE_FRAGMENT);
      break;
    case 'g':
    case 'k':
    case 'd':
      if (force_cdrom_device) {
        fprintf(stderr,
                "Multiple cdrom devices given. Previous device %s ignored\n",
                force_cdrom_device);
        free(force_cdrom_device);
      }
      force_cdrom_device=strdup(optarg);
      break;
    case 'h':
      usage(stdout);
      exit(0);
    case 'l':
      if(logfile_name)free(logfile_name);
      logfile_name=NULL;
      if(optarg)
	logfile_name=strdup(optarg);
      logfile_open=1;
      break;
    case 'L':
      if(reportfile_name)free(reportfile_name);
      reportfile_name=NULL;
      if(optarg)
	reportfile_name=strdup(optarg);
      reportfile_open=1;
      break;
    case 'm':
      {
        long int mmc_timeout_sec;
        if (get_int_arg(c, &mmc_timeout_sec)) {
          mmc_timeout_ms = 1000*mmc_timeout_sec;
        }
      }
      break;
    case 'n':
      get_int_arg(c, &force_cdrom_sectors);
      break;
    case 'o':
      get_int_arg(c, &force_cdrom_overlap);
      break;
    case 'O':
      get_int_arg(c, &sample_offset);
      break;
    case 'p':
      output_type=0;
      output_endian=-1;
      break;
    case 'r':
      output_type=0;
      output_endian=0;
      break;
    case 'q':
      verbose=CDDA_MESSAGE_FORGETIT;
      quiet=1;
      break;
    case 'Q':
      query_only=1;
      break;
    case 'R':
      output_type=0;
      output_endian=1;
      break;
    case 'S':
      get_int_arg(c, &force_cdrom_speed);
      break;
    case 't':
      get_int_arg(c, &toc_offset);
      break;
    case 'T':
      toc_bias=-1;
      break;
    case 'v':
      verbose=CDDA_MESSAGE_PRINTIT;
      quiet=0;
      break;
    case 'V':
      fprintf(stderr,PARANOIA_VERSION);
      fprintf(stderr,"\n");
      exit(0);
      break;
    case 'w':
      output_type=1;
      output_endian=0;
      break;
    case 'W':
      paranoia_mode&=~PARANOIA_MODE_REPAIR;
      break;
    case 'x':
      get_int_arg(c, &test_flags);
      break;
    case 'X':
      /*paranoia_mode&=~(PARANOIA_MODE_SCRATCH|PARANOIA_MODE_REPAIR);*/
      abort_on_skip=1;
      break;
    case 'Y':
      paranoia_mode|=PARANOIA_MODE_OVERLAP; /* cdda2wav style overlap
                                                check only */
      paranoia_mode&=~PARANOIA_MODE_VERIFY;
      break;
    case 'Z':
      paranoia_mode=PARANOIA_MODE_DISABLE;
      break;
    case 'A':
      run_cache_test=1;
      query_only=1;
      reportfile_open=1;
      verbose=CDDA_MESSAGE_PRINTIT;
      break;
    case 'z':
      if (optarg) {
        get_int_arg(c, &max_retries);
        paranoia_mode&=~PARANOIA_MODE_NEVERSKIP;
      } else {
        paranoia_mode|=PARANOIA_MODE_NEVERSKIP;
      }
      break;
    case 'E':
      force_overread=1;
      break;
    default:
      usage(stderr);
      exit(1);
    }
  }

  if(logfile_open){
    if(logfile_name==NULL)
      logfile_name=strdup("cdparanoia.log");
    if(!strcmp(logfile_name,"-")){
      logfile=stdout;
      logfile_open=0;
    }else{
      logfile=fopen(logfile_name,"w");
      if(logfile==NULL){
	report("Cannot open log summary file %s: %s",logfile_name,
	       strerror(errno));
	exit(1);
      }
    }
  }
  if(reportfile_open){
    if(reportfile_name==NULL)
      reportfile_name=strdup("cdparanoia.log");
    if(!strcmp(reportfile_name,"-")){
      reportfile=stdout;
      reportfile_open=0;
    }else{
      if(logfile_name && !strcmp(reportfile_name,logfile_name)){
	reportfile=logfile;
	reportfile_open=0;
      }else{
	reportfile=fopen(reportfile_name,"w");
	if(reportfile==NULL){
	  report("Cannot open debug log file %s: %s",reportfile_name,
		 strerror(errno));
	  exit(1);
	}
      }
    }
  }

  if(logfile){
    /* log command line and version */
    int i;
    for (i = 0; i < argc; i++)
      fprintf(logfile,"%s ",argv[i]);
    fprintf(logfile,"\n");

    if(reportfile!=logfile){
      fprintf(logfile,VERSION);
      fprintf(logfile,"\n");
      fprintf(logfile,"Using cdda library version: %s\n",cdda_version());
      fprintf(logfile,"Using paranoia library version: %s\n",paranoia_version());
    }
    fflush(logfile);
  }

  if(reportfile && reportfile!=logfile){
    /* log command line */
    int i;
    for (i = 0; i < argc; i++)
      fprintf(reportfile,"%s ",argv[i]);
    fprintf(reportfile,"\n");
    fflush(reportfile);
  }

  if(optind>=argc && !query_only){
    if(batch)
      span=NULL;
    else{
      /* D'oh.  No span. Fetch me a brain, Igor. */
      usage(stderr);
      exit(1);
    }
  }else
    if (argv[optind]) span=strdup(argv[optind]);

  report(PARANOIA_VERSION);
  if(verbose){
    report("Using cdda library version: %s",cdda_version());
    report("Using paranoia library version: %s",paranoia_version());
  }

  /* Query the cdrom/disc; we may need to override some settings */

  if(force_cdrom_device)
    d=cdda_identify(force_cdrom_device,verbose,NULL);
  else {
    driver_id_t driver_id;
    char **ppsz_cd_drives = cdio_get_devices_with_cap_ret(NULL,
                                                          CDIO_FS_AUDIO,
                                                          false,
                                                          &driver_id);
    if (ppsz_cd_drives && *ppsz_cd_drives) {
      d=cdda_identify(*ppsz_cd_drives,verbose, NULL);
    } else {
      report("\nUnable find or access a CD-ROM drive with an audio CD"
             " in it.");
      report("\nYou might try specifying the drive, especially if it has"
             " mixed-mode (and non-audio) format tracks");
      exit(1);
    }

    cdio_free_device_list(ppsz_cd_drives);
  }

  if(!d){
    if(!verbose)
      report("\nUnable to open cdrom drive; -v might give more information.");
    exit(1);
  }

  if(verbose)
    cdda_verbose_set(d,CDDA_MESSAGE_PRINTIT,CDDA_MESSAGE_PRINTIT);
  else
    cdda_verbose_set(d,CDDA_MESSAGE_PRINTIT,CDDA_MESSAGE_FORGETIT);

  /* possibly force hand on endianness of drive, sector request size */
  if(force_cdrom_endian!=-1){
    d->bigendianp=force_cdrom_endian;
    switch(force_cdrom_endian){
    case 0:
      report("Forcing CDROM sense to little-endian; ignoring preset and autosense");
      break;
    case 1:
      report("Forcing CDROM sense to big-endian; ignoring preset and autosense");
      break;
    }
  }
  if (force_cdrom_sectors!=-1) {
    if(force_cdrom_sectors<0 || force_cdrom_sectors>100){
      report("Default sector read size must be 1<= n <= 100\n");
      cdda_close(d);
      d=NULL;
      exit(1);
    }
    report("Forcing default to read %ld sectors; "
	   "ignoring preset and autosense",force_cdrom_sectors);
    d->nsectors=force_cdrom_sectors;
  }
  if (force_cdrom_overlap!=-1) {
    if (force_cdrom_overlap<0 || force_cdrom_overlap>CDIO_CD_FRAMES_PER_SEC) {
      report("Search overlap sectors must be 0<= n <=75\n");
      cdda_close(d);
      d=NULL;
      if(logfile && logfile != stdout)
        fclose(logfile);
      exit(1);
    }
    report("Forcing search overlap to %ld sectors; "
	   "ignoring autosense",force_cdrom_overlap);
  }

  switch( cdda_open(d) ) {
  case -2:case -3:case -4:case -5:
    report("\nUnable to open disc.  Is there an audio CD in the drive?");
    exit(1);
  case -6:
    report("\nCdparanoia could not find a way to read audio from this drive.");
    exit(1);
  case 0:
    break;
  default:
    report("\nUnable to open disc.");
    exit(1);
  }

  d->i_test_flags = test_flags;

  if (force_cdrom_speed == 0) force_cdrom_speed = -1;

  if (force_cdrom_speed != -1) {
    report("\nAttempting to set speed to %ldx... ", force_cdrom_speed);
  } else {
    if (verbose)
      report("\nAttempting to set cdrom to full speed... ");
  }

  if (cdda_speed_set(d, force_cdrom_speed)) {
    if (verbose || force_cdrom_speed != -1)
      report("\tCDROM speed set FAILED. Continuing anyway...");
  } else {
    if (verbose)
      report("\tdrive returned OK.");
  }

  if(run_cache_test){
    int warn=analyze_cache(d, stderr, reportfile, force_cdrom_speed);

    if(warn==0){
      reportC("\nDrive tests OK with Paranoia.\n\n");
      return 0;
    }

    if(warn==1)
      reportC("\nWARNING! PARANOIA MAY NOT BE TRUSTWORTHY WITH THIS DRIVE!\n"
	      "\nThe Paranoia library may not model this CDROM drive's cache"
	      "\ncorrectly according to this analysis run. Analysis is not"
	      "\nalways accurate (it can be fooled by machine load or random"
	      "\nkernel latencies), but if a failed result happens more often"
	      "\nthan one time in twenty on an unloaded machine, please mail"
	      "\nthe %s file produced by this failed analysis to"
	      "\[email protected] to assist developers in extending"
	      "\nParanoia to handle this CDROM properly.\n\n",reportfile_name);
    return 1;
  }


  /* Dump the TOC */
  if (query_only || verbose ) display_toc(d);

  if (query_only) exit(0);

  /* bias the disc.  A hack.  Of course. this is never the default. */
  /*
     Some CD-ROM/CD-R drives will add an offset to the position on
     reading audio data. This is usually around 500-700 audio samples
     (ca. 1/75 second) on reading. So when this program queries a
     specific sector, it might not receive exactly that sector, but
     shifted by some amount.

     Note that if ripping includes the end of the CD, this will this
     cause this program to attempt to read partial sectors before or
     past the known user data area of the disc, probably causing read
     errors on most drives and possibly even hard lockups on some
     buggy hardware.

     [Note to libcdio driver hackers: make sure all CD-drivers don't
     try to read outside of the stated disc boundaries.]
  */
  if(sample_offset){
    toc_offset+=sample_offset/588;
    sample_offset%=588;
    if(sample_offset<0){
      sample_offset+=588;
      toc_offset--;
    }
  }

  if (toc_bias) {
    toc_offset = -cdda_track_firstsector(d,1);
  }

  {
    int i;
    for( i=0; i < d->tracks+1; i++ )
      d->disc_toc[i].dwStartSector+=toc_offset;
  }

  if (d->nsectors==1) {
    report("WARNING: The autosensed/selected sectors per read value is\n"
           "         one sector, making it very unlikely Paranoia can \n"
           "         work.\n\n"
           "         Attempting to continue...\n\n");
  }

  /* parse the span, set up begin and end sectors */

  {
    long i_first_lsn;
    long i_last_lsn;
    long batch_first;
    long batch_last;
    int batch_track;

    if (span) {
      /* look for the hyphen */
      char *span2=strchr(span,'-');
      if(strrchr(span,'-')!=span2){
        report("Error parsing span argument");
        exit(1);
      }

      if (span2!=NULL) {
        *span2='\0';
        span2++;
      }

      i_first_lsn=parse_offset(d, span, -1);

      if(i_first_lsn==-1)
        i_last_lsn=parse_offset(d, span2, cdda_disc_firstsector(d));

      else
        i_last_lsn=parse_offset(d, span2, i_first_lsn);

      if (i_first_lsn == -1) {
        if (i_last_lsn == -1) {
          report("Error parsing span argument");
          exit(1);
        } else {
          i_first_lsn=cdda_disc_firstsector(d);
        }
      } else {
        if (i_last_lsn==-1) {
          if (span2) { /* There was a hyphen */
            i_last_lsn=cdda_disc_lastsector(d);
          } else {
            i_last_lsn=
              cdda_track_lastsector(d,cdda_sector_gettrack(d, i_first_lsn));
          }
        }
      }
    } else {
      i_first_lsn = cdda_disc_firstsector(d);
      i_last_lsn  = cdda_disc_lastsector(d);
    }

    {
      int track1 = cdda_sector_gettrack(d, i_first_lsn);

      int track2 = cdda_sector_gettrack(d, i_last_lsn);
      long off1  = i_first_lsn - cdda_track_firstsector(d, track1);
      long off2  = i_last_lsn  - cdda_track_firstsector(d, track2);
      int i;

      for( i=track1; i<=track2; i++ ) {
        if(i != 0 && !cdda_track_audiop(d,i)){
	  report("Selected span contains non audio track at track %02d.  Aborting.\n\n", i);
          exit(1);
          if (i == 0)
            i = cdio_get_first_track_num(d->p_cdio) - 1;
        }
      }

      report("Ripping from sector %7ld (track %2d [%d:%02d.%02d])\n"
	     "\t  to sector %7ld (track %2d [%d:%02d.%02d])\n",
	     i_first_lsn,
	     track1,
	     (int) (off1/(CDIO_CD_FRAMES_PER_MIN)),
	     (int) ((off1/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN),
	     (int)(off1 % CDIO_CD_FRAMES_PER_SEC),
	     i_last_lsn,
	     track2,
	     (int) (off2/(CDIO_CD_FRAMES_PER_MIN)),
	     (int) ((off2/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN),
	     (int)(off2 % CDIO_CD_FRAMES_PER_SEC));

    }

    if (toc_offset && !force_overread) {
	d->disc_toc[d->tracks].dwStartSector -= toc_offset;
	if (i_last_lsn > cdda_track_lastsector(d, d->tracks))
		i_last_lsn -= toc_offset;
    }
    {
      long cursor;
      int16_t offset_buffer[1176];
      int offset_buffer_used=0;
      int offset_skip=sample_offset*4;
      off_t sectorlen;

#if defined(HAVE_GETUID) && (defined(HAVE_SETEUID) || defined(HAVE_SETEGID))
      int dummy __attribute__((unused));
#endif
      p=paranoia_init(d);
      paranoia_modeset(p,paranoia_mode);
      if(force_cdrom_overlap!=-1)paranoia_overlapset(p,force_cdrom_overlap);

      if(verbose) {
        cdda_verbose_set(d,CDDA_MESSAGE_LOGIT,CDDA_MESSAGE_LOGIT);
        cdio_loglevel_default = CDIO_LOG_INFO;
      } else
        cdda_verbose_set(d,CDDA_MESSAGE_FORGETIT,CDDA_MESSAGE_FORGETIT);

      paranoia_seek(p,cursor=i_first_lsn,SEEK_SET);

      /* this is probably a good idea in general */
#if defined(HAVE_GETUID) && defined(HAVE_SETEUID)
      dummy = seteuid(getuid());
#endif
#if defined(HAVE_GETGID) && defined(HAVE_SETEGID)
      dummy = setegid(getgid());
#endif

      /* we'll need to be able to read one sector past user data if we
         have a sample offset in order to pick up the last bytes.  We
         need to set the disc length forward here so that the libs are
         willing to read past, assuming that works on the hardware, of
         course */
      if(sample_offset && force_overread)
        d->disc_toc[d->tracks].dwStartSector++;

      while(cursor<=i_last_lsn){
        char outfile_name[PATH_MAX];
        if ( batch ){
          batch_first = cursor;
          batch_track = cdda_sector_gettrack(d,cursor);
          batch_last  = cdda_track_lastsector(d, batch_track);
          if (batch_last>i_last_lsn) batch_last=i_last_lsn;
        } else {
          batch_first = i_first_lsn;
          batch_last  = i_last_lsn;
          batch_track = -1;
        }

        callbegin=batch_first;
        callend=batch_last;

        /* argv[optind] is the span, argv[optind+1] (if exists) is outfile */

        if (optind+1<argc) {
          if (!strcmp(argv[optind+1],"-") ){
            out = dup(fileno(stdout));
            if(out==-1){
              report("Cannot dupplicate stdout: %s",
                     strerror(errno));
              exit(1);
            }
            if(batch)
              report("Are you sure you wanted 'batch' "
                     "(-B) output with stdout?");
            report("outputting to stdout\n");
            if(logfile){
              fprintf(logfile,"outputting to stdout\n");
              fflush(logfile);
            }
            outfile_name[0]='\0';
          } else {
            char dirname[PATH_MAX];
            char *basename=split_base_dir(argv[optind+1], dirname,
					  PATH_MAX);

	    if (NULL == basename) {
	      report("Output filename too long");
	      exit(1);
	    }

            if(batch) {
	      if (strlen(argv[optind+1]) - 10 > PATH_MAX) {
		report("Output filename too long");
		exit(1);
	      }
              snprintf(outfile_name, PATH_MAX,
		       " %strack%02d.%s", dirname,
                       batch_track, basename);
            } else
              snprintf(outfile_name, PATH_MAX, "%s%s", dirname, basename);

            if(basename[0]=='\0'){
              switch (output_type) {
              case 0: /* raw */
                strncat(outfile_name, "cdda.raw", sizeof("cdda.raw"));
                break;
              case 1:
                strncat(outfile_name, "cdda.wav", sizeof("cdda.wav"));
                break;
              case 2:
                strncat(outfile_name, "cdda.aifc", sizeof("cdda.aifc"));
                break;
              case 3:
                strncat(outfile_name, "cdda.aiff", sizeof("cdda.aiff"));
                break;
              }
            }

            out=open(outfile_name,O_RDWR|O_CREAT|O_TRUNC|O_BINARY,0666);
            if(out==-1){
              report("Cannot open specified output file %s: %s",
                      outfile_name, strerror(errno));
              exit(1);
            }
            report("outputting to %s\n", outfile_name);
            if(logfile){
              fprintf(logfile,"outputting to %s\n",outfile_name);
              fflush(logfile);
            }
          }
        } else {
          /* default */
          if (batch)
            sprintf(outfile_name,"track%02d.", batch_track);
          else
            outfile_name[0]='\0';

          switch(output_type){
          case 0: /* raw */
            strncat(outfile_name, "cdda.raw", sizeof("cdda.raw"));
            break;
          case 1:
            strncat(outfile_name, "cdda.wav", sizeof("cdda.wav"));
            break;
          case 2:
            strncat(outfile_name, "cdda.aifc", sizeof("cdda.aifc"));
            break;
          case 3:
            strncat(outfile_name, "cdda.aiff", sizeof("cdda.aiff"));
            break;
          }

          out = open(outfile_name, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
          if(out==-1){
            report("Cannot open default output file %s: %s", outfile_name,
                    strerror(errno));
            exit(1);
          }
          report("outputting to %s\n", outfile_name);
          if(logfile){
            fprintf(logfile,"outputting to %s\n",outfile_name);
            fflush(logfile);
          }

        }

	sectorlen = batch_last - batch_first + 1;
	if (cdda_sector_gettrack(d, cursor) == d->tracks &&
		toc_offset > 0 && !force_overread){
		sectorlen += toc_offset;
	}
        switch(output_type) {
        case 0: /* raw */
          break;
        case 1: /* wav */
	  WriteWav(out, sectorlen * CD_FRAMESIZE_RAW);
          break;
        case 2: /* aifc */
	  WriteAifc(out, sectorlen * CD_FRAMESIZE_RAW);
          break;
        case 3: /* aiff */
	  WriteAiff(out, sectorlen * CD_FRAMESIZE_RAW);
          break;
        }

        /* Off we go! */

        if(offset_buffer_used){
          /* partial sector from previous batch read */
          cursor++;
          if (buffering_write(out,
                              ((char *)offset_buffer)+offset_buffer_used,
                              CDIO_CD_FRAMESIZE_RAW-offset_buffer_used)){
            report("Error writing output: %s", strerror(errno));
            exit(1);
          }
        }

        skipped_flag=0;
        while(cursor<=batch_last){
          /* read a sector */
          int16_t *readbuf=paranoia_read_limited(p, callback, max_retries);
          char *err=cdda_errors(d);
          char *mes=cdda_messages(d);

          if(mes || err)
            fprintf(stderr,"\r                               "
                    "                                           \r%s%s\n",
                    mes?mes:"",err?err:"");

          if (err) free(err);
          if (mes) free(mes);
          if( readbuf==NULL) {
	    if(errno==EBADF || errno==ENOMEDIUM){
	      report("\nparanoia_read: CDROM drive unavailable, bailing.\n");
	      exit(1);
	    }
            skipped_flag=1;
            report("\nparanoia_read: Unrecoverable error, bailing.\n");
            break;
          }
          if(skipped_flag && abort_on_skip){
            cursor=batch_last+1;
            break;
          }

          skipped_flag=0;
          cursor++;

          if (output_endian!=bigendianp()) {
            int i;
            for (i=0; i<CDIO_CD_FRAMESIZE_RAW/2; i++)
              readbuf[i]=UINT16_SWAP_LE_BE_C(readbuf[i]);
          }

          callback(cursor*(CD_FRAMEWORDS)-1, PARANOIA_CB_WROTE);

          if (buffering_write(out,((char *)readbuf)+offset_skip,
                             CDIO_CD_FRAMESIZE_RAW-offset_skip)){
            report("Error writing output: %s", strerror(errno));
            exit(1);
          }
          offset_skip=0;

          if (output_endian != bigendianp()){
            int i;
            for (i=0; i<CDIO_CD_FRAMESIZE_RAW/2; i++)
              readbuf[i] = UINT16_SWAP_LE_BE_C(readbuf[i]);
          }

          /* One last bit of silliness to deal with sample offsets */
          if(sample_offset && cursor>batch_last){
	    if (cdda_sector_gettrack(d, batch_last) < d->tracks || force_overread) {
	      int i;

	      /* Need to flush the buffer when overreading into the leadout */
	      if (cdda_sector_gettrack(d, batch_last) == d->tracks)
		paranoia_seek(p, cursor, SEEK_SET);

	      /* read a sector and output the partial offset.  Save the
		 rest for the next batch iteration */
	      readbuf=paranoia_read_limited(p,callback,max_retries);
	      err=cdda_errors(d);mes=cdda_messages(d);

	      if(mes || err)
		fprintf(stderr,"\r                               "
			"                                           \r%s%s\n",
			mes?mes:"",err?err:"");

	      if(err)free(err);if(mes)free(mes);
	      if(readbuf==NULL){
		skipped_flag=1;
		report("\nparanoia_read: Unrecoverable error reading through "
		       "sample_offset shift\n\tat end of track, bailing.\n");
		break;
	      }
	      if (skipped_flag && abort_on_skip) break;
	      skipped_flag=0;
	      /* do not move the cursor */

	      if(output_endian!=bigendianp())
		for(i=0;i<CD_FRAMESIZE_RAW/2;i++)
		  offset_buffer[i]=UINT16_SWAP_LE_BE_C(readbuf[i]);
	      else
		memcpy(offset_buffer,readbuf,CD_FRAMESIZE_RAW);
	      offset_buffer_used=sample_offset*4;
	      callback(cursor* (CD_FRAMEWORDS), PARANOIA_CB_WROTE);
	    } else {
	      memset(offset_buffer, 0, sizeof(offset_buffer));
	      offset_buffer_used = sample_offset * 4;
	    }

	    if(buffering_write(out,(char *)offset_buffer,
			       offset_buffer_used)){
	      report("Error writing output: %s", strerror(errno));
	      exit(1);
	    }
	  }
        }

	/* Write sectors of silent audio to compensate for
	   missing samples that would be in the leadout */
	if (cdda_sector_gettrack(d, batch_last) == d->tracks &&
		toc_offset > 0 && !force_overread)
	{
		char *silence;
		size_t missing_sector_bytes = CD_FRAMESIZE_RAW * toc_offset;

		silence = calloc(toc_offset, CD_FRAMESIZE_RAW);
		if (!silence || buffering_write(out, silence, missing_sector_bytes)) {
		      report("Error writing output: %s", strerror(errno));
		      exit(1);
		}
		free(silence);
	}

        callback(cursor* (CDIO_CD_FRAMESIZE_RAW/2)-1,
		 PARANOIA_CB_FINISHED);
        buffering_close(out);
        if(skipped_flag){
          /* remove the file */
          report("\nRemoving aborted file: %s", outfile_name);
          unlink(outfile_name);
          /* make the cursor correct if we have another track */
          if(batch_track!=-1){
            batch_track++;
            cursor=cdda_track_firstsector(d,batch_track);
            paranoia_seek(p,cursor, SEEK_SET);
            offset_skip=sample_offset*4;
            offset_buffer_used=0;
          }
        }
        report("\n");
      }

      paranoia_free(p);
      p=NULL;
    }
  }

  report("Done.\n\n");

  return 0;
}
Beispiel #17
0
int
main(int argc, const char *argv[])
{
  cdrom_drive_t *d = NULL; /* Place to store handle given by cd-parapnioa. */
  driver_id_t driver_id;
  char **ppsz_cd_drives;  /* List of all drives with a loaded CDDA in it. */
  int i_rc=0;

  /* See if we can find a device with a loaded CD-DA in it. If successful
     drive_id will be set.  */
  ppsz_cd_drives = cdio_get_devices_with_cap_ret(NULL, CDIO_FS_AUDIO, false,
						 &driver_id);

  if (ppsz_cd_drives && *ppsz_cd_drives) {
    /* Found such a CD-ROM with a CD-DA loaded. Use the first drive in
       the list. */
    d=cdda_identify(*ppsz_cd_drives, 1, NULL);
  } else {
    printf("Unable find or access a CD-ROM drive with an audio CD in it.\n");
    exit(SKIP_TEST_RC);
  }

  /** We had a bug in is_device when driver_id == DRIVER_UNKNOWN or
     DRIVER_DEVICE. Let's make sure we've fixed that problem. **/
  if (!cdio_is_device(*ppsz_cd_drives, DRIVER_UNKNOWN) || 
      !cdio_is_device(*ppsz_cd_drives, DRIVER_DEVICE))
    exit(99);
  
  /* Don't need a list of CD's with CD-DA's any more. */
  cdio_free_device_list(ppsz_cd_drives);

  /* We'll set for verbose paranoia messages. */
  cdda_verbose_set(d, CDDA_MESSAGE_PRINTIT, CDDA_MESSAGE_PRINTIT);

  if ( 0 != cdio_cddap_open(d) ) {
    printf("Unable to open disc.\n");
    exit(SKIP_TEST_RC);
  }

  /* Okay now set up to read up to the first 300 frames of the first
     audio track of the Audio CD. */
  { 
    cdrom_paranoia_t *p = paranoia_init(d);
    lsn_t i_first_lsn = cdda_disc_firstsector(d);

    if ( -1 == i_first_lsn ) {
      printf("Trouble getting starting LSN\n");
    } else {
      lsn_t   i_lsn; /* Current LSN to read */
      lsn_t   i_last_lsn = cdda_disc_lastsector(d);
      unsigned int i_sectors = i_last_lsn - i_first_lsn + 1;
      unsigned int j;
      unsigned int i_good = 0;
      unsigned int i_bad  = 0;
      
      /* Set reading mode for full paranoia, but allow skipping sectors. */
      paranoia_modeset(p, PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP);

      for ( j=0; j<10; j++ ) {
	
	/* Pick a place to start reading. */
	i_lsn = i_first_lsn + (rand() % i_sectors);
	paranoia_seek(p, i_lsn, SEEK_SET);

	printf("Testing %d sectors starting at %ld\n",
	       MAX_SECTORS, (long int) i_lsn);
	for ( i = 0; 
	      i < MAX_SECTORS && i_lsn <= i_last_lsn; 
	      i++, i_lsn++ ) {
	  /* read a sector */
	  int16_t *p_readbuf = paranoia_read(p, callback);
	  char *psz_err=cdio_cddap_errors(d);
	  char *psz_mes=cdio_cddap_messages(d);

	  memcpy(audio_buf[i], p_readbuf, CDIO_CD_FRAMESIZE_RAW);
	  
	  if (psz_mes || psz_err)
	    printf("%s%s\n", psz_mes ? psz_mes: "", psz_err ? psz_err: "");
	  
	  if (psz_err) free(psz_err);
	  if (psz_mes) free(psz_mes);
	  if( !p_readbuf ) {
	    printf("paranoia read error. Stopping.\n");
	    goto out;
	  }
	}

	/* Compare with the sectors from paranoia. */
	i_lsn -= MAX_SECTORS;
	for ( i = 0; i < MAX_SECTORS; i++, i_lsn++ ) {
	  uint8_t readbuf[CDIO_CD_FRAMESIZE_RAW] = {0,};
	  if ( PARANOIA_CB_READ == audio_status[i] || 
	       PARANOIA_CB_VERIFY == audio_status[i] ) {
	    /* We read the block via paranoia without an error. */

	    if ( 0 == cdio_read_audio_sector(d->p_cdio, readbuf, i_lsn) ) {
	      if ( BIGENDIAN != d->bigendianp ) {
		/* We will compare in the slow, pedantic way*/
		int j;
		for (j=0; j < CDIO_CD_FRAMESIZE_RAW ; j +=2) {
		  if (audio_buf[i][j]   != readbuf[j+1] && 
		      audio_buf[i][j+1] != readbuf[j] ) {
		    printf("LSN %ld doesn't match\n", (long int) i_lsn);
		    i_bad++;
		  } else {
		    i_good++;
		  }
		}
	      } else {
		if ( 0 != memcmp(audio_buf[i], readbuf, 
				 CDIO_CD_FRAMESIZE_RAW) ) {
		  printf("LSN %ld doesn't match\n", (long int) i_lsn);
		  i_bad++;
		} else {
		  i_good++;
		}
	      }
	    }
	  } else {
	    printf("Skipping LSN %ld because of status: %s\n", 
		   (long int) i_lsn, paranoia_cb_mode2str[audio_status[i]]);
	  }
	}
      }
      printf("%u sectors compared okay %u sectors were different\n",
	     i_good, i_bad);
      if (i_bad > i_good) i_rc = 1;
    }
  out: paranoia_free(p);
  }
  
  cdio_cddap_close(d);

  exit(i_rc);
}