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