Skip to content
Snippets Groups Projects
SEIFilmGrainSynthesizer.cpp 51.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* The copyright in this software is being made available under the BSD
     * License, included below. This software may be subject to other third party
     * and contributor rights, including patent rights, and no such rights are
     * granted under this license.
     *
    
     * Copyright (c) 2010-2025, ITU/ISO/IEC
    
     * 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 the ITU/ISO/IEC 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.
     */
    
     /** \file     SEIFilmGrainSynthesizer.cpp
         \brief    SMPTE RDD5 based film grain synthesis functionality from SEI messages
     */
    
    #include "SEIFilmGrainSynthesizer.h"
    
    #include <stdio.h>
    #include <cmath>
    
    
    /* static look up table definitions */
    static const int8_t gaussianLUT[2048] =
    {
    -11, 12, 103, -11, 42, -35, 12, 59, 77, 98, -87, 3, 65, -78, 45, 56,
    -51, 21, 13, -11, -20, -19, 33, -127, 17, -6, -105, 18, 19, 71, 48, -10,
    -38, 42, -2, 75, -67, 52, -90, 33, -47, 21, -3, -56, 49, 1, -57, -42,
    -1, 120, -127, -108, -49, 9, 14, 127, 122, 109, 52, 127, 2, 7, 114, 19,
    30, 12, 77, 112, 82, -61, -127, 111, -52, -29, 2, -49, -24, 58, -29, -73,
    12, 112, 67, 79, -3, -114, -87, -6, -5, 40, 58, -81, 49, -27, -31, -34,
    -105, 50, 16, -24, -35, -14, -15, -127, -55, -22, -55, -127, -112, 5, -26, -72,
    127, 127, -2, 41, 87, -65, -16, 55, 19, 91, -81, -65, -64, 35, -7, -54,
    99, -7, 88, 125, -26, 91, 0, 63, 60, -14, -23, 113, -33, 116, 14, 26,
    51, -16, 107, -8, 53, 38, -34, 17, -7, 4, -91, 6, 63, 63, -15, 39,
    -36, 19, 55, 17, -51, 40, 33, -37, 126, -39, -118, 17, -30, 0, 19, 98,
    60, 101, -12, -73, -17, -52, 98, 3, 3, 60, 33, -3, -2, 10, -42, -106,
    -38, 14, 127, 16, -127, -31, -86, -39, -56, 46, -41, 75, 23, -19, -22, -70,
    74, -54, -2, 32, -45, 17, -92, 59, -64, -67, 56, -102, -29, -87, -34, -92,
    68, 5, -74, -61, 93, -43, 14, -26, -38, -126, -17, 16, -127, 64, 34, 31,
    93, 17, -51, -59, 71, 77, 81, 127, 127, 61, 33, -106, -93, 0, 0, 75,
    -69, 71, 127, -19, -111, 30, 23, 15, 2, 39, 92, 5, 42, 2, -6, 38,
    15, 114, -30, -37, 50, 44, 106, 27, 119, 7, -80, 25, -68, -21, 92, -11,
    -1, 18, 41, -50, 79, -127, -43, 127, 18, 11, -21, 32, -52, 27, -88, -90,
    -39, -19, -10, 24, -118, 72, -24, -44, 2, 12, 86, -107, 39, -33, -127, 47,
    51, -24, -22, 46, 0, 15, -35, -69, -2, -74, 24, -6, 0, 29, -3, 45,
    32, -32, 117, -45, 79, -24, -17, -109, -10, -70, 88, -48, 24, -91, 120, -37,
    50, -127, 58, 32, -82, -10, -17, -7, 46, -127, -15, 89, 127, 17, 98, -39,
    -33, 37, 42, -40, -32, -21, 105, -19, 19, 19, -59, -9, 30, 0, -127, 34,
    127, -84, 75, 24, -40, -49, -127, -107, -14, 45, -75, 1, 30, -20, 41, -68,
    -40, 12, 127, -3, 5, 20, -73, -59, -127, -3, -3, -53, -6, -119, 93, 120,
    -80, -50, 0, 20, -46, 67, 78, -12, -22, -127, 36, -41, 56, 119, -5, -116,
    -22, 68, -14, -90, 24, -82, -44, -127, 107, -25, -37, 40, -7, -7, -82, 5,
    -87, 44, -34, 9, -127, 39, 70, 49, -63, 74, -49, 109, -27, -89, -47, -39,
    44, 49, -4, 60, -42, 80, 9, -127, -9, -56, -49, 125, -66, 47, 36, 117,
    15, -11, -96, 109, 94, -17, -56, 70, 8, -14, -5, 50, 37, -45, 120, -30,
    -76, 40, -46, 6, 3, 69, 17, -78, 1, -79, 6, 127, 43, 26, 127, -127,
    28, -55, -26, 55, 112, 48, 107, -1, -77, -1, 53, -9, -22, -43, 123, 108,
    127, 102, 68, 46, 5, 1, 123, -13, -55, -34, -49, 89, 65, -105, -5, 94,
    -53, 62, 45, 30, 46, 18, -35, 15, 41, 47, -98, -24, 94, -75, 127, -114,
    127, -68, 1, -17, 51, -95, 47, 12, 34, -45, -75, 89, -107, -9, -58, -29,
    -109, -24, 127, -61, -13, 77, -45, 17, 19, 83, -24, 9, 127, -66, 54, 4,
    26, 13, 111, 43, -113, -22, 10, -24, 83, 67, -14, 75, -123, 59, 127, -12,
    99, -19, 64, -38, 54, 9, 7, 61, -56, 3, -57, 113, -104, -59, 3, -9,
    -47, 74, 85, -55, -34, 12, 118, 28, 93, -72, 13, -99, -72, -20, 30, 72,
    -94, 19, -54, 64, -12, -63, -25, 65, 72, -10, 127, 0, -127, 103, -20, -73,
    -112, -103, -6, 28, -42, -21, -59, -29, -26, 19, -4, -51, 94, -58, -95, -37,
    35, 20, -69, 127, -19, -127, -22, -120, -53, 37, 74, -127, -1, -12, -119, -53,
    -28, 38, 69, 17, 16, -114, 89, 62, 24, 37, -23, 49, -101, -32, -9, -95,
    -53, 5, 93, -23, -49, -8, 51, 3, -75, -90, -10, -39, 127, -86, -22, 20,
    20, 113, 75, 52, -31, 92, -63, 7, -12, 46, 36, 101, -43, -17, -53, -7,
    -38, -76, -31, -21, 62, 31, 62, 20, -127, 31, 64, 36, 102, -85, -10, 77,
    80, 58, -79, -8, 35, 8, 80, -24, -9, 3, -17, 72, 127, 83, -87, 55,
    18, -119, -123, 36, 10, 127, 56, -55, 113, 13, 26, 32, -13, -48, 22, -13,
    5, 58, 27, 24, 26, -11, -36, 37, -92, 78, 81, 9, 51, 14, 67, -13,
    0, 32, 45, -76, 32, -39, -22, -49, -127, -27, 31, -9, 36, 14, 71, 13,
    57, 12, -53, -86, 53, -44, -35, 2, 127, 12, -66, -44, 46, -115, 3, 10,
    56, -35, 119, -19, -61, 52, -59, -127, -49, -23, 4, -5, 17, -82, -6, 127,
    25, 79, 67, 64, -25, 14, -64, -37, -127, -28, 21, -63, 66, -53, -41, 109,
    -62, 15, -22, 13, 29, -63, 20, 27, 95, -44, -59, -116, -10, 79, -49, 22,
    -43, -16, 46, -47, -120, -36, -29, -52, -44, 29, 127, -13, 49, -9, -127, 75,
    -28, -23, 88, 59, 11, -95, 81, -59, 58, 60, -26, 40, -92, -3, -22, -58,
    -45, -59, -22, -53, 71, -29, 66, -32, -23, 14, -17, -66, -24, -28, -62, 47,
    38, 17, 16, -37, -24, -11, 8, -27, -19, 59, 45, -49, -47, -4, -22, -81,
    30, -67, -127, 74, 102, 5, -18, 98, 34, -66, 42, -52, 7, -59, 24, -58,
    -19, -24, -118, -73, 91, 15, -16, 79, -32, -79, -127, -36, 41, 77, -83, 2,
    56, 22, -75, 127, -16, -21, 12, 31, 56, -113, -127, 90, 55, 61, 12, 55,
    -14, -113, -14, 32, 49, -67, -17, 91, -10, 1, 21, 69, -70, 99, -19, -112,
    66, -90, -10, -9, -71, 127, 50, -81, -49, 24, 61, -61, -111, 7, -41, 127,
    88, -66, 108, -127, -6, 36, -14, 41, -50, 14, 14, 73, -101, -28, 77, 127,
    -8, -100, 88, 38, 121, 88, -125, -60, 13, -94, -115, 20, -67, -87, -94, -119,
    44, -28, -30, 18, 5, -53, -61, 20, -43, 11, -77, -60, 13, 29, 3, 6,
    -72, 38, -60, -11, 108, -53, 41, 66, -12, -127, -127, -49, 24, 29, 46, 36,
    91, 34, -33, 116, -51, -34, -52, 91, 7, -83, 73, -26, -103, 24, -10, 76,
    84, 5, 68, -80, -13, -17, -32, -48, 20, 50, 26, 10, 63, -104, -14, 37,
    127, 114, 97, 35, 1, -33, -55, 127, -124, -33, 61, -7, 119, -32, -127, -53,
    -42, 63, 3, -5, -26, 70, -58, -33, -44, -43, 34, -56, -127, 127, 25, -35,
    -11, 16, -81, 29, -58, 40, -127, -127, 20, -47, -11, -36, -63, -52, -32, -82,
    78, -76, -73, 8, 27, -72, -9, -74, -85, -86, -57, 25, 78, -10, -97, 35,
    -65, 8, -59, 14, 1, -42, 32, -88, -44, 17, -3, -9, 59, 40, 12, -108,
    -40, 24, 34, 18, -28, 2, 51, -110, -4, 100, 1, 65, 22, 0, 127, 61,
    45, 25, -31, 6, 9, -7, -48, 99, 16, 44, -2, -40, 32, -39, -52, 10,
    -110, -19, 56, -127, 69, 26, 51, 92, 40, 61, -52, 45, -38, 13, 85, 122,
    27, 66, 45, -111, -83, -3, 31, 37, 19, -36, 58, 71, 39, -78, -47, 58,
    -78, 8, -62, -36, -14, 61, 42, -127, 71, -4, 24, -54, 52, -127, 67, -4,
    -42, 30, -63, 59, -3, -1, -18, -46, -92, -81, -96, -14, -53, -10, -11, -77,
    13, 1, 8, -67, -127, 127, -28, 26, -14, 18, -13, -26, 2, 10, -46, -32,
    -15, 27, -31, -59, 59, 77, -121, 28, 40, -54, -62, -31, -21, -37, -32, -6,
    -127, -25, -60, 70, -127, 112, -127, 127, 88, -7, 116, 110, 53, 87, -127, 3,
    16, 23, 74, -106, -51, 3, 74, -82, -112, -74, 65, 81, 25, 53, 127, -45,
    -50, -103, -41, -65, -29, 79, -67, 64, -33, -30, -8, 127, 0, -13, -51, 67,
    -14, 5, -92, 29, -35, -8, -90, -57, -3, 36, 43, 44, -31, -69, -7, 36,
    39, -51, 43, -81, 58, 6, 127, 12, 57, 66, 46, 59, -43, -42, 41, -15,
    -120, 24, 3, -11, 19, -13, 51, 28, 3, 55, -48, -12, -1, 2, 97, -19,
    29, 42, 13, 43, 78, -44, 56, -108, -43, -19, 127, 15, -11, -18, -81, 83,
    -37, 77, -109, 15, 65, -50, 43, 12, 13, 27, 28, 61, 57, 30, 26, 106,
    -18, 56, 13, 97, 4, -8, -62, -103, 94, 108, -44, 52, 27, -47, -9, 105,
    -53, 46, 89, 103, -33, 38, -34, 55, 51, 70, -94, -35, -87, -107, -19, -31,
    9, -19, 79, -14, 77, 5, -19, -107, 85, 21, -45, -39, -42, 9, -29, 74,
    47, -75, 60, -127, 120, -112, -57, -32, 41, 7, 79, 76, 66, 57, 41, -25,
    31, 37, -47, -36, 43, -73, -37, 63, 127, -69, -52, 90, -33, -61, 60, -55,
    44, 15, 4, -67, 13, -92, 64, 29, -39, -3, 83, -2, -38, -85, -86, 58,
    35, -69, -61, 29, -37, -95, -78, 4, 30, -4, -32, -80, -22, -9, -77, 46,
    7, -93, -71, 65, 9, -50, 127, -70, 26, -12, -39, -114, 63, -127, -100, 4,
    -32, 111, 22, -60, 65, -101, 26, -42, 21, -59, -27, -74, 2, -94, 6, 126,
    5, 76, -88, -9, -43, -101, 127, 1, 125, 92, -63, 52, 56, 4, 81, -127,
    127, 80, 127, -29, 30, 116, -74, -17, -57, 105, 48, 45, 25, -72, 48, -38,
    -108, 31, -34, 4, -11, 41, -127, 52, -104, -43, -37, 52, 2, 47, 87, -9,
    77, 27, -41, -25, 90, 86, -56, 75, 10, 33, 78, 58, 127, 127, -7, -73,
    49, -33, -106, -35, 38, 57, 53, -17, -4, 83, 52, -108, 54, -125, 28, 23,
    56, -43, -88, -17, -6, 47, 23, -9, 0, -13, 111, 75, 27, -52, -38, -34,
    39, 30, 66, 39, 38, -64, 38, 3, 21, -32, -51, -28, 54, -38, -87, 20,
    52, 115, 18, -81, -70, 0, -14, -46, -46, -3, 125, 16, -14, 23, -82, -84,
    -69, -20, -65, -127, 9, 81, -49, 61, 7, -36, -45, -42, 57, -26, 47, 20,
    -85, 46, -13, 41, -37, -75, -60, 86, -78, -127, 12, 50, 2, -3, 13, 47,
    5, 19, -78, -55, -27, 65, -71, 12, -108, 20, -16, 11, -31, 63, -55, 37,
    75, -17, 127, -73, -33, -28, -120, 105, 68, 106, -103, -106, 71, 61, 2, 23,
    -3, 33, -5, -15, -67, -15, -23, -54, 15, -63, 76, 58, -110, 1, 83, -27,
    22, 75, -39, -17, -11, 64, -17, -127, -54, -66, 31, 96, 116, 3, -114, -7,
    -108, -63, 97, 9, 50, 8, 75, -28, 72, 112, -36, -112, 95, -50, 23, -13,
    -19, 55, 21, 23, 92, 91, 22, -49, 16, -75, 23, 9, -49, -97, -37, 49,
    -36, 36, -127, -86, 43, 127, -24, -24, 84, 83, -35, -34, -12, 109, 102, -38,
    51, -68, 34, 19, -22, 49, -32, 127, 40, 24, -93, -4, -3, 105, 3, -58,
    -18, 8, 127, -18, 125, 68, 69, -62, 30, -36, 54, -57, -24, 17, 43, -36,
    -27, -57, -67, -21, -10, -49, 68, 12, 65, 4, 48, 55, 127, -75, 44, 89,
    -66, -13, -78, -82, -91, 22, 30, 33, -40, -87, -34, 96, -91, 39, 10, -64,
    -3, -12, 127, -50, -37, -56, 23, -35, -36, -54, 90, -91, 2, 50, 77, -6,
    -127, 16, 46, -5, -73, 0, -56, -18, -72, 28, 93, 60, 49, 20, 18, 111,
    -111, 32, -83, 47, 47, -10, 35, -88, 43, 57, -98, 127, -17, 0, 1, -39,
    -127, -2, 0, 63, 93, 0, 36, -66, -61, -19, 39, -127, 58, 50, -17, 127,
    88, -43, -108, -51, -16, 7, -36, 68, 46, -14, 107, 40, 57, 7, 19, 8,
    3, 88, -90, -92, -18, -21, -24, 13, 7, -4, -78, -91, -4, 8, -35, -5,
    19, 2, -111, 4, -66, -81, 122, -20, -34, -37, -84, 127, 68, 46, 17, 47
    };
    
    static const uint32_t seedLUT[256] = {
    747538460, 1088979410, 1744950180, 1767011913, 1403382928, 521866116, 1060417601, 2110622736,
    1557184770, 105289385, 585624216, 1827676546, 1191843873, 1018104344, 1123590530, 663361569,
    2023850500, 76561770, 1226763489, 80325252, 1992581442, 502705249, 740409860, 516219202,
    557974537, 1883843076, 720112066, 1640137737, 1820967556, 40667586, 155354121, 1820967557,
    1115949072, 1631803309, 98284748, 287433856, 2119719977, 988742797, 1827432592, 579378475,
    1017745956, 1309377032, 1316535465, 2074315269, 1923385360, 209722667, 1546228260, 168102420,
    135274561, 355958469, 248291472, 2127839491, 146920100, 585982612, 1611702337, 696506029,
    1386498192, 1258072451, 1212240548, 1043171860, 1217404993, 1090770605, 1386498193, 169093201,
    541098240, 1468005469, 456510673, 1578687785, 1838217424, 2010752065, 2089828354, 1362717428,
    970073673, 854129835, 714793201, 1266069081, 1047060864, 1991471829, 1098097741, 913883585,
    1669598224, 1337918685, 1219264706, 1799741108, 1834116681, 683417731, 1120274457, 1073098457,
    1648396544, 176642749, 31171789, 718317889, 1266977808, 1400892508, 549749008, 1808010512,
    67112961, 1005669825, 903663673, 1771104465, 1277749632, 1229754427, 950632997, 1979371465,
    2074373264, 305357524, 1049387408, 1171033360, 1686114305, 2147468765, 1941195985, 117709841,
    809550080, 991480851, 1816248997, 1561503561, 329575568, 780651196, 1659144592, 1910793616,
    604016641, 1665084765, 1530186961, 1870928913, 809550081, 2079346113, 71307521, 876663040,
    1073807360, 832356664, 1573927377, 204073344, 2026918147, 1702476788, 2043881033, 57949587,
    2001393952, 1197426649, 1186508931, 332056865, 950043140, 890043474, 349099312, 148914948,
    236204097, 2022643605, 1441981517, 498130129, 1443421481, 924216797, 1817491777, 1913146664,
    1411989632, 929068432, 495735097, 1684636033, 1284520017, 432816184, 1344884865, 210843729,
    676364544, 234449232, 12112337, 1350619139, 1753272996, 2037118872, 1408560528, 533334916,
    1043640385, 357326099, 201376421, 110375493, 541106497, 416159637, 242512193, 777294080,
    1614872576, 1535546636, 870600145, 910810409, 1821440209, 1605432464, 1145147393, 951695441,
    1758494976, 1506656568, 1557150160, 608221521, 1073840384, 217672017, 684818688, 1750138880,
    16777217, 677990609, 953274371, 1770050213, 1359128393, 1797602707, 1984616737, 1865815816,
    2120835200, 2051677060, 1772234061, 1579794881, 1652821009, 1742099468, 1887260865, 46468113,
    1011925248, 1134107920, 881643832, 1354774993, 472508800, 1892499769, 1752793472, 1962502272,
    687898625, 883538000, 1354355153, 1761673473, 944820481, 2020102353, 22020353, 961597696,
    1342242816, 964808962, 1355809701, 17016649, 1386540177, 647682692, 1849012289, 751668241,
    1557184768, 127374604, 1927564752, 1045744913, 1614921984, 43588881, 1016185088, 1544617984,
    1090519041, 136122424, 215038417, 1563027841, 2026918145, 1688778833, 701530369, 1372639488,
    1342242817, 2036945104, 953274369, 1750192384, 16842753, 964808960, 1359020032, 1358954497
    };
    
    static const uint32_t deblockFactor[13] =
    { 64, 71, 77, 84, 90, 96, 103, 109, 116, 122, 128, 128, 128 };
    
    SEIFilmGrainSynthesizer::SEIFilmGrainSynthesizer()
    
      : m_width(0)
      , m_height(0)
    
      , m_chromaFormat(ChromaFormat::UNDEFINED)
    
      , m_bitDepth(0)
      , m_idrPicId(0)
      , m_grainSynt(nullptr)
      , m_fgsBlkSize(8)
      , m_poc(0)
      , m_errorCode(0)
      , m_fgcParameters(nullptr)
    
    {
    
    }
    
    void SEIFilmGrainSynthesizer::create(uint32_t width, uint32_t height, ChromaFormat fmt, uint8_t bitDepth, uint32_t idrPicId)
    {
      m_width             = width;
      m_height            = height;
      m_chromaFormat      = fmt;
      m_bitDepth          = bitDepth;
      m_idrPicId          = idrPicId;
      m_fgsBlkSize        = 8;
      m_errorCode         = 0;
    
      if (!m_grainSynt)
        m_grainSynt       = new GrainSynthesisStruct;
      if (!m_fgcParameters)
        m_fgcParameters   = new SEIFilmGrainCharacteristics;
    }
    
    SEIFilmGrainSynthesizer::~SEIFilmGrainSynthesizer()
    {
      destroy();
    }
    
    void SEIFilmGrainSynthesizer::fgsInit()
    {
      deriveFGSBlkSize();
      dataBaseGen();
    }
    
    void SEIFilmGrainSynthesizer::destroy()
    {
      if (m_fgcParameters)
        delete m_fgcParameters;
      if (m_grainSynt)
        delete m_grainSynt;
    }
    
    void SEIFilmGrainSynthesizer::grainSynthesizeAndBlend(PelStorage* pGrainBuf, bool isIdrPic)
    {
    
      uint8_t     compCtr; /* number of color components */
    
      uint8_t     color_offset[MAX_NUM_COMPONENT];
    
    Frank Bossen's avatar
    Frank Bossen committed
      uint32_t    widthComp[MAX_NUM_COMPONENT], heightComp[MAX_NUM_COMPONENT];
      ptrdiff_t   strideComp[MAX_NUM_COMPONENT];
    
      uint32_t *  offsetsArr[MAX_NUM_COMPONENT];
      Pel *       decComp[MAX_NUM_COMPONENT];
      uint32_t    pseudoRandValEc;
      uint32_t    picOffset;
    
      /* from SMPTE RDD5 */
      color_offset[0] = COLOUR_OFFSET_LUMA;
      color_offset[1] = COLOUR_OFFSET_CR;
      color_offset[2] = COLOUR_OFFSET_CB;
    
      if (0 != m_fgcParameters->m_filmGrainCharacteristicsCancelFlag)
      {
        return;
      }
    
    
      const int numComp = getNumberValidComponents(m_chromaFormat);
    
    
      widthComp[0]  = m_width;
      heightComp[0] = m_height;
    
    
      if (ChromaFormat::_420 == m_chromaFormat)
    
      {
        widthComp[1]  = (m_width >> 1);
        widthComp[2]  = (m_width >> 1);
        heightComp[1] = (m_height >> 1);
        heightComp[2] = (m_height >> 1);
      }
    
      else if (ChromaFormat::_422 == m_chromaFormat)
    
      {
        widthComp[1]  = (m_width >> 1);
        widthComp[2]  = (m_width >> 1);
        heightComp[1] = m_height;
        heightComp[2] = m_height;
      }
    
      /*Allocate memory for offsets assuming 16x16 block size,
      32x32 will need lesser than this*/
      uint32_t maxNumBlocks = ((m_width >> 4) + 1) * ((m_height >> 4) + 1);
    
      for (compCtr = 0; compCtr < numComp; compCtr++)
      {
        offsetsArr[compCtr] = new uint32_t[maxNumBlocks];
      }
    
      decComp[0] = pGrainBuf->bufs[0].buf;
      decComp[1] = pGrainBuf->bufs[1].buf;
      decComp[2] = pGrainBuf->bufs[2].buf;
    
      /* component strides */
      strideComp[0] = pGrainBuf->bufs[0].stride;
      strideComp[1] = 0;
      strideComp[2] = 0;
    
    
      if (isChromaEnabled(m_chromaFormat))
    
      {
        strideComp[1] = pGrainBuf->bufs[1].stride;
        strideComp[2] = pGrainBuf->bufs[2].stride;
      }
    
      int32_t numBlks_x[MAX_NUM_COMPONENT];
      int32_t numBlks_y[MAX_NUM_COMPONENT];
    
      picOffset = m_poc;
      for (compCtr = 0; compCtr < numComp; compCtr++)
      {
        if (BLK_32 == m_fgsBlkSize)
        {
          numBlks_x[compCtr]         = (widthComp[compCtr] >> 5) + ((widthComp[compCtr] & 0x1F) ? 1 : 0);
          numBlks_y[compCtr]         = (heightComp[compCtr] >> 5) + ((heightComp[compCtr] & 0x1F) ? 1 : 0);
        }
        else
        {
          numBlks_x[compCtr]         = (widthComp[compCtr] >> 4) + ((widthComp[compCtr] & 0xF) ? 1 : 0);
          numBlks_y[compCtr]         = (heightComp[compCtr] >> 4) + ((heightComp[compCtr] & 0xF) ? 1 : 0);
        }
      }
    
      for (compCtr = 0; compCtr < numComp; compCtr++)
      {
        if (1 == m_fgcParameters->m_compModel[compCtr].presentFlag)
        {
          uint32_t *tmp = offsetsArr[compCtr];
          int       i, j;
    
          /* Seed initialization for current picture*/
          pseudoRandValEc = seedLUT[((picOffset + color_offset[compCtr]) & 0xFF)];
    
          for (i = 0; i < numBlks_y[compCtr]; i++)
          {
            for (j = 0; j < numBlks_x[compCtr]; j++)
            {
              *tmp            = pseudoRandValEc;
              pseudoRandValEc = prng(pseudoRandValEc);
              tmp++;
            }
          }
        }
      }
    
      m_fgsArgs.numComp = numComp;
      for (compCtr = 0; compCtr < numComp; compCtr++)
      {
        if (1 == m_fgcParameters->m_compModel[compCtr].presentFlag)
        {
          m_fgsArgs.decComp[compCtr]    = decComp[compCtr];
          m_fgsArgs.widthComp[compCtr]  = widthComp[compCtr];
          m_fgsArgs.strideComp[compCtr] = strideComp[compCtr];
          m_fgsArgs.fgsOffsets[compCtr] = offsetsArr[compCtr];
    
          if (BLK_32 == m_fgsBlkSize)
          {
            m_fgsArgs.heightComp[compCtr] = numBlks_y[compCtr] * BLK_32;
          }
          else
          {
            m_fgsArgs.heightComp[compCtr] = numBlks_y[compCtr] * BLK_16;
          }
        }
      }
      m_fgsArgs.pFgcParameters = m_fgcParameters;
      m_fgsArgs.blkSize = m_fgsBlkSize;
      m_fgsArgs.bitDepth = m_bitDepth;
      m_fgsArgs.pGrainSynt = m_grainSynt;
    
      fgsProcess(m_fgsArgs);
    
      for (compCtr = 0; compCtr < numComp; compCtr++)
      {
        delete offsetsArr[compCtr];
      }
      return;
    }
    
    /* Function validates film grain parameters and returns 0 for valid parameters of SMPTE-RDD5 else 1*/
    /* Also down converts the chroma model values for 4:2:0 and 4:2:2 chroma_formats */
    uint8_t SEIFilmGrainSynthesizer::grainValidateParams()
    {
    
      uint8_t   compCtr, intensityCtr, multiGrainCheck[MAX_NUM_COMPONENT][MAX_NUM_INTENSITIES] = { { 0 } };
    
      uint16_t  multiGrainCtr;
      uint8_t   limitCompModelVal1[10] = { 0 }, limitCompModelVal2[10] = { 0 };
      uint8_t   num_comp_model_pairs = 0, limitCompModelCtr, compPairMatch;
    
      memset(m_grainSynt->intensityInterval, INTENSITY_INTERVAL_MATCH_FAIL, sizeof(m_grainSynt->intensityInterval));
    
      if ((m_width < MIN_WIDTH) || (m_width > MAX_WIDTH) || (m_width % 4))
      {
        return FGS_INVALID_WIDTH; /* Width not supported */
      }
      if ((m_height < MIN_HEIGHT) || (m_height > MAX_HEIGHT) || (m_height % 4))
      {
        return FGS_INVALID_HEIGHT; /* Height not  supported */
      }
    
      if (m_chromaFormat == ChromaFormat::UNDEFINED)
    
      {
        return FGS_INVALID_CHROMA_FORMAT; /* Chroma format not supported */
      }
    
    
      const int numComp = getNumberValidComponents(m_chromaFormat);
    
    
      if ((m_bitDepth < MIN_BIT_DEPTH) || (m_bitDepth > MAX_BIT_DEPTH))
      {
        return FGS_INVALID_BIT_DEPTH; /* Bit depth not supported */
      }
    
      if ((0 != m_fgcParameters->m_filmGrainCharacteristicsCancelFlag) &&
          (1 != m_fgcParameters->m_filmGrainCharacteristicsCancelFlag))
      {
        return FGS_INVALID_FGC_CANCEL_FLAG; /* Film grain synthesis disabled */
      }
    
      if (FILM_GRAIN_MODEL_ID_VALUE != m_fgcParameters->m_filmGrainModelId)
      {
        return FGS_INVALID_GRAIN_MODEL_ID; /* Not supported */
      }
    
      if (0 != m_fgcParameters->m_separateColourDescriptionPresentFlag)
      {
        return FGS_INVALID_SEP_COL_DES_FLAG; /* Not supported */
      }
    
      if (BLENDING_MODE_VALUE != m_fgcParameters->m_blendingModeId)
      {
        return FGS_INVALID_BLEND_MODE; /* Not supported */
      }
    
      if (m_fgcParameters->m_compModel[0].presentFlag || m_fgcParameters->m_compModel[1].presentFlag || m_fgcParameters->m_compModel[2].presentFlag) {
        if ((m_fgcParameters->m_log2ScaleFactor < MIN_LOG2SCALE_VALUE) ||
          (m_fgcParameters->m_log2ScaleFactor > MAX_LOG2SCALE_VALUE))
        {
          return FGS_INVALID_LOG2_SCALE_FACTOR; /* Not supported  */
        }
      }
    
      /* validation of component model present flag */
      for (compCtr = 0; compCtr < numComp; compCtr++)
      {
        if ((m_fgcParameters->m_compModel[compCtr].presentFlag != true) &&
            (m_fgcParameters->m_compModel[compCtr].presentFlag != false))
        {
          return FGS_INVALID_COMP_MODEL_PRESENT_FLAG; /* Not supported  */
        }
        if (m_fgcParameters->m_compModel[compCtr].presentFlag &&
           (m_fgcParameters->m_compModel[compCtr].numModelValues > MAX_ALLOWED_MODEL_VALUES))
        {
          return FGS_INVALID_NUM_MODEL_VALUES; /* Not supported  */
        }
      }
    
      /* validation of intensity intervals and  */
      for (compCtr = 0; compCtr < numComp; compCtr++)
      {
        if (m_fgcParameters->m_compModel[compCtr].presentFlag)
        {
          for (intensityCtr = 0; intensityCtr < m_fgcParameters->m_compModel[compCtr].intensityValues.size(); intensityCtr++)
          {
    
            if (m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].intensityIntervalLowerBound >
                m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].intensityIntervalUpperBound)
            {
              return FGS_INVALID_INTENSITY_BOUNDARY_VALUES; /* Not supported  */
            }
    
            for (multiGrainCtr = m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].intensityIntervalLowerBound;
                 multiGrainCtr <= m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].intensityIntervalUpperBound; multiGrainCtr++)
            {
              m_grainSynt->intensityInterval[compCtr][multiGrainCtr] = intensityCtr;
              if (multiGrainCheck[compCtr][multiGrainCtr]) /* Non over lap */
              {
                return FGS_INVALID_INTENSITY_BOUNDARY_VALUES; /* Not supported  */
              }
              else
              {
                multiGrainCheck[compCtr][multiGrainCtr] = 1;
              }
            }
    
            m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue.resize(MAX_NUM_MODEL_VALUES);
            /* default initialization for cut off frequencies */
            if (1 == m_fgcParameters->m_compModel[compCtr].numModelValues)
            {
              m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1] = DEFAULT_HORZ_CUT_OFF_FREQUENCY;
              m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[2] = m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1];
            }
            else if (2 == m_fgcParameters->m_compModel[compCtr].numModelValues)
            {
              m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[2] = m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1];
            }
    
            /* Error check on model component value */
            if (m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[0] > (MAX_STANDARD_DEVIATION << (m_bitDepth - BIT_DEPTH_8)))
            {
              return FGS_INVALID_STANDARD_DEVIATION; /* Not supported  */
            }
            else if ((m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1] < MIN_CUT_OFF_FREQUENCY) ||
                     (m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1] > MAX_CUT_OFF_FREQUENCY))
            {
              return FGS_INVALID_CUT_OFF_FREQUENCIES; /* Not supported  */
            }
            else if ((m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[2] < MIN_CUT_OFF_FREQUENCY) ||
                     (m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[2] > MAX_CUT_OFF_FREQUENCY))
            {
              return FGS_INVALID_CUT_OFF_FREQUENCIES; /* Not supported  */
            }
    
            /* conversion of component model values for 4:2:0 and 4:4:4 */
    
            if (ChromaFormat::_444 != m_chromaFormat && (compCtr > 0))
    
              if (ChromaFormat::_420 == m_chromaFormat) /* 4:2:0 */
    
              {
                m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[0] >>= 1;
                m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1] =
                  CLIP3(MIN_CUT_OFF_FREQUENCY, MAX_CUT_OFF_FREQUENCY,
                  (m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1] << 1));
                m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[2] =
                  CLIP3(MIN_CUT_OFF_FREQUENCY, MAX_CUT_OFF_FREQUENCY,
                  (m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[2] << 1));
    
              }
    
              else if (ChromaFormat::_422 == m_chromaFormat) /* 4:2:2 */
    
              {
                m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[0] =
                  (m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[0] * SCALE_DOWN_422) >> Q_FORMAT_SCALING;
    
                m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1] =
                  CLIP3(MIN_CUT_OFF_FREQUENCY, MAX_CUT_OFF_FREQUENCY,
                  (m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1] << 1));
              }
            }
    
            compPairMatch = 0;
            for (limitCompModelCtr = 0; limitCompModelCtr <= num_comp_model_pairs; limitCompModelCtr++)
            {
              if ((limitCompModelVal1[limitCompModelCtr] ==
                m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1]) &&
                (limitCompModelVal2[limitCompModelCtr] ==
                  m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[2]))
              {
                compPairMatch = 1;
              }
            }
    
            if (0 == compPairMatch)
            {
              num_comp_model_pairs++;
              /* max allowed pairs are 10 as per SMPTE -RDD5*/
              if (num_comp_model_pairs > MAX_ALLOWED_COMP_MODEL_PAIRS)
              {
                return FGS_INVALID_NUM_CUT_OFF_FREQ_PAIRS; /* Not supported  */
              }
              limitCompModelVal1[num_comp_model_pairs - 1] =
                m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[1];
              limitCompModelVal2[num_comp_model_pairs - 1] =
                m_fgcParameters->m_compModel[compCtr].intensityValues[intensityCtr].compModelValue[2];
            }
          }
        }
      }
      return FGS_SUCCESS; /* Success */
    }
    
    void SEIFilmGrainSynthesizer::deriveFGSBlkSize()
    {
      uint32_t picSizeInLumaSamples = m_height * m_width;
      if (picSizeInLumaSamples <= (1920 * 1080))
      {
        m_fgsBlkSize = BLK_8;
      }
      else if (picSizeInLumaSamples <= (3840 * 2160))
      {
        m_fgsBlkSize = BLK_16;
      }
      else
      {
        m_fgsBlkSize = BLK_32;
      }
    }
    void SEIFilmGrainSynthesizer::dataBaseGen()
    {
      uint32_t      pseudoRandValEhv;
      uint8_t       h, v; /* Horizaontal and vertical cut off frequencies (+2)*/
      uint32_t      ScaleCutOffFh, ScaleCutOffFv, l, r, i, j, k;
      int32_t       B[DATA_BASE_SIZE][DATA_BASE_SIZE], IDCT[DATA_BASE_SIZE][DATA_BASE_SIZE];
      int32_t       Grain[DATA_BASE_SIZE][DATA_BASE_SIZE];
    
      const TMatrixCoeff* Tmp = g_trCoreDCT2P64[TRANSFORM_FORWARD][0];
      const int transform_scale = 9;                  // upscaling of original transform as specified in VVC (for 64x64 block)
      const int add_1st = 1 << (transform_scale - 1);
    
      TMatrixCoeff T[DATA_BASE_SIZE][DATA_BASE_SIZE]; // Original
      TMatrixCoeff TT[DATA_BASE_SIZE][DATA_BASE_SIZE]; // Transpose
      for (int x = 0; x < DATA_BASE_SIZE; x++)
      {
        for (int y = 0; y < DATA_BASE_SIZE; y++)
        {
          T[x][y] = Tmp[x * 64 + y]; /* Matrix Original */
          TT[y][x] = Tmp[x * 64 + y]; /* Matrix Transpose */
        }
      }
    
      for (h = 0; h < NUM_CUT_OFF_FREQ; h++)
      {
        for (v = 0; v < NUM_CUT_OFF_FREQ; v++)
        {
          memset(&B, 0, DATA_BASE_SIZE*DATA_BASE_SIZE * sizeof(int32_t));
          memset(&IDCT, 0, DATA_BASE_SIZE*DATA_BASE_SIZE * sizeof(int32_t));
          memset(&Grain, 0, DATA_BASE_SIZE*DATA_BASE_SIZE * sizeof(int32_t));
          ScaleCutOffFh = ((h + 3) << 2) - 1;
          ScaleCutOffFv = ((v + 3) << 2) - 1;
    
          /* ehv : seed to be used for the psudo random generator for a given h and v */
          pseudoRandValEhv = seedLUT[h + v * 13];
    
          for (l = 0, r = 0; l <= ScaleCutOffFv; l++)
          {
            for (k = 0; k <= ScaleCutOffFh; k += 4)
            {
              B[k][l] = gaussianLUT[pseudoRandValEhv % 2048];
              B[k + 1][l] = gaussianLUT[(pseudoRandValEhv + 1) % 2048];
              B[k + 2][l] = gaussianLUT[(pseudoRandValEhv + 2) % 2048];
              B[k + 3][l] = gaussianLUT[(pseudoRandValEhv + 3) % 2048];
              r++;
              pseudoRandValEhv = prng(pseudoRandValEhv);
            }
          }
          B[0][0] = 0;
    
          for (i = 0; i < DATA_BASE_SIZE; i++)
          {
            for (j = 0; j < DATA_BASE_SIZE; j++)
            {
              for (k = 0; k < DATA_BASE_SIZE; k++)
              {
                IDCT[i][j] += TT[i][k] * B[k][j];
              }
              IDCT[i][j] += add_1st;
              IDCT[i][j] = IDCT[i][j] >> transform_scale;
            }
          }
    
          for (i = 0; i < DATA_BASE_SIZE; i++)
          {
            for (j = 0; j < DATA_BASE_SIZE; j++)
            {
              for (k = 0; k < DATA_BASE_SIZE; k++)
              {
                Grain[i][j] += IDCT[i][k] * T[k][j];
              }
              Grain[i][j] += add_1st;
              Grain[i][j] = Grain[i][j] >> transform_scale;
              m_grainSynt->dataBase[h][v][j][i] = CLIP3(-127, 127, Grain[i][j]);
            }
          }
    
          /* De-blocking at horizontal block edges */
          for (l = 0; l < DATA_BASE_SIZE; l += m_fgsBlkSize)
          {
            for (k = 0; k < DATA_BASE_SIZE; k++)
            {
              m_grainSynt->dataBase[h][v][l][k] = ((m_grainSynt->dataBase[h][v][l][k]) * deblockFactor[v]) >> 7;
              m_grainSynt->dataBase[h][v][l + m_fgsBlkSize - 1][k] = ((m_grainSynt->dataBase[h][v][l + m_fgsBlkSize - 1][k]) * deblockFactor[v]) >> 7;
            }
          }
        }
      }
      return;
    }
    
    uint32_t SEIFilmGrainSynthesizer::prng(uint32_t x_r)
    {
      uint32_t addVal;
      addVal  = (1 + ((x_r & (POS_2)) > 0) + ((x_r & (POS_30)) > 0)) % 2;
      x_r     = (x_r << 1) + addVal;
      return x_r;
    }
    
    uint32_t SEIFilmGrainSynthesizer::fgsProcess(fgsProcessArgs &inArgs)
    {
      uint32_t errorCode;
      uint8_t  blkSize = inArgs.blkSize;
    
      if (blkSize == 8)
        errorCode = fgsSimulationBlending_8x8(&inArgs);
      else if (blkSize == 16)
        errorCode = fgsSimulationBlending_16x16(&inArgs);
      else if (blkSize == 32)
        errorCode = fgsSimulationBlending_32x32(&inArgs);
      else
        errorCode = FGS_FAIL;
    
      return errorCode;
    }
    
    void SEIFilmGrainSynthesizer::deblockGrainStripe(Pel *grainStripe, uint32_t widthComp, uint32_t heightComp,
      uint32_t strideComp, uint32_t blkSize)
    {
      int32_t  left1, left0, right0, right1;
      uint32_t pos, vertCtr;
    
      uint32_t widthCropped = (widthComp - blkSize);
    
      for (vertCtr = 0; vertCtr < heightComp; vertCtr++)
      {
        for (pos = 0; pos < widthCropped; pos += blkSize)
        {
          left1 = *(grainStripe + blkSize - 2);
          left0 = *(grainStripe + blkSize - 1);
          right0 = *(grainStripe + blkSize + 0);
          right1 = *(grainStripe + blkSize + 1);
          *(grainStripe + blkSize + 0) = (left0 + (right0 << 1) + right1) >> 2;
          *(grainStripe + blkSize - 1) = (left1 + (left0 << 1) + right0) >> 2;
          grainStripe += blkSize;
        }
        grainStripe = grainStripe + (strideComp - pos);
      }
      return;
    }
    
    void SEIFilmGrainSynthesizer::blendStripe(Pel *decSampleHbdOffsetY, Pel *grainStripe, uint32_t widthComp,
    
    Frank Bossen's avatar
    Frank Bossen committed
                                              ptrdiff_t strideSrc, ptrdiff_t strideGrain, uint32_t blockHeight,
                                              uint8_t bitDepth)
    
    {
      uint32_t k, l;
      uint16_t maxRange;
      maxRange = (1 << bitDepth) - 1;
    
      int32_t  grainSample;
      uint16_t decodeSampleHbd;
      uint8_t bitDepthShift = (bitDepth - BIT_DEPTH_8);
    
    Frank Bossen's avatar
    Frank Bossen committed
      ptrdiff_t bufInc        = (strideSrc - widthComp);
      ptrdiff_t grainBufInc   = (strideGrain - widthComp);
    
    
      for (l = 0; l < blockHeight; l++) /* y direction */
      {
        for (k = 0; k < widthComp; k++) /* x direction */
        {
          decodeSampleHbd = *decSampleHbdOffsetY;
          grainSample = *grainStripe;
          grainSample <<= bitDepthShift;
          grainSample = CLIP3(0, maxRange, grainSample + decodeSampleHbd);
          *decSampleHbdOffsetY = (Pel)grainSample;
          decSampleHbdOffsetY++;
          grainStripe++;
        }
        decSampleHbdOffsetY += bufInc;
        grainStripe += grainBufInc;
      }
      return;
    }
    
    void SEIFilmGrainSynthesizer::blendStripe_32x32(Pel *decSampleHbdOffsetY, Pel *grainStripe, uint32_t widthComp,
    
    Frank Bossen's avatar
    Frank Bossen committed
                                                    ptrdiff_t strideSrc, ptrdiff_t strideGrain, uint32_t blockHeight,
                                                    uint8_t bitDepth)
    
    {
      uint32_t k, l;
      uint16_t maxRange;
      maxRange = (1 << bitDepth) - 1;
    
      int32_t  grainSample;
      uint16_t decodeSampleHbd;
      uint8_t bitDepthShift = (bitDepth - BIT_DEPTH_8);
    
    Frank Bossen's avatar
    Frank Bossen committed
      ptrdiff_t bufInc        = (strideSrc - widthComp);
      ptrdiff_t grainBufInc   = (strideGrain - widthComp);
    
    
      for (l = 0; l < blockHeight; l++) /* y direction */
      {
        for (k = 0; k < widthComp; k++) /* x direction */
        {
          decodeSampleHbd = *decSampleHbdOffsetY;
          grainSample = *grainStripe;
          grainSample <<= bitDepthShift;
          grainSample = CLIP3(0, maxRange, grainSample + decodeSampleHbd);
          *decSampleHbdOffsetY = (Pel)grainSample;
          decSampleHbdOffsetY++;
          grainStripe++;
        }
        decSampleHbdOffsetY += bufInc;
        grainStripe += grainBufInc;
      }
      return;
    }
    
    
    Frank Bossen's avatar
    Frank Bossen committed
    Pel SEIFilmGrainSynthesizer::blockAverage_8x8(Pel *decSampleBlk8, ptrdiff_t widthComp, uint16_t *pNumSamples,
                                                  uint8_t ySize, uint8_t xSize, uint8_t bitDepth)
    
    {
      uint32_t blockAvg = 0;
      uint8_t  k;
      uint8_t l;
      for (k = 0; k < ySize; k++)
      {
        for (l = 0; l < xSize; l++)
        {
          blockAvg += *decSampleBlk8;
          decSampleBlk8++;
        }
        decSampleBlk8 += widthComp - xSize;
      }
    
      blockAvg = blockAvg >> (BLK_8_shift + (bitDepth - BIT_DEPTH_8));
      *pNumSamples = BLK_AREA_8x8;
    
      return blockAvg;
    }
    
    
    Frank Bossen's avatar
    Frank Bossen committed
    uint32_t SEIFilmGrainSynthesizer::blockAverage_16x16(Pel *decSampleBlk8, ptrdiff_t widthComp, uint16_t *pNumSamples,
                                                         uint8_t ySize, uint8_t xSize, uint8_t bitDepth)
    
    {
      uint32_t blockAvg = 0;
      uint8_t  k;
      uint8_t l;
      for (k = 0; k < ySize; k++)
      {
        for (l = 0; l < xSize; l++)
        {
          blockAvg += *decSampleBlk8;
          decSampleBlk8++;
        }
        decSampleBlk8 += widthComp - xSize;
      }
    
      // blockAvg = blockAvg >> (BLK_16_shift + (bitDepth - BIT_DEPTH_8));
      // If BLK_16 is not used or changed BLK_AREA_16x16 has to be changed
      *pNumSamples = BLK_AREA_16x16;
      return blockAvg;
    }
    
    
    Frank Bossen's avatar
    Frank Bossen committed
    uint32_t SEIFilmGrainSynthesizer::blockAverage_32x32(Pel *decSampleBlk32, ptrdiff_t strideComp, uint8_t bitDepth)
    
    {
      uint32_t blockAvg = 0;
      uint8_t  k;
      uint8_t l;
    
    Frank Bossen's avatar
    Frank Bossen committed
      ptrdiff_t bufInc = strideComp - BLK_32;
    
      for (k = 0; k < BLK_32; k++)
      {
        for (l = 0; l < BLK_32; l++)
        {
          blockAvg += *decSampleBlk32++;
        }
        decSampleBlk32 += bufInc;
      }
      blockAvg = blockAvg >> (BLK_32_shift + (bitDepth - BIT_DEPTH_8));
      return blockAvg;
    }
    
    void SEIFilmGrainSynthesizer::simulateGrainBlk8x8(Pel *grainStripe, uint32_t grainStripeOffsetBlk8,
      GrainSynthesisStruct *grain_synt, uint32_t width,
      uint8_t log2ScaleFactor, int16_t scaleFactor, uint32_t kOffset,
      uint32_t lOffset, uint8_t h, uint8_t v, uint32_t xSize)
    {
      uint32_t l;
      int8_t * database_h_v = &grain_synt->dataBase[h][v][lOffset][kOffset];
      grainStripe += grainStripeOffsetBlk8;
      uint32_t k;
      for (l = 0; l < BLK_8; l++) /* y direction */
      {
        for (k = 0; k < xSize; k++) /* x direction */
        {
          *grainStripe = ((scaleFactor * (*database_h_v)) >> (log2ScaleFactor + GRAIN_SCALE));
          grainStripe++;
          database_h_v++;
        }
        grainStripe += width - xSize;
        database_h_v += DATA_BASE_SIZE - xSize;
      }
      return;
    }
    
    void SEIFilmGrainSynthesizer::simulateGrainBlk16x16(Pel *grainStripe, uint32_t grainStripeOffsetBlk8,
      GrainSynthesisStruct *grain_synt, uint32_t width,
      uint8_t log2ScaleFactor, int16_t scaleFactor, uint32_t kOffset,
      uint32_t lOffset, uint8_t h, uint8_t v, uint32_t xSize)
    {
      uint32_t l;
      int8_t * database_h_v = &grain_synt->dataBase[h][v][lOffset][kOffset];
      grainStripe += grainStripeOffsetBlk8;
      uint32_t k;
      for (l = 0; l < BLK_16; l++) /* y direction */
      {
        for (k = 0; k < xSize; k++) /* x direction */
        {
          *grainStripe = (int16_t)(((int32_t)scaleFactor * (*database_h_v)) >> (log2ScaleFactor + GRAIN_SCALE));
          grainStripe++;
          database_h_v++;
        }
        grainStripe += width - xSize;
        database_h_v += DATA_BASE_SIZE - xSize;
      }
      return;
    }
    
    void SEIFilmGrainSynthesizer::simulateGrainBlk32x32(Pel *grainStripe, uint32_t grainStripeOffsetBlk32,
      GrainSynthesisStruct *grain_synt, uint32_t width,
      uint8_t log2ScaleFactor, int16_t scaleFactor, uint32_t kOffset,
      uint32_t lOffset, uint8_t h, uint8_t v)
    {
      uint32_t l;
      int8_t * database_h_v = &grain_synt->dataBase[h][v][lOffset][kOffset];
      grainStripe += grainStripeOffsetBlk32;
      uint32_t k;
      uint8_t shiftVal = log2ScaleFactor + GRAIN_SCALE;
      uint32_t grainbufInc = width - BLK_32;
    
      for (l = 0; l < BLK_32; l++) /* y direction */
      {
        for (k = 0; k < BLK_32; k++) /* x direction */
        {
          *grainStripe = ((scaleFactor * (*database_h_v)) >> shiftVal);
          grainStripe++;
          database_h_v++;
        }
        grainStripe += grainbufInc;
        database_h_v += DATA_BASE_SIZE - BLK_32;
      }
      return;
    }
    
    uint32_t SEIFilmGrainSynthesizer::fgsSimulationBlending_8x8(fgsProcessArgs *inArgs)
    {
      uint8_t  numComp, compCtr, blkId; /* number of color components */
      uint8_t  log2ScaleFactor, h, v;
      uint8_t  bitDepth; /*grain bit depth and decoded bit depth are assumed to be same */
    
    Frank Bossen's avatar
    Frank Bossen committed
      uint32_t  widthComp[MAX_NUM_COMPONENT], heightComp[MAX_NUM_COMPONENT];
      ptrdiff_t strideComp[MAX_NUM_COMPONENT];
    
      Pel *    decSampleHbdBlk16, *decSampleHbdBlk8, *decSampleHbdOffsetY;
      Pel *    decHbdComp[MAX_NUM_COMPONENT];
      uint16_t numSamples;
      int16_t  scaleFactor;
    
    Frank Bossen's avatar
    Frank Bossen committed
      uint32_t  kOffset, lOffset, grainStripeOffset, grainStripeOffsetBlk8;
      ptrdiff_t offsetBlk8x8;
    
      uint32_t kOffset_const, lOffset_const;
      int16_t  scaleFactor_const;
      Pel *    grainStripe; /* worth a row of 16x16 : Max size : 16xw;*/
      int32_t  yOffset8x8, xOffset8x8;
      uint32_t x, y;
      uint32_t blockAvg, intensityInt; /* ec : seed to be used for the psudo random generator for a given color component */
      uint32_t grainStripeWidth;
      uint32_t wdPadded;
    
      bitDepth        = inArgs->bitDepth;
      numComp         = inArgs->numComp;
      log2ScaleFactor = inArgs->pFgcParameters->m_log2ScaleFactor;
    
      for (compCtr = 0; compCtr < numComp; compCtr++)
      {
        decHbdComp[compCtr] = inArgs->decComp[compCtr];
        strideComp[compCtr] = inArgs->strideComp[compCtr];
        widthComp[compCtr]  = inArgs->widthComp[compCtr];
        heightComp[compCtr] = inArgs->heightComp[compCtr];
      }
    
      wdPadded = ((inArgs->widthComp[0] - 1) | 0xF) + 1;
      grainStripe = new Pel[wdPadded * BLK_16];
    
      if (0 == inArgs->pFgcParameters->m_filmGrainCharacteristicsCancelFlag)
      {
        for (compCtr = 0; compCtr < numComp; compCtr++)
        {
          if (1 == inArgs->pFgcParameters->m_compModel[compCtr].presentFlag)
          {
            decSampleHbdOffsetY  = decHbdComp[compCtr];
            uint32_t *offset_tmp = inArgs->fgsOffsets[compCtr];
            grainStripeWidth = ((widthComp[compCtr] - 1) | 0xF) + 1;   // Make next muliptle of 16
    
            /* Loop of 16x16 blocks */
            for (y = 0; y < heightComp[compCtr]; y += BLK_16)
            {
              /* Initialization of grain stripe of 16xwidth size */
              memset(grainStripe, 0, (grainStripeWidth * BLK_16 * sizeof(Pel)));
              for (x = 0; x < widthComp[compCtr]; x += BLK_16)
              {
                /* start position offset of decoded sample in x direction */