1 /*
2 mkvmerge -- utility for splicing together matroska files
3 from component media subtypes
4
5 Distributed under the GPL v2
6 see the file COPYING for details
7 or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
8
9 FLAC packetizer
10
11 Written by Moritz Bunkus <moritz@bunkus.org>.
12 */
13
14 #include "common/common_pch.h"
15
16 #if defined(HAVE_FLAC_FORMAT_H)
17
18 #include <ogg/ogg.h>
19 #include <vorbis/codec.h>
20
21 #include "common/checksums/base.h"
22 #include "common/codec.h"
23 #include "common/flac.h"
24 #include "common/hacks.h"
25 #include "merge/connection_checks.h"
26 #include "output/p_flac.h"
27
28 using namespace libmatroska;
29
flac_packetizer_c(generic_reader_c * p_reader,track_info_c & p_ti,unsigned char * header,int l_header)30 flac_packetizer_c::flac_packetizer_c(generic_reader_c *p_reader,
31 track_info_c &p_ti,
32 unsigned char *header,
33 int l_header)
34 : generic_packetizer_c(p_reader, p_ti)
35 , m_header{memory_c::clone(header, l_header)}
36 {
37 int result;
38
39 if ((4 > l_header) || memcmp(header, "fLaC", 4)) {
40 m_header->resize(l_header + 4);
41 memcpy(m_header->get_buffer(), "fLaC", 4);
42 memcpy(m_header->get_buffer() + 4, header, l_header);
43 }
44
45
46 result = mtx::flac::decode_headers(m_header->get_buffer(), m_header->get_size(), 1, mtx::flac::HEADER_STREAM_INFO, &m_stream_info);
47 if (!(result & mtx::flac::HEADER_STREAM_INFO))
48 mxerror_tid(m_ti.m_fname, m_ti.m_id, Y("The FLAC headers could not be parsed: the stream info structure was not found.\n"));
49
50 set_track_type(track_audio);
51 if (m_stream_info.min_blocksize == m_stream_info.max_blocksize)
52 set_track_default_duration((int64_t)(1000000000ll * m_stream_info.min_blocksize / m_stream_info.sample_rate));
53 }
54
~flac_packetizer_c()55 flac_packetizer_c::~flac_packetizer_c() {
56 }
57
58 void
set_headers()59 flac_packetizer_c::set_headers() {
60 set_codec_id(MKV_A_FLAC);
61 set_codec_private(m_header);
62 set_audio_sampling_freq(m_stream_info.sample_rate);
63 set_audio_channels(m_stream_info.channels);
64 set_audio_bit_depth(m_stream_info.bits_per_sample);
65
66 generic_packetizer_c::set_headers();
67 }
68
69 void
process_impl(packet_cptr const & packet)70 flac_packetizer_c::process_impl(packet_cptr const &packet) {
71 m_num_packets++;
72
73 packet->duration = mtx::flac::get_num_samples(packet->data->get_buffer(), packet->data->get_size(), m_stream_info);
74
75 if (-1 == packet->duration) {
76 mxwarn_tid(m_ti.m_fname, m_ti.m_id, fmt::format(Y("Packet number {0} contained an invalid FLAC header and is being skipped.\n"), m_num_packets));
77 return;
78 }
79
80 packet->duration = packet->duration * 1000000000ll / m_stream_info.sample_rate;
81 add_packet(packet);
82 }
83
84 connection_result_e
can_connect_to(generic_packetizer_c * src,std::string & error_message)85 flac_packetizer_c::can_connect_to(generic_packetizer_c *src,
86 std::string &error_message) {
87 if (!mtx::hacks::is_engaged(mtx::hacks::APPEND_AND_SPLIT_FLAC))
88 return CAN_CONNECT_NO_UNSUPPORTED;
89
90 flac_packetizer_c *fsrc = dynamic_cast<flac_packetizer_c *>(src);
91 if (!fsrc)
92 return CAN_CONNECT_NO_FORMAT;
93
94 connect_check_a_samplerate(m_stream_info.sample_rate, fsrc->m_stream_info.sample_rate);
95 connect_check_a_channels(m_stream_info.channels, fsrc->m_stream_info.channels);
96 connect_check_a_bitdepth(m_stream_info.bits_per_sample, fsrc->m_stream_info.bits_per_sample);
97
98 return CAN_CONNECT_YES;
99 }
100
101 split_result_e
can_be_split(std::string &)102 flac_packetizer_c::can_be_split(std::string &/* error_message */) {
103 if (mtx::hacks::is_engaged(mtx::hacks::APPEND_AND_SPLIT_FLAC)) {
104 return CAN_SPLIT_YES;
105 }
106
107 return CAN_SPLIT_NO_UNSUPPORTED;
108 }
109
110 #endif
111