1 /*
2 mkvextract -- extract tracks from Matroska files into other files
3
4 Distributed under the GPL v2
5 see the file COPYING for details
6 or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
7
8 extracts tracks from Matroska files into other files
9
10 Written by Moritz Bunkus <moritz@bunkus.org>.
11 */
12
13 #include "common/common_pch.h"
14
15 #include <matroska/KaxBlock.h>
16
17 #include "common/alac.h"
18 #include "common/caf.h"
19 #include "common/ebml.h"
20 #include "common/endian.h"
21 #include "common/mm_proxy_io.h"
22 #include "common/mm_write_buffer_io.h"
23
24 #include "extract/xtr_alac.h"
25 #include "extract/xtr_base.h"
26
xtr_alac_c(std::string const & codec_id,int64_t tid,track_spec_t & tspec)27 xtr_alac_c::xtr_alac_c(std::string const &codec_id,
28 int64_t tid,
29 track_spec_t &tspec)
30 : xtr_base_c(codec_id, tid, tspec)
31 , m_priv{}
32 , m_free_chunk_size{}
33 , m_free_chunk_offset{}
34 , m_data_chunk_offset{}
35 , m_frames_written{}
36 , m_packets_written{}
37 , m_prev_written{}
38 {
39 }
40
41 void
create_file(xtr_base_c * master,libmatroska::KaxTrackEntry & track)42 xtr_alac_c::create_file(xtr_base_c *master,
43 libmatroska::KaxTrackEntry &track) {
44 init_content_decoder(track);
45
46 auto channels = kt_get_a_channels(track);
47 auto priv = FindChild<libmatroska::KaxCodecPrivate>(&track);
48 if (!priv)
49 mxerror(fmt::format(Y("Track {0} with the CodecID '{1}' is missing the \"codec private\" element and cannot be extracted.\n"), m_tid, m_codec_id));
50
51 m_priv = decode_codec_private(priv);
52 if (m_priv->get_size() != sizeof(mtx::alac::codec_config_t))
53 mxerror(fmt::format(Y("ALAC private data size mismatch\n")));
54
55 xtr_base_c::create_file(master, track);
56
57 m_out->write("caff"s); // mFileType
58 m_out->write_uint16_be(1); // mFileVersion
59 m_out->write_uint16_be(0); // mFileFlags
60
61 m_out->write("desc"s); // Audio Description chunk
62 m_out->write_uint64_be(32ULL); // mChunkSize
63 m_out->write_double(static_cast<int>(kt_get_a_sfreq(track))); // mSampleRate
64 m_out->write("alac"s); // mFormatID
65 m_out->write_uint32_be(0); // mFormatFlags
66 m_out->write_uint32_be(0); // mBytesPerPacket
67 m_out->write_uint32_be(mtx::caf::defs::default_frames_per_packet); // mFramesPerPacket
68 m_out->write_uint32_be(channels); // mChannelsPerFrame
69 m_out->write_uint32_be(0); // mBitsPerChannel
70
71 auto kuki_size = 12 + 36 + 8 + (2 < channels ? 24 : 0); // add the size of ALACChannelLayoutInfo for more than 2 channels
72 m_out->write("kuki"s);
73 m_out->write_uint64_be(kuki_size);
74 m_out->write_uint8('\0');
75 m_out->write_uint8('\0');
76 m_out->write_uint8('\0');
77 m_out->write_uint8('\14');
78 m_out->write("frma"s);
79 m_out->write("alac"s);
80
81 m_out->write_uint32_be(12 + sizeof(mtx::alac::codec_config_t)); // ALAC Specific Info size = 36 (12 + sizeof(ALAXSpecificConfig))
82 m_out->write("alac"s); // ALAC Specific Info ID
83 m_out->write_uint32_be(0L); // Version Flags
84
85 m_out->write(m_priv); // audio specific config
86
87 auto alo = mtx::caf::channel_layout_t();
88 if (2 < channels) {
89 switch (channels) {
90 case 3:
91 alo.channel_layout_tag = mtx::caf::channel_layout_t::mpeg_3_0_b;
92 alo.channel_bitmap = mtx::caf::channel_layout_t::left | mtx::caf::channel_layout_t::right | mtx::caf::channel_layout_t::center;
93 break;
94 case 4:
95 alo.channel_layout_tag = mtx::caf::channel_layout_t::mpeg_4_0_b;
96 alo.channel_bitmap = mtx::caf::channel_layout_t::left | mtx::caf::channel_layout_t::right | mtx::caf::channel_layout_t::center | mtx::caf::channel_layout_t::center_surround;
97 break;
98 case 5:
99 alo.channel_layout_tag = mtx::caf::channel_layout_t::mpeg_5_0_d;
100 alo.channel_bitmap = mtx::caf::channel_layout_t::left | mtx::caf::channel_layout_t::right | mtx::caf::channel_layout_t::center
101 | mtx::caf::channel_layout_t::left_surround | mtx::caf::channel_layout_t::right_surround;
102 break;
103 case 6:
104 alo.channel_layout_tag = mtx::caf::channel_layout_t::mpeg_5_1_d;
105 alo.channel_bitmap = mtx::caf::channel_layout_t::left | mtx::caf::channel_layout_t::right | mtx::caf::channel_layout_t::center
106 | mtx::caf::channel_layout_t::left_surround | mtx::caf::channel_layout_t::right_surround | mtx::caf::channel_layout_t::lfe_screen;
107 break;
108 case 7:
109 alo.channel_layout_tag = mtx::caf::channel_layout_t::aac_6_1;
110 alo.channel_bitmap = mtx::caf::channel_layout_t::left | mtx::caf::channel_layout_t::right | mtx::caf::channel_layout_t::center
111 | mtx::caf::channel_layout_t::left_surround | mtx::caf::channel_layout_t::right_surround | mtx::caf::channel_layout_t::center_surround
112 | mtx::caf::channel_layout_t::lfe_screen;
113 break;
114 case 8:
115 alo.channel_layout_tag = mtx::caf::channel_layout_t::mpeg_7_1_b;
116 alo.channel_bitmap = mtx::caf::channel_layout_t::left | mtx::caf::channel_layout_t::right | mtx::caf::channel_layout_t::center
117 | mtx::caf::channel_layout_t::left_center | mtx::caf::channel_layout_t::right_center
118 | mtx::caf::channel_layout_t::left_surround | mtx::caf::channel_layout_t::right_surround
119 | mtx::caf::channel_layout_t::lfe_screen;
120 break;
121 }
122
123 auto acli = mtx::caf::channel_layout_info_t();
124
125 put_uint32_be(&acli.channel_layout_info_size, 24); // = sizeof(ALACChannelLayoutInfo)
126 put_uint32_be(&acli.channel_layout_info_id, mtx::calc_fourcc('c', 'h', 'a', 'n')); // = 'chan'
127 put_uint32_be(&acli.channel_layout_tag, alo.channel_layout_tag);
128 m_out->write(&acli, sizeof(acli));
129 }
130
131 // Terminator atom
132 m_out->write_uint32_be(8); // Channel Layout Info Size
133 m_out->write_uint32_be(0); // Channel Layout Info ID
134
135 if (2 < channels) {
136 m_out->write("chan"s); // 'chan' chunk immediately following the kuki
137 m_out->write_uint64_be(12ULL); // = sizeof(ALACAudioChannelLayout)
138
139 m_out->write_uint32_be(alo.channel_layout_tag);
140 m_out->write_uint32_be(alo.channel_bitmap);
141 m_out->write_uint32_be(alo.number_channel_descriptions);
142 }
143
144 m_free_chunk_offset = m_out->getFilePointer(); // remember the location of
145 m_free_chunk_size = 16384;
146
147 auto free_chunk = memory_c::alloc(m_free_chunk_size);
148 memset(free_chunk->get_buffer(), 0, sizeof(m_free_chunk_size));
149
150 // the 'free' chunk
151 m_out->write("free"s);
152 m_out->write_uint64_be(m_free_chunk_size);
153 m_out->write(free_chunk);
154
155 m_data_chunk_offset = m_out->getFilePointer();
156 m_out->write("data"s); // Audio Data Chunk
157 m_out->write_uint64_be(-1LL); // mChunkSize (= -1 if unknown)
158 m_out->write_uint32_be(1); // mEditCount
159 }
160
161 void
finish_file()162 xtr_alac_c::finish_file() {
163 unsigned int const table_header_size = 24;
164 uint64_t const outsize = 4 + 8 + 8 + 8 + 4 + 4 + m_pkt_sizes.size();
165 auto tdiff = static_cast<int64_t>(m_data_chunk_offset) - static_cast<int64_t>(m_free_chunk_offset + outsize);
166 auto write_pakt = [this]() {
167 m_out->write("pakt"s);
168 m_out->write_uint64_be(table_header_size + m_pkt_sizes.size());
169 m_out->write_uint64_be(m_packets_written);
170 m_out->write_uint64_be(m_frames_written);
171 m_out->write_uint32_be(0); // priming frames
172 m_out->write_uint32_be(0); // remainder frames
173
174 // generate the Packet Table Chunk data section
175 m_out->write(m_pkt_sizes.data(), m_pkt_sizes.size());
176 };
177
178 if (tdiff && (16 > tdiff))
179 write_pakt();
180
181 else {
182 m_out->setFilePointer(m_free_chunk_offset);
183 write_pakt();
184
185 // regenerate a 'free' chunk to fill the interstitium between the 'pakt' and 'data' chunks
186 if (tdiff && (16 <= tdiff)) {
187 m_out->write("free"s);
188 m_out->write_uint64_be(tdiff - 12);
189
190 auto free_chunk = memory_c::alloc(tdiff - 12);
191 memset(free_chunk->get_buffer(), 0, tdiff - 12);
192 m_out->write(free_chunk);
193 }
194 }
195
196 // now that the size of the complete data chunk is known, go back and fill in the
197 // mChunkSize field for the 'data' chunk
198 m_out->setFilePointer(m_data_chunk_offset + 4);
199 m_out->write_uint64_be(m_bytes_written + 4);
200 }
201
202 void
handle_frame(xtr_frame_t & f)203 xtr_alac_c::handle_frame(xtr_frame_t &f) {
204 m_out->write(f.frame);
205 auto tval = f.frame->get_size();
206 m_bytes_written += tval;
207
208 auto amt_diff = m_bytes_written - m_prev_written;
209 m_prev_written = m_bytes_written;
210
211 for (int i = 4; i > 0; i--) {
212 unsigned top = amt_diff >> i * 7;
213
214 if (top)
215 m_pkt_sizes.push_back(128 | top);
216 }
217
218 m_pkt_sizes.push_back(amt_diff & 127);
219
220 m_packets_written++;
221 m_frames_written += mtx::caf::defs::default_frames_per_packet;
222 }
223