From c96745578ffc52300e7371e5362d8b8a9f350d18 Mon Sep 17 00:00:00 2001 From: Moritz Bunkus Date: Mon, 2 Dec 2019 22:35:08 +0100 Subject: [PATCH] WAV reader: add support for RF64 files --- NEWS.md | 1 + src/input/r_wav.cpp | 52 ++++++++++++++++++++++++++++++++++++++++--- src/input/r_wav.h | 7 ++++++ tests/results.txt | 1 + tests/test-678rf64.rb | 5 +++++ 5 files changed, 63 insertions(+), 3 deletions(-) create mode 100755 tests/test-678rf64.rb diff --git a/NEWS.md b/NEWS.md index 55d97ded6..d4e977ac1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -26,6 +26,7 @@ * MKVToolNix GUI: update check: the dialog showing the latest news & version information states explicitly where the links take the user (the MKVToolNix `NEWS.md` file and YouTube respectively). +* mkvmerge: WAV reader: added support for reading RF64 files. ## Bug fixes diff --git a/src/input/r_wav.cpp b/src/input/r_wav.cpp index 5649824cc..13294b46a 100644 --- a/src/input/r_wav.cpp +++ b/src/input/r_wav.cpp @@ -64,6 +64,10 @@ wav_reader_c::determine_type() { && !std::memcmp(&wheader.riff.wave_id, "WAVE", 4)) return type_e::wave; + if ( !std::memcmp(&wheader.riff.id, "RF64", 4) + && !std::memcmp(&wheader.riff.wave_id, "WAVE", 4)) + return type_e::rf64; + if ( !std::memcmp(w64_header.riff.guid, mtx::w64::g_guid_riff, 16) && !std::memcmp(w64_header.wave_guid, mtx::w64::g_guid_wave, 16)) return type_e::wave64; @@ -138,9 +142,9 @@ wav_reader_c::parse_file() { void wav_reader_c::dump_headers() { - mxinfo(fmt::format("File '{0}' header dump (mode: {1})\n", m_ti.m_fname, m_type == type_e::wave ? "WAV" : "Wave64")); + mxinfo(fmt::format("File '{0}' header dump (mode: {1})\n", m_ti.m_fname, m_type == type_e::rf64 ? "RF64" : m_type == type_e::wave ? "WAV" : "Wave64")); - if (m_type == type_e::wave) + if ((m_type == type_e::rf64) || (m_type == type_e::wave)) mxinfo(fmt::format(" riff:\n" " id: {0}{1}{2}{3}\n" " len: {4}\n" @@ -149,6 +153,13 @@ wav_reader_c::dump_headers() { get_uint32_le(&m_wheader.riff.len), char(m_wheader.riff.wave_id[0]), char(m_wheader.riff.wave_id[1]), char(m_wheader.riff.wave_id[2]), char(m_wheader.riff.wave_id[3]))); + if (m_type == type_e::rf64) + mxinfo(fmt::format(" ds64:\n" + " riff_size: {0}\n" + " data_size: {1}\n" + " sample_count: {2}\n", + m_ds64.riff_size, m_ds64.data_size, m_ds64.sample_count)); + mxinfo(fmt::format(" common:\n" " wFormatTag: {0:04x}\n" " wChannels: {1}\n" @@ -235,12 +246,47 @@ wav_reader_c::read(generic_packetizer_c *, void wav_reader_c::scan_chunks() { - if (m_type == type_e::wave) + if (m_type == type_e::rf64) + scan_chunks_rf64(); + else if (m_type == type_e::wave) scan_chunks_wave(); else scan_chunks_wave64(); } +void +wav_reader_c::scan_chunks_rf64() { + scan_chunks_wave(); + + auto chunk_idx = find_chunk("ds64"); + auto debug_chunks = debugging_c::requested("wav_reader|wav_reader_chunks"); + + if (!chunk_idx) { + mxdebug_if(debug_chunks, fmt::format("scan_chunks_rf64() no ds64 chunk found\n")); + throw mtx::input::header_parsing_x(); + } + + auto const &chunk = m_chunks[*chunk_idx]; + + mxdebug_if(debug_chunks, fmt::format("scan_chunks_rf64() found ds64 at {0} size {1}\n", chunk.pos, chunk.len)); + + if (chunk.len < 24) + throw mtx::input::header_parsing_x(); + + m_in->setFilePointer(chunk.pos); + + m_ds64.riff_size = m_in->read_uint64_le(); + m_ds64.data_size = m_in->read_uint64_le(); + m_ds64.sample_count = m_in->read_uint64_le(); + + m_bytes_in_data_chunks = m_ds64.data_size; + + chunk_idx = find_chunk("data"); + + if (chunk_idx) + m_chunks[*chunk_idx].len = m_ds64.data_size; +} + void wav_reader_c::scan_chunks_wave() { m_in->setFilePointer(0); diff --git a/src/input/r_wav.h b/src/input/r_wav.h index dc9b6dc09..df5c7309e 100644 --- a/src/input/r_wav.h +++ b/src/input/r_wav.h @@ -58,8 +58,13 @@ struct wav_chunk_t { class wav_reader_c: public generic_reader_c { public: + struct ds64_chunk_t { + uint64_t riff_size{}, data_size{}, sample_count{}; + }; + enum class type_e { unknown, + rf64, wave, wave64, }; @@ -75,6 +80,7 @@ private: wav_demuxer_cptr m_demuxer; uint32_t m_format_tag; + ds64_chunk_t m_ds64; public: virtual mtx::file_type_e get_format_type() const { @@ -98,6 +104,7 @@ protected: boost::optional find_chunk(const char *id, int start_idx = 0, bool allow_empty = true); void scan_chunks(); + void scan_chunks_rf64(); void scan_chunks_wave(); void scan_chunks_wave64(); diff --git a/tests/results.txt b/tests/results.txt index 34f74574c..c271e4496 100644 --- a/tests/results.txt +++ b/tests/results.txt @@ -523,3 +523,4 @@ T_674ui_locale_bg_BG:dd68e655c0478092911742dc17732ad9-c4878d09282b7199ee7aac5860 T_675mp4_cover:fde70c906b8cd3e28f3575244e79b938-263986c0b88ed5d2e7e99bfc27e11077-060170d57bac3c83175be67abc289b27+060170d57bac3c83175be67abc289b27+true-ab252d885c54298aef5e588ca7a9caa3:passed:20191103-131313:0.260241763 T_676cover_art_vorbis_opus:51817472f0c8e80978da32091bdb0787-0cee77f31051e123a9e38ae2e9b728c2-72e193b0682dad985317cd03d2be1ab9+72e193b0682dad985317cd03d2be1ab9+true-11715255451ec40862d95c8a71c331ec-b36830d164a318af72c40cf6a2f57b1f-72e193b0682dad985317cd03d2be1ab9+72e193b0682dad985317cd03d2be1ab9+true-51817472f0c8e80978da32091bdb0787-df51bd4a5723741480be7c6fe2874a7e-e55849ace1748ac515b16881e397101a+e55849ace1748ac515b16881e397101a+true-11715255451ec40862d95c8a71c331ec-6c91f480a84a3ac81f51728a81f3706c-e55849ace1748ac515b16881e397101a+e55849ace1748ac515b16881e397101a+true:passed:20191110-132634:0.286118478 T_677vorbis_in_matroska_with_comments:41b4fa33ce8acdd4f98f2d8a2cf90874-e8ce8a969fb44adfbd6411d909d5f89f-d038d66d9c8d9af5b31103645640fb8d-517bbf85726d51c831b476d6cd503ec3-98b764f6d71c45e0302cd8ef65d1fb6d:passed:20191201-213124:0.250158232 +T_678rf64:20f16e90d6877679fc0deada17ab520b:passed:20191202-223330:0.055722438 diff --git a/tests/test-678rf64.rb b/tests/test-678rf64.rb new file mode 100755 index 000000000..c0bec163a --- /dev/null +++ b/tests/test-678rf64.rb @@ -0,0 +1,5 @@ +#!/usr/bin/ruby -w + +# T_678rf64 +describe "mkvmerge / reading WAV of type RF64" +test_merge "data/wav/v.rf64"