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 
10 #include "common/common_pch.h"
11 
12 #include "common/bit_reader.h"
13 #include "common/mm_io_x.h"
14 #include "common/vp9.h"
15 
16 namespace mtx::vp9 {
17 
18 namespace {
19 bool
parse_color_config(mtx::bits::reader_c & r,header_data_t & h)20 parse_color_config(mtx::bits::reader_c &r,
21                    header_data_t &h) {
22   if (h.profile >= 2)
23     h.bit_depth = r.get_bit() ? 12 : 10;
24   else
25     h.bit_depth = 8;
26 
27   auto color_space = r.get_bits(3);
28   h.subsampling_x  = false;
29   h.subsampling_y  = false;
30 
31   if (color_space == CS_RGB) {
32     r.skip_bit();               // color_range
33     if ((h.profile == 1) || (h.profile == 3)) {
34       h.subsampling_x = r.get_bit();
35       h.subsampling_y = r.get_bit();
36     } else {
37       h.subsampling_x  = true;
38       h.subsampling_y  = true;
39     }
40   }
41 
42   return true;
43 }
44 
45 bool
parse_uncompressed_header(mtx::bits::reader_c & r,header_data_t & h)46 parse_uncompressed_header(mtx::bits::reader_c &r,
47                           header_data_t &h) {
48   if (r.get_bits(2) != 2)       // frame_marker
49     return false;
50 
51   h.profile = r.get_bit() + (r.get_bit() << 1);
52 
53   if (h.profile == 3)
54     r.skip_bit();               // reserved_zero
55 
56   if (r.get_bit())              // show_existing_frame
57     return false;
58 
59   if (r.get_bit())              // frame_type, 0 == KEY_FRAME, 1 == NON_KEY_FRAME
60     return false;
61 
62   r.skip_bits(2);               // show_frame, error_resilient_mode
63 
64   auto frame_sync_marker = r.get_bits(24);
65   if (frame_sync_marker != 0x498342)
66     return false;
67 
68   if (!parse_color_config(r, h))
69     return false;
70 
71   return true;
72 }
73 }
74 
75 std::optional<header_data_t>
parse_header_data(memory_c const & mem)76 parse_header_data(memory_c const &mem) {
77   header_data_t h;
78 
79   try {
80     mtx::bits::reader_c r{mem.get_buffer(), mem.get_size()};
81 
82     if (!parse_uncompressed_header(r, h))
83       return std::nullopt;
84 
85   } catch (mtx::mm_io::end_of_file_x &) {
86     return std::nullopt;
87   }
88 
89   return h;
90 }
91 
92 }
93