package pl.droidsonroids.gif;
import android.content.ContentResolver;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.support.annotation.FloatRange;
import android.support.annotation.IntRange;
import android.view.Surface;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
/**
* Native library wrapper
*/
final class GifInfoHandle {
static {
LibraryLoader.loadLibrary(null);
}
/**
* Pointer to native structure. Access must be synchronized, heap corruption may occur otherwise
* when {@link #recycle()} is called during another operation.
*/
private volatile long gifInfoPtr;
GifInfoHandle() {
}
GifInfoHandle(FileDescriptor fd) throws GifIOException {
gifInfoPtr = openFd(fd, 0);
}
GifInfoHandle(byte[] bytes) throws GifIOException {
gifInfoPtr = openByteArray(bytes);
}
GifInfoHandle(ByteBuffer buffer) throws GifIOException {
gifInfoPtr = openDirectByteBuffer(buffer);
}
GifInfoHandle(String filePath) throws GifIOException {
gifInfoPtr = openFile(filePath);
}
GifInfoHandle(InputStream stream) throws GifIOException {
if (!stream.markSupported()) {
throw new IllegalArgumentException("InputStream does not support marking");
}
gifInfoPtr = openStream(stream);
}
GifInfoHandle(AssetFileDescriptor afd) throws IOException {
try {
gifInfoPtr = openFd(afd.getFileDescriptor(), afd.getStartOffset());
} finally {
try {
afd.close();
} catch (IOException ignored) {
//no-op
}
}
}
static GifInfoHandle openUri(ContentResolver resolver, Uri uri) throws IOException {
if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) { //workaround for #128
return new GifInfoHandle(uri.getPath());
}
return new GifInfoHandle(resolver.openAssetFileDescriptor(uri, "r"));
}
static native long openFd(FileDescriptor fd, long offset) throws GifIOException;
static native long openByteArray(byte[] bytes) throws GifIOException;
static native long openDirectByteBuffer(ByteBuffer buffer) throws GifIOException;
static native long openStream(InputStream stream) throws GifIOException;
static native long openFile(String filePath) throws GifIOException;
private static native long renderFrame(long gifFileInPtr, Bitmap frameBuffer);
private static native void bindSurface(long gifInfoPtr, Surface surface, long[] savedState);
private static native void free(long gifFileInPtr);
private static native boolean reset(long gifFileInPtr);
private static native void setSpeedFactor(long gifFileInPtr, float factor);
private static native String getComment(long gifFileInPtr);
private static native int getLoopCount(long gifFileInPtr);
private static native void setLoopCount(long gifFileInPtr, char loopCount);
private static native long getSourceLength(long gifFileInPtr);
private static native int getDuration(long gifFileInPtr);
private static native int getCurrentPosition(long gifFileInPtr);
private static native void seekToTime(long gifFileInPtr, int position, Bitmap buffer);
private static native void seekToFrame(long gifFileInPtr, int frameNr, Bitmap buffer);
private static native void saveRemainder(long gifFileInPtr);
private static native long restoreRemainder(long gifFileInPtr);
private static native long getAllocationByteCount(long gifFileInPtr);
private static native long getMetadataByteCount(long gifFileInPtr);
private static native int getNativeErrorCode(long gifFileInPtr);
private static native int getCurrentFrameIndex(long gifFileInPtr);
private static native int getCurrentLoop(long gifFileInPtr);
private static native void postUnbindSurface(long gifFileInPtr);
private static native boolean isAnimationCompleted(long gifInfoPtr);
private static native long[] getSavedState(long gifInfoPtr);
private static native int restoreSavedState(long gifInfoPtr, long[] savedState, Bitmap mBuffer);
private static native int getFrameDuration(long gifInfoPtr, int index);
private static native void setOptions(long gifInfoPtr, char sampleSize, boolean isOpaque);
private static native int getWidth(long gifFileInPtr);
private static native int getHeight(long gifFileInPtr);
private static native int getNumberOfFrames(long gifInfoPtr);
private static native boolean isOpaque(long gifInfoPtr);
private static native void startDecoderThread(long gifInfoPtr);
private static native void stopDecoderThread(long gifInfoPtr);
private static native void glTexImage2D(long gifInfoPtr, int target, int level);
private static native void glTexSubImage2D(long gifInfoPtr, int target, int level);
private static native void seekToFrameGL(long gifInfoPtr, int index);
private static native void initTexImageDescriptor(long gifInfoPtr);
synchronized long renderFrame(Bitmap frameBuffer) {
return renderFrame(gifInfoPtr, frameBuffer);
}
void bindSurface(Surface surface, long[] savedState) {
bindSurface(gifInfoPtr, surface, savedState);
}
synchronized void recycle() {
free(gifInfoPtr);
gifInfoPtr = 0L;
}
synchronized long restoreRemainder() {
return restoreRemainder(gifInfoPtr);
}
synchronized boolean reset() {
return reset(gifInfoPtr);
}
synchronized void saveRemainder() {
saveRemainder(gifInfoPtr);
}
synchronized String getComment() {
return getComment(gifInfoPtr);
}
synchronized int getLoopCount() {
return getLoopCount(gifInfoPtr);
}
void setLoopCount(@IntRange(from = 0, to = Character.MAX_VALUE) final int loopCount) {
if (loopCount < 0 || loopCount > Character.MAX_VALUE) {
throw new IllegalArgumentException("Loop count of range <0, 65535>");
}
synchronized (this) {
setLoopCount(gifInfoPtr, (char) loopCount);
}
}
synchronized long getSourceLength() {
return getSourceLength(gifInfoPtr);
}
synchronized int getNativeErrorCode() {
return getNativeErrorCode(gifInfoPtr);
}
void setSpeedFactor(@FloatRange(from = 0, fromInclusive = false) float factor) {
if (factor <= 0f || Float.isNaN(factor)) {
throw new IllegalArgumentException("Speed factor is not positive");
}
if (factor < 1f / Integer.MAX_VALUE) {
factor = 1f / Integer.MAX_VALUE;
}
synchronized (this) {
setSpeedFactor(gifInfoPtr, factor);
}
}
synchronized int getDuration() {
return getDuration(gifInfoPtr);
}
synchronized int getCurrentPosition() {
return getCurrentPosition(gifInfoPtr);
}
synchronized int getCurrentFrameIndex() {
return getCurrentFrameIndex(gifInfoPtr);
}
synchronized int getCurrentLoop() {
return getCurrentLoop(gifInfoPtr);
}
synchronized void seekToTime(@IntRange(from = 0, to = Integer.MAX_VALUE) final int position, final Bitmap buffer) {
seekToTime(gifInfoPtr, position, buffer);
}
synchronized void seekToFrame(@IntRange(from = 0, to = Integer.MAX_VALUE) final int frameIndex, final Bitmap buffer) {
seekToFrame(gifInfoPtr, frameIndex, buffer);
}
synchronized long getAllocationByteCount() {
return getAllocationByteCount(gifInfoPtr);
}
synchronized long getMetadataByteCount() {
return getMetadataByteCount(gifInfoPtr);
}
synchronized boolean isRecycled() {
return gifInfoPtr == 0L;
}
@Override
@SuppressWarnings("ThrowFromFinallyBlock")
protected void finalize() throws Throwable {
try {
recycle();
} finally {
super.finalize();
}
}
synchronized void postUnbindSurface() {
postUnbindSurface(gifInfoPtr);
}
synchronized boolean isAnimationCompleted() {
return isAnimationCompleted(gifInfoPtr);
}
synchronized long[] getSavedState() {
return getSavedState(gifInfoPtr);
}
synchronized int restoreSavedState(long[] savedState, Bitmap mBuffer) {
return restoreSavedState(gifInfoPtr, savedState, mBuffer);
}
int getFrameDuration(@IntRange(from = 0) final int index) {
synchronized (this) {
if (index < 0 || index >= getNumberOfFrames(gifInfoPtr)) {
throw new IndexOutOfBoundsException("Frame index is out of bounds");
}
return getFrameDuration(gifInfoPtr, index);
}
}
void setOptions(char sampleSize, boolean isOpaque) {
setOptions(gifInfoPtr, sampleSize, isOpaque);
}
synchronized int getWidth() {
return getWidth(gifInfoPtr);
}
synchronized int getHeight() {
return getHeight(gifInfoPtr);
}
synchronized int getNumberOfFrames() {
return getNumberOfFrames(gifInfoPtr);
}
synchronized boolean isOpaque() {
return isOpaque(gifInfoPtr);
}
void glTexImage2D(int target, int level) {
glTexImage2D(gifInfoPtr, target, level);
}
void glTexSubImage2D(int target, int level) {
glTexSubImage2D(gifInfoPtr, target, level);
}
void startDecoderThread() {
startDecoderThread(gifInfoPtr);
}
void stopDecoderThread() {
stopDecoderThread(gifInfoPtr);
}
void initTexImageDescriptor() {
initTexImageDescriptor(gifInfoPtr);
}
void seekToFrameGL(@IntRange(from = 0) final int index) {
if (index < 0 || index >= getNumberOfFrames(gifInfoPtr)) {
throw new IndexOutOfBoundsException("Frame index is out of bounds");
}
seekToFrameGL(gifInfoPtr, index);
}
}