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