@Override
  public void process(FilterContext context) {
    if (mLogVerbose) Log.v(TAG, "Processing new frame");

    // First, get new frame if available
    if (mWaitForNewFrame || mFirstFrame) {
      boolean gotNewFrame;
      if (mWaitTimeout != 0) {
        gotNewFrame = mNewFrameAvailable.block(mWaitTimeout);
        if (!gotNewFrame) {
          if (!mCloseOnTimeout) {
            throw new RuntimeException("Timeout waiting for new frame");
          } else {
            if (mLogVerbose) Log.v(TAG, "Timeout waiting for a new frame. Closing.");
            closeOutputPort("video");
            return;
          }
        }
      } else {
        mNewFrameAvailable.block();
      }
      mNewFrameAvailable.close();
      mFirstFrame = false;
    }

    mSurfaceTexture.updateTexImage();

    mSurfaceTexture.getTransformMatrix(mFrameTransform);
    Matrix.multiplyMM(
        mMappedCoords, 0,
        mFrameTransform, 0,
        mSourceCoords, 0);
    mFrameExtractor.setSourceRegion(
        mMappedCoords[0], mMappedCoords[1],
        mMappedCoords[4], mMappedCoords[5],
        mMappedCoords[8], mMappedCoords[9],
        mMappedCoords[12], mMappedCoords[13]);
    // Next, render to output
    Frame output = context.getFrameManager().newFrame(mOutputFormat);
    mFrameExtractor.process(mMediaFrame, output);

    output.setTimestamp(mSurfaceTexture.getTimestamp());

    pushOutput("video", output);
    output.release();
  }
  @Override
  public boolean process(
      FilterContext context, VideoEventFilter myfilter, boolean isRenderOutput, GLFrame output) {
    super.process(context, myfilter, isRenderOutput, output);

    GLFrame camera = myfilter.getInputCameraGLFrame();

    FrameFormat inputFormat;
    inputFormat = camera.getFormat();

    if (null == mMainFrame) {
      MutableFrameFormat outputFormat = inputFormat.mutableCopy();
      mMainFrame = (GLFrame) context.getFrameManager().newFrame(outputFormat);
      mMainFrame.focus();
      mCopyProgramWithColor.process(camera, mMainFrame);
    }

    if (null == mPreviousFrame) {
      MutableFrameFormat outputFormat = inputFormat.mutableCopy();
      mPreviousFrame = (GLFrame) context.getFrameManager().newFrame(outputFormat);
      mPreviousFrame.focus();
    }

    Frame[] subtractInputs = {camera, mPreviousFrame};

    long currentTimeStamp = myfilter.getNowTimeStamp();
    long cameraPhoto;

    if (this.containsKey("camera_photo")) {
      try {
        cameraPhoto = ((Long) this.get("camera_photo")).longValue() + mStart;
      } catch (ClassCastException e) {
        e.printStackTrace();
        return false;
      }

      // get fix frame
      if (currentTimeStamp >= cameraPhoto) {
        if (false == mGotMainFrame) {
          mMainFrame.focus();
          mColor[3] = 1.0f;
          mCopyProgramWithColor.setHostValue("ccc", mColor);
          mCopyProgramWithColor.process(camera, mMainFrame);
          mGotMainFrame = true;
          mTool.log('d', "Got CameraInput:" + currentTimeStamp);
        }
        subtractInputs[0] = mMainFrame;
      }

      if (false == mIsGotPreviousFrame
          || true == mIsGotPreviousFrame && currentTimeStamp < mEffectStart) {
        mPreviousFrame.focus();
        if (isRenderOutput) {
          mCopyProgramWithColor.process(output, mPreviousFrame);
        } else {
          mCopyProgramWithColor.process(camera, mPreviousFrame);
        }
        mIsGotPreviousFrame = true;
        mTool.log('d', "Got PreviousInput:" + currentTimeStamp);
      }

      // finished, no need to do
      if (currentTimeStamp >= mEffectEnd || currentTimeStamp < mEffectStart) {
        return false;
      }

      float center_r = 0.0f;

      if (cameraPhoto >= currentTimeStamp) {
        center_r =
            1.0f - (float) (currentTimeStamp - mEffectStart) / (float) (cameraPhoto - mEffectStart);
        subtractInputs[0] = mPreviousFrame;
      } else {
        center_r = (float) (currentTimeStamp - cameraPhoto) / (float) (mEffectEnd - cameraPhoto);
        subtractInputs[0] = mMainFrame;
      }

      mCopyProgram.setHostValue("center_r", center_r);

      if (null != output && isRenderOutput == false) {
        mCopyProgram.process(subtractInputs, output);
      }
      return true;
    }
    return false;
  }