blob: d2bd128dbcf1a1536b7e56c0458cf743e1e32c45 [file] [log] [blame]
Chris Craika3ac0a22014-01-06 12:43:42 -08001/*
2 * Copyright (C) 2013 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
17package android.support.rastermill;
18
19import android.graphics.Bitmap;
20
21import java.io.InputStream;
22
23public class FrameSequence {
24 static {
25 System.loadLibrary("framesequence");
26 }
27
Chris Craike36c5d62014-01-13 19:37:04 -080028 private final long mNativeFrameSequence;
Chris Craika3ac0a22014-01-06 12:43:42 -080029 private final int mWidth;
30 private final int mHeight;
Chris Craika3ac0a22014-01-06 12:43:42 -080031 private final boolean mOpaque;
Chris Craike36c5d62014-01-13 19:37:04 -080032 private final int mFrameCount;
33 private final int mDefaultLoopCount;
Chris Craika3ac0a22014-01-06 12:43:42 -080034
35 public int getWidth() { return mWidth; }
36 public int getHeight() { return mHeight; }
Chris Craika3ac0a22014-01-06 12:43:42 -080037 public boolean isOpaque() { return mOpaque; }
Chris Craike36c5d62014-01-13 19:37:04 -080038 public int getFrameCount() { return mFrameCount; }
39 public int getDefaultLoopCount() { return mDefaultLoopCount; }
Chris Craika3ac0a22014-01-06 12:43:42 -080040
41 private static native FrameSequence nativeDecodeByteArray(byte[] data, int offset, int length);
42 private static native FrameSequence nativeDecodeStream(InputStream is, byte[] tempStorage);
Chris Craike36c5d62014-01-13 19:37:04 -080043 private static native void nativeDestroyFrameSequence(long nativeFrameSequence);
44 private static native long nativeCreateState(long nativeFrameSequence);
45 private static native void nativeDestroyState(long nativeState);
46 private static native long nativeGetFrame(long nativeState, int frameNr,
Chris Craika3ac0a22014-01-06 12:43:42 -080047 Bitmap output, int previousFrameNr);
48
49 @SuppressWarnings("unused") // called by native
Chris Craike36c5d62014-01-13 19:37:04 -080050 private FrameSequence(long nativeFrameSequence, int width, int height,
51 boolean opaque, int frameCount, int defaultLoopCount) {
Chris Craika3ac0a22014-01-06 12:43:42 -080052 mNativeFrameSequence = nativeFrameSequence;
53 mWidth = width;
54 mHeight = height;
Chris Craika3ac0a22014-01-06 12:43:42 -080055 mOpaque = opaque;
Chris Craike36c5d62014-01-13 19:37:04 -080056 mFrameCount = frameCount;
57 mDefaultLoopCount = defaultLoopCount;
Chris Craika3ac0a22014-01-06 12:43:42 -080058 }
59
60 public static FrameSequence decodeByteArray(byte[] data) {
61 return decodeByteArray(data, 0, data.length);
62 }
63
64 public static FrameSequence decodeByteArray(byte[] data, int offset, int length) {
65 if (data == null) throw new IllegalArgumentException();
66 if (offset < 0 || length < 0 || (offset + length > data.length)) {
67 throw new IllegalArgumentException("invalid offset/length parameters");
68 }
69 return nativeDecodeByteArray(data, offset, length);
70 }
71
72 public static FrameSequence decodeStream(InputStream stream) {
73 if (stream == null) throw new IllegalArgumentException();
74 byte[] tempStorage = new byte[16 * 1024]; // TODO: use buffer pool
75 return nativeDecodeStream(stream, tempStorage);
76 }
77
78 State createState() {
79 if (mNativeFrameSequence == 0) {
80 throw new IllegalStateException("attempted to use incorrectly built FrameSequence");
81 }
82
Chris Craike36c5d62014-01-13 19:37:04 -080083 long nativeState = nativeCreateState(mNativeFrameSequence);
Chris Craika3ac0a22014-01-06 12:43:42 -080084 if (nativeState == 0) {
85 return null;
86 }
87 return new State(nativeState);
88 }
89
90 @Override
91 protected void finalize() throws Throwable {
92 try {
93 if (mNativeFrameSequence != 0) nativeDestroyFrameSequence(mNativeFrameSequence);
94 } finally {
95 super.finalize();
96 }
97 }
98
99 /**
100 * Playback state used when moving frames forward in a frame sequence.
101 *
102 * Note that this doesn't require contiguous frames to be rendered, it just stores
103 * information (in the case of gif, a recall buffer) that will be used to construct
104 * frames based upon data recorded before previousFrameNr.
105 *
Chris Craik4eb541a2014-04-23 15:06:06 -0700106 * Note: {@link #destroy()} *must* be called before the object is GC'd to free native resources
Chris Craika3ac0a22014-01-06 12:43:42 -0800107 *
108 * Note: State holds a native ref to its FrameSequence instance, so its FrameSequence should
109 * remain ref'd while it is in use
110 */
111 static class State {
Chris Craike36c5d62014-01-13 19:37:04 -0800112 private long mNativeState;
Chris Craika3ac0a22014-01-06 12:43:42 -0800113
Chris Craike36c5d62014-01-13 19:37:04 -0800114 public State(long nativeState) {
Chris Craika3ac0a22014-01-06 12:43:42 -0800115 mNativeState = nativeState;
116 }
117
Chris Craik4eb541a2014-04-23 15:06:06 -0700118 public void destroy() {
Chris Craika3ac0a22014-01-06 12:43:42 -0800119 if (mNativeState != 0) {
120 nativeDestroyState(mNativeState);
121 mNativeState = 0;
122 }
123 }
124
125 // TODO: consider adding alternate API for drawing into a SurfaceTexture
126 public long getFrame(int frameNr, Bitmap output, int previousFrameNr) {
127 if (output == null || output.getConfig() != Bitmap.Config.ARGB_8888) {
128 throw new IllegalArgumentException("Bitmap passed must be non-null and ARGB_8888");
129 }
130 if (mNativeState == 0) {
Chris Craik4eb541a2014-04-23 15:06:06 -0700131 throw new IllegalStateException("attempted to draw destroyed FrameSequenceState");
Chris Craika3ac0a22014-01-06 12:43:42 -0800132 }
133 return nativeGetFrame(mNativeState, frameNr, output, previousFrameNr);
134 }
135 }
Chris Craika3ac0a22014-01-06 12:43:42 -0800136}