/* * H.265 video codec. * Copyright (c) 2013-2014 struktur AG, Dirk Farin * * This file is part of libde265. * * libde265 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * libde265 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with libde265. If not, see . */ #include #include #include #include #include #include #include #include const bool D = false; /* There are numerical stability problems in the matrix inverse. Switching to long double seems to provide enough accuracy. TODO: in the long term, use a better regression algorithm. */ typedef long double FP; struct datapoint { double rate; double distortion; }; struct BjoentegaardParams { // a*log^3 R + b*log^2 R + c*log R + d double a,b,c,d; double minRate, maxRate; }; std::vector curveA,curveB; BjoentegaardParams paramsA,paramsB; #define RATE_NORMALIZATION_FACTOR 1 //(1/1000.0) FP invf(int i,int j,const FP* m) { int o = 2+(j-i); i += 4+o; j += 4-o; #define e(a,b) m[ ((j+b)%4)*4 + ((i+a)%4) ] FP inv = + e(+1,-1)*e(+0,+0)*e(-1,+1) + e(+1,+1)*e(+0,-1)*e(-1,+0) + e(-1,-1)*e(+1,+0)*e(+0,+1) - e(-1,-1)*e(+0,+0)*e(+1,+1) - e(-1,+1)*e(+0,-1)*e(+1,+0) - e(+1,-1)*e(-1,+0)*e(+0,+1); return (o%2)?inv : -inv; #undef e } bool inverseMatrix4x4(const FP *m, FP *out) { FP inv[16]; for(int i=0;i<4;i++) for(int j=0;j<4;j++) inv[j*4+i] = invf(i,j,m); FP D = 0; for(int k=0;k<4;k++) D += m[k] * inv[k*4]; if (D == 0) return false; D = 1.0 / D; for (int i = 0; i < 16; i++) out[i] = inv[i] * D; return true; } BjoentegaardParams fitParams(const std::vector& curve) { // build regression matrix int n = curve.size(); FP X[4*n]; // regression matrix FP XT[n*4]; // transpose of X for (int i=0;i= 0) mini = std::max(mini, min_rate); if (max_rate >= 0) maxi = std::min(maxi, max_rate); if (D) printf("range: %f %f\n",mini,maxi); FP intA = evalIntegralAt(paramsA, maxi) - evalIntegralAt(paramsA, mini); FP intB = evalIntegralAt(paramsB, maxi) - evalIntegralAt(paramsB, mini); if (D) printf("int1:%f int2:%f\n",(double)intA,(double)intB); return (intA-intB)/(maxi-mini); } std::vector readRDFile(const char* filename, float min_rate, float max_rate) { std::vector curve; std::ifstream istr(filename); for (;;) { std::string line; getline(istr, line); if (istr.eof()) break; if (line[0]=='#') continue; std::stringstream sstr(line); datapoint p; sstr >> p.rate >> p.distortion; if (min_rate>=0 && p.rate < min_rate) continue; if (max_rate>=0 && p.rate > max_rate) continue; curve.push_back(p); } return curve; } int main(int argc, char** argv) { float min_rate = -1; float max_rate = -1; int c; while ((c=getopt(argc,argv, "l:h:")) != -1) { switch (c) { case 'l': min_rate = atof(optarg); break; case 'h': max_rate = atof(optarg); break; } } curveA = readRDFile(argv[optind], min_rate, max_rate); paramsA = fitParams(curveA); printf("params A: %f %f %f %f\n",paramsA.a,paramsA.b,paramsA.c,paramsA.d); printf("gnuplot: %f*log(x)**3+%f*log(x)**2+%f*log(x)+%f\n",paramsA.a,paramsA.b,paramsA.c,paramsA.d); if (optind+1 >0 -> first (A) is better)\n",delta); if (delta>=0) { printf("-> first is better by %f dB\n",delta); } else { printf("-> second is better by %f dB\n",-delta); } } return 0; }