util/chd.cpp, util/chdcodec.cpp: Added a safer way to let codecs do special stuff with hunks.

This commit is contained in:
Vas Crabb 2024-10-14 03:22:17 +11:00
parent ec9aec11be
commit ad459a9025
11 changed files with 183 additions and 95 deletions

View File

@ -38,7 +38,7 @@ static char const *const hd_option_spec =
// device type definition
DEFINE_DEVICE_TYPE(HARDDISK, harddisk_image_device, "harddisk_image", "Harddisk")
DEFINE_DEVICE_TYPE(HARDDISK, harddisk_image_device, "harddisk_image", "Hard disk")
//-------------------------------------------------
// harddisk_image_base_device - constructor

View File

@ -2,8 +2,6 @@
// copyright-holders:Aaron Giles
/*************************************************************************
laserdsc.c
Core laserdisc player implementation.
*************************************************************************/
@ -321,15 +319,15 @@ void laserdisc_device::device_start()
void laserdisc_device::device_stop()
{
// make sure all async operations have completed
if (m_disc != nullptr)
if (m_disc)
osd_work_queue_wait(m_work_queue, osd_ticks_per_second() * 10);
// free any textures and palettes
if (m_videotex != nullptr)
if (m_videotex)
machine().render().texture_free(m_videotex);
if (m_videopalette != nullptr)
if (m_videopalette)
m_videopalette->deref();
if (m_overtex != nullptr)
if (m_overtex)
machine().render().texture_free(m_overtex);
}
@ -343,7 +341,7 @@ void laserdisc_device::device_reset()
// attempt to wire up the audio
m_stream->set_sample_rate(m_samplerate);
// set up the general ld
// set up the general LD
m_audiosquelch = 3;
m_videosquelch = 1;
m_fieldnum = 0;
@ -729,10 +727,10 @@ void laserdisc_device::init_disc()
m_fps_times_1million = 59940000;
m_samplerate = 48000;
// get the disc metadata and extract the ld
// get the disc metadata and extract the LD
m_chdtracks = 0;
m_maxtrack = VIRTUAL_LEAD_IN_TRACKS + MAX_TOTAL_TRACKS + VIRTUAL_LEAD_OUT_TRACKS;
if (m_disc != nullptr)
if (m_disc)
{
// require the A/V codec and nothing else
if (m_disc->compression(0) != CHD_CODEC_AVHUFF || m_disc->compression(1) != CHD_CODEC_NONE)
@ -1078,7 +1076,7 @@ void laserdisc_device::read_track_data()
void *laserdisc_device::read_async_static(void *param, int threadid)
{
laserdisc_device &ld = *reinterpret_cast<laserdisc_device *>(param);
ld.m_readresult = ld.m_disc->read_hunk(ld.m_queued_hunknum, nullptr);
ld.m_readresult = ld.m_disc->codec_process_hunk(ld.m_queued_hunknum);
return nullptr;
}

View File

@ -2,8 +2,6 @@
// copyright-holders:Aaron Giles
/*************************************************************************
laserdsc.h
Core laserdisc player implementation.
*************************************************************************/
@ -15,8 +13,9 @@
#include "emupal.h"
#include "screen.h"
#include "vbiparse.h"
#include "avhuff.h"
#include "vbiparse.h"
#include <algorithm>
#include <system_error>
@ -98,7 +97,7 @@ protected:
public:
// delegates
typedef device_delegate<chd_file *(void)> get_disc_delegate;
typedef device_delegate<chd_file * ()> get_disc_delegate;
typedef device_delegate<void (int samplerate, int samples, const int16_t *ch0, const int16_t *ch1)> audio_delegate;
laserdisc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);

View File

