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 */
16// Takes in an array, returns the size of the array
17
18package androidx.media.filterfw.samples.simplecamera;
19
20import android.graphics.Rect;
21import android.hardware.Camera;
22import android.hardware.Camera.Face;
23import android.util.Log;
24import androidx.media.filterfw.Filter;
25import androidx.media.filterfw.Frame;
26import androidx.media.filterfw.FrameImage2D;
27import androidx.media.filterfw.FrameType;
28import androidx.media.filterfw.FrameValues;
29import androidx.media.filterfw.MffContext;
30import androidx.media.filterfw.OutputPort;
31import androidx.media.filterfw.Signature;
32
33import java.nio.ByteBuffer;
34
35public class FaceSquareFilter extends Filter {
36
37    private static final String TAG = "FaceSquareFilter";
38    private static boolean mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
39
40    private static int FACE_X_RANGE = 2000;
41    private static int WIDTH_OFFSET = 1000;
42    private static int HEIGHT_OFFSET = 1000;
43
44    public FaceSquareFilter(MffContext context, String name) {
45        super(context, name);
46    }
47
48    @Override
49    public Signature getSignature() {
50        FrameType imageType = FrameType.buffer2D(FrameType.ELEMENT_RGBA8888);
51        FrameType facesType = FrameType.array(Camera.Face.class);
52        return new Signature()
53                .addInputPort("image", Signature.PORT_REQUIRED, imageType)
54                .addInputPort("faces", Signature.PORT_REQUIRED, facesType)
55                .addOutputPort("image", Signature.PORT_REQUIRED, imageType)
56                .disallowOtherPorts();
57    }
58
59    /**
60     * @see androidx.media.filterfw.Filter#onProcess()
61     */
62    @Override
63    protected void onProcess() {
64        // Get inputs
65        FrameImage2D imageFrame = getConnectedInputPort("image").pullFrame().asFrameImage2D();
66        FrameValues facesFrame = getConnectedInputPort("faces").pullFrame().asFrameValues();
67        Face[] faces = (Face[]) facesFrame.getValues();
68        int[] dims = imageFrame.getDimensions();
69        ByteBuffer buffer = imageFrame.lockBytes(Frame.MODE_WRITE);
70        byte[] pixels = buffer.array();
71
72        // For every face in faces, draw a white rect around the
73        // face following the rect member of the Face
74        drawBoxes(pixels, faces, dims);
75
76        imageFrame.unlock();
77
78        OutputPort outPort = getConnectedOutputPort("image");
79        outPort.pushFrame(imageFrame);
80    }
81
82    public void drawBoxes(byte[] pixels, Face[] faces, int[] dims) {
83        for(int i = 0; i < faces.length; i++) {
84            Rect tempRect = faces[i].rect;
85            int top = (tempRect.top+HEIGHT_OFFSET)*dims[1]/FACE_X_RANGE;
86            int bottom = (tempRect.bottom+HEIGHT_OFFSET)*dims[1]/FACE_X_RANGE;
87            int left = (tempRect.left+WIDTH_OFFSET)*dims[0]/FACE_X_RANGE;
88            int right = (tempRect.right+WIDTH_OFFSET)*dims[0]/FACE_X_RANGE;
89
90            if (top < 0) {
91                top = 0;
92            } else if (top > dims[1]) {
93                top = dims[1];
94            }
95            if (left < 0) {
96                left = 0;
97            } else if (left > dims[0]) {
98                left = dims[0];
99            }
100            if (bottom > dims[1]) {
101                bottom = dims[1];
102            } else if (bottom < 0) {
103                bottom = 0;
104            }
105            if (right > dims[0]) {
106                right = dims[0];
107            } else if (right < 0) {
108                right = 0;
109            }
110
111            for (int j = 0; j < (bottom - top); j++) {
112                // Left edge
113                if (left > 0 && top > 0) {
114                    pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + left) +
115                           ImageConstants.RED_OFFSET] = (byte) ImageConstants.MAX_BYTE;
116                    pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + left) +
117                           ImageConstants.GREEN_OFFSET] = (byte) ImageConstants.MAX_BYTE;
118                    pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + left) +
119                           ImageConstants.BLUE_OFFSET] = (byte) ImageConstants.MAX_BYTE;
120                }
121
122                // Right edge
123                if (right > 0 && top > 0) {
124                    pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + right) +
125                           ImageConstants.RED_OFFSET] = (byte) ImageConstants.MAX_BYTE;
126                    pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + right) +
127                           ImageConstants.GREEN_OFFSET] = (byte) ImageConstants.MAX_BYTE;
128                    pixels[ImageConstants.PIX_CHANNELS * (dims[0] * (top + j) + right) +
129                           ImageConstants.BLUE_OFFSET] = (byte) ImageConstants.MAX_BYTE;
130                }
131
132            }
133            for (int k = 0; k < (right - left); k++) {
134                // Top edge
135                if (top < dims[1]) {
136                    pixels[ImageConstants.PIX_CHANNELS * (dims[0] * top + left + k) +
137                           ImageConstants.RED_OFFSET] = (byte) ImageConstants.MAX_BYTE;
138                    pixels[ImageConstants.PIX_CHANNELS * (dims[0] * top + left + k) +
139                           ImageConstants.GREEN_OFFSET] = (byte) ImageConstants.MAX_BYTE;
140                    pixels[ImageConstants.PIX_CHANNELS * (dims[0] * top + left + k) +
141                           ImageConstants.BLUE_OFFSET] = (byte) ImageConstants.MAX_BYTE;
142
143                }
144                // Bottom edge
145                if (bottom < dims[1]) {
146                    pixels[ImageConstants.PIX_CHANNELS * (dims[0] * bottom + left + k) +
147                           ImageConstants.RED_OFFSET] = (byte) ImageConstants.MAX_BYTE;
148                    pixels[ImageConstants.PIX_CHANNELS * (dims[0] * bottom + left + k) +
149                           ImageConstants.GREEN_OFFSET] = (byte) ImageConstants.MAX_BYTE;
150                    pixels[ImageConstants.PIX_CHANNELS * (dims[0] * bottom + left + k) +
151                           ImageConstants.BLUE_OFFSET] = (byte) ImageConstants.MAX_BYTE;
152                }
153
154
155            }
156
157        }
158    }
159}
160