xref: /aosp_15_r20/external/libultrahdr/java/UltraHdrApp.java (revision 89a0ef05262152531a00a15832a2d3b1e3990773)
1 /*
2  * Copyright 2024 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 import static com.google.media.codecs.ultrahdr.UltraHDRCommon.*;
18 import static com.google.media.codecs.ultrahdr.UltraHDREncoder.UHDR_USAGE_BEST_QUALITY;
19 
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.BufferedReader;
23 import java.io.FileReader;
24 import java.io.BufferedWriter;
25 import java.io.FileWriter;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.nio.ByteBuffer;
29 import java.nio.ByteOrder;
30 
31 import com.google.media.codecs.ultrahdr.UltraHDRDecoder;
32 import com.google.media.codecs.ultrahdr.UltraHDREncoder;
33 import com.google.media.codecs.ultrahdr.UltraHDRDecoder.GainMapMetadata;
34 import com.google.media.codecs.ultrahdr.UltraHDRDecoder.RawImage;
35 
36 /**
37  * Ultra HDR Encoding/Decoding Demo Application
38  */
39 public class UltraHdrApp {
40     private final String mHdrIntentRawFile;
41     private final String mSdrIntentRawFile;
42     private final String mSdrIntentCompressedFile;
43     private final String mGainMapCompressedFile;
44     private final String mGainMapMetadaCfgFile;
45     private final String mExifFile;
46     private final String mUhdrFile;
47     private final String mOutputFile;
48     private final int mWidth;
49     private final int mHeight;
50     private final int mHdrCf;
51     private final int mSdrCf;
52     private final int mHdrCg;
53     private final int mSdrCg;
54     private final int mHdrTf;
55     private final int mQuality;
56     private final int mOTF;
57     private final int mOfmt;
58     private final boolean mFullRange;
59     private final int mMapDimensionScaleFactor;
60     private final int mMapCompressQuality;
61     private final boolean mUseMultiChannelGainMap;
62     private final float mGamma;
63     private final boolean mEnableGLES;
64     private final int mEncPreset;
65     private final float mMinContentBoost;
66     private final float mMaxContentBoost;
67     private final float mTargetDispPeakBrightness;
68 
69     byte[] mYuv420YData, mYuv420CbData, mYuv420CrData;
70     short[] mP010YData, mP010CbCrData;
71     int[] mRgba1010102Data, mRgba8888Data;
72     long[] mRgbaF16Data;
73     byte[] mCompressedImageData;
74     byte[] mGainMapCompressedImageData;
75     byte[] mExifData;
76     byte[] mUhdrImagedata;
77     GainMapMetadata mMetadata;
78     RawImage mDecodedUhdrRgbImage;
79 
UltraHdrApp(String hdrIntentRawFile, String sdrIntentRawFile, String sdrIntentCompressedFile, String gainmapCompressedFile, String gainmapMetadataCfgFile, String exifFile, String outputFile, int width, int height, int hdrCf, int sdrCf, int hdrCg, int sdrCg, int hdrTf, int quality, int oTf, int oFmt, boolean isHdrCrFull, int gainmapScaleFactor, int gainmapQuality, boolean enableMultiChannelGainMap, float gamma, int encPreset, float minContentBoost, float maxContentBoost, float targetDispPeakBrightness)80     public UltraHdrApp(String hdrIntentRawFile, String sdrIntentRawFile,
81             String sdrIntentCompressedFile, String gainmapCompressedFile,
82             String gainmapMetadataCfgFile, String exifFile, String outputFile, int width,
83             int height, int hdrCf, int sdrCf, int hdrCg, int sdrCg, int hdrTf, int quality, int oTf,
84             int oFmt, boolean isHdrCrFull, int gainmapScaleFactor, int gainmapQuality,
85             boolean enableMultiChannelGainMap, float gamma, int encPreset, float minContentBoost,
86             float maxContentBoost, float targetDispPeakBrightness) {
87         mHdrIntentRawFile = hdrIntentRawFile;
88         mSdrIntentRawFile = sdrIntentRawFile;
89         mSdrIntentCompressedFile = sdrIntentCompressedFile;
90         mGainMapCompressedFile = gainmapCompressedFile;
91         mGainMapMetadaCfgFile = gainmapMetadataCfgFile;
92         mExifFile = exifFile;
93         mUhdrFile = null;
94         mOutputFile = outputFile;
95         mWidth = width;
96         mHeight = height;
97         mHdrCf = hdrCf;
98         mSdrCf = sdrCf;
99         mHdrCg = hdrCg;
100         mSdrCg = sdrCg;
101         mHdrTf = hdrTf;
102         mQuality = quality;
103         mOTF = oTf;
104         mOfmt = oFmt;
105         mFullRange = isHdrCrFull;
106         mMapDimensionScaleFactor = gainmapScaleFactor;
107         mMapCompressQuality = gainmapQuality;
108         mUseMultiChannelGainMap = enableMultiChannelGainMap;
109         mGamma = gamma;
110         mEnableGLES = false;
111         mEncPreset = encPreset;
112         mMinContentBoost = minContentBoost;
113         mMaxContentBoost = maxContentBoost;
114         mTargetDispPeakBrightness = targetDispPeakBrightness;
115     }
116 
UltraHdrApp(String gainmapMetadataCfgFile, String uhdrFile, String outputFile, int oTF, int oFmt, boolean enableGLES)117     public UltraHdrApp(String gainmapMetadataCfgFile, String uhdrFile, String outputFile, int oTF,
118             int oFmt, boolean enableGLES) {
119         mHdrIntentRawFile = null;
120         mSdrIntentRawFile = null;
121         mSdrIntentCompressedFile = null;
122         mGainMapCompressedFile = null;
123         mGainMapMetadaCfgFile = gainmapMetadataCfgFile;
124         mExifFile = null;
125         mUhdrFile = uhdrFile;
126         mOutputFile = outputFile;
127         mWidth = 0;
128         mHeight = 0;
129         mHdrCf = UHDR_IMG_FMT_UNSPECIFIED;
130         mSdrCf = UHDR_IMG_FMT_UNSPECIFIED;
131         mHdrCg = UHDR_CG_UNSPECIFIED;
132         mSdrCg = UHDR_CG_UNSPECIFIED;
133         mHdrTf = UHDR_CT_UNSPECIFIED;
134         mQuality = 95;
135         mOTF = oTF;
136         mOfmt = oFmt;
137         mFullRange = false;
138         mMapDimensionScaleFactor = 1;
139         mMapCompressQuality = 95;
140         mUseMultiChannelGainMap = true;
141         mGamma = 1.0f;
142         mEnableGLES = enableGLES;
143         mEncPreset = UHDR_USAGE_BEST_QUALITY;
144         mMinContentBoost = Float.MIN_VALUE;
145         mMaxContentBoost = Float.MAX_VALUE;
146         mTargetDispPeakBrightness = -1.0f;
147     }
148 
readFile(String filename)149     public byte[] readFile(String filename) throws IOException {
150         byte[] data;
151         try (FileInputStream fis = new FileInputStream(filename)) {
152             File descriptor = new File(filename);
153             long size = descriptor.length();
154             if (size <= 0 || size > Integer.MAX_VALUE) {
155                 throw new IOException("Unexpected file size received for file: " + filename);
156             }
157             data = new byte[(int) size];
158             if (fis.read(data) != size) {
159                 throw new IOException("Failed to read file: " + filename + " completely");
160             }
161         }
162         return data;
163     }
164 
fillP010ImageHandle()165     public void fillP010ImageHandle() throws IOException {
166         final int bpp = 2;
167         final int lumaSampleCount = mWidth * mHeight;
168         final int chromaSampleCount = (mWidth / 2) * (mHeight / 2) * 2;
169         final int expectedSize = (lumaSampleCount + chromaSampleCount) * bpp;
170         byte[] data = readFile(mHdrIntentRawFile);
171         if (data.length < expectedSize) {
172             throw new RuntimeException(
173                     "For the configured width, height, P010 Image File is expected to contain "
174                             + expectedSize + " bytes, but the file has " + data.length + " bytes");
175         }
176         ByteBuffer byteBuffer = ByteBuffer.wrap(data);
177         byteBuffer.order(ByteOrder.nativeOrder());
178         mP010YData = new short[lumaSampleCount];
179         byteBuffer.asShortBuffer().get(mP010YData);
180         byteBuffer.position(lumaSampleCount * bpp);
181         mP010CbCrData = new short[chromaSampleCount];
182         byteBuffer.asShortBuffer().get(mP010CbCrData);
183     }
184 
fillRGBA1010102ImageHandle()185     public void fillRGBA1010102ImageHandle() throws IOException {
186         final int bpp = 4;
187         final int rgbSampleCount = mHeight * mWidth;
188         final int expectedSize = rgbSampleCount * bpp;
189         byte[] data = readFile(mHdrIntentRawFile);
190         if (data.length < expectedSize) {
191             throw new RuntimeException("For the configured width, height, RGBA1010102 Image File is"
192                     + " expected to contain " + expectedSize + " bytes, but the file has "
193                     + data.length + " bytes");
194         }
195         ByteBuffer byteBuffer = ByteBuffer.wrap(data);
196         byteBuffer.order(ByteOrder.nativeOrder());
197         mRgba1010102Data = new int[mHeight * mWidth];
198         byteBuffer.asIntBuffer().get(mRgba1010102Data);
199     }
200 
fillRGBAF16ImageHandle()201     public void fillRGBAF16ImageHandle() throws IOException {
202         final int bpp = 8;
203         final int rgbSampleCount = mHeight * mWidth;
204         final int expectedSize = rgbSampleCount * bpp;
205         byte[] data = readFile(mHdrIntentRawFile);
206         if (data.length < expectedSize) {
207             throw new RuntimeException("For the configured width, height, RGBA1010102 Image File is"
208                     + " expected to contain " + expectedSize + " bytes, but the file has "
209                     + data.length + " bytes");
210         }
211         ByteBuffer byteBuffer = ByteBuffer.wrap(data);
212         byteBuffer.order(ByteOrder.nativeOrder());
213         mRgbaF16Data = new long[mHeight * mWidth];
214         byteBuffer.asLongBuffer().get(mRgbaF16Data);
215     }
216 
fillRGBA8888Handle()217     public void fillRGBA8888Handle() throws IOException {
218         final int bpp = 4;
219         final int rgbSampleCount = mHeight * mWidth;
220         final int expectedSize = rgbSampleCount * bpp;
221         byte[] data = readFile(mSdrIntentRawFile);
222         if (data.length < expectedSize) {
223             throw new RuntimeException("For the configured width, height, RGBA8888 Image File is"
224                     + " expected to contain " + expectedSize + " bytes, but the file has "
225                     + data.length + " bytes");
226         }
227         ByteBuffer byteBuffer = ByteBuffer.wrap(data);
228         byteBuffer.order(ByteOrder.nativeOrder());
229         mRgba8888Data = new int[mHeight * mWidth];
230         byteBuffer.asIntBuffer().get(mRgba8888Data);
231     }
232 
fillYUV420ImageHandle()233     public void fillYUV420ImageHandle() throws IOException {
234         final int lumaSampleCount = mWidth * mHeight;
235         final int cbSampleCount = (mWidth / 2) * (mHeight / 2);
236         final int crSampleCount = (mWidth / 2) * (mHeight / 2);
237         try (FileInputStream fis = new FileInputStream(mSdrIntentRawFile)) {
238             mYuv420YData = new byte[lumaSampleCount];
239             int bytesRead = fis.read(mYuv420YData);
240             if (bytesRead != lumaSampleCount) {
241                 throw new IOException("Failed to read " + lumaSampleCount + " bytes from file: "
242                         + mSdrIntentRawFile);
243             }
244             mYuv420CbData = new byte[cbSampleCount];
245             bytesRead = fis.read(mYuv420CbData);
246             if (bytesRead != cbSampleCount) {
247                 throw new IOException("Failed to read " + cbSampleCount + " bytes from file: "
248                         + mSdrIntentRawFile);
249             }
250             mYuv420CrData = new byte[crSampleCount];
251             bytesRead = fis.read(mYuv420CrData);
252             if (bytesRead != crSampleCount) {
253                 throw new IOException("Failed to read " + crSampleCount + " bytes from file: "
254                         + mSdrIntentRawFile);
255             }
256         }
257     }
258 
fillSdrCompressedImageHandle()259     public void fillSdrCompressedImageHandle() throws IOException {
260         mCompressedImageData = readFile(mSdrIntentCompressedFile);
261     }
262 
fillGainMapCompressedImageHandle()263     public void fillGainMapCompressedImageHandle() throws IOException {
264         mGainMapCompressedImageData = readFile(mGainMapCompressedFile);
265     }
266 
fillExifMemoryBlock()267     public void fillExifMemoryBlock() throws IOException {
268         mExifData = readFile(mExifFile);
269     }
270 
fillUhdrImageHandle()271     public void fillUhdrImageHandle() throws IOException {
272         mUhdrImagedata = readFile(mUhdrFile);
273     }
274 
fillGainMapMetadataDescriptor()275     public void fillGainMapMetadataDescriptor() throws IOException {
276         mMetadata = new GainMapMetadata();
277         try (BufferedReader reader = new BufferedReader(new FileReader(mGainMapMetadaCfgFile))) {
278             String line;
279             while ((line = reader.readLine()) != null) {
280                 String[] parts = line.split("\\s+");
281                 if (parts.length == 2 && parts[0].startsWith("--")) {
282                     String option = parts[0].substring(2); // remove the "--" prefix
283                     float value = Float.parseFloat(parts[1]);
284                     switch (option) {
285                         case "maxContentBoost":
286                             mMetadata.maxContentBoost = value;
287                             break;
288                         case "minContentBoost":
289                             mMetadata.minContentBoost = value;
290                             break;
291                         case "gamma":
292                             mMetadata.gamma = value;
293                             break;
294                         case "offsetSdr":
295                             mMetadata.offsetSdr = value;
296                             break;
297                         case "offsetHdr":
298                             mMetadata.offsetHdr = value;
299                             break;
300                         case "hdrCapacityMin":
301                             mMetadata.hdrCapacityMin = value;
302                             break;
303                         case "hdrCapacityMax":
304                             mMetadata.hdrCapacityMax = value;
305                             break;
306                         default:
307                             System.err.println("ignoring option: " + option);
308                             break;
309                     }
310                 } else {
311                     System.err.println("Unable to parse line : " + line);
312                 }
313             }
314         }
315     }
316 
writeGainMapMetadataToFile(GainMapMetadata metadata)317     public void writeGainMapMetadataToFile(GainMapMetadata metadata) throws IOException {
318         try (BufferedWriter writer = new BufferedWriter(new FileWriter(mGainMapMetadaCfgFile))) {
319             writer.write("--maxContentBoost " + metadata.maxContentBoost + "\n");
320             writer.write("--minContentBoost " + metadata.minContentBoost + "\n");
321             writer.write("--gamma " + metadata.gamma + "\n");
322             writer.write("--offsetSdr " + metadata.offsetSdr + "\n");
323             writer.write("--offsetHdr " + metadata.offsetHdr + "\n");
324             writer.write("--hdrCapacityMin " + metadata.hdrCapacityMin + "\n");
325             writer.write("--hdrCapacityMax " + metadata.hdrCapacityMax + "\n");
326         }
327     }
328 
writeFile(String fileName, RawImage img)329     public void writeFile(String fileName, RawImage img) throws IOException {
330         try (FileOutputStream fos = new FileOutputStream(fileName)) {
331             if (img.fmt == UHDR_IMG_FMT_32bppRGBA8888 || img.fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat
332                     || img.fmt == UHDR_IMG_FMT_32bppRGBA1010102) {
333                 byte[] data = img.nativeOrderBuffer;
334                 int bpp = img.fmt == UHDR_IMG_FMT_64bppRGBAHalfFloat ? 8 : 4;
335                 int stride = img.stride * bpp;
336                 int length = img.w * bpp;
337                 for (int i = 0; i < img.h; i++) {
338                     fos.write(data, i * stride, length);
339                 }
340             } else {
341                 throw new RuntimeException("Unsupported color format ");
342             }
343         }
344     }
345 
writeFile(String fileName, byte[] data)346     public void writeFile(String fileName, byte[] data) throws IOException {
347         try (FileOutputStream fos = new FileOutputStream(fileName)) {
348             fos.write(data);
349         }
350     }
351 
encode()352     public void encode() throws Exception {
353         try (UltraHDREncoder handle = new UltraHDREncoder()) {
354             if (mHdrIntentRawFile != null) {
355                 if (mHdrCf == UHDR_IMG_FMT_24bppYCbCrP010) {
356                     fillP010ImageHandle();
357                     handle.setRawImage(mP010YData, mP010CbCrData, mWidth, mHeight, mWidth, mWidth,
358                             mHdrCg, mHdrTf, mFullRange ? UHDR_CR_FULL_RANGE : UHDR_CR_LIMITED_RANGE,
359                             mHdrCf, UHDR_HDR_IMG);
360                 } else if (mHdrCf == UHDR_IMG_FMT_32bppRGBA1010102) {
361                     fillRGBA1010102ImageHandle();
362                     handle.setRawImage(mRgba1010102Data, mWidth, mHeight, mWidth, mHdrCg, mHdrTf,
363                             UHDR_CR_FULL_RANGE, mHdrCf, UHDR_HDR_IMG);
364                 } else if (mHdrCf == UHDR_IMG_FMT_64bppRGBAHalfFloat) {
365                     fillRGBAF16ImageHandle();
366                     handle.setRawImage(mRgbaF16Data, mWidth, mHeight, mWidth, mHdrCg, mHdrTf,
367                             UHDR_CR_FULL_RANGE, mHdrCf, UHDR_HDR_IMG);
368                 } else {
369                     throw new IllegalArgumentException("invalid hdr intent color format " + mHdrCf);
370                 }
371             }
372             if (mSdrIntentRawFile != null) {
373                 if (mSdrCf == UHDR_IMG_FMT_12bppYCbCr420) {
374                     fillYUV420ImageHandle();
375                     handle.setRawImage(mYuv420YData, mYuv420CbData, mYuv420CrData, mWidth, mHeight,
376                             mWidth, mWidth / 2, mWidth / 2, mSdrCg, UHDR_CT_SRGB,
377                             UHDR_CR_FULL_RANGE, mSdrCf, UHDR_SDR_IMG);
378                 } else if (mSdrCf == UHDR_IMG_FMT_32bppRGBA8888) {
379                     fillRGBA8888Handle();
380                     handle.setRawImage(mRgba8888Data, mWidth, mHeight, mWidth, mSdrCg, UHDR_CT_SRGB,
381                             UHDR_CR_FULL_RANGE, mSdrCf, UHDR_SDR_IMG);
382                 } else {
383                     throw new IllegalArgumentException("invalid sdr intent color format " + mSdrCf);
384                 }
385             }
386             if (mSdrIntentCompressedFile != null) {
387                 fillSdrCompressedImageHandle();
388                 handle.setCompressedImage(mCompressedImageData, mCompressedImageData.length, mSdrCg,
389                         UHDR_CT_UNSPECIFIED, UHDR_CR_UNSPECIFIED,
390                         (mGainMapCompressedFile != null && mGainMapMetadaCfgFile != null) ?
391                                 UHDR_BASE_IMG : UHDR_SDR_IMG);
392             }
393             if (mGainMapCompressedFile != null && mGainMapMetadaCfgFile != null) {
394                 fillGainMapCompressedImageHandle();
395                 fillGainMapMetadataDescriptor();
396                 handle.setGainMapImageInfo(mGainMapCompressedImageData,
397                         mGainMapCompressedImageData.length, mMetadata.maxContentBoost,
398                         mMetadata.minContentBoost, mMetadata.gamma, mMetadata.offsetSdr,
399                         mMetadata.offsetHdr, mMetadata.hdrCapacityMin, mMetadata.hdrCapacityMax);
400             }
401             if (mExifFile != null) {
402                 fillExifMemoryBlock();
403                 handle.setExifData(mExifData, mExifData.length);
404             }
405             handle.setQualityFactor(mQuality, UHDR_BASE_IMG);
406             handle.setQualityFactor(mMapCompressQuality, UHDR_GAIN_MAP_IMG);
407             handle.setMultiChannelGainMapEncoding(mUseMultiChannelGainMap);
408             handle.setGainMapScaleFactor(mMapDimensionScaleFactor);
409             handle.setGainMapGamma(mGamma);
410             handle.setEncPreset(mEncPreset);
411             if (mMinContentBoost != Float.MIN_VALUE || mMaxContentBoost != Float.MAX_VALUE) {
412                 handle.setMinMaxContentBoost(mMinContentBoost, mMaxContentBoost);
413             }
414             if (mTargetDispPeakBrightness != -1.0f) {
415                 handle.setTargetDisplayPeakBrightness(mTargetDispPeakBrightness);
416             }
417             handle.encode();
418             mUhdrImagedata = handle.getOutput();
419             writeFile(mOutputFile, mUhdrImagedata);
420         }
421     }
422 
decode()423     public void decode() throws Exception {
424         fillUhdrImageHandle();
425         try (UltraHDRDecoder handle = new UltraHDRDecoder()) {
426             handle.setCompressedImage(mUhdrImagedata, mUhdrImagedata.length, UHDR_CG_UNSPECIFIED,
427                     UHDR_CG_UNSPECIFIED, UHDR_CR_UNSPECIFIED);
428             handle.setColorTransfer(mOTF);
429             handle.setOutputFormat(mOfmt);
430             if (mEnableGLES) {
431                 handle.enableGpuAcceleration(mEnableGLES ? 1 : 0);
432             }
433             handle.probe();
434             if (mGainMapMetadaCfgFile != null) {
435                 GainMapMetadata metadata = handle.getGainmapMetadata();
436                 writeGainMapMetadataToFile(metadata);
437             }
438             handle.decode();
439             mDecodedUhdrRgbImage = handle.getDecodedImage();
440             writeFile(mOutputFile, mDecodedUhdrRgbImage);
441         }
442     }
443 
usage()444     public static void usage() {
445         System.out.println("\n## uhdr demo application. lib version: " + getVersionString());
446         System.out.println("Usage : java -Djava.library.path=<path> -jar uhdr-java.jar");
447         System.out.println("    -m    mode of operation. [0:encode, 1:decode]");
448         System.out.println("\n## encoder options :");
449         System.out.println("    -p    raw hdr intent input resource (10-bit), required for encoding"
450                 + " scenarios 0, 1, 2, 3.");
451         System.out.println("    -y    raw sdr intent input resource (8-bit), required for encoding"
452                 + " scenarios 1, 2.");
453         System.out.println("    -a    raw hdr intent color format, optional. [0:p010, "
454                 + "4: rgbahalffloat, 5:rgba1010102 (default)]");
455         System.out.println("    -b    raw sdr intent color format, optional. [1:yuv420, 3:rgba8888"
456                 + " (default)]");
457         System.out.println("    -i    compressed sdr intent input resource (jpeg), required for "
458                 + "encoding scenarios 2, 3, 4.");
459         System.out.println("    -g    compressed gainmap input resource (jpeg), required for "
460                 + "encoding scenario 4.");
461         System.out.println(
462                 "    -w    input file width, required for encoding scenarios 0, 1, 2, 3.");
463         System.out.println(
464                 "    -h    input file height, required for encoding scenarios 0, 1, 2, 3.");
465         System.out.println(
466                 "    -C    hdr intent color gamut, optional. [0:bt709, 1:p3 (default), 2:bt2100]");
467         System.out.println(
468                 "    -c    sdr intent color gamut, optional. [0:bt709 (default), 1:p3, 2:bt2100]");
469         System.out.println(
470                 "    -t    hdr intent color transfer, optional. [0:linear, 1:hlg (default), 2:pq]");
471         System.out.println(
472                 "          It should be noted that not all combinations of input color format and"
473                         + " input color transfer are supported.");
474         System.out.println(
475                 "          srgb color transfer shall be paired with rgba8888 or yuv420 only.");
476         System.out.println("          hlg, pq shall be paired with rgba1010102 or p010.");
477         System.out.println("          linear shall be paired with rgbahalffloat.");
478         System.out.println("    -q    quality factor to be used while encoding sdr intent, "
479                 + "optional. [0-100], 95 : default.");
480         System.out.println("    -R    color range of hdr intent, optional. [0:narrow-range "
481                 + "(default), 1:full-range].");
482         System.out.println("    -s    gainmap image downsample factor, optional. [integer values"
483                 + " in range [1 - 128] (1 : default)].");
484         System.out.println("    -Q    quality factor to be used while encoding gain map image,"
485                 + " optional. [0-100], 95 : default.");
486         System.out.println("    -G    gamma correction to be applied on the gainmap image, "
487                 + "optional. [any positive real number (1.0 : default)].");
488         System.out.println("    -M    select multi channel gain map, optional. [0:disable, "
489                 + " 1:enable (default)].");
490         System.out.println("    -D    select encoding preset, optional. [0:real time,"
491                 + " 1:best quality (default)].");
492         System.out.println("    -k    min content boost recommendation, must be in linear scale,"
493                 + " optional. any positive real number");
494         System.out.println("    -K    max content boost recommendation, must be in linear scale,"
495                 + " optional. any positive real number");
496         System.out.println("    -L    set target display peak brightness in nits, optional");
497         System.out.println("          For HLG content, this defaults to 1000 nits.");
498         System.out.println("          For PQ content, this defaults to 10000 nits.");
499         System.out.println("          any real number in range [203, 10000].");
500         System.out.println("    -x    binary input resource containing exif data to insert, "
501                 + "optional.");
502         System.out.println("\n## decoder options :");
503         System.out.println("    -j    ultra hdr compressed input resource, required.");
504         System.out.println("    -o    output transfer function, optional. [0:linear,"
505                 + " 1:hlg (default), 2:pq, 3:srgb]");
506         System.out.println("    -O    output color format, optional. [3:rgba8888, 4:rgbahalffloat, "
507                 + "5:rgba1010102 (default)]");
508         System.out.println("          It should be noted that not all combinations of output color"
509                 + " format and output");
510         System.out.println("          transfer function are supported.");
511         System.out.println(
512                 "          srgb output color transfer shall be paired with rgba8888 only.");
513         System.out.println("          hlg, pq shall be paired with rgba1010102.");
514         System.out.println("          linear shall be paired with rgbahalffloat.");
515         System.out.println(
516                 "    -u    enable gles acceleration, optional. [0:disable (default), 1:enable].");
517         System.out.println("\n## common options :");
518         System.out.println("    -z    output filename, optional.");
519         System.out.println("          in encoding mode, default output filename 'out.jpeg'.");
520         System.out.println("          in decoding mode, default output filename 'outrgb.raw'.");
521         System.out.println("    -f    gainmap metadata config file.");
522         System.out.println("          in encoding mode, resource from which gainmap metadata is "
523                 + "read, required for encoding scenario 4.");
524         System.out.println("          in decoding mode, resource to which gainmap metadata is "
525                 + "written, optional.");
526         System.out.println("\n## examples of usage :");
527         System.out.println("\n## encode scenario 0 :");
528         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 0 -p "
529                 + "cosmat_1920x1080_p010.yuv -w 1920 -h 1080 -q 97 -a 0");
530         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 0 -p "
531                 + "cosmat_1920x1080_rgba1010102.raw -w  1920 -h 1080 -q 97 -a 5");
532         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 0 -p "
533                 + "cosmat_1920x1080_p010.yuv -w 1920 -h 1080 -q 97 -C 1 -t 2 -a 0");
534         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 0 -p "
535                 + "cosmat_1920x1080_rgba1010102.raw -w 1920 -h 1080 -q 97 -C 1 -t 2 -a 5");
536         System.out.println("\n## encode scenario 1 :");
537         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 0 -p "
538                 + "cosmat_1920x1080_p010.yuv -y cosmat_1920x1080_420.yuv -w 1920 -h 1080 -q 97 "
539                 + "-a 0 -b 1");
540         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 0 -p "
541                 + "cosmat_1920x1080_rgba1010102.raw -y cosmat_1920x1080_rgba8888.raw -w 1920 -h "
542                 + "1080 -q 97 -a 5 -b 3");
543         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 0 -p "
544                 + "cosmat_1920x1080_p010.yuv -y cosmat_1920x1080_420.yuv -w 1920 -h 1080 -q 97 -C"
545                 + " 2 -c 1 -t 1 -a 0 -b 1");
546         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 0 -p "
547                 + "cosmat_1920x1080_rgba1010102.raw -y cosmat_1920x1080_rgba8888.raw -w 1920 "
548                 + "-h 1080 -q 97 -C 2 -c 1 -t 1 -a 5 -b 3");
549         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 0 -p "
550                 + "cosmat_1920x1080_p010.yuv -y cosmat_1920x1080_420.yuv -w 1920 -h 1080 -q 97 -C"
551                 + " 2 -c 1 -t 1 -a 0 -b 1");
552         System.out.println("\n## encode scenario 2 :");
553         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 0 -p "
554                 + "cosmat_1920x1080_p010.yuv -y cosmat_1920x1080_420.yuv -i "
555                 + "cosmat_1920x1080_420_8bit.jpg -w 1920 -h 1080 -t 1 -o 3 -O 3 -a 0 -b 1");
556         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 0 -p "
557                 + "cosmat_1920x1080_rgba1010102.raw -y cosmat_1920x1080_420.yuv -i "
558                 + "cosmat_1920x1080_420_8bit.jpg -w 1920 -h 1080 -t 1 -o 3 -O 3 -a 5 -b 1");
559         System.out.println("\n## encode scenario 3 :");
560         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 0 -p "
561                 + "cosmat_1920x1080_p010.yuv -i cosmat_1920x1080_420_8bit.jpg -w 1920 -h 1080 -t "
562                 + "1 -o 1 -O 5 -a 0");
563         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 0 -p "
564                 + "cosmat_1920x1080_rgba1010102.raw -i cosmat_1920x1080_420_8bit.jpg -w 1920 -h "
565                 + "1080 -t 1 -o 1 -O 5 -a 5");
566         System.out.println("\n## encode scenario 4 :");
567         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 0 -i "
568                 + "cosmat_1920x1080_420_8bit.jpg -g cosmat_1920x1080_420_8bit.jpg -f metadata.cfg");
569         System.out.println("\n## encode at high quality :");
570         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 0 -p "
571                 + "hdr_intent.raw -y sdr_intent.raw -w 640 -h 480 -c <select> -C <select> -t "
572                 + "<select> -s 1 -M 1 -Q 98 -q 98 -D 1");
573         System.out.println("\n## decode api :");
574         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 1 "
575                 + "-j cosmat_1920x1080_hdr.jpg");
576         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 1 -j "
577                 + "cosmat_1920x1080_hdr.jpg -o 3 -O 3");
578         System.out.println("    java -Djava.library.path=<path> -jar uhdr-java.jar -m 1 -j "
579                 + "cosmat_1920x1080_hdr.jpg -o 1 -O 5");
580         System.out.println("\n");
581     }
582 
main(String[] args)583     public static void main(String[] args) throws Exception {
584         String hdr_intent_raw_file = null;
585         String sdr_intent_raw_file = null;
586         String sdr_intent_compressed_file = null;
587         String gainmap_compressed_file = null;
588         String uhdr_file = null;
589         String gainmap_metadata_cfg_file = null;
590         String output_file = null;
591         String exif_file = null;
592         int width = 0, height = 0;
593         int hdr_cg = UHDR_CG_DISPLAY_P3;
594         int sdr_cg = UHDR_CG_BT709;
595         int hdr_cf = UHDR_IMG_FMT_32bppRGBA1010102;
596         int sdr_cf = UHDR_IMG_FMT_32bppRGBA8888;
597         int hdr_tf = UHDR_CT_HLG;
598         int quality = 95;
599         int out_tf = UHDR_CT_HLG;
600         int out_cf = UHDR_IMG_FMT_32bppRGBA1010102;
601         int mode = -1;
602         int gain_map_scale_factor = 1;
603         int gainmap_compression_quality = 95;
604         int enc_preset = UHDR_USAGE_BEST_QUALITY;
605         float gamma = 1.0f;
606         boolean enable_gles = false;
607         float min_content_boost = Float.MIN_VALUE;
608         float max_content_boost = Float.MAX_VALUE;
609         float target_disp_max_brightness = -1.0f;
610         boolean use_full_range_color_hdr = false;
611         boolean use_multi_channel_gainmap = true;
612 
613         for (int i = 0; i < args.length; i++) {
614             if (args[i].length() == 2 && args[i].charAt(0) == '-') {
615                 switch (args[i].charAt(1)) {
616                     case 'a':
617                         hdr_cf = Integer.parseInt(args[++i]);
618                         break;
619                     case 'b':
620                         sdr_cf = Integer.parseInt(args[++i]);
621                         break;
622                     case 'p':
623                         hdr_intent_raw_file = args[++i];
624                         break;
625                     case 'y':
626                         sdr_intent_raw_file = args[++i];
627                         break;
628                     case 'i':
629                         sdr_intent_compressed_file = args[++i];
630                         break;
631                     case 'g':
632                         gainmap_compressed_file = args[++i];
633                         break;
634                     case 'f':
635                         gainmap_metadata_cfg_file = args[++i];
636                         break;
637                     case 'w':
638                         width = Integer.parseInt(args[++i]);
639                         break;
640                     case 'h':
641                         height = Integer.parseInt(args[++i]);
642                         break;
643                     case 'C':
644                         hdr_cg = Integer.parseInt(args[++i]);
645                         break;
646                     case 'c':
647                         sdr_cg = Integer.parseInt(args[++i]);
648                         break;
649                     case 't':
650                         hdr_tf = Integer.parseInt(args[++i]);
651                         break;
652                     case 'q':
653                         quality = Integer.parseInt(args[++i]);
654                         break;
655                     case 'O':
656                         out_cf = Integer.parseInt(args[++i]);
657                         break;
658                     case 'o':
659                         out_tf = Integer.parseInt(args[++i]);
660                         break;
661                     case 'm':
662                         mode = Integer.parseInt(args[++i]);
663                         break;
664                     case 'R':
665                         use_full_range_color_hdr = Integer.parseInt(args[++i]) == 1;
666                         break;
667                     case 's':
668                         gain_map_scale_factor = Integer.parseInt(args[++i]);
669                         break;
670                     case 'M':
671                         use_multi_channel_gainmap = Integer.parseInt(args[++i]) == 1;
672                         break;
673                     case 'Q':
674                         gainmap_compression_quality = Integer.parseInt(args[++i]);
675                         break;
676                     case 'G':
677                         gamma = Float.parseFloat(args[++i]);
678                         break;
679                     case 'j':
680                         uhdr_file = args[++i];
681                         break;
682                     case 'z':
683                         output_file = args[++i];
684                         break;
685                     case 'x':
686                         exif_file = args[++i];
687                         break;
688                     case 'u':
689                         enable_gles = Integer.parseInt(args[++i]) == 1;
690                         break;
691                     case 'D':
692                         enc_preset = Integer.parseInt(args[++i]);
693                         break;
694                     case 'k':
695                         min_content_boost = Float.parseFloat(args[++i]);
696                         break;
697                     case 'K':
698                         max_content_boost = Float.parseFloat(args[++i]);
699                         break;
700                     case 'L':
701                         target_disp_max_brightness = Float.parseFloat(args[++i]);
702                         break;
703                     default:
704                         System.err.println("Unrecognized option, arg: " + args[i]);
705                         usage();
706                         return;
707                 }
708             } else {
709                 System.err.println("Invalid argument format, arg: " + args[i]);
710                 usage();
711                 return;
712             }
713         }
714         if (mode == 0) {
715             if (width <= 0 && gainmap_metadata_cfg_file == null) {
716                 System.err.println("did not receive valid image width for encoding. width : "
717                         + width);
718                 return;
719             }
720             if (height <= 0 && gainmap_metadata_cfg_file == null) {
721                 System.err.println("did not receive valid image height for encoding. height : "
722                         + height);
723                 return;
724             }
725             if (hdr_intent_raw_file == null && (sdr_intent_compressed_file == null
726                     || gainmap_compressed_file == null || gainmap_metadata_cfg_file == null)) {
727                 System.err.println("did not receive raw resources for encoding.");
728                 return;
729             }
730             UltraHdrApp appInput = new UltraHdrApp(hdr_intent_raw_file, sdr_intent_raw_file,
731                     sdr_intent_compressed_file, gainmap_compressed_file, gainmap_metadata_cfg_file,
732                     exif_file, output_file != null ? output_file : "out.jpeg", width, height,
733                     hdr_cf, sdr_cf, hdr_cg, sdr_cg, hdr_tf, quality, out_tf, out_cf,
734                     use_full_range_color_hdr, gain_map_scale_factor, gainmap_compression_quality,
735                     use_multi_channel_gainmap, gamma, enc_preset, min_content_boost,
736                     max_content_boost, target_disp_max_brightness);
737             appInput.encode();
738         } else if (mode == 1) {
739             if (uhdr_file == null) {
740                 System.err.println("did not receive resources for decoding");
741                 return;
742             }
743             UltraHdrApp appInput = new UltraHdrApp(gainmap_metadata_cfg_file, uhdr_file,
744                     output_file != null ? output_file : "outrgb.raw", out_tf, out_cf, enable_gles);
745             appInput.decode();
746         } else {
747             if (args.length > 0) {
748                 System.err.println("did not receive valid mode of operation");
749             }
750             usage();
751         }
752     }
753 }
754