1b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar/*
2b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar * Copyright (C) 2015 The Android Open Source Project
3b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar *
4b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar * Licensed under the Apache License, Version 2.0 (the "License");
5b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar * you may not use this file except in compliance with the License.
6b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar * You may obtain a copy of the License at
7b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar *
8b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar *      http://www.apache.org/licenses/LICENSE-2.0
9b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar *
10b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar * Unless required by applicable law or agreed to in writing, software
11b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar * distributed under the License is distributed on an "AS IS" BASIS,
12b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar * See the License for the specific language governing permissions and
14b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar * limitations under the License.
15b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar */
16b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar
17b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekharpackage com.android.camera.burst;
18b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar
19b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekharimport android.support.v4.util.LongSparseArray;
20b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar
21b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekharimport com.android.camera.async.SafeCloseable;
22b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekharimport com.android.camera.one.v2.camera2proxy.ImageProxy;
23b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar
24b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekharimport java.util.ArrayList;
25b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekharimport java.util.List;
26b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar
27b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar/**
28b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar * A RingBuffer that is used during burst capture. It takes a
29b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar * {@link EvictionHandler} instance and uses it to evict frames when the ring
30b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar * buffer runs out of capacity.
31b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar */
32f6031c016d916db9789026dc0a6c559d8163a088Spike Spragueclass RingBuffer<T extends ImageProxy> implements SafeCloseable {
33b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar    private final int mMaxCapacity;
34b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar    private final EvictionHandler mEvictionHandler;
35f6031c016d916db9789026dc0a6c559d8163a088Spike Sprague    private final LongSparseArray<T> mImages = new LongSparseArray<>();
36b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar
37b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar    /**
38b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar     * Create a new ring buffer instance.
39b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar     *
40b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar     * @param maxCapacity the maximum number of images in the ring buffer.
41b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar     * @param evictionHandler
42b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar     */
43b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar    public RingBuffer(int maxCapacity, EvictionHandler evictionHandler) {
44b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        mMaxCapacity = maxCapacity;
45b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        mEvictionHandler = evictionHandler;
46b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar    }
47b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar
48b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar    /**
49b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar     * Insert an image in the ring buffer, evicting any frames if necessary.
50b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar     *
51b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar     * @param image the image to be inserted.
52b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar     */
53f6031c016d916db9789026dc0a6c559d8163a088Spike Sprague    public synchronized void insertImage(T image) {
54b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        long timestamp = image.getTimestamp();
55b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        if (mImages.get(timestamp) != null) {
56b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar            image.close();
57b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar            return;
58b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        }
59b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        // Add image to ring buffer so it can be closed in case eviction
60b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        // handler throws.
61b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        addImage(image);
62b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        mEvictionHandler.onFrameInserted(timestamp);
63b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        if (mImages.size() > mMaxCapacity) {
64b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar            long selectFrameToDrop = mEvictionHandler.selectFrameToDrop();
65b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar            removeAndCloseImage(selectFrameToDrop);
66b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar            mEvictionHandler.onFrameDropped(selectFrameToDrop);
67b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        }
68b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar    }
69b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar
70b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar    /**
71b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar     * Returns all images present in the ring buffer.
72b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar     */
73f6031c016d916db9789026dc0a6c559d8163a088Spike Sprague    public synchronized List<T> getAndRemoveAllImages() {
74f6031c016d916db9789026dc0a6c559d8163a088Spike Sprague        List<T> allImages = new ArrayList<>(mImages.size());
75b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        for (int i = 0; i < mImages.size(); i++) {
76b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar            allImages.add(mImages.valueAt(i));
77b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        }
78b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        mImages.clear();
79b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        return allImages;
80b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar    }
81b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar
82b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar    /**
83b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar     * Closes the ring buffer and any images in the ring buffer.
84b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar     */
85b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar    @Override
86b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar    public synchronized void close() {
87b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        for (int i = 0; i < mImages.size(); i++) {
88b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar            mImages.valueAt(i).close();
89b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        }
90b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        mImages.clear();
91b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar    }
92b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar
93b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar    private synchronized void removeAndCloseImage(long timestampNs) {
94f6031c016d916db9789026dc0a6c559d8163a088Spike Sprague        mImages.get(timestampNs).close();
95b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        mImages.remove(timestampNs);
96b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar    }
97b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar
98f6031c016d916db9789026dc0a6c559d8163a088Spike Sprague    private synchronized void addImage(T image) {
99b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar        mImages.put(image.getTimestamp(), image);
100b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar    }
101b4b27f2c7738cd5e3f31a281d66a33f4698810b3Shashi Shekhar}
102