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