1/*
2 * Copyright (C) 2011 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
18package android.filterpacks.imageproc;
19
20import android.filterfw.core.Filter;
21import android.filterfw.core.FilterContext;
22import android.filterfw.core.Frame;
23import android.filterfw.core.FrameFormat;
24import android.filterfw.core.KeyValueMap;
25import android.filterfw.core.NativeProgram;
26import android.filterfw.core.NativeFrame;
27import android.filterfw.core.Program;
28import android.filterfw.core.ShaderProgram;
29import android.filterfw.format.ImageFormat;
30
31import java.lang.reflect.Field;
32import java.util.HashSet;
33import java.util.Set;
34
35/**
36 * @hide
37 */
38public abstract class ImageCombineFilter extends Filter {
39
40    protected Program mProgram;
41    protected String[] mInputNames;
42    protected String mOutputName;
43    protected String mParameterName;
44    protected int mCurrentTarget = FrameFormat.TARGET_UNSPECIFIED;
45
46    public ImageCombineFilter(String name,
47                              String[] inputNames,
48                              String outputName,
49                              String parameterName) {
50        super(name);
51        mInputNames = inputNames;
52        mOutputName = outputName;
53        mParameterName = parameterName;
54    }
55
56    @Override
57    public void setupPorts() {
58        if (mParameterName != null) {
59            try {
60                Field programField = ImageCombineFilter.class.getDeclaredField("mProgram");
61                addProgramPort(mParameterName, mParameterName, programField, float.class, false);
62            } catch (NoSuchFieldException e) {
63                throw new RuntimeException("Internal Error: mProgram field not found!");
64            }
65        }
66        for (String inputName : mInputNames) {
67            addMaskedInputPort(inputName, ImageFormat.create(ImageFormat.COLORSPACE_RGBA));
68        }
69        addOutputBasedOnInput(mOutputName, mInputNames[0]);
70    }
71
72    @Override
73    public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) {
74        return inputFormat;
75    }
76
77    private void assertAllInputTargetsMatch() {
78        int target = getInputFormat(mInputNames[0]).getTarget();
79        for (String inputName : mInputNames) {
80            if (target != getInputFormat(inputName).getTarget()) {
81                throw new RuntimeException("Type mismatch of input formats in filter " + this
82                    + ". All input frames must have the same target!");
83            }
84        }
85    }
86
87    @Override
88    public void process(FilterContext context) {
89        // Pull input frames
90        int i = 0;
91        Frame[] inputs = new Frame[mInputNames.length];
92        for (String inputName : mInputNames) {
93            inputs[i++] = pullInput(inputName);
94        }
95
96        // Create output frame
97        Frame output = context.getFrameManager().newFrame(inputs[0].getFormat());
98
99        // Make sure we have a program
100        updateProgramWithTarget(inputs[0].getFormat().getTarget(), context);
101
102        // Process
103        mProgram.process(inputs, output);
104
105        // Push output
106        pushOutput(mOutputName, output);
107
108        // Release pushed frame
109        output.release();
110    }
111
112    protected void updateProgramWithTarget(int target, FilterContext context) {
113        if (target != mCurrentTarget) {
114            switch (target) {
115                case FrameFormat.TARGET_NATIVE:
116                    mProgram = getNativeProgram(context);
117                    break;
118
119                case FrameFormat.TARGET_GPU:
120                    mProgram = getShaderProgram(context);
121                    break;
122
123                default:
124                    mProgram = null;
125                    break;
126            }
127            if (mProgram == null) {
128                throw new RuntimeException("Could not create a program for image filter "
129                    + this + "!");
130            }
131            initProgramInputs(mProgram, context);
132            mCurrentTarget = target;
133        }
134    }
135
136    protected abstract Program getNativeProgram(FilterContext context);
137
138    protected abstract Program getShaderProgram(FilterContext context);
139}
140