Bd Rate Calculation

BD-Rate Calculator (Bjontegaard Delta) – Video Compression Analysis :root { –primary-color: #2c3e50; –secondary-color: #3498db; –accent-color: #e74c3c; –light-bg: #f8f9fa; –border-color: #dee2e6; } body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; line-height: 1.6; color: #333; max-width: 1200px; margin: 0 auto; padding: 20px; background-color: #f5f5f5; } .container { display: flex; flex-wrap: wrap; gap: 30px; } .calculator-panel { flex: 1; min-width: 350px; background: #fff; padding: 25px; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); } .content-panel { flex: 1; min-width: 350px; background: #fff; padding: 30px; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); } h1 { color: var(–primary-color); text-align: center; margin-bottom: 30px; width: 100%; } h2 { color: var(–secondary-color); border-bottom: 2px solid var(–border-color); padding-bottom: 10px; margin-top: 0; } h3 { color: var(–primary-color); margin-top: 20px; margin-bottom: 10px; font-size: 1.1em; } .input-group { margin-bottom: 20px; background: var(–light-bg); padding: 15px; border-radius: 6px; border: 1px solid var(–border-color); } .data-row { display: flex; gap: 10px; margin-bottom: 10px; align-items: center; } .data-row label { width: 30px; font-weight: bold; color: #666; } .input-field { flex: 1; } .input-field label { display: block; font-size: 0.8em; margin-bottom: 2px; width: 100%; color: #666; } input[type="number"] { width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; box-sizing: border-box; } button { width: 100%; padding: 12px; background-color: var(–secondary-color); color: white; border: none; border-radius: 4px; font-size: 16px; font-weight: bold; cursor: pointer; transition: background 0.3s; margin-top: 10px; } button:hover { background-color: #2980b9; } #result { margin-top: 25px; padding: 20px; background-color: #edf7ed; border: 1px solid #c3e6cb; border-radius: 4px; display: none; } .result-item { margin-bottom: 10px; font-size: 1.1em; display: flex; justify-content: space-between; border-bottom: 1px solid rgba(0,0,0,0.05); padding-bottom: 5px; } .result-item:last-child { border-bottom: none; } .value { font-weight: bold; } .positive { color: #d32f2f; } /* Increase in bitrate is bad */ .negative { color: #2e7d32; } /* Decrease in bitrate is good */ .tooltip { font-size: 0.85em; color: #666; margin-top: 5px; font-style: italic; }

BD-Rate (Bjontegaard Delta) Calculator

RD Curve Data Points

Enter 4 pairs of Bitrate (kbps) and Quality (PSNR/SSIM) for both Reference and Test codecs.

Anchor (Reference) Codec

#

Test Codec

#
BD-Rate (Bitrate Savings):
BD-PSNR (Quality Gain):

Understanding BD-Rate

Bjontegaard Delta Rate (BD-Rate) is the standard metric used in video compression research and engineering to compare the coding efficiency of two different video codecs (or different settings of the same codec).

Instead of comparing bitrate at a single quality point, BD-Rate calculates the average percentage difference in bitrate required to achieve the same objective quality (usually measured in PSNR or SSIM) over a range of bitrates.

How it Works

The calculation involves constructing Rate-Distortion (RD) curves for both the Reference (Anchor) and the Test case using 4 data points (typically generated by quantization parameters like 22, 27, 32, 37).

  • Logarithmic Scale: Bitrates are converted to a logarithmic scale because the relationship between bitrate and distortion is roughly exponential.
  • Polynomial Fitting: A curve (typically a 3rd-order polynomial) is fitted to the data points for both codecs.
  • Integration: The area between the two curves is integrated over the overlapping quality range.

Interpreting the Result

The output is expressed as a percentage:

  • Negative Value (e.g., -15%): The Test codec is more efficient. It requires 15% less bitrate to achieve the same quality as the Reference.
  • Positive Value (e.g., +10%): The Test codec is less efficient. It requires 10% more bitrate for the same quality.
  • Zero (0%): Both codecs perform identically.

About BD-PSNR

BD-PSNR measures the average difference in quality (dB) at the same bitrate. A positive BD-PSNR indicates higher quality for the same file size.

function calculateBDRate() { // Helper to get value function getVal(id) { var el = document.getElementById(id); var val = parseFloat(el.value); if (isNaN(val)) return null; return val; } // Gather Data var ancR = [getVal('anc_r1'), getVal('anc_r2'), getVal('anc_r3'), getVal('anc_r4')]; var ancQ = [getVal('anc_q1'), getVal('anc_q2'), getVal('anc_q3'), getVal('anc_q4')]; var tstR = [getVal('tst_r1'), getVal('tst_r2'), getVal('tst_r3'), getVal('tst_r4')]; var tstQ = [getVal('tst_q1'), getVal('tst_q2'), getVal('tst_q3'), getVal('tst_q4')]; // Validation if (ancR.includes(null) || ancQ.includes(null) || tstR.includes(null) || tstQ.includes(null)) { alert("Please enter all 4 data points (Bitrate and PSNR) for both Reference and Test codecs."); return; } // — Math Logic Starts Here — // 1. Log conversion of rates for BD-Rate calculation var logAncR = ancR.map(function(r) { return Math.log10(r); }); var logTstR = tstR.map(function(r) { return Math.log10(r); }); // 2. Calculate BD-Rate: // Curve fit: LogRate = f(PSNR). We integrate over PSNR range. // Find overlapping range of PSNR var minPSNR = Math.max(Math.min.apply(null, ancQ), Math.min.apply(null, tstQ)); var maxPSNR = Math.min(Math.max.apply(null, ancQ), Math.max.apply(null, tstQ)); var bdRate = 0; var bdPsnr = 0; if (maxPSNR > minPSNR) { // Fit Poly: x=PSNR, y=LogRate var polyAnc = polyFit(ancQ, logAncR, 3); var polyTst = polyFit(tstQ, logTstR, 3); // Integrate var intAnc = integratePoly(polyAnc, minPSNR, maxPSNR); var intTst = integratePoly(polyTst, minPSNR, maxPSNR); // Average difference var avgDiff = (intTst – intAnc) / (maxPSNR – minPSNR); // Convert back from log scale to percentage bdRate = (Math.pow(10, avgDiff) – 1) * 100; } else { bdRate = NaN; // No overlap } // 3. Calculate BD-PSNR: // Curve fit: PSNR = f(LogRate). We integrate over LogRate range. var minLogR = Math.max(Math.min.apply(null, logAncR), Math.min.apply(null, logTstR)); var maxLogR = Math.min(Math.max.apply(null, logAncR), Math.max.apply(null, logTstR)); if (maxLogR > minLogR) { // Fit Poly: x=LogRate, y=PSNR var polyAncP = polyFit(logAncR, ancQ, 3); var polyTstP = polyFit(logTstR, tstQ, 3); var intAncP = integratePoly(polyAncP, minLogR, maxLogR); var intTstP = integratePoly(polyTstP, minLogR, maxLogR); bdPsnr = (intTstP – intAncP) / (maxLogR – minLogR); } else { bdPsnr = NaN; } // Display Results var resDiv = document.getElementById("result"); resDiv.style.display = "block"; var bdRateEl = document.getElementById("bdRateValue"); var bdPsnrEl = document.getElementById("bdPsnrValue"); var interpEl = document.getElementById("interpretation"); if (!isNaN(bdRate)) { bdRateEl.innerText = bdRate.toFixed(2) + "%"; bdRateEl.className = bdRate < 0 ? "value negative" : "value positive"; var savingsText = bdRate < 0 ? "Bitrate SAVINGS of " + Math.abs(bdRate).toFixed(2) + "%" : "Bitrate INCREASE of " + bdRate.toFixed(2) + "%"; interpEl.innerHTML = "Result: The Test codec shows a <span style='color:" + (bdRate " + savingsText + " compared to the Anchor at equal quality."; } else { bdRateEl.innerText = "No Overlap"; interpEl.innerText = "Error: The quality ranges of the two curves do not overlap."; } if (!isNaN(bdPsnr)) { bdPsnrEl.innerText = bdPsnr.toFixed(3) + " dB"; bdPsnrEl.className = bdPsnr > 0 ? "value negative" : "value positive"; // Positive PSNR gain is "Green/Good" } else { bdPsnrEl.innerText = "No Overlap"; } } // — Math Helpers — // Polynomial Fit (Least Squares) // Solves y = a0 + a1*x + a2*x^2 + a3*x^3 // Returns array [a0, a1, a2, a3] function polyFit(x, y, order) { // Setup matrices for Normal Equation: (X^T * X) * Beta = X^T * Y // Since order is small (3), we can hardcode Gaussian elimination or similar // But for robustness in 4 points, order 3 is exact interpolation if points distinct. var n = x.length; var k = order + 1; var X = []; // Matrix X var Y = y; // Vector Y // Build X Matrix for (var i = 0; i < n; i++) { var row = []; for (var j = 0; j < k; j++) { row.push(Math.pow(x[i], j)); } X.push(row); } // Transpose X var XT = []; for (var i = 0; i < k; i++) { var row = []; for (var j = 0; j < n; j++) { row.push(X[j][i]); } XT.push(row); } // B = X^T * X var B = multiplyMatrices(XT, X); // C = X^T * Y var C = multiplyVector(XT, Y); // Solve B * Beta = C using Gaussian Elimination return gaussianElimination(B, C); } function multiplyMatrices(m1, m2) { var r1 = m1.length; var c1 = m1[0].length; var c2 = m2[0].length; var res = []; for (var i = 0; i < r1; i++) { res[i] = []; for (var j = 0; j < c2; j++) { var sum = 0; for (var k = 0; k < c1; k++) { sum += m1[i][k] * m2[k][j]; } res[i][j] = sum; } } return res; } function multiplyVector(m, v) { var r = m.length; var c = m[0].length; var res = []; for (var i = 0; i < r; i++) { var sum = 0; for (var j = 0; j < c; j++) { sum += m[i][j] * v[j]; } res.push(sum); } return res; } function gaussianElimination(A, b) { var n = A.length; // Augmented matrix for (var i = 0; i < n; i++) { A[i].push(b[i]); } // Forward elimination for (var i = 0; i < n; i++) { // Find pivot var maxEl = Math.abs(A[i][i]); var maxRow = i; for (var k = i + 1; k maxEl) { maxEl = Math.abs(A[k][i]); maxRow = k; } } // Swap var tmp = A[maxRow]; A[maxRow] = A[i]; A[i] = tmp; // Make 0 below for (var k = i + 1; k < n; k++) { var c = -A[k][i] / A[i][i]; for (var j = i; j -1; i–) { var sum = 0; for (var j = i + 1; j < n; j++) { sum += A[i][j] * x[j]; } x[i] = (A[i][n] – sum) / A[i][i]; } return x; } // Integrate Polynomial: a0 + a1*x + a2*x^2 + a3*x^3 // Integral is: a0*x + a1*x^2/2 + a2*x^3/3 + a3*x^4/4 function integratePoly(coeffs, min, max) { function evalInt(x, c) { var sum = 0; for (var i = 0; i < c.length; i++) { sum += c[i] * Math.pow(x, i + 1) / (i + 1); } return sum; } return evalInt(max, coeffs) – evalInt(min, coeffs); }

Leave a Comment