1 /* 2 * Copyright 2022 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 package com.google.android.exoplayer2.transformer; 17 18 import androidx.annotation.Nullable; 19 import com.google.android.exoplayer2.C; 20 import org.json.JSONException; 21 import org.json.JSONObject; 22 23 /** A test only class for holding the details of a test transformation. */ 24 public class TransformationTestResult { 25 /** Represents an unset or unknown SSIM score. */ 26 public static final double SSIM_UNSET = -1.0d; 27 28 /** A builder for {@link TransformationTestResult}. */ 29 public static class Builder { 30 private final TransformationResult transformationResult; 31 32 @Nullable private String filePath; 33 @Nullable private Exception analysisException; 34 private long elapsedTimeMs; 35 private double ssim; 36 37 /** Creates a new {@link Builder}. */ Builder(TransformationResult transformationResult)38 public Builder(TransformationResult transformationResult) { 39 this.transformationResult = transformationResult; 40 this.elapsedTimeMs = C.TIME_UNSET; 41 this.ssim = SSIM_UNSET; 42 } 43 44 /** 45 * Sets the file path of the output file. 46 * 47 * <p>{@code null} represents an unset or unknown value. 48 * 49 * @param filePath The path. 50 * @return This {@link Builder}. 51 */ setFilePath(@ullable String filePath)52 public Builder setFilePath(@Nullable String filePath) { 53 this.filePath = filePath; 54 return this; 55 } 56 57 /** 58 * Sets the amount of time taken to perform the transformation in milliseconds. {@link 59 * C#TIME_UNSET} if unset. 60 * 61 * <p>{@link C#TIME_UNSET} represents an unset or unknown value. 62 * 63 * @param elapsedTimeMs The time, in ms. 64 * @return This {@link Builder}. 65 */ setElapsedTimeMs(long elapsedTimeMs)66 public Builder setElapsedTimeMs(long elapsedTimeMs) { 67 this.elapsedTimeMs = elapsedTimeMs; 68 return this; 69 } 70 71 /** 72 * Sets the SSIM of the output file, compared to input file. 73 * 74 * <p>{@link #SSIM_UNSET} represents an unset or unknown value. 75 * 76 * @param ssim The structural similarity index. 77 * @return This {@link Builder}. 78 */ setSsim(double ssim)79 public Builder setSsim(double ssim) { 80 this.ssim = ssim; 81 return this; 82 } 83 84 /** 85 * Sets an {@link Exception} that occurred during post-transformation analysis. 86 * 87 * <p>{@code null} represents an unset or unknown value. 88 * 89 * @param analysisException The {@link Exception} thrown during analysis. 90 * @return This {@link Builder}. 91 */ setAnalysisException(@ullable Exception analysisException)92 public Builder setAnalysisException(@Nullable Exception analysisException) { 93 this.analysisException = analysisException; 94 return this; 95 } 96 97 /** Builds the {@link TransformationTestResult} instance. */ build()98 public TransformationTestResult build() { 99 return new TransformationTestResult( 100 transformationResult, filePath, elapsedTimeMs, ssim, analysisException); 101 } 102 } 103 104 public final TransformationResult transformationResult; 105 @Nullable public final String filePath; 106 /** 107 * The average rate (per second) at which frames are processed by the transformer, or {@link 108 * C#RATE_UNSET} if unset or unknown. 109 */ 110 public final float throughputFps; 111 /** 112 * The amount of time taken to perform the transformation in milliseconds. {@link C#TIME_UNSET} if 113 * unset. 114 */ 115 public final long elapsedTimeMs; 116 /** The SSIM score of the transformation, {@link #SSIM_UNSET} if unavailable. */ 117 public final double ssim; 118 /** 119 * The {@link Exception} that was thrown during post-transformation analysis, or {@code null} if 120 * nothing was thrown. 121 */ 122 @Nullable public final Exception analysisException; 123 124 /** Returns a {@link JSONObject} representing all the values in {@code this}. */ asJsonObject()125 public JSONObject asJsonObject() throws JSONException { 126 JSONObject jsonObject = new JSONObject(); 127 if (transformationResult.durationMs != C.LENGTH_UNSET) { 128 jsonObject.put("durationMs", transformationResult.durationMs); 129 } 130 if (transformationResult.fileSizeBytes != C.LENGTH_UNSET) { 131 jsonObject.put("fileSizeBytes", transformationResult.fileSizeBytes); 132 } 133 if (transformationResult.averageAudioBitrate != C.RATE_UNSET_INT) { 134 jsonObject.put("averageAudioBitrate", transformationResult.averageAudioBitrate); 135 } 136 if (transformationResult.averageVideoBitrate != C.RATE_UNSET_INT) { 137 jsonObject.put("averageVideoBitrate", transformationResult.averageVideoBitrate); 138 } 139 if (transformationResult.videoFrameCount > 0) { 140 jsonObject.put("videoFrameCount", transformationResult.videoFrameCount); 141 } 142 if (throughputFps != C.RATE_UNSET) { 143 jsonObject.put("throughputFps", throughputFps); 144 } 145 if (elapsedTimeMs != C.TIME_UNSET) { 146 jsonObject.put("elapsedTimeMs", elapsedTimeMs); 147 } 148 if (ssim != TransformationTestResult.SSIM_UNSET) { 149 jsonObject.put("ssim", ssim); 150 } 151 if (analysisException != null) { 152 jsonObject.put("analysisException", AndroidTestUtil.exceptionAsJsonObject(analysisException)); 153 } 154 return jsonObject; 155 } 156 TransformationTestResult( TransformationResult transformationResult, @Nullable String filePath, long elapsedTimeMs, double ssim, @Nullable Exception analysisException)157 private TransformationTestResult( 158 TransformationResult transformationResult, 159 @Nullable String filePath, 160 long elapsedTimeMs, 161 double ssim, 162 @Nullable Exception analysisException) { 163 this.transformationResult = transformationResult; 164 this.filePath = filePath; 165 this.elapsedTimeMs = elapsedTimeMs; 166 this.ssim = ssim; 167 this.analysisException = analysisException; 168 this.throughputFps = 169 elapsedTimeMs != C.TIME_UNSET && transformationResult.videoFrameCount > 0 170 ? 1000f * transformationResult.videoFrameCount / elapsedTimeMs 171 : C.RATE_UNSET; 172 } 173 } 174