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 MPEG4 part 10 video output module
10
11 Written by Moritz Bunkus <moritz@bunkus.org>.
12 */
13
14 #include "common/common_pch.h"
15
16 #include <cmath>
17
18 #include "common/avc/es_parser.h"
19 #include "common/codec.h"
20 #include "common/endian.h"
21 #include "common/hacks.h"
22 #include "common/list_utils.h"
23 #include "common/mpeg.h"
24 #include "common/strings/formatting.h"
25 #include "merge/output_control.h"
26 #include "output/p_avc.h"
27
28 avc_video_packetizer_c::
avc_video_packetizer_c(generic_reader_c * p_reader,track_info_c & p_ti,int64_t default_duration,int width,int height)29 avc_video_packetizer_c(generic_reader_c *p_reader,
30 track_info_c &p_ti,
31 int64_t default_duration,
32 int width,
33 int height)
34 : generic_video_packetizer_c{p_reader, p_ti, MKV_V_MPEG4_AVC, default_duration, width, height}
35 , m_debug_fix_bistream_timing_info{"fix_bitstream_timing_info"}
36 {
37 m_relaxed_timestamp_checking = true;
38
39 if (5 <= m_ti.m_private_data->get_size())
40 m_nalu_size_len = (m_ti.m_private_data->get_buffer()[4] & 0x03) + 1;
41
42 set_codec_private(m_ti.m_private_data);
43 }
44
45 void
set_headers()46 avc_video_packetizer_c::set_headers() {
47 if (m_ti.m_private_data && m_ti.m_private_data->get_size())
48 extract_aspect_ratio();
49
50 int64_t divisor = 2;
51
52 if (m_default_duration_forced) {
53 if (m_htrack_default_duration_indicates_fields) {
54 set_track_default_duration(m_htrack_default_duration / 2, true);
55 divisor = 1;
56 }
57
58 m_track_default_duration = m_htrack_default_duration;
59 }
60
61 if ((-1 == m_track_default_duration) && m_timestamp_factory)
62 m_track_default_duration = m_timestamp_factory->get_default_duration(-1);
63
64 if ((-1 == m_track_default_duration) && (0 < m_default_duration))
65 m_track_default_duration = m_default_duration;
66
67 if (-1 != m_track_default_duration)
68 m_track_default_duration /= divisor;
69
70 mxdebug_if(m_debug_fix_bistream_timing_info,
71 fmt::format("fix_bitstream_timing_info [AVCC]: factory default_duration {0} default_duration_forced? {1} htrack_default_duration {2} default_duration {3} m_track_default_duration {4}\n",
72 m_timestamp_factory ? m_timestamp_factory->get_default_duration(-1) : -2,
73 m_default_duration_forced, m_htrack_default_duration,
74 m_default_duration, m_track_default_duration));
75
76 if ( m_ti.m_private_data
77 && m_ti.m_private_data->get_size()
78 && m_ti.m_fix_bitstream_frame_rate
79 && (-1 != m_track_default_duration))
80 set_codec_private(mtx::avc::fix_sps_fps(m_ti.m_private_data, m_track_default_duration));
81
82 generic_video_packetizer_c::set_headers();
83 }
84
85 void
extract_aspect_ratio()86 avc_video_packetizer_c::extract_aspect_ratio() {
87 auto result = mtx::avc::extract_par(m_ti.m_private_data);
88
89 set_codec_private(result.new_avcc);
90
91 if (!result.is_valid() || display_dimensions_or_aspect_ratio_set())
92 return;
93
94 auto par = mtx::rational(result.numerator, result.denominator);
95
96 set_video_display_dimensions(1 <= par ? mtx::to_int_rounded(m_width * par) : m_width,
97 1 <= par ? m_height : mtx::to_int_rounded(m_height / par),
98 generic_packetizer_c::ddu_pixels,
99 OPTION_SOURCE_BITSTREAM);
100
101 mxinfo_tid(m_ti.m_fname, m_ti.m_id,
102 fmt::format(Y("Extracted the aspect ratio information from the MPEG-4 layer 10 (AVC) video data and set the display dimensions to {0}/{1}.\n"),
103 m_ti.m_display_width, m_ti.m_display_height));
104 }
105
106 void
process_impl(packet_cptr const & packet)107 avc_video_packetizer_c::process_impl(packet_cptr const &packet) {
108 if (VFT_PFRAMEAUTOMATIC == packet->bref) {
109 packet->fref = -1;
110 packet->bref = m_ref_timestamp;
111 }
112
113 m_ref_timestamp = packet->timestamp;
114
115 process_nalus(*packet->data);
116
117 add_packet(packet);
118 }
119
120 connection_result_e
can_connect_to(generic_packetizer_c * src,std::string & error_message)121 avc_video_packetizer_c::can_connect_to(generic_packetizer_c *src,
122 std::string &error_message) {
123 avc_video_packetizer_c *vsrc = dynamic_cast<avc_video_packetizer_c *>(src);
124 if (!vsrc)
125 return CAN_CONNECT_NO_FORMAT;
126
127 if (m_ti.m_private_data && vsrc->m_ti.m_private_data && memcmp(m_ti.m_private_data->get_buffer(), vsrc->m_ti.m_private_data->get_buffer(), m_ti.m_private_data->get_size())) {
128 error_message = fmt::format(Y("The codec's private data does not match. Both have the same length ({0}) but different content."), m_ti.m_private_data->get_size());
129 return CAN_CONNECT_MAYBE_CODECPRIVATE;
130 }
131
132 return CAN_CONNECT_YES;
133 }
134
135 void
process_nalus(memory_c & data) const136 avc_video_packetizer_c::process_nalus(memory_c &data)
137 const {
138 auto ptr = data.get_buffer();
139 auto total_size = data.get_size();
140 auto idx = 0u;
141
142 while ((idx + m_nalu_size_len) < total_size) {
143 auto nalu_size = get_uint_be(&ptr[idx], m_nalu_size_len) + m_nalu_size_len;
144
145 if ((idx + nalu_size) > total_size)
146 break;
147
148 if (static_cast<int>(nalu_size) < m_nalu_size_len)
149 break;
150
151 auto const nalu_type = ptr[idx + m_nalu_size_len] & 0x1f;
152
153 if ( (static_cast<int>(nalu_size) == m_nalu_size_len) // empty NALU?
154 || mtx::included_in(nalu_type, mtx::avc::NALU_TYPE_FILLER_DATA, mtx::avc::NALU_TYPE_ACCESS_UNIT)) {
155 memory_c::splice(data, idx, nalu_size);
156 total_size -= nalu_size;
157 ptr = data.get_buffer();
158 continue;
159 }
160
161 if ( (nalu_type == mtx::avc::NALU_TYPE_SEQ_PARAM)
162 && m_ti.m_fix_bitstream_frame_rate
163 && (-1 != m_track_default_duration)) {
164 mxdebug_if(m_debug_fix_bistream_timing_info, fmt::format("fix_bitstream_timing_info [NALU]: m_track_default_duration {0}\n", m_track_default_duration));
165
166 mtx::avc::sps_info_t sps_info;
167 auto parsed_nalu = mtx::avc::parse_sps(mtx::mpeg::nalu_to_rbsp(memory_c::clone(&ptr[idx + m_nalu_size_len], nalu_size - m_nalu_size_len)), sps_info, true, true, m_track_default_duration);
168
169 if (parsed_nalu) {
170 parsed_nalu = mtx::mpeg::rbsp_to_nalu(parsed_nalu);
171
172 memory_c::splice(data, idx + m_nalu_size_len, nalu_size - m_nalu_size_len, *parsed_nalu);
173
174 total_size = data.get_size();
175 ptr = data.get_buffer();
176
177 put_uint_be(&ptr[idx], parsed_nalu->get_size(), m_nalu_size_len);
178
179 idx += parsed_nalu->get_size() + m_nalu_size_len;
180 continue;
181 }
182 }
183
184 idx += nalu_size;
185 }
186
187 // empty NALU at the end?
188 if (total_size == (idx + m_nalu_size_len))
189 data.set_size(idx);
190 }
191