diff options
Diffstat (limited to 'tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphReader.java')
-rw-r--r-- | tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphReader.java | 576 |
1 files changed, 576 insertions, 0 deletions
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphReader.java b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphReader.java new file mode 100644 index 0000000..ef885e3 --- /dev/null +++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/src/androidx/media/filterfw/GraphReader.java @@ -0,0 +1,576 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.media.filterfw; + +import android.text.TextUtils; + +import java.io.InputStream; +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; + +/** + * A GraphReader allows obtaining filter graphs from XML graph files or strings. + */ +public class GraphReader { + + private static interface Command { + public void execute(CommandStack stack); + } + + private static class CommandStack { + private ArrayList<Command> mCommands = new ArrayList<Command>(); + private FilterGraph.Builder mBuilder; + private FilterFactory mFactory; + private MffContext mContext; + + public CommandStack(MffContext context) { + mContext = context; + mBuilder = new FilterGraph.Builder(mContext); + mFactory = new FilterFactory(); + } + + public void execute() { + for (Command command : mCommands) { + command.execute(this); + } + } + + public void append(Command command) { + mCommands.add(command); + } + + public FilterFactory getFactory() { + return mFactory; + } + + public MffContext getContext() { + return mContext; + } + + protected FilterGraph.Builder getBuilder() { + return mBuilder; + } + } + + private static class ImportPackageCommand implements Command { + private String mPackageName; + + public ImportPackageCommand(String packageName) { + mPackageName = packageName; + } + + @Override + public void execute(CommandStack stack) { + try { + stack.getFactory().addPackage(mPackageName); + } catch (IllegalArgumentException e) { + throw new RuntimeException(e.getMessage()); + } + } + } + + private static class AddLibraryCommand implements Command { + private String mLibraryName; + + public AddLibraryCommand(String libraryName) { + mLibraryName = libraryName; + } + + @Override + public void execute(CommandStack stack) { + FilterFactory.addFilterLibrary(mLibraryName); + } + } + + private static class AllocateFilterCommand implements Command { + private String mClassName; + private String mFilterName; + + public AllocateFilterCommand(String className, String filterName) { + mClassName = className; + mFilterName = filterName; + } + + @Override + public void execute(CommandStack stack) { + Filter filter = null; + try { + filter = stack.getFactory().createFilterByClassName(mClassName, + mFilterName, + stack.getContext()); + } catch (IllegalArgumentException e) { + throw new RuntimeException("Error creating filter " + mFilterName + "!", e); + } + stack.getBuilder().addFilter(filter); + } + } + + private static class AddSourceSlotCommand implements Command { + private String mName; + private String mSlotName; + + public AddSourceSlotCommand(String name, String slotName) { + mName = name; + mSlotName = slotName; + } + + @Override + public void execute(CommandStack stack) { + stack.getBuilder().addFrameSlotSource(mName, mSlotName); + } + } + + private static class AddTargetSlotCommand implements Command { + private String mName; + private String mSlotName; + + public AddTargetSlotCommand(String name, String slotName) { + mName = name; + mSlotName = slotName; + } + + @Override + public void execute(CommandStack stack) { + stack.getBuilder().addFrameSlotTarget(mName, mSlotName); + } + } + + private static class AddVariableCommand implements Command { + private String mName; + private Object mValue; + + public AddVariableCommand(String name, Object value) { + mName = name; + mValue = value; + } + + @Override + public void execute(CommandStack stack) { + stack.getBuilder().addVariable(mName, mValue); + } + } + + private static class SetFilterInputCommand implements Command { + private String mFilterName; + private String mFilterInput; + private Object mValue; + + public SetFilterInputCommand(String filterName, String input, Object value) { + mFilterName = filterName; + mFilterInput = input; + mValue = value; + } + + @Override + public void execute(CommandStack stack) { + if (mValue instanceof Variable) { + String varName = ((Variable)mValue).name; + stack.getBuilder().assignVariableToFilterInput(varName, mFilterName, mFilterInput); + } else { + stack.getBuilder().assignValueToFilterInput(mValue, mFilterName, mFilterInput); + } + } + } + + private static class ConnectCommand implements Command { + private String mSourceFilter; + private String mSourcePort; + private String mTargetFilter; + private String mTargetPort; + + public ConnectCommand(String sourceFilter, + String sourcePort, + String targetFilter, + String targetPort) { + mSourceFilter = sourceFilter; + mSourcePort = sourcePort; + mTargetFilter = targetFilter; + mTargetPort = targetPort; + } + + @Override + public void execute(CommandStack stack) { + stack.getBuilder().connect(mSourceFilter, mSourcePort, mTargetFilter, mTargetPort); + } + } + + private static class Variable { + public String name; + + public Variable(String name) { + this.name = name; + } + } + + private static class XmlGraphReader { + + private SAXParserFactory mParserFactory; + + private static class GraphDataHandler extends DefaultHandler { + + private CommandStack mCommandStack; + private boolean mInGraph = false; + private String mCurFilterName = null; + + public GraphDataHandler(CommandStack commandStack) { + mCommandStack = commandStack; + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes attr) + throws SAXException { + if (localName.equals("graph")) { + beginGraph(); + } else { + assertInGraph(localName); + if (localName.equals("import")) { + addImportCommand(attr); + } else if (localName.equals("library")) { + addLibraryCommand(attr); + } else if (localName.equals("connect")) { + addConnectCommand(attr); + } else if (localName.equals("var")) { + addVarCommand(attr); + } else if (localName.equals("filter")) { + beginFilter(attr); + } else if (localName.equals("input")) { + addFilterInput(attr); + } else { + throw new SAXException("Unknown XML element '" + localName + "'!"); + } + } + } + + @Override + public void endElement (String uri, String localName, String qName) { + if (localName.equals("graph")) { + endGraph(); + } else if (localName.equals("filter")) { + endFilter(); + } + } + + private void addImportCommand(Attributes attributes) throws SAXException { + String packageName = getRequiredAttribute(attributes, "package"); + mCommandStack.append(new ImportPackageCommand(packageName)); + } + + private void addLibraryCommand(Attributes attributes) throws SAXException { + String libraryName = getRequiredAttribute(attributes, "name"); + mCommandStack.append(new AddLibraryCommand(libraryName)); + } + + private void addConnectCommand(Attributes attributes) { + String sourcePortName = null; + String sourceFilterName = null; + String targetPortName = null; + String targetFilterName = null; + + // check for shorthand: <connect source="filter:port" target="filter:port"/> + String sourceTag = attributes.getValue("source"); + if (sourceTag != null) { + String[] sourceParts = sourceTag.split(":"); + if (sourceParts.length == 2) { + sourceFilterName = sourceParts[0]; + sourcePortName = sourceParts[1]; + } else { + throw new RuntimeException( + "'source' tag needs to have format \"filter:port\"! " + + "Alternatively, you may use the form " + + "'sourceFilter=\"filter\" sourcePort=\"port\"'."); + } + } else { + sourceFilterName = attributes.getValue("sourceFilter"); + sourcePortName = attributes.getValue("sourcePort"); + } + + String targetTag = attributes.getValue("target"); + if (targetTag != null) { + String[] targetParts = targetTag.split(":"); + if (targetParts.length == 2) { + targetFilterName = targetParts[0]; + targetPortName = targetParts[1]; + } else { + throw new RuntimeException( + "'target' tag needs to have format \"filter:port\"! " + + "Alternatively, you may use the form " + + "'targetFilter=\"filter\" targetPort=\"port\"'."); + } + } else { + targetFilterName = attributes.getValue("targetFilter"); + targetPortName = attributes.getValue("targetPort"); + } + + String sourceSlotName = attributes.getValue("sourceSlot"); + String targetSlotName = attributes.getValue("targetSlot"); + if (sourceSlotName != null) { + sourceFilterName = "sourceSlot_" + sourceSlotName; + mCommandStack.append(new AddSourceSlotCommand(sourceFilterName, + sourceSlotName)); + sourcePortName = "frame"; + } + if (targetSlotName != null) { + targetFilterName = "targetSlot_" + targetSlotName; + mCommandStack.append(new AddTargetSlotCommand(targetFilterName, + targetSlotName)); + targetPortName = "frame"; + } + assertValueNotNull("sourceFilter", sourceFilterName); + assertValueNotNull("sourcePort", sourcePortName); + assertValueNotNull("targetFilter", targetFilterName); + assertValueNotNull("targetPort", targetPortName); + // TODO: Should slot connections auto-branch? + mCommandStack.append(new ConnectCommand(sourceFilterName, + sourcePortName, + targetFilterName, + targetPortName)); + } + + private void addVarCommand(Attributes attributes) throws SAXException { + String varName = getRequiredAttribute(attributes, "name"); + Object varValue = getAssignmentValue(attributes); + mCommandStack.append(new AddVariableCommand(varName, varValue)); + } + + private void beginGraph() throws SAXException { + if (mInGraph) { + throw new SAXException("Found more than one graph element in XML!"); + } + mInGraph = true; + } + + private void endGraph() { + mInGraph = false; + } + + private void beginFilter(Attributes attributes) throws SAXException { + String className = getRequiredAttribute(attributes, "class"); + mCurFilterName = getRequiredAttribute(attributes, "name"); + mCommandStack.append(new AllocateFilterCommand(className, mCurFilterName)); + } + + private void endFilter() { + mCurFilterName = null; + } + + private void addFilterInput(Attributes attributes) throws SAXException { + // Make sure we are in a filter element + if (mCurFilterName == null) { + throw new SAXException("Found 'input' element outside of 'filter' " + + "element!"); + } + + // Get input name and value + String inputName = getRequiredAttribute(attributes, "name"); + Object inputValue = getAssignmentValue(attributes); + if (inputValue == null) { + throw new SAXException("No value specified for input '" + inputName + "' " + + "of filter '" + mCurFilterName + "'!"); + } + + // Push commmand + mCommandStack.append(new SetFilterInputCommand(mCurFilterName, + inputName, + inputValue)); + } + + private void assertInGraph(String localName) throws SAXException { + if (!mInGraph) { + throw new SAXException("Encountered '" + localName + "' element outside of " + + "'graph' element!"); + } + } + + private static Object getAssignmentValue(Attributes attributes) { + String strValue = null; + if ((strValue = attributes.getValue("stringValue")) != null) { + return strValue; + } else if ((strValue = attributes.getValue("booleanValue")) != null) { + return Boolean.parseBoolean(strValue); + } else if ((strValue = attributes.getValue("intValue")) != null) { + return Integer.parseInt(strValue); + } else if ((strValue = attributes.getValue("floatValue")) != null) { + return Float.parseFloat(strValue); + } else if ((strValue = attributes.getValue("floatsValue")) != null) { + String[] floatStrings = TextUtils.split(strValue, ","); + float[] result = new float[floatStrings.length]; + for (int i = 0; i < floatStrings.length; ++i) { + result[i] = Float.parseFloat(floatStrings[i]); + } + return result; + } else if ((strValue = attributes.getValue("varValue")) != null) { + return new Variable(strValue); + } else { + return null; + } + } + + private static String getRequiredAttribute(Attributes attributes, String name) + throws SAXException { + String result = attributes.getValue(name); + if (result == null) { + throw new SAXException("Required attribute '" + name + "' not found!"); + } + return result; + } + + private static void assertValueNotNull(String valueName, Object value) { + if (value == null) { + throw new NullPointerException("Required value '" + value + "' not specified!"); + } + } + + } + + public XmlGraphReader() { + mParserFactory = SAXParserFactory.newInstance(); + } + + public void parseString(String graphString, CommandStack commandStack) throws IOException { + try { + XMLReader reader = getReaderForCommandStack(commandStack); + reader.parse(new InputSource(new StringReader(graphString))); + } catch (SAXException e) { + throw new IOException("XML parse error during graph parsing!", e); + } + } + + public void parseInput(InputStream inputStream, CommandStack commandStack) + throws IOException { + try { + XMLReader reader = getReaderForCommandStack(commandStack); + reader.parse(new InputSource(inputStream)); + } catch (SAXException e) { + throw new IOException("XML parse error during graph parsing!", e); + } + } + + private XMLReader getReaderForCommandStack(CommandStack commandStack) throws IOException { + try { + SAXParser parser = mParserFactory.newSAXParser(); + XMLReader reader = parser.getXMLReader(); + GraphDataHandler graphHandler = new GraphDataHandler(commandStack); + reader.setContentHandler(graphHandler); + return reader; + } catch (ParserConfigurationException e) { + throw new IOException("Error creating SAXParser for graph parsing!", e); + } catch (SAXException e) { + throw new IOException("Error creating XMLReader for graph parsing!", e); + } + } + } + + /** + * Read an XML graph from a String. + * + * This function automatically checks each filters' signatures and throws a Runtime Exception + * if required ports are unconnected. Use the 3-parameter version to avoid this behavior. + * + * @param context the MffContext into which to load the graph. + * @param xmlSource the graph specified in XML. + * @return the FilterGraph instance for the XML source. + * @throws IOException if there was an error parsing the source. + */ + public static FilterGraph readXmlGraph(MffContext context, String xmlSource) + throws IOException { + FilterGraph.Builder builder = getBuilderForXmlString(context, xmlSource); + return builder.build(); + } + + /** + * Read an XML sub-graph from a String. + * + * @param context the MffContext into which to load the graph. + * @param xmlSource the graph specified in XML. + * @param parentGraph the parent graph. + * @return the FilterGraph instance for the XML source. + * @throws IOException if there was an error parsing the source. + */ + public static FilterGraph readXmlSubGraph( + MffContext context, String xmlSource, FilterGraph parentGraph) + throws IOException { + FilterGraph.Builder builder = getBuilderForXmlString(context, xmlSource); + return builder.buildSubGraph(parentGraph); + } + + /** + * Read an XML graph from a resource. + * + * This function automatically checks each filters' signatures and throws a Runtime Exception + * if required ports are unconnected. Use the 3-parameter version to avoid this behavior. + * + * @param context the MffContext into which to load the graph. + * @param resourceId the XML resource ID. + * @return the FilterGraph instance for the XML source. + * @throws IOException if there was an error reading or parsing the resource. + */ + public static FilterGraph readXmlGraphResource(MffContext context, int resourceId) + throws IOException { + FilterGraph.Builder builder = getBuilderForXmlResource(context, resourceId); + return builder.build(); + } + + /** + * Read an XML graph from a resource. + * + * This function automatically checks each filters' signatures and throws a Runtime Exception + * if required ports are unconnected. Use the 3-parameter version to avoid this behavior. + * + * @param context the MffContext into which to load the graph. + * @param resourceId the XML resource ID. + * @return the FilterGraph instance for the XML source. + * @throws IOException if there was an error reading or parsing the resource. + */ + public static FilterGraph readXmlSubGraphResource( + MffContext context, int resourceId, FilterGraph parentGraph) + throws IOException { + FilterGraph.Builder builder = getBuilderForXmlResource(context, resourceId); + return builder.buildSubGraph(parentGraph); + } + + private static FilterGraph.Builder getBuilderForXmlString(MffContext context, String source) + throws IOException { + XmlGraphReader reader = new XmlGraphReader(); + CommandStack commands = new CommandStack(context); + reader.parseString(source, commands); + commands.execute(); + return commands.getBuilder(); + } + + private static FilterGraph.Builder getBuilderForXmlResource(MffContext context, int resourceId) + throws IOException { + InputStream inputStream = context.getApplicationContext().getResources() + .openRawResource(resourceId); + XmlGraphReader reader = new XmlGraphReader(); + CommandStack commands = new CommandStack(context); + reader.parseInput(inputStream, commands); + commands.execute(); + return commands.getBuilder(); + } +} + |