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 IVF demultiplexer module
10
11 Written by Moritz Bunkus <moritz@bunkus.org>.
12 */
13
14 #include "common/common_pch.h"
15
16 #include <algorithm>
17
18 #include "common/endian.h"
19 #include "common/ivf.h"
20 #include "common/id_info.h"
21 #include "input/r_ivf.h"
22 #include "output/p_av1.h"
23 #include "output/p_vpx.h"
24 #include "merge/input_x.h"
25 #include "merge/file_status.h"
26
27 bool
probe_file()28 ivf_reader_c::probe_file() {
29 if (m_in->read(&m_header, sizeof(ivf::file_header_t)) < sizeof(ivf::file_header_t))
30 return false;
31
32 if (memcmp(m_header.file_magic, "DKIF", 4))
33 return false;
34
35 m_codec = m_header.get_codec();
36
37 return m_codec.is(codec_c::type_e::V_AV1) || m_codec.is(codec_c::type_e::V_VP8) || m_codec.is(codec_c::type_e::V_VP9);
38 }
39
40 void
read_headers()41 ivf_reader_c::read_headers() {
42 m_in->setFilePointer(sizeof(ivf::file_header_t));
43
44 m_width = get_uint16_le(&m_header.width);
45 m_height = get_uint16_le(&m_header.height);
46 m_frame_rate_num = get_uint32_le(&m_header.frame_rate_num);
47 m_frame_rate_den = get_uint32_le(&m_header.frame_rate_den);
48 m_ok = m_width && m_height && m_frame_rate_num && m_frame_rate_den;
49
50 show_demuxer_info();
51 }
52
53 void
add_available_track_ids()54 ivf_reader_c::add_available_track_ids() {
55 if (m_ok)
56 add_available_track_id(0);
57 }
58
59 void
create_packetizer(int64_t)60 ivf_reader_c::create_packetizer(int64_t) {
61 if (!demuxing_requested('v', 0) || !m_reader_packetizers.empty() || !m_ok)
62 return;
63
64 if (m_codec.is(codec_c::type_e::V_AV1))
65 create_av1_packetizer();
66
67 else if (m_codec.is(codec_c::type_e::V_VP8) || m_codec.is(codec_c::type_e::V_VP9))
68 create_vpx_packetizer();
69
70 auto &packetizer = ptzr(0);
71
72 packetizer.set_video_pixel_width(m_width);
73 packetizer.set_video_pixel_height(m_height);
74
75 auto default_duration = 1000000000ll * m_frame_rate_den / m_frame_rate_num;
76 if (default_duration >= 1000000)
77 packetizer.set_track_default_duration(default_duration);
78
79 show_packetizer_info(0, packetizer);
80 }
81
82 void
create_av1_packetizer()83 ivf_reader_c::create_av1_packetizer() {
84 auto av1_ptzr = new av1_video_packetizer_c(this, m_ti);
85 av1_ptzr->set_is_unframed();
86
87 add_packetizer(av1_ptzr);
88 }
89
90 void
create_vpx_packetizer()91 ivf_reader_c::create_vpx_packetizer() {
92 add_packetizer(new vpx_video_packetizer_c(this, m_ti, m_codec.get_type()));
93 }
94
95 file_status_e
read(generic_packetizer_c *,bool)96 ivf_reader_c::read(generic_packetizer_c *,
97 bool) {
98 size_t remaining_bytes = m_size - m_in->getFilePointer();
99
100 ivf::frame_header_t header;
101 if ((sizeof(ivf::frame_header_t) > remaining_bytes) || (m_in->read(&header, sizeof(ivf::frame_header_t)) != sizeof(ivf::frame_header_t)))
102 return flush_packetizers();
103
104 remaining_bytes -= sizeof(ivf::frame_header_t);
105 uint32_t frame_size = get_uint32_le(&header.frame_size);
106
107 if (remaining_bytes < frame_size) {
108 m_in->setFilePointer(0, seek_end);
109 return flush_packetizers();
110 }
111
112 memory_cptr buffer = memory_c::alloc(frame_size);
113 if (m_in->read(buffer->get_buffer(), frame_size) < frame_size) {
114 m_in->setFilePointer(0, seek_end);
115 return flush_packetizers();
116 }
117
118 int64_t timestamp = get_uint64_le(&header.timestamp) * 1000000000ull * m_frame_rate_den / m_frame_rate_num;
119
120 mxdebug_if(m_debug, fmt::format("key {4} header.ts {0} num {1} den {2} res {3}\n", get_uint64_le(&header.timestamp), m_frame_rate_num, m_frame_rate_den, timestamp, ivf::is_keyframe(buffer, m_codec.get_type())));
121
122 ptzr(0).process(std::make_shared<packet_t>(buffer, timestamp));
123
124 return FILE_STATUS_MOREDATA;
125 }
126
127 void
identify()128 ivf_reader_c::identify() {
129 id_result_container();
130
131 if (!m_ok)
132 return;
133
134 auto info = mtx::id::info_c{};
135 info.add(mtx::id::pixel_dimensions, fmt::format("{0}x{1}", m_width, m_height));
136 id_result_track(0, ID_RESULT_TRACK_VIDEO, m_codec.get_name(), info.get());
137 }
138