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