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