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    VobSub packetizer
10 
11    Written by Moritz Bunkus <moritz@bunkus.org>.
12 */
13 
14 #include "common/common_pch.h"
15 
16 #include <matroska/KaxContentEncoding.h>
17 #include <matroska/KaxTracks.h>
18 
19 #include "common/codec.h"
20 #include "common/compression.h"
21 #include "common/spu.h"
22 #include "common/strings/formatting.h"
23 #include "input/subtitles.h"
24 #include "output/p_vobsub.h"
25 
26 using namespace libmatroska;
27 
vobsub_packetizer_c(generic_reader_c * reader,track_info_c & ti)28 vobsub_packetizer_c::vobsub_packetizer_c(generic_reader_c *reader,
29                                          track_info_c &ti)
30   : generic_packetizer_c(reader, ti)
31 {
32   set_track_type(track_subtitle);
33   set_default_compression_method(COMPRESSION_ZLIB);
34 }
35 
~vobsub_packetizer_c()36 vobsub_packetizer_c::~vobsub_packetizer_c() {
37 }
38 
39 void
set_headers()40 vobsub_packetizer_c::set_headers() {
41   set_codec_id(MKV_S_VOBSUB);
42   set_codec_private(m_ti.m_private_data);
43 
44   generic_packetizer_c::set_headers();
45 
46   m_track_entry->EnableLacing(false);
47 }
48 
49 void
process_impl(packet_cptr const & packet)50 vobsub_packetizer_c::process_impl(packet_cptr const &packet) {
51   packet->duration_mandatory = true;
52   add_packet(packet);
53 }
54 
55 connection_result_e
can_connect_to(generic_packetizer_c * src,std::string &)56 vobsub_packetizer_c::can_connect_to(generic_packetizer_c *src,
57                                     std::string &) {
58   vobsub_packetizer_c *vsrc;
59 
60   vsrc = dynamic_cast<vobsub_packetizer_c *>(src);
61   if (!vsrc)
62     return CAN_CONNECT_NO_FORMAT;
63   return CAN_CONNECT_YES;
64 }
65 
66 void
after_packet_timestamped(packet_t & packet)67 vobsub_packetizer_c::after_packet_timestamped(packet_t &packet) {
68   static debugging_option_c debug{"spu|spu_duration"};
69 
70   if (!packet.has_duration() || (0 == packet.duration)) {
71     auto new_duration = mtx::spu::get_duration(packet.data->get_buffer(), packet.data->get_size());
72     packet.duration   = new_duration.to_ns(0);
73 
74     mxdebug_if(debug, fmt::format("vobsub: no duration at the container level; setting to {0} from SPU packets\n", mtx::string::format_timestamp(new_duration.to_ns(0))));
75 
76     return;
77   }
78 
79   auto current_duration = mtx::spu::get_duration(packet.data->get_buffer(), packet.data->get_size());
80   auto diff             = current_duration.valid() ? (current_duration - timestamp_c::ns(packet.duration)).abs() : timestamp_c::ns(0);
81 
82   if (diff >= timestamp_c::ms(1)) {
83     mxdebug_if(debug,
84                fmt::format("vobsub: setting SPU duration to {0} (existing duration: {1}, difference: {2})\n",
85                            mtx::string::format_timestamp(packet.duration), mtx::string::format_timestamp(current_duration.to_ns(0)), mtx::string::format_timestamp(diff)));
86     mtx::spu::set_duration(packet.data->get_buffer(), packet.data->get_size(), timestamp_c::ns(packet.duration));
87   }
88 }
89