Movie を使うとアニメーション Gif を表示できるのですが、まぁバグがあるとかなんとかは自分でぐぐってください。
よくあるサンプルは assets や raw にある Gif を読むやつばっかりです。
- InputStream is = context.getResources().openRawResource(R.drawable.piggy);
- Movie movie = Movie.decodeStream(is);
InputStream is = context.getResources().openRawResource(R.drawable.piggy);
Movie movie = Movie.decodeStream(is);
http://androidosbeginning.blogspot.jp/2010/09/gif-animation-in-android.html
とか
- InputStream is = context.getAssets().open("piggy.gif");
- Movie movie = Movie.decodeStream(is);
InputStream is = context.getAssets().open("piggy.gif");
Movie movie = Movie.decodeStream(is);
とか
SD にある Gif ファイルから読もうとして
- try {
- InputStream is = new FileInputStream(filePath);
- Movie movie = Movie.decodeStream(is);
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- }
try {
InputStream is = new FileInputStream(filePath);
Movie movie = Movie.decodeStream(is);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
とすると Native 側で IOException が起こって表示されません。
LogCat で
09-19 15:38:37.828: W/System.err(7523): java.io.IOException
09-19 15:38:37.828: W/System.err(7523): at java.io.InputStream.reset(InputStream.java:218)
09-19 15:38:37.828: W/System.err(7523): at android.graphics.Movie.decodeStream(Native Method)
と出ていて、どうも InputStream の reset() で起こっていると。
InputStream のコードをみると、サブクラスが Override しないかぎり IOException が投げられるようになっています。
http://tools.oesf.biz/android-4.0.1_r1.0/xref/libcore/luni/src/main/java/java/io/InputStream.java#217
- 217 public synchronized void reset() throws IOException {
- 218 throw new IOException();
- 219 }
217 public synchronized void reset() throws IOException {
218 throw new IOException();
219 }
FileInputStream は Override してませんでした。
http://tools.oesf.biz/android-4.0.1_r1.0/xref/libcore/luni/src/main/java/java/io/FileInputStream.java
AssetManager の open() で返ってくる InputStream は AssetInputStream です。
http://tools.oesf.biz/android-4.0.1_r1.0/xref/frameworks/base/core/java/android/content/res/AssetManager.java#288
- 288 public final InputStream open(String fileName) throws IOException {
- 289 return open(fileName, ACCESS_STREAMING);
- 290 }
-
- 309 public final InputStream open(String fileName, int accessMode)
- 310 throws IOException {
- 311 synchronized (this) {
- 312 if (!mOpen) {
- 313 throw new RuntimeException("Assetmanager has been closed");
- 314 }
- 315 int asset = openAsset(fileName, accessMode);
- 316 if (asset != 0) {
- 317 AssetInputStream res = new AssetInputStream(asset);
- 318 incRefsLocked(res.hashCode());
- 319 return res;
- 320 }
- 321 }
- 322 throw new FileNotFoundException("Asset file: " + fileName);
- 323 }
288 public final InputStream open(String fileName) throws IOException {
289 return open(fileName, ACCESS_STREAMING);
290 }
...
309 public final InputStream open(String fileName, int accessMode)
310 throws IOException {
311 synchronized (this) {
312 if (!mOpen) {
313 throw new RuntimeException("Assetmanager has been closed");
314 }
315 int asset = openAsset(fileName, accessMode);
316 if (asset != 0) {
317 AssetInputStream res = new AssetInputStream(asset);
318 incRefsLocked(res.hashCode());
319 return res;
320 }
321 }
322 throw new FileNotFoundException("Asset file: " + fileName);
323 }
この AssetInputStream は reset() を Override しています。
http://tools.oesf.biz/android-4.0.1_r1.0/xref/frameworks/base/core/java/android/content/res/AssetManager.java#538
- 538 public final class AssetInputStream extends InputStream {
-
- 569 public final void reset() throws IOException {
- 570 seekAsset(mAsset, mMarkPos, -1);
- 571 }
-
- 597 }
538 public final class AssetInputStream extends InputStream {
...
569 public final void reset() throws IOException {
570 seekAsset(mAsset, mMarkPos, -1);
571 }
...
597 }
InputStream のサブクラスで reset() を継承しているクラスとして
BufferedInputStream があります。
このクラスを使って、次のようにすると IOException が発生せずに読むことができます。
- try {
- InputStream stream = new BufferedInputStream(
- new FileInputStream(filePath), 16 * 1024);
- stream.mark(16 * 1024);
- mMovie = Movie.decodeStream(stream);
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- }
try {
InputStream stream = new BufferedInputStream(
new FileInputStream(filePath), 16 * 1024);
stream.mark(16 * 1024);
mMovie = Movie.decodeStream(stream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
ポイントは mark() メソッドを呼ぶ必要がある点です。
ちなみに Movie には deocdeFile() というメソッドもあるのですが、なかみは FileInputStream 使ってるだけなので、使えません。。。
http://tools.oesf.biz/android-4.0.1_r1.0/xref/frameworks/base/graphics/java/android/graphics/Movie.java#51
- 51 public static Movie decodeFile(String pathName) {
- 52 InputStream is;
- 53 try {
- 54 is = new FileInputStream(pathName);
- 55 }
- 56 catch (java.io.FileNotFoundException e) {
- 57 return null;
- 58 }
- 59 return decodeTempStream(is);
- 60 }
51 public static Movie decodeFile(String pathName) {
52 InputStream is;
53 try {
54 is = new FileInputStream(pathName);
55 }
56 catch (java.io.FileNotFoundException e) {
57 return null;
58 }
59 return decodeTempStream(is);
60 }
おまけ
Movie.cpp
http://tools.oesf.biz/android-4.0.1_r1.0/xref/frameworks/base/core/jni/android/graphics/Movie.cpp#82
- 82 static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) {
- 83
- 84 NPE_CHECK_RETURN_ZERO(env, istream);
- 85
- 86
- 87 jbyteArray byteArray = env->NewByteArray(16*1024);
- 88 SkStream* strm = CreateJavaInputStreamAdaptor(env, istream, byteArray);
- 89 if (NULL == strm) {
- 90 return 0;
- 91 }
- 92
- 93 SkMovie* moov = SkMovie::DecodeStream(strm);
- 94 strm->unref();
- 95 return create_jmovie(env, moov);
- 96 }
82 static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) {
83
84 NPE_CHECK_RETURN_ZERO(env, istream);
85
86 // what is the lifetime of the array? Can the skstream hold onto it?
87 jbyteArray byteArray = env->NewByteArray(16*1024);
88 SkStream* strm = CreateJavaInputStreamAdaptor(env, istream, byteArray);
89 if (NULL == strm) {
90 return 0;
91 }
92
93 SkMovie* moov = SkMovie::DecodeStream(strm);
94 strm->unref();
95 return create_jmovie(env, moov);
96 }
http://tools.oesf.biz/android-4.0.1_r1.0/xref/frameworks/base/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp#CreateJavaInputStreamAdaptor
- 12 class JavaInputStreamAdaptor : public SkStream {
- 13 public:
- 14 JavaInputStreamAdaptor(JNIEnv* env, jobject js, jbyteArray ar)
- 15 : fEnv(env), fJavaInputStream(js), fJavaByteArray(ar) {
- 16 SkASSERT(ar);
- 17 fCapacity = env->GetArrayLength(ar);
- 18 SkASSERT(fCapacity > 0);
- 19 fBytesRead = 0;
- 20 }
- 21
- 22 virtual bool rewind() {
- 23 JNIEnv* env = fEnv;
- 24
- 25 fBytesRead = 0;
- 26
- 27 env->CallVoidMethod(fJavaInputStream, gInputStream_resetMethodID);
- 28 if (env->ExceptionCheck()) {
- 29 env->ExceptionDescribe();
- 30 env->ExceptionClear();
- 31 SkDebugf("------- reset threw an exception\n");
- 32 return false;
- 33 }
- 34 return true;
- 35 }
- ...
- 145 SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
- 146 jbyteArray storage, int markSize) {
- 147 static bool gInited;
- 148
- 149 if (!gInited) {
- 150 jclass inputStream_Clazz = env->FindClass("java/io/InputStream");
- 151 RETURN_NULL_IF_NULL(inputStream_Clazz);
- 152
- 153 gInputStream_resetMethodID = env->GetMethodID(inputStream_Clazz,
- 154 "reset", "()V");
- 155 gInputStream_markMethodID = env->GetMethodID(inputStream_Clazz,
- 156 "mark", "(I)V");
- 157 gInputStream_availableMethodID = env->GetMethodID(inputStream_Clazz,
- 158 "available", "()I");
- 159 gInputStream_readMethodID = env->GetMethodID(inputStream_Clazz,
- 160 "read", "([BII)I");
- 161 gInputStream_skipMethodID = env->GetMethodID(inputStream_Clazz,
- 162 "skip", "(J)J");
- 163
- 164 RETURN_NULL_IF_NULL(gInputStream_resetMethodID);
- 165 RETURN_NULL_IF_NULL(gInputStream_markMethodID);
- 166 RETURN_NULL_IF_NULL(gInputStream_availableMethodID);
- 167 RETURN_NULL_IF_NULL(gInputStream_availableMethodID);
- 168 RETURN_NULL_IF_NULL(gInputStream_skipMethodID);
- 169
- 170 gInited = true;
- 171 }
- 172
- 173 if (markSize) {
- 174 env->CallVoidMethod(stream, gInputStream_markMethodID, markSize);
- 175 }
- 176
- 177 return new JavaInputStreamAdaptor(env, stream, storage);
- 178 }
12 class JavaInputStreamAdaptor : public SkStream {
13 public:
14 JavaInputStreamAdaptor(JNIEnv* env, jobject js, jbyteArray ar)
15 : fEnv(env), fJavaInputStream(js), fJavaByteArray(ar) {
16 SkASSERT(ar);
17 fCapacity = env->GetArrayLength(ar);
18 SkASSERT(fCapacity > 0);
19 fBytesRead = 0;
20 }
21
22 virtual bool rewind() {
23 JNIEnv* env = fEnv;
24
25 fBytesRead = 0;
26
27 env->CallVoidMethod(fJavaInputStream, gInputStream_resetMethodID);
28 if (env->ExceptionCheck()) {
29 env->ExceptionDescribe();
30 env->ExceptionClear();
31 SkDebugf("------- reset threw an exception\n");
32 return false;
33 }
34 return true;
35 }
...
145 SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
146 jbyteArray storage, int markSize) {
147 static bool gInited;
148
149 if (!gInited) {
150 jclass inputStream_Clazz = env->FindClass("java/io/InputStream");
151 RETURN_NULL_IF_NULL(inputStream_Clazz);
152
153 gInputStream_resetMethodID = env->GetMethodID(inputStream_Clazz,
154 "reset", "()V");
155 gInputStream_markMethodID = env->GetMethodID(inputStream_Clazz,
156 "mark", "(I)V");
157 gInputStream_availableMethodID = env->GetMethodID(inputStream_Clazz,
158 "available", "()I");
159 gInputStream_readMethodID = env->GetMethodID(inputStream_Clazz,
160 "read", "([BII)I");
161 gInputStream_skipMethodID = env->GetMethodID(inputStream_Clazz,
162 "skip", "(J)J");
163
164 RETURN_NULL_IF_NULL(gInputStream_resetMethodID);
165 RETURN_NULL_IF_NULL(gInputStream_markMethodID);
166 RETURN_NULL_IF_NULL(gInputStream_availableMethodID);
167 RETURN_NULL_IF_NULL(gInputStream_availableMethodID);
168 RETURN_NULL_IF_NULL(gInputStream_skipMethodID);
169
170 gInited = true;
171 }
172
173 if (markSize) {
174 env->CallVoidMethod(stream, gInputStream_markMethodID, markSize);
175 }
176
177 return new JavaInputStreamAdaptor(env, stream, storage);
178 }