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 VC1 ES video output module
10
11 Written by Moritz Bunkus <moritz@bunkus.org>.
12 */
13
14 #include "common/common_pch.h"
15
16 #include <matroska/KaxTracks.h>
17
18 #include "avilib.h"
19 #include "common/codec.h"
20 #include "common/endian.h"
21 #include "common/hacks.h"
22 #include "merge/output_control.h"
23 #include "merge/generic_reader.h"
24 #include "merge/packet_extensions.h"
25 #include "output/p_vc1.h"
26
27 using namespace libmatroska;
28
vc1_video_packetizer_c(generic_reader_c * n_reader,track_info_c & n_ti)29 vc1_video_packetizer_c::vc1_video_packetizer_c(generic_reader_c *n_reader, track_info_c &n_ti)
30 : generic_packetizer_c(n_reader, n_ti)
31 , m_previous_timestamp(-1)
32 {
33 m_relaxed_timestamp_checking = true;
34
35 set_track_type(track_video);
36 set_codec_id(MKV_V_MSCOMP);
37
38 // Dummy values
39 m_seqhdr.pixel_width = 123;
40 m_seqhdr.pixel_height = 123;
41 }
42
43 void
set_headers()44 vc1_video_packetizer_c::set_headers() {
45 int priv_size = sizeof(alBITMAPINFOHEADER) + (m_raw_headers ? m_raw_headers->get_size() + 1 : 0);
46 auto buf = memory_c::alloc(priv_size);
47 auto bih = reinterpret_cast<alBITMAPINFOHEADER *>(buf->get_buffer());
48
49 memset(bih, 0, priv_size);
50 memcpy(&bih->bi_compression, "WVC1", 4);
51
52 put_uint32_le(&bih->bi_size, priv_size);
53 put_uint16_le(&bih->bi_planes, 1);
54 put_uint16_le(&bih->bi_bit_count, 24);
55 put_uint32_le(&bih->bi_width, m_seqhdr.pixel_width);
56 put_uint32_le(&bih->bi_height, m_seqhdr.pixel_height);
57 put_uint32_le(&bih->bi_size_image, get_uint32_le(&bih->bi_width) * get_uint32_le(&bih->bi_height) * 3);
58 put_uint32_le(&bih->bi_x_pels_per_meter, 1);
59 put_uint32_le(&bih->bi_y_pels_per_meter, 1);
60
61 set_video_pixel_width(m_seqhdr.pixel_width);
62 set_video_pixel_height(m_seqhdr.pixel_height);
63
64 if (m_raw_headers) {
65 if (m_seqhdr.display_info_flag) {
66 int display_width = m_seqhdr.display_width;
67 int display_height = m_seqhdr.display_height;
68
69 set_video_display_dimensions(display_width, display_height, generic_packetizer_c::ddu_pixels, OPTION_SOURCE_BITSTREAM);
70
71 } else
72 set_video_display_dimensions(m_seqhdr.pixel_width, m_seqhdr.pixel_height, generic_packetizer_c::ddu_pixels, OPTION_SOURCE_BITSTREAM);
73
74 if (m_default_duration_forced)
75 m_parser.set_default_duration(get_track_default_duration());
76 else
77 set_track_default_duration(m_parser.get_default_duration());
78
79 memcpy(((unsigned char *)bih) + sizeof(alBITMAPINFOHEADER) + 1, m_raw_headers->get_buffer(), m_raw_headers->get_size());
80
81 } else
82 set_track_default_duration(1000000000ll * 1001 / 30000);
83
84 set_codec_private(buf);
85
86 generic_packetizer_c::set_headers();
87
88 m_track_entry->EnableLacing(false);
89 }
90
91 void
add_timestamps_to_parser(packet_cptr const & packet)92 vc1_video_packetizer_c::add_timestamps_to_parser(packet_cptr const &packet) {
93 if (-1 != packet->timestamp)
94 m_parser.add_timestamp(packet->timestamp, 0);
95
96 for (auto &extension : packet->extensions) {
97 if (extension->get_type() != packet_extension_c::MULTIPLE_TIMESTAMPS)
98 continue;
99
100 multiple_timestamps_packet_extension_c *tc_extension = static_cast<multiple_timestamps_packet_extension_c *>(extension.get());
101 int64_t timestamp, position;
102
103 while (tc_extension->get_next(timestamp, position))
104 m_parser.add_timestamp(timestamp, position);
105 }
106 }
107
108 void
process_impl(packet_cptr const & packet)109 vc1_video_packetizer_c::process_impl(packet_cptr const &packet) {
110 add_timestamps_to_parser(packet);
111
112 m_parser.add_bytes(packet->data->get_buffer(), packet->data->get_size());
113
114 if (!m_raw_headers && m_parser.are_headers_available())
115 headers_found();
116
117 flush_frames();
118 }
119
120 void
headers_found()121 vc1_video_packetizer_c::headers_found() {
122 m_parser.get_sequence_header(m_seqhdr);
123
124 memory_cptr raw_seqhdr = m_parser.get_raw_sequence_header();
125 memory_cptr raw_entrypoint = m_parser.get_raw_entrypoint();
126
127 m_raw_headers = memory_c::alloc(raw_seqhdr->get_size() + raw_entrypoint->get_size());
128
129 memcpy(m_raw_headers->get_buffer(), raw_seqhdr->get_buffer(), raw_seqhdr->get_size());
130 memcpy(m_raw_headers->get_buffer() + raw_seqhdr->get_size(), raw_entrypoint->get_buffer(), raw_entrypoint->get_size());
131
132 if (!m_reader->m_appending) {
133 set_headers();
134 rerender_track_headers();
135 }
136 }
137
138 void
flush_impl()139 vc1_video_packetizer_c::flush_impl() {
140 m_parser.flush();
141 flush_frames();
142 }
143
144 void
flush_frames()145 vc1_video_packetizer_c::flush_frames() {
146 while (m_parser.is_frame_available()) {
147 auto frame = m_parser.get_frame();
148 add_packet(std::make_shared<packet_t>(frame->data, frame->timestamp, frame->duration, frame->is_key() ? -1 : m_previous_timestamp));
149
150 m_previous_timestamp = frame->timestamp;
151 }
152 }
153
154 connection_result_e
can_connect_to(generic_packetizer_c * src,std::string &)155 vc1_video_packetizer_c::can_connect_to(generic_packetizer_c *src,
156 std::string &) {
157 vc1_video_packetizer_c *vsrc = dynamic_cast<vc1_video_packetizer_c *>(src);
158 if (!vsrc)
159 return CAN_CONNECT_NO_FORMAT;
160
161 return CAN_CONNECT_YES;
162 }
163