summaryrefslogtreecommitdiff
path: root/gst-libs
diff options
context:
space:
mode:
authorSeungha Yang <seungha@centricular.com>2021-03-27 15:32:59 +0900
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>2021-04-07 19:32:29 +0000
commitc36190cbda60bc3c9c6253ac4c43d0d206b6ac2a (patch)
tree6c948b242b2a12f5409c92e2d09704909fc6454a /gst-libs
parent771326a0fb292ae86882cc2dfe160409674ef3ea (diff)
downloadgstreamer-plugins-bad-c36190cbda60bc3c9c6253ac4c43d0d206b6ac2a.tar.gz
codecparsers: Reimplement VP9 parser
Existing VP9 parser implementation doesn't provide information required by other stateless decoding APIs (i.e., DXVA and NVDEC), specifically loop filter and segmentation parameters might not exist current frame. So parser needs to fill the information by using previously parsed information. We can update the gstvp9parser implementation so that it can provide all information required by stateless decoding APIs with a huge API break, or adding more ugly struct in it. Instead doing as such, this commit introduce a new VP9 parser implementation. What is different from existing one? * All variables will follow the specification as much as possible: VP9 Bitstream & Decoding Process Specification - v0.6 31st March 2016 * Parser will fill all the required information for decoding frame to GstVp9FrameHeader struct. In case of old VP9 parser, user needs to read additional data from parser's member variables. * GstVp9StatefulParser object struct is completely completely opaque Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2112>
Diffstat (limited to 'gst-libs')
-rw-r--r--gst-libs/gst/codecs/gstvp9statefulparser.c1214
-rw-r--r--gst-libs/gst/codecs/gstvp9statefulparser.h344
-rw-r--r--gst-libs/gst/codecs/meson.build2
3 files changed, 1560 insertions, 0 deletions
diff --git a/gst-libs/gst/codecs/gstvp9statefulparser.c b/gst-libs/gst/codecs/gstvp9statefulparser.c
new file mode 100644
index 000000000..425e9dd34
--- /dev/null
+++ b/gst-libs/gst/codecs/gstvp9statefulparser.c
@@ -0,0 +1,1214 @@
+/* GStreamer
+ * Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Google, nor the WebM Project, nor the names
+ * of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
+ */
+
+/**
+ * SECTION:gstvp9statefulparser
+ * @title: GstVp9StatefulParser
+ * @short_description: Convenience library for parsing vp9 video bitstream.
+ *
+ * This object is used to parse VP9 bitstream header.
+ *
+ * Since: 1.20
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/base/gstbitreader.h>
+#include "gstvp9statefulparser.h"
+#include <string.h>
+
+#ifndef GST_DISABLE_GST_DEBUG
+#define GST_CAT_DEFAULT ensure_debug_category()
+static GstDebugCategory *
+ensure_debug_category (void)
+{
+ static gsize cat_gonce = 0;
+
+ if (g_once_init_enter (&cat_gonce)) {
+ gsize cat_done;
+
+ cat_done = (gsize) _gst_debug_category_new ("codecparsers_vp9stateful", 0,
+ "VP9 parser library");
+
+ g_once_init_leave (&cat_gonce, cat_done);
+ }
+
+ return (GstDebugCategory *) cat_gonce;
+}
+#else
+#define ensure_debug_category()
+#endif /* GST_DISABLE_GST_DEBUG */
+
+#define VP9_READ_UINT8(val,nbits) G_STMT_START { \
+ if (!gst_bit_reader_get_bits_uint8 (br, &val, nbits)) { \
+ GST_ERROR ("failed to read uint8 for '" G_STRINGIFY (val) "', nbits: %d", nbits); \
+ return GST_VP9_PARSER_BROKEN_DATA; \
+ } \
+} G_STMT_END
+
+#define VP9_READ_UINT16(val,nbits) G_STMT_START { \
+ if (!gst_bit_reader_get_bits_uint16 (br, &val, nbits)) { \
+ GST_ERROR ("failed to read uint16 for '" G_STRINGIFY (val) "', nbits: %d", nbits); \
+ return GST_VP9_PARSER_BROKEN_DATA; \
+ } \
+} G_STMT_END
+
+#define VP9_READ_UINT32(val,nbits) G_STMT_START { \
+ if (!gst_bit_reader_get_bits_uint32 (br, &val, nbits)) { \
+ GST_ERROR ("failed to read uint32 for '" G_STRINGIFY (val) "', nbits: %d", nbits); \
+ return GST_VP9_PARSER_BROKEN_DATA; \
+ } \
+} G_STMT_END
+
+#define VP9_READ_BIT(val) VP9_READ_UINT8(val, 1)
+
+#define VP9_READ_SIGNED_8(val,nbits) G_STMT_START { \
+ guint8 _value; \
+ guint8 _negative; \
+ VP9_READ_UINT8(_value, nbits); \
+ VP9_READ_BIT(_negative); \
+ if (_negative) { \
+ val = (gint8) _value * -1; \
+ } else { \
+ val = _value; \
+ } \
+} G_STMT_END
+
+#define VP9_READ_SIGNED_16(val,nbits) G_STMT_START { \
+ guint16 _value; \
+ guint8 _negative; \
+ VP9_READ_UINT16(_value, nbits); \
+ VP9_READ_BIT(_negative); \
+ if (_negative) { \
+ val = (gint16) _value * -1; \
+ } else { \
+ val = _value; \
+ } \
+} G_STMT_END
+
+#define CHECK_ALLOWED_WITH_DEBUG(dbg, val, min, max) { \
+ if (val < min || val > max) { \
+ GST_WARNING ("value for '" dbg "' not in allowed range. value: %d, range %d-%d", \
+ val, min, max); \
+ return GST_VP9_PARSER_ERROR; \
+ } \
+}
+
+#define CHECK_ALLOWED(val, min, max) \
+ CHECK_ALLOWED_WITH_DEBUG (G_STRINGIFY (val), val, min, max)
+
+static const gint16 dc_qlookup[256] = {
+ 4, 8, 8, 9, 10, 11, 12, 12,
+ 13, 14, 15, 16, 17, 18, 19, 19,
+ 20, 21, 22, 23, 24, 25, 26, 26,
+ 27, 28, 29, 30, 31, 32, 32, 33,
+ 34, 35, 36, 37, 38, 38, 39, 40,
+ 41, 42, 43, 43, 44, 45, 46, 47,
+ 48, 48, 49, 50, 51, 52, 53, 53,
+ 54, 55, 56, 57, 57, 58, 59, 60,
+ 61, 62, 62, 63, 64, 65, 66, 66,
+ 67, 68, 69, 70, 70, 71, 72, 73,
+ 74, 74, 75, 76, 77, 78, 78, 79,
+ 80, 81, 81, 82, 83, 84, 85, 85,
+ 87, 88, 90, 92, 93, 95, 96, 98,
+ 99, 101, 102, 104, 105, 107, 108, 110,
+ 111, 113, 114, 116, 117, 118, 120, 121,
+ 123, 125, 127, 129, 131, 134, 136, 138,
+ 140, 142, 144, 146, 148, 150, 152, 154,
+ 156, 158, 161, 164, 166, 169, 172, 174,
+ 177, 180, 182, 185, 187, 190, 192, 195,
+ 199, 202, 205, 208, 211, 214, 217, 220,
+ 223, 226, 230, 233, 237, 240, 243, 247,
+ 250, 253, 257, 261, 265, 269, 272, 276,
+ 280, 284, 288, 292, 296, 300, 304, 309,
+ 313, 317, 322, 326, 330, 335, 340, 344,
+ 349, 354, 359, 364, 369, 374, 379, 384,
+ 389, 395, 400, 406, 411, 417, 423, 429,
+ 435, 441, 447, 454, 461, 467, 475, 482,
+ 489, 497, 505, 513, 522, 530, 539, 549,
+ 559, 569, 579, 590, 602, 614, 626, 640,
+ 654, 668, 684, 700, 717, 736, 755, 775,
+ 796, 819, 843, 869, 896, 925, 955, 988,
+ 1022, 1058, 1098, 1139, 1184, 1232, 1282, 1336,
+};
+
+static const gint16 dc_qlookup_10[256] = {
+ 4, 9, 10, 13, 15, 17, 20, 22,
+ 25, 28, 31, 34, 37, 40, 43, 47,
+ 50, 53, 57, 60, 64, 68, 71, 75,
+ 78, 82, 86, 90, 93, 97, 101, 105,
+ 109, 113, 116, 120, 124, 128, 132, 136,
+ 140, 143, 147, 151, 155, 159, 163, 166,
+ 170, 174, 178, 182, 185, 189, 193, 197,
+ 200, 204, 208, 212, 215, 219, 223, 226,
+ 230, 233, 237, 241, 244, 248, 251, 255,
+ 259, 262, 266, 269, 273, 276, 280, 283,
+ 287, 290, 293, 297, 300, 304, 307, 310,
+ 314, 317, 321, 324, 327, 331, 334, 337,
+ 343, 350, 356, 362, 369, 375, 381, 387,
+ 394, 400, 406, 412, 418, 424, 430, 436,
+ 442, 448, 454, 460, 466, 472, 478, 484,
+ 490, 499, 507, 516, 525, 533, 542, 550,
+ 559, 567, 576, 584, 592, 601, 609, 617,
+ 625, 634, 644, 655, 666, 676, 687, 698,
+ 708, 718, 729, 739, 749, 759, 770, 782,
+ 795, 807, 819, 831, 844, 856, 868, 880,
+ 891, 906, 920, 933, 947, 961, 975, 988,
+ 1001, 1015, 1030, 1045, 1061, 1076, 1090, 1105,
+ 1120, 1137, 1153, 1170, 1186, 1202, 1218, 1236,
+ 1253, 1271, 1288, 1306, 1323, 1342, 1361, 1379,
+ 1398, 1416, 1436, 1456, 1476, 1496, 1516, 1537,
+ 1559, 1580, 1601, 1624, 1647, 1670, 1692, 1717,
+ 1741, 1766, 1791, 1817, 1844, 1871, 1900, 1929,
+ 1958, 1990, 2021, 2054, 2088, 2123, 2159, 2197,
+ 2236, 2276, 2319, 2363, 2410, 2458, 2508, 2561,
+ 2616, 2675, 2737, 2802, 2871, 2944, 3020, 3102,
+ 3188, 3280, 3375, 3478, 3586, 3702, 3823, 3953,
+ 4089, 4236, 4394, 4559, 4737, 4929, 5130, 5347,
+};
+
+static const gint16 dc_qlookup_12[256] = {
+ 4, 12, 18, 25, 33, 41, 50, 60,
+ 70, 80, 91, 103, 115, 127, 140, 153,
+ 166, 180, 194, 208, 222, 237, 251, 266,
+ 281, 296, 312, 327, 343, 358, 374, 390,
+ 405, 421, 437, 453, 469, 484, 500, 516,
+ 532, 548, 564, 580, 596, 611, 627, 643,
+ 659, 674, 690, 706, 721, 737, 752, 768,
+ 783, 798, 814, 829, 844, 859, 874, 889,
+ 904, 919, 934, 949, 964, 978, 993, 1008,
+ 1022, 1037, 1051, 1065, 1080, 1094, 1108, 1122,
+ 1136, 1151, 1165, 1179, 1192, 1206, 1220, 1234,
+ 1248, 1261, 1275, 1288, 1302, 1315, 1329, 1342,
+ 1368, 1393, 1419, 1444, 1469, 1494, 1519, 1544,
+ 1569, 1594, 1618, 1643, 1668, 1692, 1717, 1741,
+ 1765, 1789, 1814, 1838, 1862, 1885, 1909, 1933,
+ 1957, 1992, 2027, 2061, 2096, 2130, 2165, 2199,
+ 2233, 2267, 2300, 2334, 2367, 2400, 2434, 2467,
+ 2499, 2532, 2575, 2618, 2661, 2704, 2746, 2788,
+ 2830, 2872, 2913, 2954, 2995, 3036, 3076, 3127,
+ 3177, 3226, 3275, 3324, 3373, 3421, 3469, 3517,
+ 3565, 3621, 3677, 3733, 3788, 3843, 3897, 3951,
+ 4005, 4058, 4119, 4181, 4241, 4301, 4361, 4420,
+ 4479, 4546, 4612, 4677, 4742, 4807, 4871, 4942,
+ 5013, 5083, 5153, 5222, 5291, 5367, 5442, 5517,
+ 5591, 5665, 5745, 5825, 5905, 5984, 6063, 6149,
+ 6234, 6319, 6404, 6495, 6587, 6678, 6769, 6867,
+ 6966, 7064, 7163, 7269, 7376, 7483, 7599, 7715,
+ 7832, 7958, 8085, 8214, 8352, 8492, 8635, 8788,
+ 8945, 9104, 9275, 9450, 9639, 9832, 10031, 10245,
+ 10465, 10702, 10946, 11210, 11482, 11776, 12081, 12409,
+ 12750, 13118, 13501, 13913, 14343, 14807, 15290, 15812,
+ 16356, 16943, 17575, 18237, 18949, 19718, 20521, 21387,
+};
+
+static const gint16 ac_qlookup[256] = {
+ 4, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, 40, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62,
+ 63, 64, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, 84, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102,
+ 104, 106, 108, 110, 112, 114, 116, 118,
+ 120, 122, 124, 126, 128, 130, 132, 134,
+ 136, 138, 140, 142, 144, 146, 148, 150,
+ 152, 155, 158, 161, 164, 167, 170, 173,
+ 176, 179, 182, 185, 188, 191, 194, 197,
+ 200, 203, 207, 211, 215, 219, 223, 227,
+ 231, 235, 239, 243, 247, 251, 255, 260,
+ 265, 270, 275, 280, 285, 290, 295, 300,
+ 305, 311, 317, 323, 329, 335, 341, 347,
+ 353, 359, 366, 373, 380, 387, 394, 401,
+ 408, 416, 424, 432, 440, 448, 456, 465,
+ 474, 483, 492, 501, 510, 520, 530, 540,
+ 550, 560, 571, 582, 593, 604, 615, 627,
+ 639, 651, 663, 676, 689, 702, 715, 729,
+ 743, 757, 771, 786, 801, 816, 832, 848,
+ 864, 881, 898, 915, 933, 951, 969, 988,
+ 1007, 1026, 1046, 1066, 1087, 1108, 1129, 1151,
+ 1173, 1196, 1219, 1243, 1267, 1292, 1317, 1343,
+ 1369, 1396, 1423, 1451, 1479, 1508, 1537, 1567,
+ 1597, 1628, 1660, 1692, 1725, 1759, 1793, 1828,
+};
+
+static const gint16 ac_qlookup_10[256] = {
+ 4, 9, 11, 13, 16, 18, 21, 24,
+ 27, 30, 33, 37, 40, 44, 48, 51,
+ 55, 59, 63, 67, 71, 75, 79, 83,
+ 88, 92, 96, 100, 105, 109, 114, 118,
+ 122, 127, 131, 136, 140, 145, 149, 154,
+ 158, 163, 168, 172, 177, 181, 186, 190,
+ 195, 199, 204, 208, 213, 217, 222, 226,
+ 231, 235, 240, 244, 249, 253, 258, 262,
+ 267, 271, 275, 280, 284, 289, 293, 297,
+ 302, 306, 311, 315, 319, 324, 328, 332,
+ 337, 341, 345, 349, 354, 358, 362, 367,
+ 371, 375, 379, 384, 388, 392, 396, 401,
+ 409, 417, 425, 433, 441, 449, 458, 466,
+ 474, 482, 490, 498, 506, 514, 523, 531,
+ 539, 547, 555, 563, 571, 579, 588, 596,
+ 604, 616, 628, 640, 652, 664, 676, 688,
+ 700, 713, 725, 737, 749, 761, 773, 785,
+ 797, 809, 825, 841, 857, 873, 889, 905,
+ 922, 938, 954, 970, 986, 1002, 1018, 1038,
+ 1058, 1078, 1098, 1118, 1138, 1158, 1178, 1198,
+ 1218, 1242, 1266, 1290, 1314, 1338, 1362, 1386,
+ 1411, 1435, 1463, 1491, 1519, 1547, 1575, 1603,
+ 1631, 1663, 1695, 1727, 1759, 1791, 1823, 1859,
+ 1895, 1931, 1967, 2003, 2039, 2079, 2119, 2159,
+ 2199, 2239, 2283, 2327, 2371, 2415, 2459, 2507,
+ 2555, 2603, 2651, 2703, 2755, 2807, 2859, 2915,
+ 2971, 3027, 3083, 3143, 3203, 3263, 3327, 3391,
+ 3455, 3523, 3591, 3659, 3731, 3803, 3876, 3952,
+ 4028, 4104, 4184, 4264, 4348, 4432, 4516, 4604,
+ 4692, 4784, 4876, 4972, 5068, 5168, 5268, 5372,
+ 5476, 5584, 5692, 5804, 5916, 6032, 6148, 6268,
+ 6388, 6512, 6640, 6768, 6900, 7036, 7172, 7312,
+};
+
+static const gint16 ac_qlookup_12[256] = {
+ 4, 13, 19, 27, 35, 44, 54, 64,
+ 75, 87, 99, 112, 126, 139, 154, 168,
+ 183, 199, 214, 230, 247, 263, 280, 297,
+ 314, 331, 349, 366, 384, 402, 420, 438,
+ 456, 475, 493, 511, 530, 548, 567, 586,
+ 604, 623, 642, 660, 679, 698, 716, 735,
+ 753, 772, 791, 809, 828, 846, 865, 884,
+ 902, 920, 939, 957, 976, 994, 1012, 1030,
+ 1049, 1067, 1085, 1103, 1121, 1139, 1157, 1175,
+ 1193, 1211, 1229, 1246, 1264, 1282, 1299, 1317,
+ 1335, 1352, 1370, 1387, 1405, 1422, 1440, 1457,
+ 1474, 1491, 1509, 1526, 1543, 1560, 1577, 1595,
+ 1627, 1660, 1693, 1725, 1758, 1791, 1824, 1856,
+ 1889, 1922, 1954, 1987, 2020, 2052, 2085, 2118,
+ 2150, 2183, 2216, 2248, 2281, 2313, 2346, 2378,
+ 2411, 2459, 2508, 2556, 2605, 2653, 2701, 2750,
+ 2798, 2847, 2895, 2943, 2992, 3040, 3088, 3137,
+ 3185, 3234, 3298, 3362, 3426, 3491, 3555, 3619,
+ 3684, 3748, 3812, 3876, 3941, 4005, 4069, 4149,
+ 4230, 4310, 4390, 4470, 4550, 4631, 4711, 4791,
+ 4871, 4967, 5064, 5160, 5256, 5352, 5448, 5544,
+ 5641, 5737, 5849, 5961, 6073, 6185, 6297, 6410,
+ 6522, 6650, 6778, 6906, 7034, 7162, 7290, 7435,
+ 7579, 7723, 7867, 8011, 8155, 8315, 8475, 8635,
+ 8795, 8956, 9132, 9308, 9484, 9660, 9836, 10028,
+ 10220, 10412, 10604, 10812, 11020, 11228, 11437, 11661,
+ 11885, 12109, 12333, 12573, 12813, 13053, 13309, 13565,
+ 13821, 14093, 14365, 14637, 14925, 15213, 15502, 15806,
+ 16110, 16414, 16734, 17054, 17390, 17726, 18062, 18414,
+ 18766, 19134, 19502, 19886, 20270, 20670, 21070, 21486,
+ 21902, 22334, 22766, 23214, 23662, 24126, 24590, 25070,
+ 25551, 26047, 26559, 27071, 27599, 28143, 28687, 29247,
+};
+
+static GstVp9ParserResult
+parse_frame_marker (GstBitReader * br)
+{
+ guint8 frame_marker;
+
+ VP9_READ_UINT8 (frame_marker, 2);
+
+ if (frame_marker != GST_VP9_FRAME_MARKER) {
+ GST_ERROR ("Invalid VP9 Frame Marker");
+ return GST_VP9_PARSER_ERROR;
+ }
+
+ return GST_VP9_PARSER_OK;
+}
+
+static GstVp9ParserResult
+parse_frame_sync_code (GstBitReader * br)
+{
+ guint32 code;
+
+ VP9_READ_UINT32 (code, 24);
+ if (code != GST_VP9_SYNC_CODE) {
+ GST_ERROR ("%d is not VP9 sync code", code);
+ return GST_VP9_PARSER_ERROR;
+ }
+
+ return GST_VP9_PARSER_OK;
+}
+
+/* 6.2.2 Color config syntax */
+static GstVp9ParserResult
+parse_color_config (GstVp9StatefulParser * self, GstBitReader * br,
+ GstVp9FrameHeader * header)
+{
+ guint8 bit = 0;
+
+ if (header->profile >= GST_VP9_PROFILE_2) {
+ VP9_READ_BIT (bit);
+ if (bit) {
+ header->bit_depth = GST_VP9_BIT_DEPTH_12;
+ } else {
+ header->bit_depth = GST_VP9_BIT_DEPTH_10;
+ }
+ } else {
+ header->bit_depth = GST_VP9_BIT_DEPTH_8;
+ }
+
+ VP9_READ_UINT8 (header->color_space, 3);
+ if (header->color_space != GST_VP9_CS_SRGB) {
+ VP9_READ_BIT (header->color_range);
+
+ if (header->profile == GST_VP9_PROFILE_1
+ || header->profile == GST_VP9_PROFILE_3) {
+ VP9_READ_BIT (header->subsampling_x);
+ VP9_READ_BIT (header->subsampling_y);
+
+ if (header->subsampling_x == 1 && header->subsampling_y == 1) {
+ GST_ERROR
+ ("4:2:0 subsampling is not supported in profile_1 or profile_3");
+ return GST_VP9_PARSER_ERROR;
+ }
+
+ /* reserved bit */
+ VP9_READ_BIT (bit);
+ } else {
+ header->subsampling_y = header->subsampling_x = 1;
+ }
+ } else {
+ header->color_range = GST_VP9_CR_FULL;
+ if (header->profile == GST_VP9_PROFILE_1
+ || header->profile == GST_VP9_PROFILE_3) {
+ /* reserved bit */
+ VP9_READ_BIT (bit);
+ } else {
+ GST_ERROR
+ ("4:4:4 subsampling is not supported in profile_0 and profile_2");
+ return GST_VP9_PARSER_ERROR;
+ }
+ }
+
+ self->bit_depth = header->bit_depth;
+ self->color_space = header->color_space;
+ self->subsampling_x = header->subsampling_x;
+ self->subsampling_y = header->subsampling_y;
+ self->color_range = header->color_range;
+
+ return GST_VP9_PARSER_OK;
+}
+
+/* 6.2 Uncompressed header syntax */
+static GstVp9ParserResult
+parse_profile (GstBitReader * br, guint8 * profile)
+{
+ guint8 profile_low_bit, profile_high_bit, ret, bit;
+
+ VP9_READ_BIT (profile_low_bit);
+ VP9_READ_BIT (profile_high_bit);
+
+ ret = (profile_high_bit << 1) | profile_low_bit;
+ if (ret == 3) {
+ /* reserved bit */
+ VP9_READ_BIT (bit);
+ }
+
+ *profile = ret;
+
+ return GST_VP9_PARSER_OK;
+}
+
+/* 6.2.6 Compute image size syntax */
+static void
+compute_image_size (GstVp9StatefulParser * self, guint32 width, guint32 height)
+{
+ self->mi_cols = (width + 7) >> 3;
+ self->mi_rows = (height + 7) >> 3;
+ self->sb64_cols = (self->mi_cols + 7) >> 3;
+ self->sb64_rows = (self->mi_rows + 7) >> 3;
+}
+
+static GstVp9ParserResult
+parse_frame_or_render_size (GstBitReader * br,
+ guint32 * width, guint32 * height)
+{
+ guint32 width_minus_1;
+ guint32 height_minus_1;
+
+ VP9_READ_UINT32 (width_minus_1, 16);
+ VP9_READ_UINT32 (height_minus_1, 16);
+
+ *width = width_minus_1 + 1;
+ *height = height_minus_1 + 1;
+
+ return GST_VP9_PARSER_OK;
+}
+
+/* 6.2.3 Frame size syntax */
+static GstVp9ParserResult
+parse_frame_size (GstVp9StatefulParser * self, GstBitReader * br,
+ guint32 * width, guint32 * height)
+{
+ GstVp9ParserResult rst;
+
+ rst = parse_frame_or_render_size (br, width, height);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Failed to parse frame size");
+ return rst;
+ }
+
+ compute_image_size (self, *width, *height);
+
+ return GST_VP9_PARSER_OK;
+}
+
+/* 6.2.4 Render size syntax */
+static GstVp9ParserResult
+parse_render_size (GstBitReader * br, GstVp9FrameHeader * header)
+{
+ VP9_READ_BIT (header->render_and_frame_size_different);
+ if (header->render_and_frame_size_different) {
+ return parse_frame_or_render_size (br,
+ &header->render_width, &header->render_height);
+ } else {
+ header->render_width = header->width;
+ header->render_height = header->height;
+ }
+
+ return GST_VP9_PARSER_OK;
+}
+
+/* 6.2.5 Frame size with refs syntax */
+static GstVp9ParserResult
+parse_frame_size_with_refs (GstVp9StatefulParser * self, GstBitReader * br,
+ GstVp9FrameHeader * header)
+{
+ guint8 found_ref = 0;
+ guint i;
+
+ for (i = 0; i < GST_VP9_REFS_PER_FRAME; i++) {
+ VP9_READ_BIT (found_ref);
+
+ if (found_ref) {
+ guint8 idx = header->ref_frame_idx[i];
+
+ header->width = self->reference[idx].width;
+ header->height = self->reference[idx].height;
+ break;
+ }
+ }
+
+ if (found_ref == 0) {
+ GstVp9ParserResult rst;
+
+ rst = parse_frame_size (self, br, &header->width, &header->height);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Failed to parse frame size without refs");
+ return rst;
+ }
+ } else {
+ compute_image_size (self, header->width, header->height);
+ }
+
+ return parse_render_size (br, header);
+}
+
+/* 6.2.7 Interpolation filter syntax */
+static GstVp9ParserResult
+read_interpolation_filter (GstBitReader * br, GstVp9FrameHeader * header)
+{
+ static const GstVp9InterpolationFilter filter_map[] = {
+ GST_VP9_INTERPOLATION_FILTER_EIGHTTAP_SMOOTH,
+ GST_VP9_INTERPOLATION_FILTER_EIGHTTAP,
+ GST_VP9_INTERPOLATION_FILTER_EIGHTTAP_SHARP,
+ GST_VP9_INTERPOLATION_FILTER_BILINEAR
+ };
+ guint8 is_filter_switchable;
+
+ VP9_READ_BIT (is_filter_switchable);
+ if (is_filter_switchable) {
+ header->interpolation_filter = GST_VP9_INTERPOLATION_FILTER_SWITCHABLE;
+ } else {
+ guint8 map_val;
+
+ VP9_READ_UINT8 (map_val, 2);
+ header->interpolation_filter = filter_map[map_val];
+ }
+
+ return GST_VP9_PARSER_OK;
+}
+
+/* 6.2.8 Loop filter params syntax */
+static GstVp9ParserResult
+parse_loop_filter_params (GstBitReader * br, GstVp9LoopFilterParams * params)
+{
+ VP9_READ_UINT8 (params->loop_filter_level, 6);
+ VP9_READ_UINT8 (params->loop_filter_sharpness, 3);
+ VP9_READ_BIT (params->loop_filter_delta_enabled);
+
+ if (params->loop_filter_delta_enabled) {
+ VP9_READ_BIT (params->loop_filter_delta_update);
+ if (params->loop_filter_delta_update) {
+ guint i;
+
+ for (i = 0; i < GST_VP9_MAX_REF_LF_DELTAS; i++) {
+ VP9_READ_BIT (params->update_ref_delta[i]);
+ if (params->update_ref_delta[i]) {
+ VP9_READ_SIGNED_8 (params->loop_filter_ref_deltas[i], 6);
+ }
+ }
+
+ for (i = 0; i < GST_VP9_MAX_MODE_LF_DELTAS; i++) {
+ VP9_READ_BIT (params->update_mode_delta[i]);
+ if (params->update_mode_delta[i])
+ VP9_READ_SIGNED_8 (params->loop_filter_mode_deltas[i], 6);
+ }
+ }
+ }
+
+ return GST_VP9_PARSER_OK;
+}
+
+/* 6.2.10 Delta quantizer syntax */
+static inline GstVp9ParserResult
+parse_delta_q (GstBitReader * br, gint8 * value)
+{
+ guint8 read_signed;
+ gint8 delta_q;
+
+ VP9_READ_BIT (read_signed);
+ if (!read_signed) {
+ *value = 0;
+ return GST_VP9_PARSER_OK;
+ }
+
+ VP9_READ_SIGNED_8 (delta_q, 4);
+ *value = delta_q;
+
+ return GST_VP9_PARSER_OK;
+}
+
+/* 6.2.9 Quantization params syntax */
+static GstVp9ParserResult
+parse_quantization_params (GstBitReader * br, GstVp9FrameHeader * header)
+{
+ GstVp9QuantizationParams *params = &header->quantization_params;
+ GstVp9ParserResult rst;
+
+ VP9_READ_UINT8 (params->base_q_idx, 8);
+ rst = parse_delta_q (br, &params->delta_q_y_dc);
+ if (rst != GST_VP9_PARSER_OK)
+ return rst;
+
+ rst = parse_delta_q (br, &params->delta_q_uv_dc);
+ if (rst != GST_VP9_PARSER_OK)
+ return rst;
+
+ rst = parse_delta_q (br, &params->delta_q_uv_ac);
+ if (rst != GST_VP9_PARSER_OK)
+ return rst;
+
+ header->lossless_flag = params->base_q_idx == 0 && params->delta_q_y_dc == 0
+ && params->delta_q_uv_dc == 0 && params->delta_q_uv_ac == 0;
+
+ return GST_VP9_PARSER_OK;
+}
+
+/* 6.2.12 Probability syntax */
+static GstVp9ParserResult
+read_prob (GstBitReader * br, guint8 * val)
+{
+ guint8 prob = GST_VP9_MAX_PROB;
+ guint8 prob_coded;
+
+ VP9_READ_BIT (prob_coded);
+
+ if (prob_coded)
+ VP9_READ_UINT8 (prob, 8);
+
+ *val = prob;
+
+ return GST_VP9_PARSER_OK;
+}
+
+/* 6.2.11 Segmentation params syntax */
+static GstVp9ParserResult
+parse_segmentation_params (GstBitReader * br, GstVp9SegmentationParams * params)
+{
+ guint i;
+ GstVp9ParserResult rst;
+
+ params->segmentation_update_map = 0;
+ params->segmentation_update_data = 0;
+
+ VP9_READ_BIT (params->segmentation_enabled);
+ if (!params->segmentation_enabled)
+ return GST_VP9_PARSER_OK;
+
+ VP9_READ_BIT (params->segmentation_update_map);
+ if (params->segmentation_update_map) {
+ for (i = 0; i < GST_VP9_SEG_TREE_PROBS; i++) {
+ rst = read_prob (br, &params->segmentation_tree_probs[i]);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Failed to read segmentation_tree_probs[%d]", i);
+ return rst;
+ }
+ }
+
+ VP9_READ_BIT (params->segmentation_temporal_update);
+ if (params->segmentation_temporal_update) {
+ for (i = 0; i < GST_VP9_PREDICTION_PROBS; i++) {
+ rst = read_prob (br, &params->segmentation_pred_prob[i]);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Failed to read segmentation_pred_prob[%d]", i);
+ return rst;
+ }
+ }
+ } else {
+ for (i = 0; i < GST_VP9_PREDICTION_PROBS; i++)
+ params->segmentation_pred_prob[i] = GST_VP9_MAX_PROB;
+ }
+ }
+
+ VP9_READ_BIT (params->segmentation_update_data);
+ if (params->segmentation_update_data) {
+ VP9_READ_BIT (params->segmentation_abs_or_delta_update);
+
+ for (i = 0; i < GST_VP9_MAX_SEGMENTS; i++) {
+ VP9_READ_BIT (params->feature_enabled[i][GST_VP9_SEG_LVL_ALT_Q]);
+ if (params->feature_enabled[i][GST_VP9_SEG_LVL_ALT_Q])
+ VP9_READ_SIGNED_16 (params->feature_data[i][GST_VP9_SEG_LVL_ALT_Q], 8);
+
+ VP9_READ_BIT (params->feature_enabled[i][GST_VP9_SEG_LVL_ALT_L]);
+ if (params->feature_enabled[i][GST_VP9_SEG_LVL_ALT_L])
+ VP9_READ_SIGNED_8 (params->feature_data[i][GST_VP9_SEG_LVL_ALT_L], 6);
+
+ VP9_READ_BIT (params->feature_enabled[i][GST_VP9_SEG_LVL_REF_FRAME]);
+ if (params->feature_enabled[i][GST_VP9_SEG_LVL_REF_FRAME]) {
+ guint8 val;
+
+ VP9_READ_UINT8 (val, 2);
+ params->feature_data[i][GST_VP9_SEG_LVL_REF_FRAME] = val;
+ }
+
+ VP9_READ_BIT (params->feature_enabled[i][GST_VP9_SEG_SEG_LVL_SKIP]);
+ }
+ }
+
+ return GST_VP9_PARSER_OK;
+}
+
+/* 6.2.14 Tile size calculation */
+static guint
+calc_min_log2_tile_cols (guint32 sb64_cols)
+{
+ guint minLog2 = 0;
+ static const guint MAX_TILE_WIDTH_B64 = 64;
+
+ while ((MAX_TILE_WIDTH_B64 << minLog2) < sb64_cols)
+ minLog2++;
+
+ return minLog2;
+}
+
+static guint
+calc_max_log2_tile_cols (guint32 sb64_cols)
+{
+ guint maxLog2 = 1;
+ static const guint MIN_TILE_WIDTH_B64 = 4;
+
+ while ((sb64_cols >> maxLog2) >= MIN_TILE_WIDTH_B64)
+ maxLog2++;
+
+ return maxLog2 - 1;
+}
+
+/* 6.2.13 Tile info syntax */
+static GstVp9ParserResult
+parse_tile_info (GstVp9StatefulParser * self, GstBitReader * br,
+ GstVp9FrameHeader * header)
+{
+ guint32 minLog2TileCols = calc_min_log2_tile_cols (self->sb64_cols);
+ guint32 maxLog2TileCols = calc_max_log2_tile_cols (self->sb64_cols);
+
+ header->tile_cols_log2 = minLog2TileCols;
+
+ while (header->tile_cols_log2 < maxLog2TileCols) {
+ guint8 increment_tile_cols_log2;
+
+ VP9_READ_BIT (increment_tile_cols_log2);
+ if (increment_tile_cols_log2)
+ header->tile_cols_log2++;
+ else
+ break;
+ }
+
+ if (header->tile_cols_log2 > 6) {
+ GST_ERROR ("Invalid number of tile columns");
+ return GST_VP9_PARSER_ERROR;
+ }
+
+ VP9_READ_BIT (header->tile_rows_log2);
+ if (header->tile_rows_log2) {
+ guint8 increment_tile_rows_log2;
+
+ VP9_READ_BIT (increment_tile_rows_log2);
+ header->tile_rows_log2 += increment_tile_rows_log2;
+ }
+
+ return GST_VP9_PARSER_OK;
+}
+
+/* 7.2 Uncompressed header semantics */
+static void
+setup_past_independence (GstVp9StatefulParser * self,
+ GstVp9FrameHeader * header)
+{
+ memset (self->segmentation_params.feature_enabled,
+ 0, sizeof (self->segmentation_params.feature_enabled));
+ memset (self->segmentation_params.feature_data,
+ 0, sizeof (self->segmentation_params.feature_data));
+
+ self->segmentation_params.segmentation_abs_or_delta_update = 0;
+
+ self->loop_filter_params.loop_filter_delta_enabled = 1;
+ self->loop_filter_params.loop_filter_ref_deltas[GST_VP9_REF_FRAME_INTRA] = 1;
+ self->loop_filter_params.loop_filter_ref_deltas[GST_VP9_REF_FRAME_LAST] = 0;
+ self->loop_filter_params.loop_filter_ref_deltas[GST_VP9_REF_FRAME_GOLDEN] =
+ -1;
+ self->loop_filter_params.loop_filter_ref_deltas[GST_VP9_REF_FRAME_ALTREF] =
+ -1;
+
+ memset (self->loop_filter_params.loop_filter_mode_deltas, 0,
+ sizeof (self->loop_filter_params.loop_filter_mode_deltas));
+ memset (header->ref_frame_sign_bias, 0, sizeof (header->ref_frame_sign_bias));
+}
+
+/**
+ * gst_vp9_stateful_parser_new:
+ *
+ * Creates a new #GstVp9StatefulParser. It should be freed with
+ * gst_vp9_stateful_parser_free() after use.
+ *
+ * Returns: a new #GstVp9StatefulParser
+ *
+ * Since: 1.20
+ */
+GstVp9StatefulParser *
+gst_vp9_stateful_parser_new (void)
+{
+ GstVp9StatefulParser *parser;
+
+ parser = g_new0 (GstVp9StatefulParser, 1);
+
+ return parser;
+}
+
+/**
+ * gst_vp9_stateful_parser_free:
+ * @parser: the #GstVp9StatefulParser to free
+ *
+ * Frees @parser.
+ *
+ * Since: 1.20
+ */
+void
+gst_vp9_stateful_parser_free (GstVp9StatefulParser * parser)
+{
+ g_free (parser);
+}
+
+/**
+ * gst_vp9_stateful_parser_parse_frame_header:
+ * @parser: The #GstVp9StatefulParser
+ * @header: The #GstVp9FrameHeader to fill
+ * @data: The data to parse
+ * @size: The size of the @data to parse
+ *
+ * Parses the VP9 bitstream contained in @data, and fills in @header
+ * with the information. The @size argument represent the whole frame size.
+ *
+ * Returns: a #GstVp9ParserResult
+ *
+ * Since: 1.20
+ */
+GstVp9ParserResult
+gst_vp9_stateful_parser_parse_frame_header (GstVp9StatefulParser * parser,
+ GstVp9FrameHeader * header, const guint8 * data, gsize size)
+{
+ GstBitReader bit_reader;
+ GstBitReader *br = &bit_reader;
+ gboolean frame_is_intra = FALSE;
+ GstVp9ParserResult rst = GST_VP9_PARSER_OK;
+ guint i;
+
+ g_return_val_if_fail (parser, GST_VP9_PARSER_ERROR);
+ g_return_val_if_fail (header, GST_VP9_PARSER_ERROR);
+ g_return_val_if_fail (data, GST_VP9_PARSER_ERROR);
+ g_return_val_if_fail (size, GST_VP9_PARSER_ERROR);
+
+ gst_bit_reader_init (br, data, size);
+ memset (header, 0, sizeof (GstVp9FrameHeader));
+
+ /* Parsing Uncompressed Data Chunk */
+ rst = parse_frame_marker (br);
+ if (rst != GST_VP9_PARSER_OK)
+ return rst;
+
+ rst = parse_profile (br, &header->profile);
+ if (rst != GST_VP9_PARSER_OK)
+ return rst;
+
+ CHECK_ALLOWED (header->profile, GST_VP9_PROFILE_0, GST_VP9_PROFILE_3);
+
+ VP9_READ_BIT (header->show_existing_frame);
+ if (header->show_existing_frame) {
+ VP9_READ_UINT8 (header->frame_to_show_map_idx, 3);
+ return GST_VP9_PARSER_OK;
+ }
+
+ VP9_READ_BIT (header->frame_type);
+ VP9_READ_BIT (header->show_frame);
+ VP9_READ_BIT (header->error_resilient_mode);
+
+ if (header->frame_type == GST_VP9_KEY_FRAME) {
+ rst = parse_frame_sync_code (br);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Invalid VP9 sync code in keyframe");
+ return rst;
+ }
+
+ rst = parse_color_config (parser, br, header);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Failed to parse color config of keyframe");
+ return rst;
+ }
+
+ rst = parse_frame_size (parser, br, &header->width, &header->height);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Failed to parse frame size of keyframe");
+ return rst;
+ }
+
+ rst = parse_render_size (br, header);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Failed to parse render size of keyframe");
+ return rst;
+ }
+
+ header->refresh_frame_flags = 0xff;
+ frame_is_intra = TRUE;
+ } else {
+ if (header->show_frame == 0)
+ VP9_READ_BIT (header->intra_only);
+
+ frame_is_intra = header->intra_only;
+ if (header->error_resilient_mode == 0)
+ VP9_READ_UINT8 (header->reset_frame_context, 2);
+
+ if (header->intra_only) {
+ rst = parse_frame_sync_code (br);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Invalid VP9 sync code in intra-only frame");
+ return rst;
+ }
+
+ if (header->profile > GST_VP9_PROFILE_0) {
+ rst = parse_color_config (parser, br, header);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Failed to parse color config of intra-only frame");
+ return rst;
+ }
+ } else {
+ parser->color_space = header->color_space = GST_VP9_CS_BT_601;
+ parser->color_range = header->color_range = GST_VP9_CR_LIMITED;
+ parser->subsampling_x = parser->subsampling_y =
+ header->subsampling_x = header->subsampling_y = 1;
+ parser->bit_depth = header->bit_depth = GST_VP9_BIT_DEPTH_8;
+ }
+
+ VP9_READ_UINT8 (header->refresh_frame_flags, 8);
+ rst = parse_frame_size (parser, br, &header->width, &header->height);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Failed to pase frame size of intra-only frame");
+ return rst;
+ }
+
+ rst = parse_render_size (br, header);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Failed to parse render size of intra-only frame");
+ return rst;
+ }
+ } else {
+ /* copy color_config from previously parsed one */
+ header->color_space = parser->color_space;
+ header->color_range = parser->color_range;
+ header->subsampling_x = parser->subsampling_x;
+ header->subsampling_y = parser->subsampling_y;
+ header->bit_depth = parser->bit_depth;
+
+ VP9_READ_UINT8 (header->refresh_frame_flags, 8);
+ for (i = 0; i < GST_VP9_REFS_PER_FRAME; i++) {
+ VP9_READ_UINT8 (header->ref_frame_idx[i], 3);
+ VP9_READ_BIT (header->ref_frame_sign_bias[GST_VP9_REF_FRAME_LAST + i]);
+ }
+
+ rst = parse_frame_size_with_refs (parser, br, header);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Failed to parse frame size with refs");
+ return rst;
+ }
+
+ VP9_READ_BIT (header->allow_high_precision_mv);
+ rst = read_interpolation_filter (br, header);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Failed to read interpolation filter information");
+ return rst;
+ }
+ }
+ }
+
+ if (!header->error_resilient_mode) {
+ VP9_READ_BIT (header->refresh_frame_context);
+ VP9_READ_BIT (header->frame_parallel_decoding_mode);
+ } else {
+ header->refresh_frame_context = 0;
+ header->frame_parallel_decoding_mode = 1;
+ }
+
+ VP9_READ_UINT8 (header->frame_context_idx, 2);
+
+ if (frame_is_intra || header->error_resilient_mode)
+ setup_past_independence (parser, header);
+
+ /* First update our own table, and we will copy to frame header later */
+ rst = parse_loop_filter_params (br, &parser->loop_filter_params);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Failed to parse loop filter params");
+ return rst;
+ }
+
+ rst = parse_quantization_params (br, header);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Failed to parse quantization params");
+ return rst;
+ }
+
+ /* Also update our own table, then it will be copied later */
+ rst = parse_segmentation_params (br, &parser->segmentation_params);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Failed to parse segmentation params");
+ return rst;
+ }
+
+ rst = parse_tile_info (parser, br, header);
+ if (rst != GST_VP9_PARSER_OK) {
+ GST_ERROR ("Failed to parse tile info");
+ return rst;
+ }
+
+ VP9_READ_UINT16 (header->header_size_in_bytes, 16);
+ if (!header->header_size_in_bytes) {
+ GST_ERROR ("Failed to parse header size in bytes");
+ return GST_VP9_PARSER_ERROR;
+ }
+
+ /* copy our values to header */
+ memcpy (&header->loop_filter_params, &parser->loop_filter_params,
+ sizeof (GstVp9LoopFilterParams));
+ memcpy (&header->segmentation_params, &parser->segmentation_params,
+ sizeof (GstVp9SegmentationParams));
+
+ /* And update reference frames */
+ for (i = 0; i < GST_VP9_REF_FRAMES; i++) {
+ guint8 flag = (1 << i);
+ if ((header->refresh_frame_flags & flag) != 0) {
+ parser->reference[i].width = header->width;
+ parser->reference[i].height = header->height;
+ }
+ }
+
+ header->frame_header_length_in_bytes = (gst_bit_reader_get_pos (br) + 7) / 8;
+
+ return GST_VP9_PARSER_OK;
+}
+
+/**
+ * gst_vp9_seg_feature_active:
+ * @params: a #GstVp9SegmentationParams
+ * @segment_id: a segment id
+ * @feature: a segmentation feature
+ *
+ * An implementation of "seg_feature_active" function specified in
+ * "6.4.9 Segmentation feature active syntax"
+ *
+ * Returns: %TRUE if feature is active
+ *
+ * Since: 1.20
+ */
+gboolean
+gst_vp9_seg_feature_active (const GstVp9SegmentationParams * params,
+ guint8 segment_id, guint8 feature)
+{
+ g_return_val_if_fail (params != NULL, FALSE);
+ g_return_val_if_fail (segment_id < GST_VP9_MAX_SEGMENTS, FALSE);
+ g_return_val_if_fail (feature < GST_VP9_SEG_LVL_MAX, FALSE);
+
+ return params->segmentation_enabled &&
+ params->feature_enabled[segment_id][feature];
+}
+
+/**
+ * gst_vp9_get_qindex:
+ * @segmentation_params: a #GstVp9SegmentationParams
+ * @quantization_params: a #GstVp9QuantizationParams
+ * @segment_id: a segment id
+ *
+ * An implementation of "get_qindex" function specfied in
+ * "8.6.1 Dequantization functions"
+ *
+ * Returns: the quantizer index
+ *
+ * Since: 1.20
+ */
+guint8
+gst_vp9_get_qindex (const GstVp9SegmentationParams * segmentation_params,
+ const GstVp9QuantizationParams * quantization_params, guint8 segment_id)
+{
+ guint8 base_q_index;
+
+ g_return_val_if_fail (segmentation_params != NULL, 0);
+ g_return_val_if_fail (quantization_params != NULL, 0);
+ g_return_val_if_fail (segment_id < GST_VP9_MAX_SEGMENTS, 0);
+
+ base_q_index = quantization_params->base_q_idx;
+
+ if (gst_vp9_seg_feature_active (segmentation_params, segment_id,
+ GST_VP9_SEG_LVL_ALT_Q)) {
+ guint data =
+ segmentation_params->feature_data[segment_id][GST_VP9_SEG_LVL_ALT_Q];
+
+ if (!segmentation_params->segmentation_abs_or_delta_update)
+ data += base_q_index;
+
+ return CLAMP (data, 0, 255);
+ }
+
+ return base_q_index;
+}
+
+/**
+ * gst_vp9_get_dc_quant:
+ * @qindex: the quantizer index
+ * @delta_q_dc: a delta_q_dc value
+ * @bit_depth: coded bit depth
+ *
+ * An implementation of "dc_q" function specified in
+ * "8.6.1 Dequantization functions"
+ *
+ * Returns: the quantizer value for the dc coefficient
+ *
+ * Since: 1.20
+ */
+gint16
+gst_vp9_get_dc_quant (guint8 qindex, gint8 delta_q_dc, guint8 bit_depth)
+{
+ guint8 q_table_idx = CLAMP (qindex + delta_q_dc, 0, 255);
+
+ switch (bit_depth) {
+ case 8:
+ return dc_qlookup[q_table_idx];
+ case 10:
+ return dc_qlookup_10[q_table_idx];
+ case 12:
+ return dc_qlookup_12[q_table_idx];
+ default:
+ GST_WARNING ("Unhandled bitdepth %d", bit_depth);
+ break;
+ }
+
+ return -1;
+}
+
+/**
+ * gst_vp9_get_ac_quant:
+ * @qindex: the quantizer index
+ * @delta_q_ac: a delta_q_ac value
+ * @bit_depth: coded bit depth
+ *
+ * An implementation of "ac_q" function specified in
+ * "8.6.1 Dequantization functions"
+ *
+ * Returns: the quantizer value for the ac coefficient
+ *
+ * Since: 1.20
+ */
+gint16
+gst_vp9_get_ac_quant (guint8 qindex, gint8 delta_q_ac, guint8 bit_depth)
+{
+ guint8 q_table_idx = CLAMP (qindex + delta_q_ac, 0, 255);
+
+ switch (bit_depth) {
+ case 8:
+ return ac_qlookup[q_table_idx];
+ case 10:
+ return ac_qlookup_10[q_table_idx];
+ case 12:
+ return ac_qlookup_12[q_table_idx];
+ default:
+ GST_WARNING ("Unhandled bitdepth %d", bit_depth);
+ break;
+ }
+
+ return -1;
+}
diff --git a/gst-libs/gst/codecs/gstvp9statefulparser.h b/gst-libs/gst/codecs/gstvp9statefulparser.h
new file mode 100644
index 000000000..0ba507191
--- /dev/null
+++ b/gst-libs/gst/codecs/gstvp9statefulparser.h
@@ -0,0 +1,344 @@
+/* GStreamer
+ * Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_VP9_STATEFUL_PARSER_H__
+#define __GST_VP9_STATEFUL_PARSER_H__
+
+#include <gst/codecs/codecs-prelude.h>
+#include <gst/codecparsers/gstvp9parser.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVp9StatefulParser GstVp9StatefulParser;
+typedef struct _GstVp9LoopFilterParams GstVp9LoopFilterParams;
+typedef struct _GstVp9QuantizationParams GstVp9QuantizationParams;
+typedef struct _GstVp9SegmentationParams GstVp9SegmentationParams;
+typedef struct _GstVp9FrameHeader GstVp9FrameHeader;
+
+/**
+ * GST_VP9_SEG_LVL_ALT_Q:
+ *
+ * Index for quantizer segment feature
+ *
+ * Since: 1.20
+ */
+#define GST_VP9_SEG_LVL_ALT_Q 0
+
+/**
+ * GST_VP9_SEG_LVL_ALT_L:
+ *
+ * Index for loop filter segment feature
+ *
+ * Since: 1.20
+ */
+#define GST_VP9_SEG_LVL_ALT_L 1
+
+/**
+ * GST_VP9_SEG_LVL_REF_FRAME:
+ *
+ * Index for reference frame segment feature
+ *
+ * Since: 1.20
+ */
+#define GST_VP9_SEG_LVL_REF_FRAME 2
+
+/**
+ * GST_VP9_SEG_SEG_LVL_SKIP:
+ *
+ * Index for skip segment feature
+ *
+ * Since: 1.20
+ */
+#define GST_VP9_SEG_SEG_LVL_SKIP 3
+
+/**
+ * GST_VP9_SEG_LVL_MAX:
+ *
+ * Number of segment features
+ *
+ * Since: 1.20
+ */
+#define GST_VP9_SEG_LVL_MAX 4
+
+/**
+ * GstVp9LoopFilterParams:
+ * @loop_filter_level: indicates the loop filter strength
+ * @loop_filter_sharpness: indicates the sharpness level
+ * @loop_filter_delta_enabled: equal to 1 means that the filter level depends
+ * on the mode and reference frame used to predict a block
+ * @loop_filter_delta_update: equal to 1 means that the bitstream contains
+ * additional syntax elements that specify which mode and reference frame
+ * deltas are to be updated
+ * @update_ref_delta: equal to 1 means that the bitstream contains the syntax
+ * element loop_filter_ref_delta
+ * @loop_filter_ref_deltas: contains the adjustment needed for the filter level
+ * based on the chosen reference frame
+ * @update_mode_delta: equal to 1 means that the bitstream contains the syntax
+ * element loop_filter_mode_deltas
+ * @loop_filter_mode_deltas: contains the adjustment needed for the filter level
+ * based on the chosen mode
+ *
+ * Loop filter params. See "6.2.8 Loop filter params syntax" and
+ * "7.2.8 Loop filter semantics".
+ *
+ * If syntax elements for @update_ref_delta
+ * and/or @loop_filter_mode_deltas are not present in bitstream,
+ * parser will fill @loop_filter_ref_deltas and @loop_filter_mode_deltas values
+ * by using previously parsed values.
+ *
+ * Since: 1.20
+ */
+struct _GstVp9LoopFilterParams
+{
+ guint8 loop_filter_level;
+ guint8 loop_filter_sharpness;
+ guint8 loop_filter_delta_enabled;
+ guint8 loop_filter_delta_update;
+
+ guint8 update_ref_delta[GST_VP9_MAX_REF_LF_DELTAS];
+ gint8 loop_filter_ref_deltas[GST_VP9_MAX_REF_LF_DELTAS];
+
+ guint8 update_mode_delta[GST_VP9_MAX_MODE_LF_DELTAS];
+ gint8 loop_filter_mode_deltas[GST_VP9_MAX_MODE_LF_DELTAS];
+};
+
+/**
+ * GstVp9QuantizationParams:
+ * @base_q_idx: indicates the base frame qindex. This is used for Y AC
+ * coefficients and as the base value for the other quantizers
+ * @delta_q_y_dc: indicates the Y DC quantizer relative to base_q_idx
+ * @delta_q_uv_dc: indicates the UV DC quantizer relative to base_q_idx
+ * @delta_q_uv_ac: indicates the UV AC quantizer relative to base_q_idx
+ *
+ * Since: 1.20
+ */
+struct _GstVp9QuantizationParams
+{
+ guint8 base_q_idx;
+ gint8 delta_q_y_dc;
+ gint8 delta_q_uv_dc;
+ gint8 delta_q_uv_ac;
+};
+
+/**
+ * GstVp9SegmentationParams:
+ * @segmentation_enabled: equal to 1 indicates that this frame makes use of the
+ * segmentation tool
+ * @segmentation_update_map: equal to 1 indicates that the segmentation map
+ * should be updated during the decoding of this frame
+ * @segmentation_tree_probs: specify the probability values to be used when
+ * decoding segment_id
+ * @segmentation_pred_prob: specify the probability values to be used when
+ * decoding seg_id_predicted
+ * @segmentation_temporal_update: equal to 1 indicates that the updates to
+ * the segmentation map are coded relative to the existing segmentation map
+ * @segmentation_update_data: equal to 1 indicates that new parameters are
+ * about to be specified for each segment
+ * @segmentation_abs_or_delta_update: equal to 0 indicates that the segmentation
+ * parameters represent adjustments relative to the standard values.
+ * equal to 1 indicates that the segmentation parameters represent the actual
+ * values to be used
+ * @feature_enabled: indicates whether feature is enabled or not
+ * @feature_data: segmentation feature data
+ *
+ * See "6.2.11 Segmentation params syntax" and
+ * "7.2.10 Segmentation params syntax". When @segmentation_update_data is equal
+ * to zero, parser will fill @feature_enabled and by @feature_data
+ * using previously parsed values.
+ *
+ * Since: 1.20
+ */
+struct _GstVp9SegmentationParams
+{
+ guint8 segmentation_enabled;
+ guint8 segmentation_update_map;
+ guint8 segmentation_tree_probs[GST_VP9_SEG_TREE_PROBS];
+ guint8 segmentation_pred_prob[GST_VP9_PREDICTION_PROBS];
+ guint8 segmentation_temporal_update;
+
+ guint8 segmentation_update_data;
+ guint8 segmentation_abs_or_delta_update;
+
+ guint8 feature_enabled[GST_VP9_MAX_SEGMENTS][GST_VP9_SEG_LVL_MAX];
+ gint16 feature_data[GST_VP9_MAX_SEGMENTS][GST_VP9_SEG_LVL_MAX];
+};
+
+/**
+ * GstVp9FrameHeader:
+ * @profile: encoded profile
+ * @bit_depth: encoded bit depth
+ * @subsampling_x: specify the chroma subsampling format for x coordinate
+ * @subsampling_y: specify the chroma subsampling format for y coordinate
+ * @color_space: specifies the color space of the stream
+ * @color_range: specifies the black level and range of the luma and chroma
+ * signals
+ * @show_existing_frame: equal to 1, indicates the frame indexed by
+ * frame_to_show_map_idx is to be displayed
+ * @frame_to_show_map_idx: specifies the frame to be displayed.
+ * It is only available if show_existing_frame is 1
+ * @frame_type: equal to 0 indicates that the current frame is a key frame
+ * @show_frame: indicate whether it is a displayable frame or not
+ * @error_resilient_mode: equal to 1 indicates that error resilient mode is
+ * enabled
+ * @width: coded frame width
+ * @height: coded frame height
+ * @render_and_frame_size_different: equal to 0 means that the render width and
+ * height are inferred from the frame width and height
+ * @render_width: render width of the frame
+ * @render_height: render width of the frame
+ * @intra_only: equal to 1 indicates that the frame is an intra-only frame
+ * @reset_frame_context: specifies whether the frame context should be reset to
+ * default values
+ * @refresh_frame_flags: contains a bitmask that specifies which reference frame
+ * slots will be updated with the current frame after it is decoded
+ * @ref_frame_idx: specifies which reference frames are used by inter frames
+ * @ref_frame_sign_bias: specifies the intended direction of the motion vector
+ * in time for each reference frame. A sign bias equal to 0 indicates that
+ * the reference frame is a backwards reference
+ * @allow_high_precision_mv: equal to 0 specifies that motion vectors are
+ * specified to quarter pel precision
+ * @interpolation_filter: specifies the filter selection used for performing
+ * inter prediction
+ * @refresh_frame_context: equal to 1 indicates that the probabilities computed
+ * for this frame
+ * @frame_parallel_decoding_mode: equal to 1 indicates that parallel decoding
+ * mode is enabled
+ * @frame_context_idx: indicates the frame context to use
+ * @loop_filter_params: a #GstVp9LoopFilterParams
+ * @quantization_params: a #GstVp9QuantizationParams
+ * @segmentation_params: a #GstVp9SegmentationParams
+ * @tile_cols_log2: specifies the base 2 logarithm of the width of each tile
+ * @tile_rows_log2: specifies the base 2 logarithm of the height of each tile
+ * @lossless_flag: lossless mode decode
+ * @frame_header_length_in_bytes: length of uncompressed header
+ *
+ * Since: 1.20
+ */
+struct _GstVp9FrameHeader
+{
+ guint8 profile;
+ guint8 bit_depth;
+ guint8 subsampling_x;
+ guint8 subsampling_y;
+ guint8 color_space;
+ guint8 color_range;
+ guint8 show_existing_frame;
+ guint8 frame_to_show_map_idx;
+ guint8 frame_type;
+ guint8 show_frame;
+ guint8 error_resilient_mode;
+ guint32 width;
+ guint32 height;
+ guint8 render_and_frame_size_different;
+ guint32 render_width;
+ guint32 render_height;
+ guint8 intra_only;
+ guint8 reset_frame_context;
+ guint8 refresh_frame_flags;
+ guint8 ref_frame_idx[GST_VP9_REFS_PER_FRAME];
+ guint8 ref_frame_sign_bias[4];
+ guint8 allow_high_precision_mv;
+ guint8 interpolation_filter;
+
+ guint8 refresh_frame_context;
+ guint8 frame_parallel_decoding_mode;
+ guint8 frame_context_idx;
+
+ GstVp9LoopFilterParams loop_filter_params;
+ GstVp9QuantizationParams quantization_params;
+ GstVp9SegmentationParams segmentation_params;
+
+ guint8 tile_cols_log2;
+ guint8 tile_rows_log2;
+
+ guint16 header_size_in_bytes;
+
+ /* calculated values */
+ guint8 lossless_flag;
+ guint32 frame_header_length_in_bytes;
+};
+
+/**
+ * GstVp9StatefulParser:
+ *
+ * Opaque VP9 parser struct.
+ * The size of this object and member variables are not API
+ *
+ * Since: 1.20
+ */
+struct _GstVp9StatefulParser
+{
+ /*< private >*/
+ guint8 bit_depth;
+ guint8 subsampling_x;
+ guint8 subsampling_y;
+ guint8 color_space;
+ guint8 color_range;
+
+ guint mi_cols;
+ guint mi_rows;
+ guint sb64_cols;
+ guint sb64_rows;
+
+ GstVp9LoopFilterParams loop_filter_params;
+ GstVp9SegmentationParams segmentation_params;
+
+ struct {
+ guint32 width;
+ guint32 height;
+ } reference[GST_VP9_REF_FRAMES];
+};
+
+GST_CODECS_API
+GstVp9StatefulParser * gst_vp9_stateful_parser_new (void);
+
+GST_CODECS_API
+void gst_vp9_stateful_parser_free (GstVp9StatefulParser * parser);
+
+GST_CODECS_API
+GstVp9ParserResult gst_vp9_stateful_parser_parse_frame_header (GstVp9StatefulParser * parser,
+ GstVp9FrameHeader * header,
+ const guint8 * data,
+ gsize size);
+
+/* Util methods */
+GST_CODECS_API
+gboolean gst_vp9_seg_feature_active (const GstVp9SegmentationParams * params,
+ guint8 segment_id,
+ guint8 feature);
+
+GST_CODECS_API
+guint8 gst_vp9_get_qindex (const GstVp9SegmentationParams * segmentation_params,
+ const GstVp9QuantizationParams * quantization_params,
+ guint8 segment_id);
+
+
+GST_CODECS_API
+gint16 gst_vp9_get_dc_quant (guint8 qindex,
+ gint8 delta_q_dc,
+ guint8 bit_depth);
+
+GST_CODECS_API
+gint16 gst_vp9_get_ac_quant (guint8 qindex,
+ gint8 delta_q_ac,
+ guint8 bit_depth);
+
+G_END_DECLS
+
+#endif /* __GST_VP9_STATEFUL_PARSER_H__ */
diff --git a/gst-libs/gst/codecs/meson.build b/gst-libs/gst/codecs/meson.build
index d77241e7e..953f0f081 100644
--- a/gst-libs/gst/codecs/meson.build
+++ b/gst-libs/gst/codecs/meson.build
@@ -11,6 +11,7 @@ codecs_sources = files([
'gstmpeg2picture.c',
'gstav1decoder.c',
'gstav1picture.c',
+ 'gstvp9statefulparser.c',
])
codecs_headers = [
@@ -26,6 +27,7 @@ codecs_headers = [
'gstmpeg2picture.h',
'gstav1decoder.h',
'gstav1picture.h',
+ 'gstvp9statefulparser.h',
]
cp_args = [