From ad459a9025b1fb2285041d32d7c21cb87e11a8f5 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Mon, 14 Oct 2024 03:22:17 +1100 Subject: util/chd.cpp, util/chdcodec.cpp: Added a safer way to let codecs do special stuff with hunks. --- src/devices/imagedev/harddriv.cpp | 2 +- src/devices/machine/laserdsc.cpp | 18 +++---- src/devices/machine/laserdsc.h | 7 ++- src/lib/util/chd.cpp | 101 +++++++++++++++++++++++++++++++++++++- src/lib/util/chd.h | 1 + src/lib/util/chdcodec.cpp | 81 +++++++++++++----------------- src/lib/util/chdcodec.h | 3 +- src/mame/virtual/ldplayer.cpp | 59 ++++++++++++---------- src/tools/chdman.cpp | 2 +- src/tools/ldresample.cpp | 2 +- src/tools/ldverify.cpp | 2 +- 11 files changed, 183 insertions(+), 95 deletions(-) diff --git a/src/devices/imagedev/harddriv.cpp b/src/devices/imagedev/harddriv.cpp index 14f4337f9d8..078131fca6b 100644 --- a/src/devices/imagedev/harddriv.cpp +++ b/src/devices/imagedev/harddriv.cpp @@ -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 diff --git a/src/devices/machine/laserdsc.cpp b/src/devices/machine/laserdsc.cpp index 246369f15ef..e1033518cb5 100644 --- a/src/devices/machine/laserdsc.cpp +++ b/src/devices/machine/laserdsc.cpp @@ -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(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; } diff --git a/src/devices/machine/laserdsc.h b/src/devices/machine/laserdsc.h index 6bd2f8299d9..04e980ae64e 100644 --- a/src/devices/machine/laserdsc.h +++ b/src/devices/machine/laserdsc.h @@ -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 #include @@ -98,7 +97,7 @@ protected: public: // delegates - typedef device_delegate get_disc_delegate; + typedef device_delegate get_disc_delegate; typedef device_delegate audio_delegate; laserdisc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); diff --git a/src/lib/util/chd.cpp b/src/lib/util/chd.cpp index 14484575e7f..08dcd43f9f1 100644 --- a/src/lib/util/chd.cpp +++ b/src/lib/util/chd.cpp @@ -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; diff --git a/src/lib/util/chd.h b/src/lib/util/chd.h index 9ea40bb9136..671f4bdbd01 100644 --- a/src/lib/util/chd.h +++ b/src/lib/util/chd.h @@ -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); diff --git a/src/lib/util/chdcodec.cpp b/src/lib/util/chdcodec.cpp index c0110002265..c8a1f573bd0 100644 --- a/src/lib/util/chdcodec.cpp +++ b/src/lib/util/chdcodec.cpp @@ -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 +template 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 +template 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); } /** diff --git a/src/lib/util/chdcodec.h b/src/lib/util/chdcodec.h index 08235ecaae6..c477333544f 100644 --- a/src/lib/util/chdcodec.h +++ b/src/lib/util/chdcodec.h @@ -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; // 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; }; diff --git a/src/mame/virtual/ldplayer.cpp b/src/mame/virtual/ldplayer.cpp index 2463d24d225..3e61d910029 100644 --- a/src/mame/virtual/ldplayer.cpp +++ b/src/mame/virtual/ldplayer.cpp @@ -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 + 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 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 +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); } diff --git a/src/tools/chdman.cpp b/src/tools/chdman.cpp index 797d48c83dc..e7aca251dd7 100644 --- a/src/tools/chdman.cpp +++ b/src/tools/chdman.cpp @@ -3082,7 +3082,7 @@ static void do_extract_ld(parameters_map ¶ms) 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); diff --git a/src/tools/ldresample.cpp b/src/tools/ldresample.cpp index 0836fd4b7a9..4fcd19c3afc 100644 --- a/src/tools/ldresample.cpp +++ b/src/tools/ldresample.cpp @@ -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; } diff --git a/src/tools/ldverify.cpp b/src/tools/ldverify.cpp index bb95c3fbad4..bdb3b8c0a1f 100644 --- a/src/tools/ldverify.cpp +++ b/src/tools/ldverify.cpp @@ -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; -- cgit v1.2.3