1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.media.videoquality.bdrate; 18 19 import org.apache.commons.math3.analysis.polynomials.PolynomialFunction; 20 import org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction; 21 22 /** Utilities for performing the calculus involved for BD-RATE and BD-QUALITY calculations. */ 23 public final class BdCalculus { 24 BdCalculus()25 private BdCalculus() {} 26 27 /** 28 * Calculates the area under the curve for the provided {@link PolynomialSplineFunction} between 29 * the min and max values. 30 */ calculateAuc(PolynomialSplineFunction func, double min, double max)31 public static double calculateAuc(PolynomialSplineFunction func, double min, double max) { 32 33 // Create the integral functions for each of the segments of the spline. 34 PolynomialFunction[] segmentFuncs = func.getPolynomials(); 35 PolynomialFunction[] integralFuncs = new PolynomialFunction[segmentFuncs.length]; 36 for (int funcIdx = 0; funcIdx < segmentFuncs.length; funcIdx++) { 37 integralFuncs[funcIdx] = integratePolynomial(segmentFuncs[funcIdx]); 38 } 39 40 // Calculate the integral for each segment, summing up the results 41 // which is the value of the spline's integral. 42 double result = 0; 43 double[] knots = func.getKnots(); 44 for (int leftKnotIdx = 0; leftKnotIdx < knots.length - 1; leftKnotIdx++) { 45 double leftKnot = knots[leftKnotIdx]; 46 double rightKnot = knots[leftKnotIdx + 1]; 47 48 if (rightKnot < min) { 49 continue; 50 } 51 52 if (leftKnot > max) { 53 break; 54 } 55 56 double integrationLeft = Math.max(0, min - leftKnot); 57 double integrationRight = Math.min(rightKnot - leftKnot, max - leftKnot); 58 59 PolynomialFunction integralFunc = integralFuncs[leftKnotIdx]; 60 result += integralFunc.value(integrationRight) - integralFunc.value(integrationLeft); 61 } 62 63 return result; 64 } 65 66 /** 67 * Perform a standard polynomial integration by parts on the provided {@link 68 * PolynomialFunction}, returning a new {@link PolynomialFunction} representing the integrated 69 * function. 70 */ integratePolynomial(PolynomialFunction function)71 private static PolynomialFunction integratePolynomial(PolynomialFunction function) { 72 double[] newCoeffs = new double[function.getCoefficients().length + 1]; 73 for (int i = 1; i <= function.getCoefficients().length; i++) { 74 newCoeffs[i] = function.getCoefficients()[i - 1] / i; 75 } 76 newCoeffs[0] = 0; 77 return new PolynomialFunction(newCoeffs); 78 } 79 } 80