content: /*
   * 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 android.filterfw.core;
  
  import android.annotation.UnsupportedAppUsage;
  import android.filterfw.core.FrameFormat;
  import android.filterfw.core.FrameManager;
  import android.graphics.Bitmap;
  
  import java.nio.ByteBuffer;
  
  /**
   * @hide
   */
  public abstract class Frame {
  
      public final static int NO_BINDING = 0;
  
      public final static long TIMESTAMP_NOT_SET = -2;
      public final static long TIMESTAMP_UNKNOWN = -1;
  
      private FrameFormat mFormat;
      private FrameManager mFrameManager;
      private boolean mReadOnly = false;
      private boolean mReusable = false;
      private int mRefCount = 1;
      private int mBindingType = NO_BINDING;
      private long mBindingId = 0;
      private long mTimestamp = TIMESTAMP_NOT_SET;
  
      Frame(FrameFormat format, FrameManager frameManager) {
          mFormat = format.mutableCopy();
          mFrameManager = frameManager;
      }
  
      Frame(FrameFormat format, FrameManager frameManager, int bindingType, long bindingId) {
          mFormat = format.mutableCopy();
          mFrameManager = frameManager;
          mBindingType = bindingType;
          mBindingId = bindingId;
      }
  
      @UnsupportedAppUsage
      public FrameFormat getFormat() {
          return mFormat;
      }
  
      public int getCapacity() {
          return getFormat().getSize();
      }
  
      public boolean isReadOnly() {
          return mReadOnly;
      }
  
      public int getBindingType() {
          return mBindingType;
      }
  
      public long getBindingId() {
          return mBindingId;
      }
  
      public void setObjectValue(Object object) {
          assertFrameMutable();
  
          // Attempt to set the value using a specific setter (which may be more optimized), and
          // fall back to the setGenericObjectValue(...) in case of no match.
          if (object instanceof int[]) {
              setInts((int[])object);
          } else if (object instanceof float[]) {
              setFloats((float[])object);
          } else if (object instanceof ByteBuffer) {
              setData((ByteBuffer)object);
          } else if (object instanceof Bitmap) {
              setBitmap((Bitmap)object);
          } else {
              setGenericObjectValue(object);
          }
      }
  
      public abstract Object getObjectValue();
  
      @UnsupportedAppUsage
      public abstract void setInts(int[] ints);
  
      public abstract int[] getInts();
  
      public abstract void setFloats(float[] floats);
  
      public abstract float[] getFloats();
  
      public abstract void setData(ByteBuffer buffer, int offset, int length);
  
      public void setData(ByteBuffer buffer) {
          setData(buffer, 0, buffer.limit());
      }
  
      public void setData(byte[] bytes, int offset, int length) {
          setData(ByteBuffer.wrap(bytes, offset, length));
      }
  
      public abstract ByteBuffer getData();
  
      public abstract void setBitmap(Bitmap bitmap);
  
      @UnsupportedAppUsage
      public abstract Bitmap getBitmap();
  
      @UnsupportedAppUsage
      public void setTimestamp(long timestamp) {
          mTimestamp = timestamp;
      }
  
      @UnsupportedAppUsage
      public long getTimestamp() {
          return mTimestamp;
      }
  
      public void setDataFromFrame(Frame frame) {
          setData(frame.getData());
      }
  
      protected boolean requestResize(int[] newDimensions) {
          return false;
      }
  
      public int getRefCount() {
          return mRefCount;
      }
  
      @UnsupportedAppUsage
      public Frame release() {
          if (mFrameManager != null) {
              return mFrameManager.releaseFrame(this);
          } else {
              return this;
          }
      }
  
      public Frame retain() {
          if (mFrameManager != null) {
              return mFrameManager.retainFrame(this);
          } else {
              return this;
          }
      }
  
      public FrameManager getFrameManager() {
          return mFrameManager;
      }
  
      protected void assertFrameMutable() {
          if (isReadOnly()) {
              throw new RuntimeException("Attempting to modify read-only frame!");
          }
      }
  
      protected void setReusable(boolean reusable) {
          mReusable = reusable;
      }
  
      protected void setFormat(FrameFormat format) {
          mFormat = format.mutableCopy();
      }
  
      protected void setGenericObjectValue(Object value) {
          throw new RuntimeException(
              "Cannot set object value of unsupported type: " + value.getClass());
      }
  
      protected static Bitmap convertBitmapToRGBA(Bitmap bitmap) {
          if (bitmap.getConfig() == Bitmap.Config.ARGB_8888) {
              return bitmap;
          } else {
              Bitmap result = bitmap.copy(Bitmap.Config.ARGB_8888, false);
              if (result == null) {
                  throw new RuntimeException("Error converting bitmap to RGBA!");
              } else if (result.getRowBytes() != result.getWidth() * 4) {
                  throw new RuntimeException("Unsupported row byte count in bitmap!");
              }
              return result;
          }
      }
  
      protected void reset(FrameFormat newFormat) {
          mFormat = newFormat.mutableCopy();
          mReadOnly = false;
          mRefCount = 1;
      }
  
      /**
       * Called just before a frame is stored, such as when storing to a cache or context.
       */
      protected void onFrameStore() {
      }
  
      /**
       * Called when a frame is fetched from an internal store such as a cache.
       */
      protected void onFrameFetch() {
      }
  
      // Core internal methods ///////////////////////////////////////////////////////////////////////
      protected abstract boolean hasNativeAllocation();
  
      protected abstract void releaseNativeAllocation();
  
      final int incRefCount() {
          ++mRefCount;
          return mRefCount;
      }
  
      final int decRefCount() {
          --mRefCount;
          return mRefCount;
      }
  
      final boolean isReusable() {
          return mReusable;
      }
  
      final void markReadOnly() {
          mReadOnly = true;
      }
  
  }
  