2 * Copyright (C) 2011 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package android.filterfw.core;
20 import android.filterfw.core.Frame;
21 import android.filterfw.core.FrameFormat;
22 import android.filterfw.core.SimpleFrameManager;
25 import java.util.SortedMap;
26 import java.util.TreeMap;
28 import android.util.Log;
33 public class CachedFrameManager extends SimpleFrameManager {
35 private SortedMap<Integer, Frame> mAvailableFrames;
36 private int mStorageCapacity = 24 * 1024 * 1024; // Cap default storage to 24MB
37 private int mStorageSize = 0;
38 private int mTimeStamp = 0;
40 public CachedFrameManager() {
42 mAvailableFrames = new TreeMap<Integer, Frame>();
46 public Frame newFrame(FrameFormat format) {
47 Frame result = findAvailableFrame(format, Frame.NO_BINDING, 0);
49 result = super.newFrame(format);
51 result.setTimestamp(Frame.TIMESTAMP_NOT_SET);
56 public Frame newBoundFrame(FrameFormat format, int bindingType, long bindingId) {
57 Frame result = findAvailableFrame(format, bindingType, bindingId);
59 result = super.newBoundFrame(format, bindingType, bindingId);
61 result.setTimestamp(Frame.TIMESTAMP_NOT_SET);
66 public Frame retainFrame(Frame frame) {
67 return super.retainFrame(frame);
71 public Frame releaseFrame(Frame frame) {
72 if (frame.isReusable()) {
73 int refCount = frame.decRefCount();
75 if (!storeFrame(frame)) {
79 } else if (refCount < 0) {
80 throw new RuntimeException("Frame reference count dropped below 0!");
83 super.releaseFrame(frame);
88 private boolean storeFrame(Frame frame) {
89 synchronized(mAvailableFrames) {
90 // Make sure this frame alone does not exceed capacity
91 int frameSize = frame.getFormat().getSize();
92 if (frameSize > mStorageCapacity) {
96 // Drop frames if adding this frame would exceed capacity
97 int newStorageSize = mStorageSize + frameSize;
98 while (newStorageSize > mStorageCapacity) {
100 newStorageSize = mStorageSize + frameSize;
104 mStorageSize = newStorageSize;
105 mAvailableFrames.put(mTimeStamp, frame);
111 private void dropOldestFrame() {
112 int oldest = mAvailableFrames.firstKey();
113 Frame frame = mAvailableFrames.get(oldest);
114 mStorageSize -= frame.getFormat().getSize();
116 mAvailableFrames.remove(oldest);
119 private Frame findAvailableFrame(FrameFormat format, int bindingType, long bindingId) {
120 // Look for a frame that is compatible with the requested format
121 synchronized(mAvailableFrames) {
122 for (Map.Entry<Integer, Frame> entry : mAvailableFrames.entrySet()) {
123 Frame frame = entry.getValue();
124 // Check that format is compatible
125 if (frame.getFormat().isReplaceableBy(format)) {
126 // Check that binding is compatible (if frame is bound)
127 if (bindingType == Frame.NO_BINDING
128 || (bindingId == frame.getBindingId()
129 && bindingType == frame.getBindingType())) {
130 // We found one! Take it out of the set of available frames and attach the
131 // requested format to it.
132 super.retainFrame(frame);
133 mAvailableFrames.remove(entry.getKey());
135 mStorageSize -= format.getSize();