1 /** VC-1 video helper functions
2 
3    mkvmerge -- utility for splicing together matroska files
4    from component media subtypes
5 
6    Distributed under the GPL v2
7    see the file COPYING for details
8    or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
9 
10    \file
11 
12    \author Written by Moritz Bunkus <moritz@bunkus.org>.
13 */
14 
15 #pragma once
16 
17 #include "common/common_pch.h"
18 
19 #include <deque>
20 
21 #include "common/vc1_fwd.h"
22 
23 namespace mtx::vc1 {
24 
25 constexpr auto PROFILE_SIMPLE    = 0x00000000;
26 constexpr auto PROFILE_MAIN      = 0x00000001;
27 constexpr auto PROFILE_COMPLEX   = 0x00000002;
28 constexpr auto PROFILE_ADVANCED  = 0x00000003;
29 
30 constexpr auto MARKER_ENDOFSEQ   = 0x0000010a;
31 constexpr auto MARKER_SLICE      = 0x0000010b;
32 constexpr auto MARKER_FIELD      = 0x0000010c;
33 constexpr auto MARKER_FRAME      = 0x0000010d;
34 constexpr auto MARKER_ENTRYPOINT = 0x0000010e;
35 constexpr auto MARKER_SEQHDR     = 0x0000010f;
36 
37 enum frame_type_e {
38   FRAME_TYPE_I,
39   FRAME_TYPE_P,
40   FRAME_TYPE_B,
41   FRAME_TYPE_BI,
42   FRAME_TYPE_P_SKIPPED,
43 };
44 
45 enum frame_coding_mode_e {
46   FCM_PROGRESSIVE = 0,
47   FCM_ILACE_FRAME,
48   FCM_ILACE_FIELD,
49 };
50 
51 struct sequence_header_t {
52   int  profile;
53   int  level;
54   int  chroma_format;
55   int  frame_rtq_postproc;
56   int  bit_rtq_postproc;
57   bool postproc_flag;
58   int  pixel_width;
59   int  pixel_height;
60   bool pulldown_flag;
61   bool interlace_flag;
62   bool tf_counter_flag;
63   bool f_inter_p_flag;
64   bool psf_mode_flag;
65   bool display_info_flag;
66   int  display_width;
67   int  display_height;
68   bool aspect_ratio_flag;
69   int  aspect_ratio_width;
70   int  aspect_ratio_height;
71   bool framerate_flag;
72   int  framerate_num;
73   int  framerate_den;
74   int  color_prim;
75   int  transfer_char;
76   int  matrix_coef;
77   bool hrd_param_flag;
78   int  hrd_num_leaky_buckets;
79 
80   sequence_header_t();
81 };
82 
83 struct entrypoint_t {
84   bool broken_link_flag;
85   bool closed_entry_flag;
86   bool pan_scan_flag;
87   bool refdist_flag;
88   bool loop_filter_flag;
89   bool fast_uvmc_flag;
90   bool extended_mv_flag;
91   int  dquant;
92   bool vs_transform_flag;
93   bool overlap_flag;
94   int  quantizer_mode;
95   bool coded_dimensions_flag;
96   int  coded_width;
97   int  coded_height;
98   bool extended_dmv_flag;
99   bool luma_scaling_flag;
100   int  luma_scaling;
101   bool chroma_scaling_flag;
102   int  chroma_scaling;
103 
104   entrypoint_t();
105 };
106 
107 struct frame_header_t {
108   int          fcm;
109   frame_type_e frame_type;
110   int          tf_counter;
111   int          repeat_frame;
112   bool         top_field_first_flag;
113   bool         repeat_first_field_flag;
114 
115   frame_header_t();
116   void init();
117 };
118 
119 struct frame_t {
120   frame_header_t header;
121   memory_cptr    data;
122   int64_t        timestamp;
123   int64_t        duration;
124   bool           contains_field, contains_entry_point;
125 
126   frame_t(frame_header_t const &p_header);
127   void init();
128   bool is_key() const;
129 };
130 
is_marker(uint32_t value)131 inline bool is_marker(uint32_t value) {
132   return (value & 0xffffff00) == 0x00000100;
133 }
134 
is_fourcc(uint32_t value)135 inline bool is_fourcc(uint32_t value) {
136   return mtx::calc_fourcc('W', 'V', 'C', '1') == value;
137 }
138 
is_fourcc(const char * value)139 inline bool is_fourcc(const char *value) {
140   return !strncasecmp(value, "WVC1", 4);
141 }
142 
143 bool parse_sequence_header(const unsigned char *buf, int size, sequence_header_t &seqhdr);
144 bool parse_entrypoint(const unsigned char *buf, int size, entrypoint_t &entrypoint, sequence_header_t &seqhdr);
145 bool parse_frame_header(const unsigned char *buf, int size, frame_header_t &frame_header, sequence_header_t &seqhdr);
146 
147 class es_parser_c {
148 protected:
149   int64_t m_stream_pos;
150 
151   bool m_seqhdr_found;
152   bool m_seqhdr_changed;
153   sequence_header_t m_seqhdr;
154   memory_cptr m_raw_seqhdr;
155   memory_cptr m_raw_entrypoint;
156 
157   memory_cptr m_unparsed_buffer;
158 
159   std::deque<memory_cptr> m_pre_frame_extra_data;
160   std::deque<memory_cptr> m_post_frame_extra_data;
161 
162   std::deque<frame_cptr> m_frames;
163   frame_cptr m_current_frame;
164 
165   std::deque<memory_cptr> m_unparsed_packets;
166 
167   std::deque<int64_t> m_timestamps;
168   std::deque<int64_t> m_timestamp_positions;
169   int64_t m_previous_timestamp;
170   int64_t m_num_timestamps;
171   int64_t m_num_repeated_fields;
172 
173   bool m_default_duration_forced;
174   int64_t m_default_duration;
175 
176 public:
177   es_parser_c();
178   virtual ~es_parser_c() = default;
179 
180   virtual void add_bytes(unsigned char *buf, int size);
add_bytes(memory_cptr & buf)181   virtual void add_bytes(memory_cptr &buf) {
182     add_bytes(buf->get_buffer(), buf->get_size());
183   };
184 
185   virtual void flush();
186 
is_sequence_header_available()187   virtual bool is_sequence_header_available() const {
188     return m_seqhdr_found;
189   }
190 
has_sequence_header_changed()191   virtual bool has_sequence_header_changed() const {
192     return m_seqhdr_changed;
193   }
194 
are_headers_available()195   virtual bool are_headers_available() const {
196     return m_seqhdr_found && m_raw_entrypoint;
197   }
198 
get_sequence_header(sequence_header_t & seqhdr)199   virtual void get_sequence_header(sequence_header_t &seqhdr) const {
200     if (m_seqhdr_found)
201       memcpy(&seqhdr, &m_seqhdr, sizeof(sequence_header_t));
202   }
203 
get_raw_sequence_header()204   virtual memory_cptr get_raw_sequence_header() const {
205     return m_seqhdr_found ? memory_cptr{m_raw_seqhdr->clone()} : memory_cptr{};
206   }
207 
get_raw_entrypoint()208   virtual memory_cptr get_raw_entrypoint() const {
209     return m_raw_entrypoint ? m_raw_entrypoint->clone() : memory_cptr{};
210   }
211 
212   virtual void handle_packet(memory_cptr packet);
213 
is_frame_available()214   virtual bool is_frame_available() const {
215     return !m_frames.empty();
216   }
217 
get_frame()218   virtual frame_cptr get_frame() {
219     frame_cptr frame;
220 
221     if (!m_frames.empty()) {
222       frame = m_frames.front();
223       m_frames.pop_front();
224     }
225 
226     return frame;
227   }
228 
229   virtual void add_timestamp(int64_t timestamp, int64_t position);
230 
set_default_duration(int64_t default_duration)231   virtual void set_default_duration(int64_t default_duration) {
232     m_default_duration        = default_duration;
233     m_default_duration_forced = true;
234   }
235 
get_default_duration()236   virtual int64_t get_default_duration() const {
237     return m_default_duration;
238   }
239 
240 protected:
241   virtual void handle_end_of_sequence_packet(memory_cptr packet);
242   virtual void handle_entrypoint_packet(memory_cptr packet);
243   virtual void handle_field_packet(memory_cptr packet);
244   virtual void handle_frame_packet(memory_cptr packet);
245   virtual void handle_sequence_header_packet(memory_cptr packet);
246   virtual void handle_slice_packet(memory_cptr packet);
247   virtual void handle_unknown_packet(uint32_t marker, memory_cptr packet);
248 
249   virtual int64_t get_next_timestamp();
250   virtual int64_t peek_next_calculated_timestamp() const;
251 
252   virtual void add_pre_frame_extra_data(memory_cptr packet);
253   virtual void add_post_frame_extra_data(memory_cptr packet);
254   virtual void combine_extra_data_with_packet();
255 
256   virtual bool postpone_processing(memory_cptr &packet);
257   virtual void process_unparsed_packets();
258 
259   virtual void flush_frame();
260 
261   virtual bool is_timestamp_available() const;
262 
263 protected:
264   static void add_extra_data_if_not_present(std::deque<memory_cptr> &extra_data, memory_cptr const &packet);
265 };
266 
267 }
268