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