Metrics¶
The Video Analyzer SDK provides comprehensive quality metrics for each analyzed video frame through the SingleFrameMetrics class.
Please obtain the actual metric values through the getXXX() methods.
Available Metrics¶
Note
As this is still in beta, we may add or change metrics in future releases, and the value ranges may be adjusted.
| Metric Name | Type | Value Range | Description |
|---|---|---|---|
getBlockiness() |
double |
0-1 | Multi-scale blockiness (0=none, 0.4=noticeable, 0.8 and above=severe) |
getBlockinessNtia() |
double |
0-? | Blockiness using the NTIA method, raw score (typically 0-0.3) |
getBlockinessVp9() |
double |
0-? | Blockiness using the VP9 method, raw score (typically 0-100) |
getBlurriness() |
double |
0-1 | Blurriness using the NTIA method (0=sharp, 1=blurry) |
getBlurrinessRaw() |
double |
0-? | Blurriness, raw score (approximately 0.5-3.2) |
getBrightness() |
double |
0-1 | Average luma value |
getChroma() |
double |
0-1 | Mean distance from grey in the U/V plane (colorfulness) |
getContrast() |
double |
0-1 | Contrast by ratio of 1st and 99th percentile |
getContrastMichelson() |
double |
0-1 | Michelson contrast |
getSumOfHighFrequencies() |
double |
? | Sum of high frequencies based on radial profile |
getNoise() |
double |
0-? | Noise in the flat areas of the luma plane (0=clean, typically below 10) |
getWhiteLevel() |
double |
0-1 | Irregular white levels (higher is worse) |
getBlackLevel() |
double |
0-1 | Irregular black levels (higher is worse) |
getFineDetail() |
double |
0-1 | High details present (higher is worse) |
getSceneScore() |
double |
0-1 | Scene change score, based on the luma SAD |
getSadNormalized() |
double |
0-1 | SAD of the luma plane against the previous frame, normalized |
getTemporalInformation() |
double |
0-? | Temporal complexity based on ITU-T P.910 |
getSpatialInformation() |
double |
0-? | Spatial complexity based on ITU-T P.910 |
getJerkiness() |
double |
0-1 | Jerkiness based on count of repeated frames in a group (luma SADs) |
getBlackScreen() |
boolean |
true/false | Whether this is a completely black screen |
getFreezing() |
boolean |
true/false | Whether the frame is frozen, based on the luma SAD |
getSceneChange() |
boolean |
true/false | Whether the scene changed, based on the luma SAD |
All metrics except chroma are computed on the full-range luma (Y) plane of the frame.
Metric Details¶
Chroma¶
getChroma() is the mean distance from grey in the U/V plane, as a vectorscope shows it. For each chroma sample, the distance sqrt((U - 128)² + (V - 128)²) is divided by its largest possible value (128 * sqrt(2)), and the result is the mean over all chroma samples (a quarter of the number of luma samples for 4:2:0 video). U and V are in full range with 128 as the neutral value.
Grey pictures have a chroma of 0. Unlike the HSV saturation, chroma is not divided by the brightness, so dark scenes with little noise or a small color cast near black do not get a high value.
Chroma replaces the former saturation metric (the mean of the S channel of HSV), which scored dark scenes as strongly saturated.
Noise¶
getNoise() estimates the noise in the source, that is grain or sensor noise that was in the video before encoding. It uses the method of VIQET on the luma plane: the local standard deviation with a Gaussian window (the window size is 1/120 of the picture height), of which the mean of the lowest 0.5 % of the values above 0.00001 is returned. These values come from the flattest areas of the picture. The value is in units of 8-bit luma levels. A clean picture gives a value close to 0; a flat grey picture with FFmpeg's noise filter at strength 10, 20 and 40 gives about 1.2, 2.6 and 5.3. On clean pictures with very flat areas (for example graphics), the value is determined by the edges and small steps of the flattest areas instead of noise.
The metric is meant for sources and mezzanine files. On encoded video, it reports the noise that is left after encoding, which is usually lower than in the source, because encoders remove noise. It does not measure encoding artifacts such as mosquito noise, which appear next to edges and not in flat areas. Noise that is only in the chroma planes is not measured.
Temporal Metrics¶
The temporal metrics compare frames on the luma plane:
getSadNormalized()is the sum of absolute differences (SAD) of the luma planes of the frame and the previous frame, divided by the number of pixels and 255. Identical frames have a value of exactly 0.getSceneScore()is the difference between the normalized SAD of the frame and that of the previous frame, but at most the normalized SAD of the frame.getFreezing()is true if the normalized SAD is at most 0.00001, that is if the frame is identical or almost identical to the previous frame. Repeated frames in encoded video are often not bit-identical (the encoder codes them with small changes) and are then only flagged if the changes are very small. A higher threshold would flag static pictures with small moving parts, such as a slide with a running clock.getSceneChange()is true if the scene score is at least 0.1.getJerkiness()counts similar values among the z-normalized SADs between the frame and the previous frames.
Spatial and Temporal Information¶
getSpatialInformation() and getTemporalInformation() follow the legacy (non-HDR) SI/TI definition from ITU-T Rec. P.910, matching the reference implementation in siti-tools. Both metrics operate on the luma plane. The analyzer treats input as limited-range expanded to full, and the values match siti-tools in its limited-range legacy mode.
Checking Metric Availability¶
Not all metrics may be available for every frame. Always check availability before using metric values:
Method 1: Using Has Methods¶
public void processMetrics(SingleFrameMetrics metrics) {
// Check availability before using
if (metrics.hasBlurriness()) {
double blur = metrics.getBlurriness();
// use blur value
}
if (metrics.hasBrightness()) {
double brightness = metrics.getBrightness();
// use brightness value
}
if (metrics.hasTemporalInformation()) {
double temporal = metrics.getTemporalInformation();
// use temporal value
}
}
Method 2: Checking for NaN Values¶
public void processMetrics(SingleFrameMetrics metrics) {
// Metrics return NaN if not available
double contrast = metrics.getContrast();
if (!Double.isNaN(contrast)) {
// use contrast value
}
double noise = metrics.getNoise();
if (!Double.isNaN(noise)) {
// use noise value
}
}
Performance and Selective Metric Calculation¶
Processing all metrics for every frame can be resource-intensive. Consider:
- Sampling frames (analyze every Nth frame)
- Selective metric calculation based on use case (see below)
- Adjusting analysis frequency based on device performance
The VideoAnalyzer SDK supports selective calculation of metrics to improve performance when you only need specific measurements. This can significantly reduce CPU usage and battery consumption on mobile devices.
Enabling Specific Features Only¶
To calculate only specific metrics, pass the names of the features to compute when creating the VideoAnalyzerManager (requires a version newer than 0.12.0):
import com.aveq.videoanalyzer.VideoAnalyzerManager;
import java.util.Arrays;
// Only these features will be calculated
VideoAnalyzerManager manager = new VideoAnalyzerManager(
context,
30.0, // fps
Arrays.asList("blurriness", "blockiness", "brightness"),
null // no disabled features
);
Disabling Specific Features¶
To calculate all metrics except certain ones, pass the names of the features to skip instead:
import java.util.Arrays;
VideoAnalyzerManager manager = new VideoAnalyzerManager(
context,
30.0, // fps
null, // all features
Arrays.asList("noise", "radialprofile") // except these
);
VideoAnalyzerManager.getAvailableFeatures() returns the list of valid names. Unknown names throw an IllegalArgumentException.
The following feature names can be used for selective calculation:
blockiness: blockiness, blockiness_ntia, blockiness_vp9blurriness: blurriness, blurriness_rawbrightness: brightnessblackscreen: black_screenchroma: chromacontrast: contrast, contrast_michelsonradialprofile: sum_of_high_frequenciesnoise: noiseautoenhancement: white_level, black_levelfinedetail: fine_detailtemporalchange: freezing, scene_change, scene_score, sad_normalized, temporal_informationspatialcomplexity: spatial_informationjerkiness: jerkiness