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