diff --git a/ChangeLog b/ChangeLog index d0b8b906e..23a53a094 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2016-03-07 Moritz Bunkus + * mkvextract: new feature: implemented the extraction of Big + Endian PCM (codec ID A_PCM/INT/BIG) to WAV files. The content will + be byte-swapped into Little Endian PCM in the process. + * mkvmerge: enhancement: Big Endian PCM tracks will now be byte-swapped into Little Endian PCM, and the codec ID A_PCM/INT/LIT will be used. This was done due to a lot of players diff --git a/src/extract/xtr_base.cpp b/src/extract/xtr_base.cpp index 60093fdf0..5900e2396 100644 --- a/src/extract/xtr_base.cpp +++ b/src/extract/xtr_base.cpp @@ -19,6 +19,7 @@ #include "common/codec.h" #include "common/ebml.h" +#include "common/list_utils.h" #include "common/mm_io_x.h" #include "common/mm_write_buffer_io.h" #include "common/strings/editing.h" @@ -142,7 +143,7 @@ xtr_base_c::create_extractor(const std::string &new_codec_id, return new xtr_base_c(new_codec_id, new_tid, tspec, "MPEG-1 Audio Layer 2/3"); else if (new_codec_id == MKV_A_DTS) return new xtr_base_c(new_codec_id, new_tid, tspec, "Digital Theater System (DTS)"); - else if (new_codec_id == MKV_A_PCM) + else if (mtx::included_in(new_codec_id, MKV_A_PCM, MKV_A_PCM_BE)) return new xtr_wav_c(new_codec_id, new_tid, tspec); else if (new_codec_id == MKV_A_FLAC) return new xtr_flac_c(new_codec_id, new_tid, tspec); diff --git a/src/extract/xtr_wav.cpp b/src/extract/xtr_wav.cpp index 194513702..29d3764e9 100644 --- a/src/extract/xtr_wav.cpp +++ b/src/extract/xtr_wav.cpp @@ -16,8 +16,11 @@ #include #include "avilib.h" +#include "common/bswap.h" +#include "common/codec.h" #include "common/ebml.h" #include "common/endian.h" +#include "common/list_utils.h" #include "common/mm_io_x.h" #include "common/mm_write_buffer_io.h" #include "extract/xtr_wav.h" @@ -60,6 +63,11 @@ xtr_wav_c::create_file(xtr_base_c *master, put_uint16_le(&m_wh.common.wBitsPerSample, bps); m_out->write(&m_wh, sizeof(wave_header)); + + if ((m_codec_id == MKV_A_PCM_BE) && mtx::included_in(bps, 16, 32, 64)) + m_byte_swapper = bps == 16 ? mtx::bswap_buffer_16 + : bps == 32 ? mtx::bswap_buffer_32 + : mtx::bswap_buffer_64; } void @@ -72,6 +80,15 @@ xtr_wav_c::finish_file() { m_out->write(&m_wh, sizeof(wave_header)); } +void +xtr_wav_c::handle_frame(xtr_frame_t &f) { + if (m_byte_swapper) + m_byte_swapper(f.frame->get_buffer(), f.frame->get_buffer(), f.frame->get_size()); + + m_out->write(f.frame); + m_bytes_written += f.frame->get_size(); +} + // ------------------------------------------------------------------------ xtr_wavpack4_c::xtr_wavpack4_c(const std::string &codec_id, diff --git a/src/extract/xtr_wav.h b/src/extract/xtr_wav.h index 7981dd5b2..5b9a51554 100644 --- a/src/extract/xtr_wav.h +++ b/src/extract/xtr_wav.h @@ -20,12 +20,14 @@ class xtr_wav_c: public xtr_base_c { private: wave_header m_wh; + std::function m_byte_swapper; public: xtr_wav_c(const std::string &codec_id, int64_t tid, track_spec_t &tspec); virtual void create_file(xtr_base_c *master, KaxTrackEntry &track) override; virtual void finish_file() override; + virtual void handle_frame(xtr_frame_t &f) override; virtual const char *get_container_name() override { return "WAV"; diff --git a/tests/results.txt b/tests/results.txt index d362e9198..0d9b0578a 100644 --- a/tests/results.txt +++ b/tests/results.txt @@ -381,3 +381,4 @@ T_532chapter_generation_when_appending:5680a0ca3f974d43ff7e4c7482812a4c-ea8f0f1e T_533chapter_generation_interval:63486951fe0717eec1e93cb8fadaed92-5a57214bb210f51311edc6e8fca19f3e-cbbd43701884c34ae5d1efd9baf39a04+0e5962f224c28b3a7fc2a318fddd7ea9+74621b5528a14b9bee0aa6b8ac28693b+dfb83af32a6472c8e2d41238b89c7521+b60c9078501798a674db97c83fd99b14+e662cf60c4365aaeff7e6b088904739d+32c2cea8051c9f848e090aac1b761cb7+ok-c3b953881e1f7d35d58ab0bfe590d7ba:passed:20160301-194459:2.043516559 T_534chapter_generation_when_appending_audio_only:000e4bfced4fae128abbb741545768c8-39028cc1508e5a37f879b3a459f3dbd2-fb20e8f516702d6a0fb9299120e6b508+e66dbfdf351112c62aa65faccdce8ee1+c4dc3cd790ee8397d0a6bdca84091981+3d716d93d0178aeabc66111b4dc10d9a+4fe4b6a15803e0c8d400ce07b4a9d48e+8b5ccf0e1b9fcba119d40727b9b7e8e4+f3f355cb0549efabdd9954f4448fc48d+ok-e668981666602602e2ed5a1b8d47f6db:passed:20160302-130929:0.645667954 T_535chapter_generation_interval_audio_only:4231b50be18c4320584d7e18c611431d-7149e4b581f601145db038035aba3ec4-7b37e30bfede450fec2a5e7b1e982b35+bb66d81871625190fbd7b15b02f6ca57+1285f17cbdb1259606bd7174e993b3f1+c0877adb7bf88212aae2212ab819cf57+78fcd2002d1a48752c5a8e4730cc2158+b2a259375cb03683b7fe6ffe95a53e21+f3f355cb0549efabdd9954f4448fc48d+ok-8f16b1baaedec4b22df0f566b39a105e:passed:20160302-131002:0.64531153 +T_536extract_big_endian_pcm:8e57291db3e924e9bb45acb306426a0a:passed:20160307-190156:0.015845204 diff --git a/tests/test-536extract_big_endian_pcm.rb b/tests/test-536extract_big_endian_pcm.rb new file mode 100755 index 000000000..75f82d918 --- /dev/null +++ b/tests/test-536extract_big_endian_pcm.rb @@ -0,0 +1,9 @@ +#!/usr/bin/ruby -w + +# T_536extract_big_endian_pcm +describe "mkvextract / extract Big Endian PCM" + +test "extraction" do + extract "data/mkv/big-endian-pcm.mka", 0 => tmp + hash_tmp +end