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 18 package android.filterfw.core; 19 20 import android.filterfw.core.FilterContext; 21 import android.filterfw.core.FilterPort; 22 import android.filterfw.core.KeyValueMap; 23 import android.filterfw.io.TextGraphReader; 24 import android.filterfw.io.GraphIOException; 25 import android.filterfw.format.ObjectFormat; 26 import android.util.Log; 27 28 import java.io.Serializable; 29 import java.lang.annotation.Annotation; 30 import java.lang.reflect.Field; 31 import java.lang.Thread; 32 import java.util.Collection; 33 import java.util.HashMap; 34 import java.util.HashSet; 35 import java.util.Map.Entry; 36 import java.util.Set; 37 38 /** 39 * @hide 40 */ 41 public abstract class Filter { 42 43 static final int STATUS_PREINIT = 0; 44 static final int STATUS_UNPREPARED = 1; 45 static final int STATUS_PREPARED = 2; 46 static final int STATUS_PROCESSING = 3; 47 static final int STATUS_SLEEPING = 4; 48 static final int STATUS_FINISHED = 5; 49 static final int STATUS_ERROR = 6; 50 static final int STATUS_RELEASED = 7; 51 52 private String mName; 53 54 private int mInputCount = -1; 55 private int mOutputCount = -1; 56 57 private HashMap<String, InputPort> mInputPorts; 58 private HashMap<String, OutputPort> mOutputPorts; 59 60 private HashSet<Frame> mFramesToRelease; 61 private HashMap<String, Frame> mFramesToSet; 62 63 private int mStatus = 0; 64 private boolean mIsOpen = false; 65 private int mSleepDelay; 66 67 private long mCurrentTimestamp; 68 69 private boolean mLogVerbose; 70 private static final String TAG = "Filter"; 71 Filter(String name)72 public Filter(String name) { 73 mName = name; 74 mFramesToRelease = new HashSet<Frame>(); 75 mFramesToSet = new HashMap<String, Frame>(); 76 mStatus = STATUS_PREINIT; 77 78 mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE); 79 } 80 81 /** Tests to see if a given filter is installed on the system. Requires 82 * full filter package name, including filterpack. 83 */ isAvailable(String filterName)84 public static final boolean isAvailable(String filterName) { 85 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); 86 Class filterClass; 87 // First see if a class of that name exists 88 try { 89 filterClass = contextClassLoader.loadClass(filterName); 90 } catch (ClassNotFoundException e) { 91 return false; 92 } 93 // Then make sure it's a subclass of Filter. 94 try { 95 filterClass.asSubclass(Filter.class); 96 } catch (ClassCastException e) { 97 return false; 98 } 99 return true; 100 } 101 initWithValueMap(KeyValueMap valueMap)102 public final void initWithValueMap(KeyValueMap valueMap) { 103 // Initialization 104 initFinalPorts(valueMap); 105 106 // Setup remaining ports 107 initRemainingPorts(valueMap); 108 109 // This indicates that final ports can no longer be set 110 mStatus = STATUS_UNPREPARED; 111 } 112 initWithAssignmentString(String assignments)113 public final void initWithAssignmentString(String assignments) { 114 try { 115 KeyValueMap valueMap = new TextGraphReader().readKeyValueAssignments(assignments); 116 initWithValueMap(valueMap); 117 } catch (GraphIOException e) { 118 throw new IllegalArgumentException(e.getMessage()); 119 } 120 } 121 initWithAssignmentList(Object... keyValues)122 public final void initWithAssignmentList(Object... keyValues) { 123 KeyValueMap valueMap = new KeyValueMap(); 124 valueMap.setKeyValues(keyValues); 125 initWithValueMap(valueMap); 126 } 127 init()128 public final void init() throws ProtocolException { 129 KeyValueMap valueMap = new KeyValueMap(); 130 initWithValueMap(valueMap); 131 } 132 getFilterClassName()133 public String getFilterClassName() { 134 return getClass().getSimpleName(); 135 } 136 getName()137 public final String getName() { 138 return mName; 139 } 140 isOpen()141 public boolean isOpen() { 142 return mIsOpen; 143 } 144 setInputFrame(String inputName, Frame frame)145 public void setInputFrame(String inputName, Frame frame) { 146 FilterPort port = getInputPort(inputName); 147 if (!port.isOpen()) { 148 port.open(); 149 } 150 port.setFrame(frame); 151 } 152 setInputValue(String inputName, Object value)153 public final void setInputValue(String inputName, Object value) { 154 setInputFrame(inputName, wrapInputValue(inputName, value)); 155 } 156 prepare(FilterContext context)157 protected void prepare(FilterContext context) { 158 } 159 parametersUpdated(Set<String> updated)160 protected void parametersUpdated(Set<String> updated) { 161 } 162 delayNextProcess(int millisecs)163 protected void delayNextProcess(int millisecs) { 164 mSleepDelay = millisecs; 165 mStatus = STATUS_SLEEPING; 166 } 167 setupPorts()168 public abstract void setupPorts(); 169 getOutputFormat(String portName, FrameFormat inputFormat)170 public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { 171 return null; 172 } 173 getInputFormat(String portName)174 public final FrameFormat getInputFormat(String portName) { 175 InputPort inputPort = getInputPort(portName); 176 return inputPort.getSourceFormat(); 177 } 178 open(FilterContext context)179 public void open(FilterContext context) { 180 } 181 process(FilterContext context)182 public abstract void process(FilterContext context); 183 getSleepDelay()184 public final int getSleepDelay() { 185 return 250; 186 } 187 close(FilterContext context)188 public void close(FilterContext context) { 189 } 190 tearDown(FilterContext context)191 public void tearDown(FilterContext context) { 192 } 193 getNumberOfConnectedInputs()194 public final int getNumberOfConnectedInputs() { 195 int c = 0; 196 for (InputPort inputPort : mInputPorts.values()) { 197 if (inputPort.isConnected()) { 198 ++c; 199 } 200 } 201 return c; 202 } 203 getNumberOfConnectedOutputs()204 public final int getNumberOfConnectedOutputs() { 205 int c = 0; 206 for (OutputPort outputPort : mOutputPorts.values()) { 207 if (outputPort.isConnected()) { 208 ++c; 209 } 210 } 211 return c; 212 } 213 getNumberOfInputs()214 public final int getNumberOfInputs() { 215 return mOutputPorts == null ? 0 : mInputPorts.size(); 216 } 217 getNumberOfOutputs()218 public final int getNumberOfOutputs() { 219 return mInputPorts == null ? 0 : mOutputPorts.size(); 220 } 221 getInputPort(String portName)222 public final InputPort getInputPort(String portName) { 223 if (mInputPorts == null) { 224 throw new NullPointerException("Attempting to access input port '" + portName 225 + "' of " + this + " before Filter has been initialized!"); 226 } 227 InputPort result = mInputPorts.get(portName); 228 if (result == null) { 229 throw new IllegalArgumentException("Unknown input port '" + portName + "' on filter " 230 + this + "!"); 231 } 232 return result; 233 } 234 getOutputPort(String portName)235 public final OutputPort getOutputPort(String portName) { 236 if (mInputPorts == null) { 237 throw new NullPointerException("Attempting to access output port '" + portName 238 + "' of " + this + " before Filter has been initialized!"); 239 } 240 OutputPort result = mOutputPorts.get(portName); 241 if (result == null) { 242 throw new IllegalArgumentException("Unknown output port '" + portName + "' on filter " 243 + this + "!"); 244 } 245 return result; 246 } 247 pushOutput(String name, Frame frame)248 protected final void pushOutput(String name, Frame frame) { 249 if (frame.getTimestamp() == Frame.TIMESTAMP_NOT_SET) { 250 if (mLogVerbose) Log.v(TAG, "Default-setting output Frame timestamp on port " + name + " to " + mCurrentTimestamp); 251 frame.setTimestamp(mCurrentTimestamp); 252 } 253 getOutputPort(name).pushFrame(frame); 254 } 255 pullInput(String name)256 protected final Frame pullInput(String name) { 257 Frame result = getInputPort(name).pullFrame(); 258 if (mCurrentTimestamp == Frame.TIMESTAMP_UNKNOWN) { 259 mCurrentTimestamp = result.getTimestamp(); 260 if (mLogVerbose) Log.v(TAG, "Default-setting current timestamp from input port " + name + " to " + mCurrentTimestamp); 261 } 262 // As result is retained, we add it to the release pool here 263 mFramesToRelease.add(result); 264 265 return result; 266 } 267 fieldPortValueUpdated(String name, FilterContext context)268 public void fieldPortValueUpdated(String name, FilterContext context) { 269 } 270 271 /** 272 * Transfers any frame from an input port to its destination. This is useful to force a 273 * transfer from a FieldPort or ProgramPort to its connected target (field or program variable). 274 */ transferInputPortFrame(String name, FilterContext context)275 protected void transferInputPortFrame(String name, FilterContext context) { 276 getInputPort(name).transfer(context); 277 } 278 279 /** 280 * Assigns all program variables to the ports they are connected to. Call this after 281 * constructing a Program instance with attached ProgramPorts. 282 */ initProgramInputs(Program program, FilterContext context)283 protected void initProgramInputs(Program program, FilterContext context) { 284 if (program != null) { 285 for (InputPort inputPort : mInputPorts.values()) { 286 if (inputPort.getTarget() == program) { 287 inputPort.transfer(context); 288 } 289 } 290 } 291 } 292 293 /** 294 * Adds an input port to the filter. You should call this from within setupPorts, if your 295 * filter has input ports. No type-checking is performed on the input. If you would like to 296 * check against a type mask, use 297 * {@link #addMaskedInputPort(String, FrameFormat) addMaskedInputPort} instead. 298 * 299 * @param name the name of the input port 300 */ addInputPort(String name)301 protected void addInputPort(String name) { 302 addMaskedInputPort(name, null); 303 } 304 305 /** 306 * Adds an input port to the filter. You should call this from within setupPorts, if your 307 * filter has input ports. When type-checking is performed, the input format is 308 * checked against the provided format mask. An exception is thrown in case of a conflict. 309 * 310 * @param name the name of the input port 311 * @param formatMask a format mask, which filters the allowable input types 312 */ addMaskedInputPort(String name, FrameFormat formatMask)313 protected void addMaskedInputPort(String name, FrameFormat formatMask) { 314 InputPort port = new StreamPort(this, name); 315 if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port); 316 mInputPorts.put(name, port); 317 port.setPortFormat(formatMask); 318 } 319 320 /** 321 * Adds an output port to the filter with a fixed output format. You should call this from 322 * within setupPorts, if your filter has output ports. You cannot use this method, if your 323 * output format depends on the input format (e.g. in a pass-through filter). In this case, use 324 * {@link #addOutputBasedOnInput(String, String) addOutputBasedOnInput} instead. 325 * 326 * @param name the name of the output port 327 * @param format the fixed output format of this port 328 */ addOutputPort(String name, FrameFormat format)329 protected void addOutputPort(String name, FrameFormat format) { 330 OutputPort port = new OutputPort(this, name); 331 if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port); 332 port.setPortFormat(format); 333 mOutputPorts.put(name, port); 334 } 335 336 /** 337 * Adds an output port to the filter. You should call this from within setupPorts, if your 338 * filter has output ports. Using this method indicates that the output format for this 339 * particular port, depends on the format of an input port. You MUST also override 340 * {@link #getOutputFormat(String, FrameFormat) getOutputFormat} to specify what format your 341 * filter will output for a given input. If the output format of your filter port does not 342 * depend on the input, use {@link #addOutputPort(String, FrameFormat) addOutputPort} instead. 343 * 344 * @param outputName the name of the output port 345 * @param inputName the name of the input port, that this output depends on 346 */ addOutputBasedOnInput(String outputName, String inputName)347 protected void addOutputBasedOnInput(String outputName, String inputName) { 348 OutputPort port = new OutputPort(this, outputName); 349 if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + port); 350 port.setBasePort(getInputPort(inputName)); 351 mOutputPorts.put(outputName, port); 352 } 353 addFieldPort(String name, Field field, boolean hasDefault, boolean isFinal)354 protected void addFieldPort(String name, 355 Field field, 356 boolean hasDefault, 357 boolean isFinal) { 358 // Make sure field is accessible 359 field.setAccessible(true); 360 361 // Create port for this input 362 InputPort fieldPort = isFinal 363 ? new FinalPort(this, name, field, hasDefault) 364 : new FieldPort(this, name, field, hasDefault); 365 366 // Create format for this input 367 if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + fieldPort); 368 MutableFrameFormat format = ObjectFormat.fromClass(field.getType(), 369 FrameFormat.TARGET_SIMPLE); 370 fieldPort.setPortFormat(format); 371 372 // Add port 373 mInputPorts.put(name, fieldPort); 374 } 375 addProgramPort(String name, String varName, Field field, Class varType, boolean hasDefault)376 protected void addProgramPort(String name, 377 String varName, 378 Field field, 379 Class varType, 380 boolean hasDefault) { 381 // Make sure field is accessible 382 field.setAccessible(true); 383 384 // Create port for this input 385 InputPort programPort = new ProgramPort(this, name, varName, field, hasDefault); 386 387 // Create format for this input 388 if (mLogVerbose) Log.v(TAG, "Filter " + this + " adding " + programPort); 389 MutableFrameFormat format = ObjectFormat.fromClass(varType, 390 FrameFormat.TARGET_SIMPLE); 391 programPort.setPortFormat(format); 392 393 // Add port 394 mInputPorts.put(name, programPort); 395 } 396 closeOutputPort(String name)397 protected void closeOutputPort(String name) { 398 getOutputPort(name).close(); 399 } 400 401 /** 402 * Specifies whether the filter should not be scheduled until a frame is available on that 403 * input port. Note, that setting this to false, does not block a new frame from coming in 404 * (though there is no necessity to pull that frame for processing). 405 * @param portName the name of the input port. 406 * @param waits true, if the filter should wait for a frame on this port. 407 */ setWaitsOnInputPort(String portName, boolean waits)408 protected void setWaitsOnInputPort(String portName, boolean waits) { 409 getInputPort(portName).setBlocking(waits); 410 } 411 412 /** 413 * Specifies whether the filter should not be scheduled until the output port is free, i.e. 414 * there is no frame waiting on that output. 415 * @param portName the name of the output port. 416 * @param waits true, if the filter should wait for the port to become free. 417 */ setWaitsOnOutputPort(String portName, boolean waits)418 protected void setWaitsOnOutputPort(String portName, boolean waits) { 419 getOutputPort(portName).setBlocking(waits); 420 } 421 toString()422 public String toString() { 423 return "'" + getName() + "' (" + getFilterClassName() + ")"; 424 } 425 426 // Core internal methods /////////////////////////////////////////////////////////////////////// getInputPorts()427 final Collection<InputPort> getInputPorts() { 428 return mInputPorts.values(); 429 } 430 getOutputPorts()431 final Collection<OutputPort> getOutputPorts() { 432 return mOutputPorts.values(); 433 } 434 getStatus()435 final synchronized int getStatus() { 436 return mStatus; 437 } 438 unsetStatus(int flag)439 final synchronized void unsetStatus(int flag) { 440 mStatus &= ~flag; 441 } 442 performOpen(FilterContext context)443 final synchronized void performOpen(FilterContext context) { 444 if (!mIsOpen) { 445 if (mStatus == STATUS_UNPREPARED) { 446 if (mLogVerbose) Log.v(TAG, "Preparing " + this); 447 prepare(context); 448 mStatus = STATUS_PREPARED; 449 } 450 if (mStatus == STATUS_PREPARED) { 451 if (mLogVerbose) Log.v(TAG, "Opening " + this); 452 open(context); 453 mStatus = STATUS_PROCESSING; 454 } 455 if (mStatus != STATUS_PROCESSING) { 456 throw new RuntimeException("Filter " + this + " was brought into invalid state during " 457 + "opening (state: " + mStatus + ")!"); 458 } 459 mIsOpen = true; 460 } 461 } 462 performProcess(FilterContext context)463 final synchronized void performProcess(FilterContext context) { 464 if (mStatus == STATUS_RELEASED) { 465 throw new RuntimeException("Filter " + this + " is already torn down!"); 466 } 467 transferInputFrames(context); 468 if (mStatus < STATUS_PROCESSING) { 469 performOpen(context); 470 } 471 if (mLogVerbose) Log.v(TAG, "Processing " + this); 472 mCurrentTimestamp = Frame.TIMESTAMP_UNKNOWN; 473 process(context); 474 releasePulledFrames(context); 475 if (filterMustClose()) { 476 performClose(context); 477 } 478 } 479 performClose(FilterContext context)480 final synchronized void performClose(FilterContext context) { 481 if (mIsOpen) { 482 if (mLogVerbose) Log.v(TAG, "Closing " + this); 483 mIsOpen = false; 484 mStatus = STATUS_PREPARED; 485 close(context); 486 closePorts(); 487 } 488 } 489 performTearDown(FilterContext context)490 final synchronized void performTearDown(FilterContext context) { 491 performClose(context); 492 if (mStatus != STATUS_RELEASED) { 493 tearDown(context); 494 mStatus = STATUS_RELEASED; 495 } 496 } 497 canProcess()498 synchronized final boolean canProcess() { 499 if (mLogVerbose) Log.v(TAG, "Checking if can process: " + this + " (" + mStatus + ")."); 500 if (mStatus <= STATUS_PROCESSING) { 501 return inputConditionsMet() && outputConditionsMet(); 502 } else { 503 return false; 504 } 505 } 506 openOutputs()507 final void openOutputs() { 508 if (mLogVerbose) Log.v(TAG, "Opening all output ports on " + this + "!"); 509 for (OutputPort outputPort : mOutputPorts.values()) { 510 if (!outputPort.isOpen()) { 511 outputPort.open(); 512 } 513 } 514 } 515 clearInputs()516 final void clearInputs() { 517 for (InputPort inputPort : mInputPorts.values()) { 518 inputPort.clear(); 519 } 520 } 521 clearOutputs()522 final void clearOutputs() { 523 for (OutputPort outputPort : mOutputPorts.values()) { 524 outputPort.clear(); 525 } 526 } 527 notifyFieldPortValueUpdated(String name, FilterContext context)528 final void notifyFieldPortValueUpdated(String name, FilterContext context) { 529 if (mStatus == STATUS_PROCESSING || mStatus == STATUS_PREPARED) { 530 fieldPortValueUpdated(name, context); 531 } 532 } 533 pushInputFrame(String inputName, Frame frame)534 final synchronized void pushInputFrame(String inputName, Frame frame) { 535 FilterPort port = getInputPort(inputName); 536 if (!port.isOpen()) { 537 port.open(); 538 } 539 port.pushFrame(frame); 540 } 541 pushInputValue(String inputName, Object value)542 final synchronized void pushInputValue(String inputName, Object value) { 543 pushInputFrame(inputName, wrapInputValue(inputName, value)); 544 } 545 546 // Filter internal methods ///////////////////////////////////////////////////////////////////// initFinalPorts(KeyValueMap values)547 private final void initFinalPorts(KeyValueMap values) { 548 mInputPorts = new HashMap<String, InputPort>(); 549 mOutputPorts = new HashMap<String, OutputPort>(); 550 addAndSetFinalPorts(values); 551 } 552 initRemainingPorts(KeyValueMap values)553 private final void initRemainingPorts(KeyValueMap values) { 554 addAnnotatedPorts(); 555 setupPorts(); // TODO: rename to addFilterPorts() ? 556 setInitialInputValues(values); 557 } 558 addAndSetFinalPorts(KeyValueMap values)559 private final void addAndSetFinalPorts(KeyValueMap values) { 560 Class filterClass = getClass(); 561 Annotation annotation; 562 for (Field field : filterClass.getDeclaredFields()) { 563 if ((annotation = field.getAnnotation(GenerateFinalPort.class)) != null) { 564 GenerateFinalPort generator = (GenerateFinalPort)annotation; 565 String name = generator.name().isEmpty() ? field.getName() : generator.name(); 566 boolean hasDefault = generator.hasDefault(); 567 addFieldPort(name, field, hasDefault, true); 568 if (values.containsKey(name)) { 569 setImmediateInputValue(name, values.get(name)); 570 values.remove(name); 571 } else if (!generator.hasDefault()) { 572 throw new RuntimeException("No value specified for final input port '" 573 + name + "' of filter " + this + "!"); 574 } 575 } 576 } 577 } 578 addAnnotatedPorts()579 private final void addAnnotatedPorts() { 580 Class filterClass = getClass(); 581 Annotation annotation; 582 for (Field field : filterClass.getDeclaredFields()) { 583 if ((annotation = field.getAnnotation(GenerateFieldPort.class)) != null) { 584 GenerateFieldPort generator = (GenerateFieldPort)annotation; 585 addFieldGenerator(generator, field); 586 } else if ((annotation = field.getAnnotation(GenerateProgramPort.class)) != null) { 587 GenerateProgramPort generator = (GenerateProgramPort)annotation; 588 addProgramGenerator(generator, field); 589 } else if ((annotation = field.getAnnotation(GenerateProgramPorts.class)) != null) { 590 GenerateProgramPorts generators = (GenerateProgramPorts)annotation; 591 for (GenerateProgramPort generator : generators.value()) { 592 addProgramGenerator(generator, field); 593 } 594 } 595 } 596 } 597 addFieldGenerator(GenerateFieldPort generator, Field field)598 private final void addFieldGenerator(GenerateFieldPort generator, Field field) { 599 String name = generator.name().isEmpty() ? field.getName() : generator.name(); 600 boolean hasDefault = generator.hasDefault(); 601 addFieldPort(name, field, hasDefault, false); 602 } 603 addProgramGenerator(GenerateProgramPort generator, Field field)604 private final void addProgramGenerator(GenerateProgramPort generator, Field field) { 605 String name = generator.name(); 606 String varName = generator.variableName().isEmpty() ? name 607 : generator.variableName(); 608 Class varType = generator.type(); 609 boolean hasDefault = generator.hasDefault(); 610 addProgramPort(name, varName, field, varType, hasDefault); 611 } 612 setInitialInputValues(KeyValueMap values)613 private final void setInitialInputValues(KeyValueMap values) { 614 for (Entry<String, Object> entry : values.entrySet()) { 615 setInputValue(entry.getKey(), entry.getValue()); 616 } 617 } 618 setImmediateInputValue(String name, Object value)619 private final void setImmediateInputValue(String name, Object value) { 620 if (mLogVerbose) Log.v(TAG, "Setting immediate value " + value + " for port " + name + "!"); 621 FilterPort port = getInputPort(name); 622 port.open(); 623 port.setFrame(SimpleFrame.wrapObject(value, null)); 624 } 625 transferInputFrames(FilterContext context)626 private final void transferInputFrames(FilterContext context) { 627 for (InputPort inputPort : mInputPorts.values()) { 628 inputPort.transfer(context); 629 } 630 } 631 wrapInputValue(String inputName, Object value)632 private final Frame wrapInputValue(String inputName, Object value) { 633 MutableFrameFormat inputFormat = ObjectFormat.fromObject(value, FrameFormat.TARGET_SIMPLE); 634 if (value == null) { 635 // If the value is null, the format cannot guess the class, so we adjust it to the 636 // class of the input port here 637 FrameFormat portFormat = getInputPort(inputName).getPortFormat(); 638 Class portClass = (portFormat == null) ? null : portFormat.getObjectClass(); 639 inputFormat.setObjectClass(portClass); 640 } 641 642 // Serialize if serializable, and type is not an immutable primitive. 643 boolean shouldSerialize = !(value instanceof Number) 644 && !(value instanceof Boolean) 645 && !(value instanceof String) 646 && value instanceof Serializable; 647 648 // Create frame wrapper 649 Frame frame = shouldSerialize 650 ? new SerializedFrame(inputFormat, null) 651 : new SimpleFrame(inputFormat, null); 652 frame.setObjectValue(value); 653 return frame; 654 } 655 releasePulledFrames(FilterContext context)656 private final void releasePulledFrames(FilterContext context) { 657 for (Frame frame : mFramesToRelease) { 658 context.getFrameManager().releaseFrame(frame); 659 } 660 mFramesToRelease.clear(); 661 } 662 inputConditionsMet()663 private final boolean inputConditionsMet() { 664 for (FilterPort port : mInputPorts.values()) { 665 if (!port.isReady()) { 666 if (mLogVerbose) Log.v(TAG, "Input condition not met: " + port + "!"); 667 return false; 668 } 669 } 670 return true; 671 } 672 outputConditionsMet()673 private final boolean outputConditionsMet() { 674 for (FilterPort port : mOutputPorts.values()) { 675 if (!port.isReady()) { 676 if (mLogVerbose) Log.v(TAG, "Output condition not met: " + port + "!"); 677 return false; 678 } 679 } 680 return true; 681 } 682 closePorts()683 private final void closePorts() { 684 if (mLogVerbose) Log.v(TAG, "Closing all ports on " + this + "!"); 685 for (InputPort inputPort : mInputPorts.values()) { 686 inputPort.close(); 687 } 688 for (OutputPort outputPort : mOutputPorts.values()) { 689 outputPort.close(); 690 } 691 } 692 filterMustClose()693 private final boolean filterMustClose() { 694 for (InputPort inputPort : mInputPorts.values()) { 695 if (inputPort.filterMustClose()) { 696 if (mLogVerbose) Log.v(TAG, "Filter " + this + " must close due to port " + inputPort); 697 return true; 698 } 699 } 700 for (OutputPort outputPort : mOutputPorts.values()) { 701 if (outputPort.filterMustClose()) { 702 if (mLogVerbose) Log.v(TAG, "Filter " + this + " must close due to port " + outputPort); 703 return true; 704 } 705 } 706 return false; 707 } 708 } 709