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/h2.65 ES demultiplexer module
10
11 */
12
13 #include "common/common_pch.h"
14
15 #include "common/avc_hevc/util.h"
16 #include "common/byte_buffer.h"
17 #include "common/codec.h"
18 #include "common/debugging.h"
19 #include "common/error.h"
20 #include "common/memory.h"
21 #include "common/id_info.h"
22 #include "common/dovi_meta.h"
23 #include "input/r_hevc.h"
24 #include "merge/input_x.h"
25 #include "merge/file_status.h"
26 #include "output/p_hevc_es.h"
27
28 static debugging_option_c s_debug_dovi_configuration_record{"dovi_configuration_record"};
29
30 bool
probe_file()31 hevc_es_reader_c::probe_file() {
32 // mxinfo(fmt::format("hevc probe {0}\n", m_probe_range_info.require_headers_at_start));
33 int num_read, i;
34 bool first = true;
35
36 mtx::hevc::es_parser_c parser;
37 parser.set_nalu_size_length(4);
38
39 for (i = 0; 50 > i; ++i) {
40 num_read = m_in->read(m_buffer->get_buffer(), m_buffer->get_size());
41 if (4 > num_read)
42 return 0;
43
44 // MPEG TS starts with 0x47.
45 if (first && (0x47 == m_buffer->get_buffer()[0]))
46 return 0;
47
48 if (first && m_probe_range_info.require_headers_at_start && !mtx::avc_hevc::might_be_avc_or_hevc(*m_buffer))
49 return false;
50
51 first = false;
52
53 parser.add_bytes(m_buffer->get_buffer(), num_read);
54
55 if (!parser.headers_parsed())
56 continue;
57
58 m_width = parser.get_width();
59 m_height = parser.get_height();
60
61 if (parser.has_stream_default_duration())
62 m_default_duration = parser.get_stream_default_duration();
63
64 if (m_block_addition_mappings.empty() && parser.has_dovi_rpu_header()) {
65 auto hdr = parser.get_dovi_rpu_header();
66 auto vui = parser.get_vui_info();
67 auto duration = parser.has_stream_default_duration() ? m_default_duration : parser.get_most_often_used_duration();
68
69 auto dovi_config_record = create_dovi_configuration_record(hdr, m_width, m_height, vui, duration);
70
71 auto mapping = mtx::dovi::create_dovi_block_addition_mapping(dovi_config_record);
72
73 if (mapping.is_valid()) {
74 if (s_debug_dovi_configuration_record) {
75 hdr.dump();
76 dovi_config_record.dump();
77 }
78
79 m_block_addition_mappings.push_back(mapping);
80 }
81 }
82
83 if ((0 >= m_width) || (0 >= m_height))
84 return false;
85
86 return true;
87 }
88
89 return false;
90 }
91
92 void
read_headers()93 hevc_es_reader_c::read_headers() {
94 show_demuxer_info();
95 }
96
97 void
create_packetizer(int64_t)98 hevc_es_reader_c::create_packetizer(int64_t) {
99 if (!demuxing_requested('v', 0) || !m_reader_packetizers.empty())
100 return;
101
102 add_packetizer(new hevc_es_video_packetizer_c(this, m_ti));
103 ptzr(0).set_video_pixel_dimensions(m_width, m_height);
104 ptzr(0).set_block_addition_mappings(m_block_addition_mappings);
105
106 show_packetizer_info(0, ptzr(0));
107 }
108
109 file_status_e
read(generic_packetizer_c *,bool)110 hevc_es_reader_c::read(generic_packetizer_c *,
111 bool) {
112 if (m_in->getFilePointer() >= m_size)
113 return FILE_STATUS_DONE;
114
115 int num_read = m_in->read(m_buffer->get_buffer(), m_buffer->get_size());
116 if (0 < num_read)
117 ptzr(0).process(std::make_shared<packet_t>(memory_c::borrow(m_buffer->get_buffer(), num_read)));
118
119 return (0 != num_read) && (m_in->getFilePointer() < m_size) ? FILE_STATUS_MOREDATA : flush_packetizers();
120 }
121
122 void
identify()123 hevc_es_reader_c::identify() {
124 auto info = mtx::id::info_c{};
125 info.add(mtx::id::packetizer, mtx::id::mpegh_p2_es_video);
126 info.add(mtx::id::pixel_dimensions, fmt::format("{0}x{1}", m_width, m_height));
127 info.add(mtx::id::default_duration, m_default_duration);
128
129 id_result_container();
130 id_result_track(0, ID_RESULT_TRACK_VIDEO, codec_c::get_name(codec_c::type_e::V_MPEGH_P2, "HEVC"), info.get());
131 }
132