/*! */ long ParanoiaReaderImpl::read(uint8_t* buffer, uint32_t begin_sector, uint32_t sectors) { if (not _audio_cd->is_open()) { THROW_EXCEPTION(CddaException, "AudioCd is closed"); } cdio_paranoia_modeset(_cdrom_paranoia, PARANOIA_MODE_FULL ^ PARANOIA_MODE_NEVERSKIP); cdio_paranoia_seek(_cdrom_paranoia, begin_sector, SEEK_SET); int16_t* read_buffer = cdio_paranoia_read_limited(_cdrom_paranoia, NULL, _max_retries); //! \todo Use another system to free returned messages char* err = cdio_cddap_errors(_audio_cd->cdrom()); //char* mes = cdio_cddap_messages(_audio_cd->cdrom()); if (err) { std::string tmp = err; delete [] err; THROW_EXCEPTION(CddaException, tmp); } buffer = reinterpret_cast<uint8_t*>(read_buffer); return sectors; }
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 }
static int read_seek(AVFormatContext *ctx, int stream_index, int64_t timestamp, int flags) { CDIOContext *s = ctx->priv_data; AVStream *st = ctx->streams[0]; cdio_paranoia_seek(s->paranoia, timestamp, SEEK_SET); st->cur_dts = timestamp; return 0; }
static unsigned CDDAReader_seek_device(cdio_CDDAReader *self, unsigned sector) { const unsigned desired_sector = MIN(sector, self->_.drive.final_sector - 1u); /*not sure what this returns, but it isn't the sector seeked to*/ cdio_paranoia_seek(self->_.drive.paranoia, (int32_t)desired_sector, (int)SEEK_SET); self->_.drive.current_sector = desired_sector; return self->_.drive.current_sector; }
static PyObject* CDDA_seek(cdio_CDDAObject* self, PyObject *args) { off_t location; lsn_t new_location; if (!PyArg_ParseTuple(args, "l", &location)) return NULL; new_location = cdio_paranoia_seek(self->paranoia, (int32_t)location, (int)SEEK_SET); return Py_BuildValue("i", new_location); }
static bool input_cdio_seek(struct input_stream *is, goffset offset, int whence, GError **error_r) { struct input_cdio_paranoia *cis = (struct input_cdio_paranoia *)is; /* calculate absolute offset */ switch (whence) { case SEEK_SET: break; case SEEK_CUR: offset += cis->base.offset; break; case SEEK_END: offset += cis->base.size; break; } if (offset < 0 || offset > cis->base.size) { g_set_error(error_r, cdio_quark(), 0, "Invalid offset to seek %ld (%ld)", (long int)offset, (long int)cis->base.size); return false; } /* simple case */ if (offset == cis->base.offset) return true; /* calculate current LSN */ cis->lsn_relofs = offset / CDIO_CD_FRAMESIZE_RAW; cis->base.offset = offset; cdio_paranoia_seek(cis->para, cis->lsn_from + cis->lsn_relofs, SEEK_SET); return true; }
static int32_t seek_track(cdpa_t *cdpa, int idx, uint32_t blk) { lsn_t lsn; mrp_debug("seeking to track #%d, block %u", idx, blk); if (idx < 0 || idx >= cdpa->ntrack) goto invalid; if (cdpa->tracks[idx].fblk + blk > cdpa->tracks[idx].lblk) goto invalid; blk += cdpa->tracks[idx].fblk; lsn = (int32_t)cdio_paranoia_seek(cdpa->cdpa, blk, SEEK_SET); if (lsn < 0) goto invalid; return (int32_t)(lsn * CDIO_CD_FRAMESIZE_RAW); invalid: errno = EINVAL; return -1; }
void cued_rip_to_file(rip_context_t *rip) { SF_INFO sfinfo; PIT(SNDFILE, sfObj); PIT(int16_t, pbuf); lsn_t currSector, offsetSectors; int wordsToWrite, wordsWritten, i; int offsetWords = rip->offsetWords; track_t track = rip->currentTrack; memset(&sfinfo, 0x00, sizeof(sfinfo)); sfinfo.samplerate = 44100; sfinfo.channels = rip->channels; sfinfo.format = SF_FORMAT_PCM_16 | rip->soundFileFormat; offsetSectors = offsetWords / CD_FRAMEWORDS; rip->firstSector += offsetSectors; rip->lastSector += offsetSectors; offsetWords %= CD_FRAMEWORDS; if (offsetWords < 0) { rip->firstSector -= 1; } else if (offsetWords > 0) { rip->lastSector += 1; } // else offsetWords is zero b/c the offset fell on a sector boundary currSector = rip->firstSector; #ifdef CUED_HAVE_PARANOIA if (ripUseParanoia) { lsn_t seekSector, prc; if (currSector < 0 && !ripReadPregap) { seekSector = 0; } else { seekSector = currSector; } // TODO: paranoia has a problem with reading leadout if (seekSector < rip->endOfDiscSector) { prc = cdio_paranoia_seek(rip->paranoiaRipObj, seekSector, SEEK_SET); cdio2_paranoia_msg(rip->paranoiaCtlObj, "paranoia seek"); if (-1 == prc) { cdio_error("paranoia returned \"%d\" during seek to \"%d\"; skipping track %02d", prc, seekSector, track); return; } } } #endif // CUED_HAVE_PARANOIA if (ripExtract) { // does not return on error (void) format_get_file_path(rip->cdObj, rip->cddbObj, rip->fileNamePattern, cued_fmt_to_ext(rip->soundFileFormat), track, rip->fileNameBuffer, rip->bufferSize ); sfObj = sf_open(rip->fileNameBuffer, SFM_WRITE, &sfinfo); if (!sfObj) { cdio_error("sf_open(\"%s\") returned \"%s\"; skipping extraction of track %02d", rip->fileNameBuffer, sf_strerror(sfObj), track); return; } } for (; currSector <= rip->lastSector; ++currSector) { if ((currSector < 0 && !ripReadPregap) || (currSector >= rip->endOfDiscSector && !ripReadLeadout)) { // N.B. assume that if mmcBuf is not NULL, it is >= sizeof(audio_buffer_t) if (!rip->mmcBuf) { // use twice the audio_buffer_t size for reading 1 sector; // this should accomodate any extra headers/sub-channel data // requested later in the normal read path // rip->mmcBuf = (uint8_t *) malloc(2 * sizeof(audio_buffer_t)); if (rip->mmcBuf) { rip->allocatedSectors = 1; } else { cdio2_abort("out of memory allocating overread sector"); } } memset(rip->mmcBuf, 0x00, sizeof(audio_buffer_t)); pbuf = (int16_t *) rip->mmcBuf; } else { // TODO: need to update track indices on skip of sector (continue) if (ripUseParanoia) { #ifdef CUED_HAVE_PARANOIA pbuf = cdio_paranoia_read_limited(rip->paranoiaRipObj, cdio2_paranoia_callback, rip->retries); cdio2_paranoia_msg(rip->paranoiaCtlObj, "read of audio sector"); if (!pbuf) { cdio_error("paranoia did not return data; skipping extraction of audio sector %d in track %02d", currSector, track); continue; } #endif // CUED_HAVE_PARANOIA } else { if (DRIVER_OP_SUCCESS == cued_read_audio(rip, currSector, 1, NULL, rip->retries)) { pbuf = (int16_t *) rip->mmcBuf; } else { continue; } } } wordsToWrite = CD_FRAMEWORDS; // N.B. firstSector == lastSector is not possible if offsetWords is non-zero // if (rip->firstSector == currSector) { if (offsetWords < 0) { pbuf += CD_FRAMEWORDS + offsetWords; wordsToWrite = -offsetWords; } else if (offsetWords > 0) { pbuf += offsetWords; wordsToWrite -= offsetWords; } } else if (rip->lastSector == currSector) { if (offsetWords < 0) { wordsToWrite += offsetWords; } else if (offsetWords > 0) { wordsToWrite = offsetWords; } } if (ripExtract) { wordsWritten = sf_write_short(sfObj, pbuf, wordsToWrite); if (wordsWritten != wordsToWrite) { // probably out of disk space, which is bad, because most things rely on it cdio2_abort("failed to write to file \"%s\" due to \"%s\"", rip->fileNameBuffer, sf_strerror(sfObj)); } } if (!track && !ripNoisyPregap) { for (i = 0; i < wordsToWrite; ++i) { if (pbuf[i]) { SETF(RIP_F_NOISY_PREGAP, rip->flags); break; } } } } if (!track && !ripNoisyPregap) { SETF(RIP_F_SILENT_PREGAP, rip->flags); } if (ripExtract) { sf_close(sfObj); } }
static struct input_stream * input_cdio_open(const char *uri, GMutex *mutex, GCond *cond, GError **error_r) { struct input_cdio_paranoia *i; struct cdio_uri parsed_uri; if (!parse_cdio_uri(&parsed_uri, uri, error_r)) return NULL; i = g_new(struct input_cdio_paranoia, 1); input_stream_init(&i->base, &input_plugin_cdio_paranoia, uri, mutex, cond); /* initialize everything (should be already) */ i->drv = NULL; i->cdio = NULL; i->para = NULL; i->trackno = parsed_uri.track; pcm_buffer_init(&i->conv_buffer); /* get list of CD's supporting CD-DA */ char *device = parsed_uri.device[0] != 0 ? g_strdup(parsed_uri.device) : cdio_detect_device(); if (device == NULL) { g_set_error(error_r, cdio_quark(), 0, "Unable find or access a CD-ROM drive with an audio CD in it."); input_cdio_close(&i->base); return NULL; } /* Found such a CD-ROM with a CD-DA loaded. Use the first drive in the list. */ i->cdio = cdio_open(device, DRIVER_UNKNOWN); g_free(device); i->drv = cdio_cddap_identify_cdio(i->cdio, 1, NULL); if ( !i->drv ) { g_set_error(error_r, cdio_quark(), 0, "Unable to identify audio CD disc."); input_cdio_close(&i->base); return NULL; } cdda_verbose_set(i->drv, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT); if ( 0 != cdio_cddap_open(i->drv) ) { g_set_error(error_r, cdio_quark(), 0, "Unable to open disc."); input_cdio_close(&i->base); return NULL; } i->endian = data_bigendianp(i->drv); switch (i->endian) { case -1: g_debug("cdda: drive returns unknown audio data, assuming Little Endian"); i->endian = 0; break; case 0: g_debug("cdda: drive returns audio data Little Endian."); break; case 1: g_debug("cdda: drive returns audio data Big Endian."); break; default: g_set_error(error_r, cdio_quark(), 0, "Drive returns unknown data type %d", i->endian); input_cdio_close(&i->base); return NULL; } i->lsn_relofs = 0; if (i->trackno >= 0) { i->lsn_from = cdio_get_track_lsn(i->cdio, i->trackno); i->lsn_to = cdio_get_track_last_lsn(i->cdio, i->trackno); } else { i->lsn_from = 0; i->lsn_to = cdio_get_disc_last_lsn(i->cdio); } i->para = cdio_paranoia_init(i->drv); /* Set reading mode for full paranoia, but allow skipping sectors. */ paranoia_modeset(i->para, PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP); /* seek to beginning of the track */ cdio_paranoia_seek(i->para, i->lsn_from, SEEK_SET); i->base.ready = true; i->base.seekable = true; i->base.size = (i->lsn_to - i->lsn_from + 1) * CDIO_CD_FRAMESIZE_RAW; /* hack to make MPD select the "pcm" decoder plugin */ i->base.mime = g_strdup("audio/x-mpd-cdda-pcm"); return &i->base; }
// private virtual void CdDecoder::run() { RunProlog(); if (!m_inited) { RunEpilog(); return; } m_stat = DecoderEvent::Decoding; // NB block scope required to prevent re-entrancy { DecoderEvent e(m_stat); dispatch(e); } // account for possible frame expansion in aobase (upmix, float conv) const std::size_t thresh = m_bks * 6; while (!m_finish && !m_user_stop) { if (m_seekTime >= +0.) { m_curpos = m_start + static_cast< lsn_t >( (m_seekTime * kSamplesPerSec) / CD_FRAMESAMPLES); if (m_paranoia) { QMutexLocker lock(&getCdioMutex()); cdio_paranoia_seek(m_paranoia, m_curpos, SEEK_SET); } m_output_at = 0; m_seekTime = -1.; } if (m_output_at < m_bks) { while (m_output_at < m_decodeBytes && !m_finish && !m_user_stop && m_seekTime <= +0.) { if (m_curpos < m_end) { QMutexLocker lock(&getCdioMutex()); if (m_paranoia) { int16_t *cdbuffer = cdio_paranoia_read_limited( m_paranoia, 0, 10); if (cdbuffer) memcpy(&m_output_buf[m_output_at], cdbuffer, CDIO_CD_FRAMESIZE_RAW); } else { driver_return_code_t c = cdio_read_audio_sector( m_cdio, &m_output_buf[m_output_at], m_curpos); if (DRIVER_OP_SUCCESS != c) { LOG(VB_MEDIA, LOG_DEBUG, QString("cdio_read_audio_sector(%1) error %2"). arg(m_curpos).arg(c)); memset( &m_output_buf[m_output_at], 0, CDIO_CD_FRAMESIZE_RAW); } } m_output_at += CDIO_CD_FRAMESIZE_RAW; ++(m_curpos); } else { m_finish = true; } } } if (!output()) continue; // Wait until we need to decode or supply more samples uint fill = 0, total = 0; while (!m_finish && !m_user_stop && m_seekTime <= +0.) { output()->GetBufferStatus(fill, total); // Make sure we have decoded samples ready and that the // audiobuffer is reasonably populated if (fill < (thresh << 6)) break; else { // Wait for half of the buffer to drain ::usleep(output()->GetAudioBufferedTime()<<9); } } // write a block if there's sufficient space for it if (!m_user_stop && m_output_at >= m_bks && fill <= total - thresh) { writeBlock(); } } if (m_user_stop) m_inited = false; else if (output()) { // Drain our buffer while (m_output_at >= m_bks) writeBlock(); // Drain ao buffer output()->Drain(); } if (m_finish) m_stat = DecoderEvent::Finished; else if (m_user_stop) m_stat = DecoderEvent::Stopped; else m_stat = DecoderEvent::Error; // NB block scope required to step onto next track { DecoderEvent e(m_stat); dispatch(e); } deinit(); RunEpilog(); }
// pure virtual bool CdDecoder::initialize() { if (m_inited) return true; m_inited = m_user_stop = m_finish = false; m_freq = m_bitrate = 0L; m_stat = DecoderEvent::Error; m_chan = 0; m_seekTime = -1.; if (output()) output()->PauseUntilBuffered(); QFile* file = dynamic_cast< QFile* >(input()); // From QIODevice* if (file) { setFilename(file->fileName()); m_tracknum = getFilename().section('.', 0, 0).toUInt(); } QMutexLocker lock(&getCdioMutex()); m_cdio = openCdio(m_devicename); if (!m_cdio) return false; m_start = cdio_get_track_lsn(m_cdio, m_tracknum); m_end = cdio_get_track_last_lsn(m_cdio, m_tracknum); if (CDIO_INVALID_LSN == m_start || CDIO_INVALID_LSN == m_end) { LOG(VB_MEDIA, LOG_INFO, "CdDecoder: No tracks on " + m_devicename); cdio_destroy(m_cdio), m_cdio = 0; return false; } LOG(VB_MEDIA, LOG_DEBUG, QString("CdDecoder track=%1 lsn start=%2 end=%3") .arg(m_tracknum).arg(m_start).arg(m_end)); m_curpos = m_start; m_device = cdio_cddap_identify_cdio(m_cdio, 0, NULL); if (NULL == m_device) { LOG(VB_GENERAL, LOG_ERR, QString("Error: CdDecoder: cdio_cddap_identify(%1) failed") .arg(m_devicename)); cdio_destroy(m_cdio), m_cdio = 0; return false; } cdio_cddap_verbose_set(m_device, VERBOSE_LEVEL_CHECK(VB_MEDIA, LOG_ANY) ? CDDA_MESSAGE_PRINTIT : CDDA_MESSAGE_FORGETIT, VERBOSE_LEVEL_CHECK(VB_MEDIA, LOG_DEBUG) ? CDDA_MESSAGE_PRINTIT : CDDA_MESSAGE_FORGETIT); if (DRIVER_OP_SUCCESS == cdio_cddap_open(m_device)) { // cdio_get_track_last_lsn is unreliable on discs with data at end lsn_t end2 = cdio_cddap_track_lastsector(m_device, m_tracknum); if (end2 < m_end) { LOG(VB_MEDIA, LOG_INFO, QString("CdDecoder: trim last lsn from %1 to %2") .arg(m_end).arg(end2)); m_end = end2; } m_paranoia = cdio_paranoia_init(m_device); if (NULL != m_paranoia) { cdio_paranoia_modeset(m_paranoia, PARANOIA_MODE_DISABLE); (void)cdio_paranoia_seek(m_paranoia, m_start, SEEK_SET); } else { LOG(VB_GENERAL, LOG_ERR, "Warn: CD reading with paranoia is disabled"); } } else { LOG(VB_GENERAL, LOG_ERR, QString("Warn: drive '%1' is not cdda capable"). arg(m_devicename)); } int chnls = cdio_get_track_channels(m_cdio, m_tracknum); m_chan = chnls > 0 ? chnls : 2; m_freq = kSamplesPerSec; if (output()) { const AudioSettings settings(FORMAT_S16, m_chan, CODEC_ID_PCM_S16LE, m_freq, false /* AC3/DTS passthru */); output()->Reconfigure(settings); output()->SetSourceBitrate(m_freq * m_chan * 16); } // 20ms worth m_bks = (m_freq * m_chan * 2) / 50; m_bksFrames = m_freq / 50; // decode 8 bks worth of samples each time we need more m_decodeBytes = m_bks << 3; m_output_buf = reinterpret_cast< char* >( ::av_malloc(m_decodeBytes + CDIO_CD_FRAMESIZE_RAW * 2)); m_output_at = 0; setCDSpeed(2); m_inited = true; return m_inited; }
static void get_track_info(ripncode_t *r) { rip_track_t *t; int i, base; char file[1024], *msg; int16_t *samples; int fd, n, l, total; base = cdio_get_first_track_num(r->cdio); r->ntrack = cdio_get_num_tracks(r->cdio); r->tracks = mrp_allocz_array(rip_track_t, r->ntrack); if (r->tracks == NULL && r->ntrack > 0) ripncode_fatal(r, "failed to allocate track info"); cdio_paranoia_modeset(r->cdpa, PARANOIA_MODE_FULL); for (i = 0, t = r->tracks; i < r->ntrack; i++, t++) { if (i >= r->last) break; t->id = base + i; t->format = cdio_get_track_format(r->cdio, base + i); t->lsn_beg = cdio_get_track_lsn(r->cdio, base + i); t->lsn_end = cdio_get_track_last_lsn(r->cdio, base + i); t->lba = cdio_get_track_lba(r->cdio, base + i); printf("track #%d (id %d): lsn: %u - %u (lba %u), format: %s\n", i, base + i, t->lsn_beg, t->lsn_end, t->lba, track_format_name(t->format)); if (r->dryrun) continue; snprintf(file, sizeof(file), "track-%d.raw", i); if ((fd = open(file, O_WRONLY|O_CREAT, 0644)) < 0) ripncode_fatal(r, "failed to open '%s' (%d: %s)", file, errno, strerror(errno)); cdio_paranoia_seek(r->cdpa, t->lsn_beg * CDIO_CD_FRAMESIZE_RAW, SEEK_SET); total = t->lsn_end - t->lsn_beg + 1; for (l = 0; l <= total; l++) { printf("\rreading track sector %d/%d (#%d)...", l, total, t->lsn_beg + l); fflush(stdout); samples = cdio_paranoia_read(r->cdpa, read_status); if (samples == NULL) { msg = cdio_cddap_errors(r->cdda); ripncode_fatal(r, "failed to seek to LSN %d (%s)", t->lsn_beg, msg ? msg : "unknown error"); } n = write(fd, samples, CDIO_CD_FRAMESIZE_RAW); if (n < 0) ripncode_fatal(r, "failed to write sector data (%d: %s)", errno, strerror(errno)); } close(fd); } }