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 com.google.auto.value.AutoValue;
20 import com.google.common.base.CharMatcher;
21 import com.google.common.base.Splitter;
22 import com.google.gson.JsonDeserializationContext;
23 import com.google.gson.JsonDeserializer;
24 import com.google.gson.JsonElement;
25 import com.google.gson.JsonObject;
26 import com.google.gson.JsonParseException;
27 
28 import java.lang.reflect.Type;
29 import java.util.PrimitiveIterator;
30 
31 @AutoValue
32 public abstract class ReferenceConfig {
testId()33     public abstract String testId();
34 
referenceFile()35     public abstract String referenceFile();
36 
referenceCurve()37     public abstract RateDistortionCurve referenceCurve();
38 
referenceThreshold()39     public abstract double referenceThreshold();
40 
create( String testId, String referenceFile, RateDistortionCurve curve, double referenceThreshold)41     public static ReferenceConfig create(
42             String testId,
43             String referenceFile,
44             RateDistortionCurve curve,
45             double referenceThreshold) {
46         return new AutoValue_ReferenceConfig(testId, referenceFile, curve, referenceThreshold);
47     }
48 
49     public static class Deserializer implements JsonDeserializer<ReferenceConfig> {
50 
51         @Override
deserialize( JsonElement json, Type typeOfT, JsonDeserializationContext context)52         public ReferenceConfig deserialize(
53                 JsonElement json, Type typeOfT, JsonDeserializationContext context)
54                 throws JsonParseException {
55             JsonObject referenceConfig = json.getAsJsonObject();
56 
57             String testId = referenceConfig.get("TestId").getAsString();
58 
59             // Trim the file extension off the reference filename.
60             String referenceFileName = referenceConfig.get("RefFileName").getAsString();
61             if (referenceFileName.endsWith(".y4m")) {
62                 referenceFileName = referenceFileName.substring(0, referenceFileName.length() - 4);
63             }
64 
65             // These are stored as whitespace separated, so parse them,
66             // split them, and convert them into a RateDistortionCurve.
67             String refRates = referenceConfig.get("RefRate").getAsString();
68             String refVmafs = referenceConfig.get("RefVmaf").getAsString();
69 
70             PrimitiveIterator.OfDouble rates =
71                     Splitter.on(CharMatcher.whitespace())
72                             .splitToStream(refRates)
73                             .mapToDouble(Double::parseDouble)
74                             .iterator();
75             PrimitiveIterator.OfDouble vmafs =
76                     Splitter.on(CharMatcher.whitespace())
77                             .splitToStream(refVmafs)
78                             .mapToDouble(Double::parseDouble)
79                             .iterator();
80 
81             RateDistortionCurve.Builder curveBuilder = RateDistortionCurve.builder();
82             while (rates.hasNext() && vmafs.hasNext()) {
83                 curveBuilder.addPoint(RateDistortionPoint.create(rates.next(), vmafs.next()));
84             }
85 
86             // If there was a misalignment of values, throw JsonParseException
87             if (rates.hasNext() || vmafs.hasNext()) {
88                 throw new JsonParseException(
89                         "Number of bitrates did not match number of VMAF scores.");
90             }
91             RateDistortionCurve curve = curveBuilder.build();
92 
93             double referenceThreshold =
94                     Double.parseDouble(referenceConfig.get("RefThreshold").getAsString());
95 
96             return ReferenceConfig.create(testId, referenceFileName, curve, referenceThreshold);
97         }
98     }
99 }
100