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    HEVC video output module
10 
11 */
12 
13 #include "common/common_pch.h"
14 
15 #include <cstdlib>
16 
17 #include "common/codec.h"
18 #include "common/endian.h"
19 #include "common/hacks.h"
20 #include "common/hevc/util.h"
21 #include "common/hevc/es_parser.h"
22 #include "common/strings/formatting.h"
23 #include "merge/output_control.h"
24 #include "output/p_hevc.h"
25 
26 class hevc_video_packetizer_private_c {
27 public:
28   int nalu_size_len{};
29   int64_t max_nalu_size{}, source_timestamp_resolution{1};
30   std::shared_ptr<mtx::hevc::es_parser_c> parser{new mtx::hevc::es_parser_c};
31 };
32 
33 hevc_video_packetizer_c::
hevc_video_packetizer_c(generic_reader_c * p_reader,track_info_c & p_ti,int64_t default_duration,int width,int height)34 hevc_video_packetizer_c(generic_reader_c *p_reader,
35                         track_info_c &p_ti,
36                         int64_t default_duration,
37                         int width,
38                         int height)
39   : generic_video_packetizer_c{p_reader, p_ti, MKV_V_MPEGH_HEVC, default_duration, width, height}
40   , p_ptr{new hevc_video_packetizer_private_c}
41 {
42   auto &p = *p_func();
43 
44   m_relaxed_timestamp_checking = true;
45 
46   if (23 <= m_ti.m_private_data->get_size())
47     p_ptr->nalu_size_len = (m_ti.m_private_data->get_buffer()[21] & 0x03) + 1;
48 
49   set_codec_private(m_ti.m_private_data);
50 
51   p.parser->set_normalize_parameter_sets(!mtx::hacks::is_engaged(mtx::hacks::DONT_NORMALIZE_PARAMETER_SETS));
52   p.parser->set_configuration_record(m_hcodec_private);
53 }
54 
55 void
set_source_timestamp_resolution(int64_t resolution)56 hevc_video_packetizer_c::set_source_timestamp_resolution(int64_t resolution) {
57   p_func()->source_timestamp_resolution = resolution;
58 }
59 
60 void
setup_default_duration()61 hevc_video_packetizer_c::setup_default_duration() {
62   auto &p                      = *p_func();
63 
64   auto source_default_duration = m_htrack_default_duration > 0 ? m_htrack_default_duration
65                                : m_default_duration        > 0 ? m_default_duration
66                                :                                 0;
67   auto stream_default_duration = p.parser->has_stream_default_duration() ? p.parser->get_stream_default_duration() : 0;
68   auto diff_source_stream      = std::abs(stream_default_duration - source_default_duration);
69   auto output_default_duration = stream_default_duration && !source_default_duration                             ? stream_default_duration
70                                : stream_default_duration && (diff_source_stream < p.source_timestamp_resolution) ? stream_default_duration
71                                :                                                                                   source_default_duration;
72 
73   if (source_default_duration > 0)
74     p.parser->set_container_default_duration(source_default_duration);
75 
76   if (output_default_duration > 0)
77     set_track_default_duration(output_default_duration);
78 }
79 
80 void
set_headers()81 hevc_video_packetizer_c::set_headers() {
82   setup_default_duration();
83 
84   if (m_ti.m_private_data && m_ti.m_private_data->get_size())
85     extract_aspect_ratio();
86 
87   if (m_ti.m_private_data && m_ti.m_private_data->get_size() && m_ti.m_fix_bitstream_frame_rate)
88     set_codec_private(m_ti.m_private_data);
89 
90   generic_video_packetizer_c::set_headers();
91 }
92 
93 void
extract_aspect_ratio()94 hevc_video_packetizer_c::extract_aspect_ratio() {
95   auto result = mtx::hevc::extract_par(m_ti.m_private_data);
96 
97   set_codec_private(result.new_hevcc);
98 
99   if (!result.is_valid() || display_dimensions_or_aspect_ratio_set())
100     return;
101 
102   auto par = mtx::rational(result.numerator, result.denominator);
103 
104   set_video_display_dimensions(1 <= par ? mtx::to_int_rounded(m_width * par) : m_width,
105                                1 <= par ? m_height                           : mtx::to_int_rounded(m_height / par),
106                                generic_packetizer_c::ddu_pixels,
107                                OPTION_SOURCE_BITSTREAM);
108 
109   mxinfo_tid(m_ti.m_fname, m_ti.m_id,
110              fmt::format(Y("Extracted the aspect ratio information from the HEVC video data and set the display dimensions to {0}/{1}.\n"),
111                          m_ti.m_display_width, m_ti.m_display_height));
112 }
113 
114 void
process_impl(packet_cptr const & packet)115 hevc_video_packetizer_c::process_impl(packet_cptr const &packet) {
116   auto &p = *p_func();
117 
118   if (packet->is_key_frame() && (VFT_PFRAMEAUTOMATIC != packet->bref))
119     p.parser->set_next_i_slice_is_key_frame();
120 
121   if (packet->has_timestamp())
122     p.parser->add_timestamp(packet->timestamp);
123 
124   p.parser->add_bytes_framed(packet->data, p.nalu_size_len);
125 
126   flush_frames();
127 }
128 
129 connection_result_e
can_connect_to(generic_packetizer_c * src,std::string & error_message)130 hevc_video_packetizer_c::can_connect_to(generic_packetizer_c *src,
131                                         [[maybe_unused]] std::string &error_message) {
132   hevc_video_packetizer_c *vsrc = dynamic_cast<hevc_video_packetizer_c *>(src);
133   if (!vsrc)
134     return CAN_CONNECT_NO_FORMAT;
135 
136   return CAN_CONNECT_YES;
137 }
138 
139 void
connect(generic_packetizer_c * src,int64_t append_timestamp_offset)140 hevc_video_packetizer_c::connect(generic_packetizer_c *src,
141                                  int64_t append_timestamp_offset) {
142   auto &p = *p_func();
143 
144   generic_packetizer_c::connect(src, append_timestamp_offset);
145 
146   if (1 == m_connected_to)
147     p.parser = static_cast<hevc_video_packetizer_c *>(src)->p_func()->parser;
148 }
149 
150 void
flush_impl()151 hevc_video_packetizer_c::flush_impl() {
152   auto &p = *p_func();
153 
154   p.parser->flush();
155   flush_frames();
156 }
157 
158 void
flush_frames()159 hevc_video_packetizer_c::flush_frames() {
160   auto &p = *p_func();
161 
162   while (p.parser->frame_available()) {
163     auto frame                    = p.parser->get_frame();
164     auto duration                 = frame.m_end > frame.m_start ? frame.m_end - frame.m_start : m_htrack_default_duration;
165     auto diff_to_default_duration = std::abs(duration - m_htrack_default_duration);
166 
167     if (diff_to_default_duration < p.source_timestamp_resolution)
168       duration = m_htrack_default_duration;
169 
170     add_packet(std::make_shared<packet_t>(frame.m_data, frame.m_start, duration,
171                                            frame.is_key_frame() ? -1 : frame.m_start + frame.m_ref1,
172                                           !frame.is_b_frame()   ? -1 : frame.m_start + frame.m_ref2));
173   }
174 }
175