diff --git a/src/input/bluray_pcm_channel_layout_packet_converter.cpp b/src/input/bluray_pcm_channel_layout_packet_converter.cpp new file mode 100644 index 000000000..aeb113aff --- /dev/null +++ b/src/input/bluray_pcm_channel_layout_packet_converter.cpp @@ -0,0 +1,128 @@ +/* + mkvmerge -- utility for splicing together matroska files + from component media subtypes + + Distributed under the GPL v2 + see the file COPYING for details + or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html + + Fix channel layout for Blu-ray PCM + + Written by Moritz Bunkus . +*/ + +#include "common/common_pch.h" + +#include "input/bluray_pcm_channel_layout_packet_converter.h" +#include "merge/generic_packetizer.h" + +bluray_pcm_channel_layout_packet_converter_c::bluray_pcm_channel_layout_packet_converter_c(std::size_t bytes_per_channel, + std::size_t num_input_channels, + std::size_t num_output_channels) + : packet_converter_c{nullptr} + , m_bytes_per_channel{bytes_per_channel} + , m_num_input_channels{num_input_channels} + , m_num_output_channels{num_output_channels} + , m_remap_buf_size{} + , m_remap{} +{ + if (m_num_output_channels == 6) { + m_remap_buf_size = m_bytes_per_channel * 3; + m_remap = &bluray_pcm_channel_layout_packet_converter_c::remap_6ch; + } else if (m_num_output_channels == 7) { + m_remap_buf_size = m_bytes_per_channel * 3; + m_remap = &bluray_pcm_channel_layout_packet_converter_c::remap_7ch; + } else if (m_num_output_channels == 8) { + m_remap_buf_size = m_bytes_per_channel * 5; + m_remap = &bluray_pcm_channel_layout_packet_converter_c::remap_8ch; + } + + if (m_remap_buf_size > 0) + m_remap_buf = memory_c::alloc(m_remap_buf_size); +} + +void +bluray_pcm_channel_layout_packet_converter_c::removal(packet_cptr const &packet) { + auto start_ptr = packet->data->get_buffer(); + auto end_ptr = start_ptr + packet->data->get_size(); + auto input_ptr = start_ptr; + auto output_ptr = start_ptr; + auto input_bytes_per_iteration = m_bytes_per_channel * m_num_input_channels; + auto output_bytes_per_iteration = m_bytes_per_channel * m_num_output_channels; + + while ((input_ptr + input_bytes_per_iteration) <= end_ptr) { + if (input_ptr != output_ptr) + std::memmove(output_ptr, input_ptr, output_bytes_per_iteration); + + input_ptr += input_bytes_per_iteration; + output_ptr += output_bytes_per_iteration; + } + + packet->data->set_size(output_ptr - start_ptr); +} + +void +bluray_pcm_channel_layout_packet_converter_c::remap_6ch(packet_cptr const &packet) { + auto start_ptr = packet->data->get_buffer(); + auto end_ptr = start_ptr + packet->data->get_size(); + + // post-remap order: FL FR FC LFE BL BR + while (start_ptr != end_ptr) { + start_ptr += m_bytes_per_channel * 3; + memcpy(m_remap_buf->get_buffer(), start_ptr, m_remap_buf_size); + memcpy(start_ptr, m_remap_buf->get_buffer() + m_bytes_per_channel * 2, m_bytes_per_channel); + memcpy(start_ptr + m_bytes_per_channel, m_remap_buf->get_buffer(), m_bytes_per_channel * 2); + start_ptr += m_remap_buf_size; + } +} + +void +bluray_pcm_channel_layout_packet_converter_c::remap_7ch(packet_cptr const &packet) { + auto start_ptr = packet->data->get_buffer(); + auto end_ptr = start_ptr + packet->data->get_size(); + + // post-remap order: FL FR FC BL BR SL SR + while (start_ptr != end_ptr) { + start_ptr += m_bytes_per_channel * 3; + memcpy(m_remap_buf->get_buffer(), start_ptr, m_remap_buf_size); + memcpy(start_ptr, m_remap_buf->get_buffer() + m_bytes_per_channel, m_bytes_per_channel * 2); + memcpy(start_ptr + m_bytes_per_channel * 2, m_remap_buf->get_buffer(), m_bytes_per_channel); + start_ptr += m_remap_buf_size + m_bytes_per_channel; + } +} + +void +bluray_pcm_channel_layout_packet_converter_c::remap_8ch(packet_cptr const &packet) { + auto start_ptr = packet->data->get_buffer(); + auto end_ptr = start_ptr + packet->data->get_size(); + + // post-remap order: FL FR FC LFE BL BR SL SR + while (start_ptr != end_ptr) { + start_ptr += m_bytes_per_channel * 3; + memcpy(m_remap_buf->get_buffer(), start_ptr, m_remap_buf_size); + memcpy(start_ptr, m_remap_buf->get_buffer() + m_bytes_per_channel * 4, m_bytes_per_channel); + // BL and BR stay at the same place + memcpy(start_ptr + m_bytes_per_channel * 3, m_remap_buf->get_buffer(), m_bytes_per_channel); + memcpy(start_ptr + m_bytes_per_channel * 4, + m_remap_buf->get_buffer() + m_bytes_per_channel * 3, m_bytes_per_channel); + start_ptr += m_remap_buf_size; + } +} + +bool +bluray_pcm_channel_layout_packet_converter_c::convert(packet_cptr const &packet) { + // remove superfluous extra channel + if ((m_num_output_channels % 2) != 0) + removal(packet); + + // remap channels into WAVEFORMATEXTENSIBLE channel order + if (m_remap_buf) { + auto remainder = packet->data->get_size() % (m_bytes_per_channel * m_num_output_channels); + if (remainder != 0) + packet->data->set_size(packet->data->get_size() - remainder); + (this->*m_remap)(packet); + } + + m_ptzr->process(packet); + return true; +} diff --git a/src/input/bluray_pcm_channel_layout_packet_converter.h b/src/input/bluray_pcm_channel_layout_packet_converter.h new file mode 100644 index 000000000..a0a731591 --- /dev/null +++ b/src/input/bluray_pcm_channel_layout_packet_converter.h @@ -0,0 +1,36 @@ +/* + mkvmerge -- utility for splicing together matroska files + from component media subtypes + + Distributed under the GPL v2 + see the file COPYING for details + or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html + + class definitions for the Blu-ray PCM channel layout converter + + Written by Moritz Bunkus . +*/ + +#pragma once + +#include "common/common_pch.h" + +#include "common/truehd.h" +#include "input/packet_converter.h" + +class bluray_pcm_channel_layout_packet_converter_c: public packet_converter_c { +protected: + std::size_t m_bytes_per_channel, m_num_input_channels, m_num_output_channels, m_remap_buf_size; + memory_cptr m_remap_buf; + void (bluray_pcm_channel_layout_packet_converter_c::*m_remap)(packet_cptr const &packet); + +public: + bluray_pcm_channel_layout_packet_converter_c(std::size_t bytes_per_channel, std::size_t num_input_channels, std::size_t num_output_channels); + virtual ~bluray_pcm_channel_layout_packet_converter_c() {}; + + virtual void removal(packet_cptr const &packet); + virtual void remap_6ch(packet_cptr const &packet); + virtual void remap_7ch(packet_cptr const &packet); + virtual void remap_8ch(packet_cptr const &packet); + virtual bool convert(packet_cptr const &packet); +}; diff --git a/src/input/bluray_pcm_channel_removal_packet_converter.cpp b/src/input/bluray_pcm_channel_removal_packet_converter.cpp deleted file mode 100644 index 4d0472d24..000000000 --- a/src/input/bluray_pcm_channel_removal_packet_converter.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - mkvmerge -- utility for splicing together matroska files - from component media subtypes - - Distributed under the GPL v2 - see the file COPYING for details - or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html - - Removal of superfluous extra channel on Blu-ray PCM with odd number of channels - - Written by Moritz Bunkus . -*/ - -#include "common/common_pch.h" - -#include "input/bluray_pcm_channel_removal_packet_converter.h" -#include "merge/generic_packetizer.h" - -bluray_pcm_channel_removal_packet_converter_c::bluray_pcm_channel_removal_packet_converter_c(std::size_t bytes_per_channel, - std::size_t num_input_channels, - std::size_t num_output_channels) - : packet_converter_c{nullptr} - , m_bytes_per_channel{bytes_per_channel} - , m_num_input_channels{num_input_channels} - , m_num_output_channels{num_output_channels} -{ -} - -bool -bluray_pcm_channel_removal_packet_converter_c::convert(packet_cptr const &packet) { - auto start_ptr = packet->data->get_buffer(); - auto end_ptr = start_ptr + packet->data->get_size(); - auto input_ptr = start_ptr; - auto output_ptr = start_ptr; - auto input_bytes_per_iteration = m_bytes_per_channel * m_num_input_channels; - auto output_bytes_per_iteration = m_bytes_per_channel * m_num_output_channels; - - while ((input_ptr + input_bytes_per_iteration) <= end_ptr) { - if (input_ptr != output_ptr) - std::memmove(output_ptr, input_ptr, output_bytes_per_iteration); - - input_ptr += input_bytes_per_iteration; - output_ptr += output_bytes_per_iteration; - } - - packet->data->set_size(output_ptr - start_ptr); - - m_ptzr->process(packet); - - return true; -} diff --git a/src/input/bluray_pcm_channel_removal_packet_converter.h b/src/input/bluray_pcm_channel_removal_packet_converter.h deleted file mode 100644 index 6a84957ac..000000000 --- a/src/input/bluray_pcm_channel_removal_packet_converter.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - mkvmerge -- utility for splicing together matroska files - from component media subtypes - - Distributed under the GPL v2 - see the file COPYING for details - or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html - - class definitions for the Blu-ray PCM channel removal converter - - Written by Moritz Bunkus . -*/ - -#pragma once - -#include "common/common_pch.h" - -#include "common/truehd.h" -#include "input/packet_converter.h" - -class bluray_pcm_channel_removal_packet_converter_c: public packet_converter_c { -protected: - std::size_t m_bytes_per_channel, m_num_input_channels, m_num_output_channels; - -public: - bluray_pcm_channel_removal_packet_converter_c(std::size_t bytes_per_channel, std::size_t num_input_channels, std::size_t num_output_channels); - virtual ~bluray_pcm_channel_removal_packet_converter_c() {}; - - virtual bool convert(packet_cptr const &packet); -}; diff --git a/src/input/r_mpeg_ts.cpp b/src/input/r_mpeg_ts.cpp index 98ef670f6..c9fcdb198 100644 --- a/src/input/r_mpeg_ts.cpp +++ b/src/input/r_mpeg_ts.cpp @@ -40,7 +40,7 @@ #include "common/regex.h" #include "common/strings/formatting.h" #include "input/aac_framing_packet_converter.h" -#include "input/bluray_pcm_channel_removal_packet_converter.h" +#include "input/bluray_pcm_channel_layout_packet_converter.h" #include "input/dvbsub_pes_framing_removal_packet_converter.h" #include "input/r_mpeg_ts.h" #include "input/teletext_to_srt_packet_converter.h" @@ -433,8 +433,7 @@ track_c::new_stream_a_pcm() { if ((a_sample_rate == 0) || !mtx::included_in(a_bits_per_sample, 16, 24)) return FILE_STATUS_DONE; - if ((a_channels % 2) != 0) - converter = std::make_shared(a_bits_per_sample / 8, a_channels + 1, a_channels); + converter = std::make_shared(a_bits_per_sample / 8, a_channels + 1, a_channels); return 0; }