input/CdioParanoia: C++ wrappers for libcdio types
This commit is contained in:
parent
48ec09ab1e
commit
4ba9357a9c
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "CdioParanoiaInputPlugin.hxx"
|
#include "CdioParanoiaInputPlugin.hxx"
|
||||||
|
#include "lib/cdio/Paranoia.hxx"
|
||||||
#include "../InputStream.hxx"
|
#include "../InputStream.hxx"
|
||||||
#include "../InputPlugin.hxx"
|
#include "../InputPlugin.hxx"
|
||||||
#include "util/TruncateString.hxx"
|
#include "util/TruncateString.hxx"
|
||||||
|
@ -41,19 +42,12 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include <cdio/version.h>
|
|
||||||
#if LIBCDIO_VERSION_NUM >= 90
|
|
||||||
#include <cdio/paranoia/paranoia.h>
|
|
||||||
#else
|
|
||||||
#include <cdio/paranoia.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <cdio/cd_types.h>
|
#include <cdio/cd_types.h>
|
||||||
|
|
||||||
class CdioParanoiaInputStream final : public InputStream {
|
class CdioParanoiaInputStream final : public InputStream {
|
||||||
cdrom_drive_t *const drv;
|
cdrom_drive_t *const drv;
|
||||||
CdIo_t *const cdio;
|
CdIo_t *const cdio;
|
||||||
cdrom_paranoia_t *const para;
|
CdromParanoia para;
|
||||||
|
|
||||||
const lsn_t lsn_from, lsn_to;
|
const lsn_t lsn_from, lsn_to;
|
||||||
int lsn_relofs;
|
int lsn_relofs;
|
||||||
|
@ -67,18 +61,17 @@ class CdioParanoiaInputStream final : public InputStream {
|
||||||
bool reverse_endian,
|
bool reverse_endian,
|
||||||
lsn_t _lsn_from, lsn_t _lsn_to)
|
lsn_t _lsn_from, lsn_t _lsn_to)
|
||||||
:InputStream(_uri, _mutex),
|
:InputStream(_uri, _mutex),
|
||||||
drv(_drv), cdio(_cdio), para(cdio_paranoia_init(drv)),
|
drv(_drv), cdio(_cdio), para(drv),
|
||||||
lsn_from(_lsn_from), lsn_to(_lsn_to),
|
lsn_from(_lsn_from), lsn_to(_lsn_to),
|
||||||
lsn_relofs(0),
|
lsn_relofs(0),
|
||||||
buffer_lsn(-1)
|
buffer_lsn(-1)
|
||||||
{
|
{
|
||||||
/* Set reading mode for full paranoia, but allow
|
/* Set reading mode for full paranoia, but allow
|
||||||
skipping sectors. */
|
skipping sectors. */
|
||||||
paranoia_modeset(para,
|
para.SetMode(PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP);
|
||||||
PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP);
|
|
||||||
|
|
||||||
/* seek to beginning of the track */
|
/* seek to beginning of the track */
|
||||||
cdio_paranoia_seek(para, lsn_from, SEEK_SET);
|
para.Seek(lsn_from);
|
||||||
|
|
||||||
seekable = true;
|
seekable = true;
|
||||||
size = (lsn_to - lsn_from + 1) * CDIO_CD_FRAMESIZE_RAW;
|
size = (lsn_to - lsn_from + 1) * CDIO_CD_FRAMESIZE_RAW;
|
||||||
|
@ -91,7 +84,7 @@ class CdioParanoiaInputStream final : public InputStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
~CdioParanoiaInputStream() {
|
~CdioParanoiaInputStream() {
|
||||||
cdio_paranoia_free(para);
|
para = {};
|
||||||
cdio_cddap_close_no_free_cdio(drv);
|
cdio_cddap_close_no_free_cdio(drv);
|
||||||
cdio_destroy(cdio);
|
cdio_destroy(cdio);
|
||||||
}
|
}
|
||||||
|
@ -278,7 +271,7 @@ CdioParanoiaInputStream::Seek(offset_type new_offset)
|
||||||
|
|
||||||
{
|
{
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
cdio_paranoia_seek(para, lsn_from + lsn_relofs, SEEK_SET);
|
para.Seek(lsn_from + lsn_relofs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,20 +291,22 @@ CdioParanoiaInputStream::Read(void *ptr, size_t length)
|
||||||
if (lsn_relofs != buffer_lsn) {
|
if (lsn_relofs != buffer_lsn) {
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
|
|
||||||
rbuf = cdio_paranoia_read(para, nullptr);
|
try {
|
||||||
|
rbuf = para.Read().data;
|
||||||
char *s_err = cdio_cddap_errors(drv);
|
} catch (...) {
|
||||||
if (s_err) {
|
char *s_err = cdio_cddap_errors(drv);
|
||||||
FormatError(cdio_domain,
|
if (s_err) {
|
||||||
"paranoia_read: %s", s_err);
|
FormatError(cdio_domain,
|
||||||
|
"paranoia_read: %s", s_err);
|
||||||
#if LIBCDIO_VERSION_NUM >= 90
|
#if LIBCDIO_VERSION_NUM >= 90
|
||||||
cdio_cddap_free_messages(s_err);
|
cdio_cddap_free_messages(s_err);
|
||||||
#else
|
#else
|
||||||
free(s_err);
|
free(s_err);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
if (!rbuf)
|
|
||||||
throw std::runtime_error("paranoia read error");
|
|
||||||
|
|
||||||
//store current buffer
|
//store current buffer
|
||||||
memcpy(buffer, rbuf, CDIO_CD_FRAMESIZE_RAW);
|
memcpy(buffer, rbuf, CDIO_CD_FRAMESIZE_RAW);
|
||||||
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Max Kellermann <max.kellermann@gmail.com>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CDIO_PARANOIA_HXX
|
||||||
|
#define CDIO_PARANOIA_HXX
|
||||||
|
|
||||||
|
#include "util/ConstBuffer.hxx"
|
||||||
|
#include "util/Compiler.h"
|
||||||
|
|
||||||
|
#include <cdio/version.h>
|
||||||
|
#if LIBCDIO_VERSION_NUM >= 90
|
||||||
|
#include <cdio/paranoia/paranoia.h>
|
||||||
|
#else
|
||||||
|
#include <cdio/paranoia.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
class CdromDrive {
|
||||||
|
cdrom_drive_t *drv = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CdromDrive() = default;
|
||||||
|
|
||||||
|
explicit CdromDrive(CdIo_t *cdio)
|
||||||
|
:drv(cdio_cddap_identify_cdio(cdio, 1, nullptr))
|
||||||
|
{
|
||||||
|
if (drv == nullptr)
|
||||||
|
throw std::runtime_error("Failed to identify audio CD");
|
||||||
|
|
||||||
|
cdda_verbose_set(drv, CDDA_MESSAGE_FORGETIT,
|
||||||
|
CDDA_MESSAGE_FORGETIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
~CdromDrive() noexcept {
|
||||||
|
if (drv != nullptr)
|
||||||
|
cdio_cddap_close_no_free_cdio(drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
CdromDrive(CdromDrive &&src) noexcept
|
||||||
|
:drv(std::exchange(src.drv, nullptr)) {}
|
||||||
|
|
||||||
|
CdromDrive &operator=(CdromDrive &&src) noexcept {
|
||||||
|
using std::swap;
|
||||||
|
swap(drv, src.drv);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto get() const noexcept {
|
||||||
|
return drv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Open() {
|
||||||
|
if (cdio_cddap_open(drv) != 0)
|
||||||
|
throw std::runtime_error("Failed to open disc");
|
||||||
|
}
|
||||||
|
|
||||||
|
gcc_pure
|
||||||
|
bool IsAudioTrack(track_t i) const noexcept {
|
||||||
|
return cdio_cddap_track_audiop(drv, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GetTrackSectorRange(track_t i) const {
|
||||||
|
auto first = cdio_cddap_track_firstsector(drv, i);
|
||||||
|
auto last = cdio_cddap_track_lastsector(drv, i);
|
||||||
|
if (first < 0 || last < 0)
|
||||||
|
throw std::runtime_error("Invalid track number");
|
||||||
|
return std::make_pair(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
gcc_pure
|
||||||
|
unsigned GetTrackCount() const noexcept {
|
||||||
|
return cdio_cddap_tracks(drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned GetTrackChannels(track_t i) const {
|
||||||
|
auto value = cdio_cddap_track_channels(drv, i);
|
||||||
|
if (value < 0)
|
||||||
|
throw std::runtime_error("cdio_cddap_track_channels() failed");
|
||||||
|
return unsigned(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CdromParanoia {
|
||||||
|
cdrom_paranoia_t *paranoia = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CdromParanoia() = default;
|
||||||
|
|
||||||
|
explicit CdromParanoia(cdrom_drive_t *drv) noexcept
|
||||||
|
:paranoia(cdio_paranoia_init(drv)) {}
|
||||||
|
|
||||||
|
~CdromParanoia() noexcept {
|
||||||
|
if (paranoia != nullptr)
|
||||||
|
cdio_paranoia_free(paranoia);
|
||||||
|
}
|
||||||
|
|
||||||
|
CdromParanoia(CdromParanoia &&src) noexcept
|
||||||
|
:paranoia(std::exchange(src.paranoia, nullptr)) {}
|
||||||
|
|
||||||
|
CdromParanoia &operator=(CdromParanoia &&src) noexcept {
|
||||||
|
using std::swap;
|
||||||
|
swap(paranoia, src.paranoia);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto get() const noexcept {
|
||||||
|
return paranoia;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetMode(int mode_flags) noexcept {
|
||||||
|
paranoia_modeset(paranoia, mode_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Seek(int32_t seek, int whence=SEEK_SET) {
|
||||||
|
if (cdio_paranoia_seek(paranoia, seek, whence) < 0)
|
||||||
|
throw std::runtime_error("Failed to seek disc");
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstBuffer<int16_t> Read() {
|
||||||
|
const int16_t *data = cdio_paranoia_read(paranoia, nullptr);
|
||||||
|
if (data == nullptr)
|
||||||
|
throw std::runtime_error("Read from audio CD failed");
|
||||||
|
|
||||||
|
return {data, CDIO_CD_FRAMESIZE_RAW / sizeof(int16_t)};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue