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    AV1 video output module
10 
11    Written by Moritz Bunkus <moritz@bunkus.org>.
12 */
13 
14 #include "common/common_pch.h"
15 
16 #include "common/av1.h"
17 #include "common/codec.h"
18 #include "common/hacks.h"
19 #include "merge/connection_checks.h"
20 #include "merge/output_control.h"
21 #include "output/p_av1.h"
22 
23 using namespace libmatroska;
24 
av1_video_packetizer_c(generic_reader_c * p_reader,track_info_c & p_ti)25 av1_video_packetizer_c::av1_video_packetizer_c(generic_reader_c *p_reader,
26                                                track_info_c &p_ti)
27   : generic_packetizer_c{p_reader, p_ti}
28 {
29   m_timestamp_factory_application_mode = TFA_SHORT_QUEUEING;
30 
31   set_track_type(track_video);
32   set_codec_id(MKV_V_AV1);
33   set_codec_private(m_ti.m_private_data);
34   set_video_pixel_width(0);
35   set_video_pixel_height(0);
36 }
37 
38 void
set_header_parameters()39 av1_video_packetizer_c::set_header_parameters() {
40   if (m_header_parameters_set)
41     return;
42 
43   if (!m_parser.headers_parsed())
44     return;
45 
46   auto need_to_rerender = false;
47 
48   if (!m_hcodec_private) {
49     set_codec_private(m_parser.get_av1c());
50     need_to_rerender = true;
51   }
52 
53   auto dimensions = m_parser.get_pixel_dimensions();
54 
55   if (!m_hvideo_pixel_width || !m_hvideo_pixel_height) {
56     set_video_pixel_width(dimensions.first);
57     set_video_pixel_height(dimensions.second);
58     need_to_rerender = true;
59   }
60 
61   if (!m_hvideo_display_width || !m_hvideo_display_height) {
62     set_video_display_width(dimensions.first);
63     set_video_display_height(dimensions.second);
64     need_to_rerender = true;
65   }
66 
67   auto frame_duration = m_parser.get_frame_duration();
68   if ((m_htrack_default_duration <= 0) && frame_duration) {
69     set_track_default_duration(mtx::to_int(frame_duration));
70     need_to_rerender = true;
71 
72   } else if ((m_htrack_default_duration > 0) && !frame_duration)
73     m_parser.set_default_duration(m_htrack_default_duration);
74 
75   if (need_to_rerender)
76     rerender_track_headers();
77 
78   m_header_parameters_set = true;
79 
80   if (!m_is_framed)
81     return;
82 
83   m_parser.set_parse_sequence_header_obus_only(true);
84 
85   while (m_parser.frame_available())
86     m_parser.get_next_frame();
87 }
88 
89 void
process_impl(packet_cptr const & packet)90 av1_video_packetizer_c::process_impl(packet_cptr const &packet) {
91   m_parser.debug_obu_types(*packet->data);
92 
93   m_parser.parse(*packet->data);
94 
95   set_header_parameters();
96 
97   if (m_is_framed)
98     process_framed(packet);
99   else
100     process_unframed();
101 }
102 
103 void
process_framed(packet_cptr packet)104 av1_video_packetizer_c::process_framed(packet_cptr packet) {
105   packet->bref         = m_parser.is_keyframe(*packet->data) ? -1 : m_previous_timestamp;
106   m_previous_timestamp = packet->timestamp;
107 
108   add_packet(packet);
109 }
110 
111 void
process_unframed()112 av1_video_packetizer_c::process_unframed() {
113   flush_frames();
114 }
115 
116 void
flush_impl()117 av1_video_packetizer_c::flush_impl() {
118   if (m_is_framed)
119     return;
120 
121   m_parser.flush();
122   flush_frames();
123 }
124 
125 void
flush_frames()126 av1_video_packetizer_c::flush_frames() {
127   while (m_parser.frame_available()) {
128     auto frame           = m_parser.get_next_frame();
129     auto bref            = frame.is_keyframe ? -1 : m_previous_timestamp;
130     auto duration        = m_htrack_default_duration > 0 ? m_htrack_default_duration : -1;
131     m_previous_timestamp = frame.timestamp;
132 
133     add_packet(std::make_shared<packet_t>(frame.mem, frame.timestamp, duration, bref));
134   }
135 }
136 
137 void
set_is_unframed()138 av1_video_packetizer_c::set_is_unframed() {
139   m_is_framed = false;
140 }
141 
142 connection_result_e
can_connect_to(generic_packetizer_c * src,std::string &)143 av1_video_packetizer_c::can_connect_to(generic_packetizer_c *src,
144                                        std::string &) {
145   auto psrc = dynamic_cast<av1_video_packetizer_c *>(src);
146   if (!psrc)
147     return CAN_CONNECT_NO_FORMAT;
148 
149   return CAN_CONNECT_YES;
150 }
151 
152 bool
is_compatible_with(output_compatibility_e compatibility)153 av1_video_packetizer_c::is_compatible_with(output_compatibility_e compatibility) {
154   return (OC_MATROSKA == compatibility) || (OC_WEBM == compatibility);
155 }
156