@ -892,6 +892,105 @@ void chd_file::close()
m_cachehunk = ~0;
}
std::error_condition chd_file::codec_process_hunk(uint32_t hunknum)
{
// punt if no file
if (UNEXPECTED(!m_file))
return std::error_condition(error::NOT_OPEN);
// return an error if out of range
if (UNEXPECTED(hunknum >= m_hunkcount))
return std::error_condition(error::HUNK_OUT_OF_RANGE);
// wrap this for clean reporting
try
{
// get a pointer to the map entry
switch (m_version)
{
// v3/v4 map entries
case 3:
case 4:
{
uint8_t const *const rawmap = &m_rawmap[16 * hunknum];
uint64_t const blockoffs = get_u64be(&rawmap[0]);
switch (rawmap[15] & V34_MAP_ENTRY_FLAG_TYPE_MASK)
{
case V34_MAP_ENTRY_TYPE_COMPRESSED:
{
uint32_t const blocklen = get_u16be(&rawmap[12]) | (uint32_t(rawmap[14]) << 16);
std::error_condition err = file_read(blockoffs, &m_compressed[0], blocklen);
if (UNEXPECTED(err))
return err;
m_decompressor[0]->process(&m_compressed[0], blocklen);
return std::error_condition();
}
case V34_MAP_ENTRY_TYPE_UNCOMPRESSED:
case V34_MAP_ENTRY_TYPE_MINI:
return std::error_condition(error::UNSUPPORTED_FORMAT);
case V34_MAP_ENTRY_TYPE_SELF_HUNK:
return codec_process_hunk(blockoffs);
case V34_MAP_ENTRY_TYPE_PARENT_HUNK:
if (UNEXPECTED(m_parent_missing))
return std::error_condition(error::REQUIRES_PARENT);
return m_parent->codec_process_hunk(blockoffs);
}
}
break;
// v5 map entries
case 5:
{
if (UNEXPECTED(!compressed()))
return std::error_condition(error::UNSUPPORTED_FORMAT);
// compressed case
uint8_t const *const rawmap = &m_rawmap[m_mapentrybytes * hunknum];
uint32_t const blocklen = get_u24be(&rawmap[1]);
uint64_t const blockoffs = get_u48be(&rawmap[4]);
switch (rawmap[0])
{
case COMPRESSION_TYPE_0:
case COMPRESSION_TYPE_1:
case COMPRESSION_TYPE_2:
case COMPRESSION_TYPE_3:
{
std::error_condition err = file_read(blockoffs, &m_compressed[0], blocklen);
if (UNEXPECTED(err))
return err;
auto &decompressor = *m_decompressor[rawmap[0]];
decompressor.process(&m_compressed[0], blocklen);
return std::error_condition();
}
case COMPRESSION_NONE:
return std::error_condition(error::UNSUPPORTED_FORMAT);
case COMPRESSION_SELF:
return codec_process_hunk(blockoffs);
case COMPRESSION_PARENT:
if (UNEXPECTED(m_parent_missing))
return std::error_condition(error::REQUIRES_PARENT);
return m_parent->codec_process_hunk(blockoffs / (m_parent->hunk_bytes() / m_parent->unit_bytes()));
}
break;
}
}
// if we get here, the map contained an unsupported block type
return std::error_condition(error::INVALID_DATA);
}
catch (std::error_condition const &err)
{
// just return errors
return err;
}
}
/**
* @fn std::error_condition chd_file::read_hunk(uint32_t hunknum, void *buffer)
*
@ -1045,7 +1144,7 @@ std::error_condition chd_file::read_hunk(uint32_t hunknum, void *buffer)
case COMPRESSION_PARENT:
if (UNEXPECTED(m_parent_missing))
return std::error_condition(error::REQUIRES_PARENT);
return m_parent->read_bytes(uint64_t(blockoffs) * uint64_t(m_parent->unit_bytes()), dest, m_hunkbytes);
return m_parent->read_bytes(blockoffs * m_parent->unit_bytes(), dest, m_hunkbytes);
}
}
break;

View File

@ -334,6 +334,7 @@ public:
void close();
// read/write
std::error_condition codec_process_hunk(uint32_t hunknum);
std::error_condition read_hunk(uint32_t hunknum, void *buffer);
std::error_condition write_hunk(uint32_t hunknum, const void *buffer);
std::error_condition read_units(uint64_t unitnum, void *buffer, uint32_t count = 1);

View File

@ -2,8 +2,6 @@
// copyright-holders:Aaron Giles
/***************************************************************************
chdcodec.c
Codecs used by the CHD format
***************************************************************************/
@ -333,16 +331,16 @@ private:
// ======================> chd_cd_compressor
template<class BaseCompressor, class SubcodeCompressor>
template <class BaseCompressor, class SubcodeCompressor>
class chd_cd_compressor : public chd_compressor
{
public:
// construction/destruction
chd_cd_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy)
: chd_compressor(chd, hunkbytes, lossy),
m_base_compressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SECTOR_DATA, lossy),
m_subcode_compressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SUBCODE_DATA, lossy),
m_buffer(hunkbytes + (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SUBCODE_DATA)
: chd_compressor(chd, hunkbytes, lossy)
, m_base_compressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SECTOR_DATA, lossy)
, m_subcode_compressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SUBCODE_DATA, lossy)
, m_buffer(hunkbytes + (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SUBCODE_DATA)
{
// make sure the CHD's hunk size is an even multiple of the frame size
if (hunkbytes % cdrom_file::FRAME_SIZE != 0)
@ -402,16 +400,16 @@ private:
// ======================> chd_cd_decompressor
template<class BaseDecompressor, class SubcodeDecompressor>
template <class BaseDecompressor, class SubcodeDecompressor>
class chd_cd_decompressor : public chd_decompressor
{
public:
// construction/destruction
chd_cd_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy)
: chd_decompressor(chd, hunkbytes, lossy),
m_base_decompressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SECTOR_DATA, lossy),
m_subcode_decompressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SUBCODE_DATA, lossy),
m_buffer(hunkbytes)
: chd_decompressor(chd, hunkbytes, lossy)
, m_base_decompressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SECTOR_DATA, lossy)
, m_subcode_decompressor(chd, (hunkbytes / cdrom_file::FRAME_SIZE) * cdrom_file::MAX_SUBCODE_DATA, lossy)
, m_buffer(hunkbytes)
{
// make sure the CHD's hunk size is an even multiple of the frame size
if (hunkbytes % cdrom_file::FRAME_SIZE != 0)
@ -490,6 +488,7 @@ public:
chd_avhuff_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy);
// core functionality
virtual void process(const uint8_t *src, uint32_t complen) override;
virtual void decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) override;
virtual void configure(int param, void *config) override;
@ -575,9 +574,9 @@ const codec_entry *find_in_list(chd_codec_type type) noexcept
//-------------------------------------------------
chd_codec::chd_codec(chd_file &chd, uint32_t hunkbytes, bool lossy)
: m_chd(chd),
m_hunkbytes(hunkbytes),
m_lossy(lossy)
: m_chd(chd)
, m_hunkbytes(hunkbytes)
, m_lossy(lossy)
{
}
@ -607,10 +606,6 @@ void chd_codec::configure(int param, void *config)
// CHD COMPRESSOR
//**************************************************************************
//-------------------------------------------------
// chd_compressor - constructor
//-------------------------------------------------
chd_compressor::chd_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy)
: chd_codec(chd, hunkbytes, lossy)
{
@ -622,15 +617,16 @@ chd_compressor::chd_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy)
// CHD DECOMPRESSOR
//**************************************************************************
//-------------------------------------------------
// chd_decompressor - constructor
//-------------------------------------------------
chd_decompressor::chd_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy)
: chd_codec(chd, hunkbytes, lossy)
{
}
void chd_decompressor::process(const uint8_t *src, uint32_t complen)
{
throw std::error_condition(chd_file::error::UNSUPPORTED_FORMAT);
}
//**************************************************************************
@ -1588,8 +1584,8 @@ void chd_flac_decompressor::decompress(const uint8_t *src, uint32_t complen, uin
//-------------------------------------------------
chd_cd_flac_compressor::chd_cd_flac_compressor(chd_file &chd, uint32_t hunkbytes, bool lossy)
: chd_compressor(chd, hunkbytes, lossy),
m_buffer(hunkbytes)
: chd_compressor(chd, hunkbytes, lossy)
, m_buffer(hunkbytes)
{
// make sure the CHD's hunk size is an even multiple of the frame size
if (hunkbytes % cdrom_file::FRAME_SIZE != 0)
@ -1717,8 +1713,8 @@ uint32_t chd_cd_flac_compressor::blocksize(uint32_t bytes)
*/
chd_cd_flac_decompressor::chd_cd_flac_decompressor(chd_file &chd, uint32_t hunkbytes, bool lossy)
: chd_decompressor(chd, hunkbytes, lossy),
m_buffer(hunkbytes)
: chd_decompressor(chd, hunkbytes, lossy)
, m_buffer(hunkbytes)
{
// make sure the CHD's hunk size is an even multiple of the frame size
if (hunkbytes % cdrom_file::FRAME_SIZE != 0)
@ -1943,21 +1939,13 @@ chd_avhuff_decompressor::chd_avhuff_decompressor(chd_file &chd, uint32_t hunkbyt
{
}
/**
* @fn void chd_avhuff_decompressor::decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
*
* @brief -------------------------------------------------
* decompress - decompress data using the A/V codec
* -------------------------------------------------.
*
* @exception CHDERR_DECOMPRESSION_ERROR Thrown when a chderr decompression error error
* condition occurs.
*
* @param src Source for the.
* @param complen The complen.
* @param [in,out] dest If non-null, destination for the.
* @param destlen The destlen.
*/
void chd_avhuff_decompressor::process(const uint8_t *src, uint32_t complen)
{
// decode the audio and video
avhuff_error averr = m_decoder.decode_data(src, complen, nullptr);
if (averr != AVHERR_NONE)
throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR);
}
void chd_avhuff_decompressor::decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
{
@ -1967,12 +1955,9 @@ void chd_avhuff_decompressor::decompress(const uint8_t *src, uint32_t complen, u
throw std::error_condition(chd_file::error::DECOMPRESSION_ERROR);
// pad short frames with 0
if (dest != nullptr)
{
int size = avhuff_encoder::raw_data_size(dest);
if (size < destlen)
memset(dest + size, 0, destlen - size);
}
auto const size = avhuff_encoder::raw_data_size(dest);
if (size < destlen)
memset(dest + size, 0, destlen - size);
}
/**

View File

@ -2,8 +2,6 @@
// copyright-holders:Aaron Giles
/***************************************************************************
chdcodec.h
Codecs used by the CHD format
***************************************************************************/
@ -89,6 +87,7 @@ public:
using ptr = std::unique_ptr<chd_decompressor>;
// implementation
virtual void process(const uint8_t *src, uint32_t complen);
virtual void decompress(const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) = 0;
};

View File

@ -39,9 +39,12 @@ public:
: driver_device(mconfig, type, tag)
, m_screen(*this, "screen")
, m_last_controls(0)
, m_playing(false) { }
, m_playing(false)
{
}
void ldplayer_ntsc(machine_config &config);
template <typename D, typename F>
void ldplayer_ntsc(machine_config &config, D &&player, F &&finder);
protected:
// device overrides
@ -107,14 +110,17 @@ class pr8210_state : public ldplayer_state
public:
// construction/destruction
pr8210_state(const machine_config &mconfig, device_type type, const char *tag)
: ldplayer_state(mconfig, type, tag),
m_laserdisc(*this, "laserdisc"),
m_command_buffer_in(0),
m_command_buffer_out(0) { }
: ldplayer_state(mconfig, type, tag)
, m_laserdisc(*this, "laserdisc")
, m_command_buffer_in(0)
, m_command_buffer_out(0)
{
}
void pr8210(machine_config &config);
void pr8210(machine_config &config);
protected:
// device overrides
// driver_device implementation
virtual void machine_start() override ATTR_COLD;
virtual void machine_reset() override ATTR_COLD;
@ -122,7 +128,7 @@ protected:
virtual void execute_command(int command) override;
// internal helpers
inline void add_command(uint8_t command);
void add_command(uint8_t command);
// timers
TIMER_CALLBACK_MEMBER(bit_on);
@ -144,10 +150,13 @@ class ldv1000_state : public ldplayer_state
public:
// construction/destruction
ldv1000_state(const machine_config &mconfig, device_type type, const char *tag)
: ldplayer_state(mconfig, type, tag),
m_laserdisc(*this, "laserdisc") { }
: ldplayer_state(mconfig, type, tag)
, m_laserdisc(*this, "laserdisc")
{
}
void ldv1000(machine_config &config);
void ldv1000(machine_config &config);
protected:
required_device<pioneer_ldv1000_device> m_laserdisc;
@ -341,7 +350,7 @@ void ldplayer_state::machine_reset()
*
*************************************/
void pr8210_state::add_command(uint8_t command)
inline void pr8210_state::add_command(uint8_t command)
{
m_command_buffer[m_command_buffer_in++ % std::size(m_command_buffer)] = (command & 0x1f) | 0x20;
m_command_buffer[m_command_buffer_in++ % std::size(m_command_buffer)] = 0x00 | 0x20;
@ -614,36 +623,34 @@ INPUT_PORTS_END
*
*************************************/
void ldplayer_state::ldplayer_ntsc(machine_config &config)
template <typename D, typename F>
void ldplayer_state::ldplayer_ntsc(machine_config &config, D &&player, F &&finder)
{
player(config, finder);
finder->set_get_disc(FUNC(ldplayer_state::get_disc));
finder->add_ntsc_screen(config, "screen");
}
void ldv1000_state::ldv1000(machine_config &config)
{
ldplayer_ntsc(config);
pioneer_ldv1000_device &laserdisc(PIONEER_LDV1000(config, "laserdisc"));
laserdisc.set_get_disc(FUNC(ldv1000_state::get_disc));
laserdisc.add_ntsc_screen(config, "screen");
ldplayer_ntsc(config, PIONEER_LDV1000, m_laserdisc);
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
laserdisc.add_route(0, "lspeaker", 1.0);
laserdisc.add_route(1, "rspeaker", 1.0);
m_laserdisc->add_route(0, "lspeaker", 1.0);
m_laserdisc->add_route(1, "rspeaker", 1.0);
}
void pr8210_state::pr8210(machine_config &config)
{
ldplayer_ntsc(config);
pioneer_pr8210_device &laserdisc(PIONEER_PR8210(config, "laserdisc"));
laserdisc.set_get_disc(FUNC(pr8210_state::get_disc));
laserdisc.add_ntsc_screen(config, "screen");
ldplayer_ntsc(config, PIONEER_PR8210, m_laserdisc);
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
laserdisc.add_route(0, "lspeaker", 1.0);
laserdisc.add_route(1, "rspeaker", 1.0);
m_laserdisc->add_route(0, "lspeaker", 1.0);
m_laserdisc->add_route(1, "rspeaker", 1.0);
}

View File

@ -3082,7 +3082,7 @@ static void do_extract_ld(parameters_map &params)
input_chd.codec_configure(CHD_CODEC_AVHUFF, AVHUFF_CODEC_DECOMPRESS_CONFIG, &avconfig);
// read the hunk into the buffers
std::error_condition err = input_chd.read_hunk(framenum, nullptr);
std::error_condition err = input_chd.codec_process_hunk(framenum);
if (err)
{
uint64_t filepos = ~uint64_t(0);

View File

@ -249,7 +249,7 @@ static bool read_chd(chd_file &file, uint32_t field, movie_info &info, uint32_t
file.codec_configure(CHD_CODEC_AVHUFF, AVHUFF_CODEC_DECOMPRESS_CONFIG, &avconfig);
// read the field
std::error_condition chderr = file.read_hunk(field, nullptr);
std::error_condition chderr = file.codec_process_hunk(field);
return !chderr;
}

View File

@ -252,7 +252,7 @@ static int read_chd(void *file, int frame, bitmap_yuy16 &bitmap, int16_t *lsound
chdfile->codec_configure(CHD_CODEC_AVHUFF, AVHUFF_CODEC_DECOMPRESS_CONFIG, &avconfig);
// read the frame
std::error_condition chderr = chdfile->read_hunk(frame * interlace_factor + fieldnum, nullptr);
std::error_condition chderr = chdfile->codec_process_hunk(frame * interlace_factor + fieldnum);
if (chderr)
return false;