1/*
2 * Copyright 2013 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 */
16package androidx.media.filterfw;
17
18import java.nio.ByteBuffer;
19
20/**
21 * Utility functions to convert between color-spaces.
22 *
23 * Currently these methods are all CPU based native methods. These could be updated in the future
24 * to provide other implementations.
25 */
26public class ColorSpace {
27
28    /**
29     * Convert YUV420-Planer data to RGBA8888.
30     *
31     * The input data is expected to be laid out in 3 planes. The width x height Y plane, followed
32     * by the U and V planes, where each chroma value corresponds to a 2x2 luminance value block.
33     * YUV to RGB conversion is done using the ITU-R BT.601 transformation. The output buffer must
34     * be large enough to hold the data, and the dimensions must be multiples of 2.
35     *
36     * @param input data encoded in YUV420-Planar.
37     * @param output buffer to hold RGBA8888 data.
38     * @param width the width of the image (must be a multiple of 2)
39     * @param height the height of the image (must be a multiple of 2)
40     */
41    public static void convertYuv420pToRgba8888(
42            ByteBuffer input, ByteBuffer output, int width, int height) {
43        expectInputSize(input, (3 * width * height) / 2);
44        expectOutputSize(output, width * height * 4);
45        nativeYuv420pToRgba8888(input, output, width, height);
46    }
47
48    /**
49     * Convert ARGB8888 to RGBA8888.
50     *
51     * The input data is expected to be encoded in 8-bit interleaved ARGB channels. The output
52     * buffer must be large enough to hold the data. The output buffer may be the same as the
53     * input buffer.
54     *
55     * @param input data encoded in ARGB8888.
56     * @param output buffer to hold RGBA8888 data.
57     * @param width the width of the image
58     * @param height the height of the image
59     */
60    public static void convertArgb8888ToRgba8888(
61            ByteBuffer input, ByteBuffer output, int width, int height) {
62        expectInputSize(input, width * height * 4);
63        expectOutputSize(output, width * height * 4);
64        nativeArgb8888ToRgba8888(input, output, width, height);
65    }
66
67    /**
68     * Convert RGBA8888 to HSVA8888.
69     *
70     * The input data is expected to be encoded in 8-bit interleaved RGBA channels. The output
71     * buffer must be large enough to hold the data. The output buffer may be the same as the
72     * input buffer.
73     *
74     * @param input data encoded in RGBA8888.
75     * @param output buffer to hold HSVA8888 data.
76     * @param width the width of the image
77     * @param height the height of the image
78     */
79    public static void convertRgba8888ToHsva8888(
80            ByteBuffer input, ByteBuffer output, int width, int height) {
81        expectInputSize(input, width * height * 4);
82        expectOutputSize(output, width * height * 4);
83        nativeRgba8888ToHsva8888(input, output, width, height);
84    }
85
86    /**
87     * Convert RGBA8888 to YCbCrA8888.
88     *
89     * The input data is expected to be encoded in 8-bit interleaved RGBA channels. The output
90     * buffer must be large enough to hold the data. The output buffer may be the same as the
91     * input buffer.
92     *
93     * @param input data encoded in RGBA8888.
94     * @param output buffer to hold YCbCrA8888 data.
95     * @param width the width of the image
96     * @param height the height of the image
97     */
98    public static void convertRgba8888ToYcbcra8888(
99            ByteBuffer input, ByteBuffer output, int width, int height) {
100        expectInputSize(input, width * height * 4);
101        expectOutputSize(output, width * height * 4);
102        nativeRgba8888ToYcbcra8888(input, output, width, height);
103    }
104
105    private static void expectInputSize(ByteBuffer input, int expectedSize) {
106        if (input.remaining() < expectedSize) {
107            throw new IllegalArgumentException("Input buffer's size does not fit given width "
108                    + "and height! Expected: " + expectedSize + ", Got: " + input.remaining()
109                    + ".");
110        }
111    }
112
113    private static void expectOutputSize(ByteBuffer output, int expectedSize) {
114        if (output.remaining() < expectedSize) {
115            throw new IllegalArgumentException("Output buffer's size does not fit given width "
116                    + "and height! Expected: " + expectedSize + ", Got: " + output.remaining()
117                    + ".");
118        }
119    }
120
121    private static native void nativeYuv420pToRgba8888(
122            ByteBuffer input, ByteBuffer output, int width, int height);
123
124    private static native void nativeArgb8888ToRgba8888(
125            ByteBuffer input, ByteBuffer output, int width, int height);
126
127    private static native void nativeRgba8888ToHsva8888(
128            ByteBuffer input, ByteBuffer output, int width, int height);
129
130    private static native void nativeRgba8888ToYcbcra8888(
131            ByteBuffer input, ByteBuffer output, int width, int height);
132
133    static {
134        System.loadLibrary("smartcamera_jni");
135    }
136
137}
138