Movie.cpp revision dcaf5593ddbfe8e1cacaf07813b1e827ba4dba8c
1#include "ScopedLocalRef.h"
2#include "SkFrontBufferedStream.h"
3#include "SkMovie.h"
4#include "SkStream.h"
5#include "GraphicsJNI.h"
6#include "SkTemplates.h"
7#include "SkUtils.h"
8#include "Utils.h"
9#include "CreateJavaOutputStreamAdaptor.h"
10
11#include <androidfw/Asset.h>
12#include <androidfw/ResourceTypes.h>
13#include <netinet/in.h>
14
15#if 0
16    #define TRACE_BITMAP(code)  code
17#else
18    #define TRACE_BITMAP(code)
19#endif
20
21static jclass       gMovie_class;
22static jmethodID    gMovie_constructorMethodID;
23static jfieldID     gMovie_nativeInstanceID;
24
25jobject create_jmovie(JNIEnv* env, SkMovie* moov) {
26    if (NULL == moov) {
27        return NULL;
28    }
29    return env->NewObject(gMovie_class, gMovie_constructorMethodID,
30            static_cast<jlong>(reinterpret_cast<uintptr_t>(moov)));
31}
32
33static SkMovie* J2Movie(JNIEnv* env, jobject movie) {
34    SkASSERT(env);
35    SkASSERT(movie);
36    SkASSERT(env->IsInstanceOf(movie, gMovie_class));
37    SkMovie* m = (SkMovie*)env->GetLongField(movie, gMovie_nativeInstanceID);
38    SkASSERT(m);
39    return m;
40}
41
42///////////////////////////////////////////////////////////////////////////////
43
44static jint movie_width(JNIEnv* env, jobject movie) {
45    NPE_CHECK_RETURN_ZERO(env, movie);
46    return static_cast<jint>(J2Movie(env, movie)->width());
47}
48
49static jint movie_height(JNIEnv* env, jobject movie) {
50    NPE_CHECK_RETURN_ZERO(env, movie);
51    return static_cast<jint>(J2Movie(env, movie)->height());
52}
53
54static jboolean movie_isOpaque(JNIEnv* env, jobject movie) {
55    NPE_CHECK_RETURN_ZERO(env, movie);
56    return J2Movie(env, movie)->isOpaque() ? JNI_TRUE : JNI_FALSE;
57}
58
59static jint movie_duration(JNIEnv* env, jobject movie) {
60    NPE_CHECK_RETURN_ZERO(env, movie);
61    return static_cast<jint>(J2Movie(env, movie)->duration());
62}
63
64static jboolean movie_setTime(JNIEnv* env, jobject movie, jint ms) {
65    NPE_CHECK_RETURN_ZERO(env, movie);
66    return J2Movie(env, movie)->setTime(ms) ? JNI_TRUE : JNI_FALSE;
67}
68
69static void movie_draw(JNIEnv* env, jobject movie, jobject canvas,
70                       jfloat fx, jfloat fy, jobject jpaint) {
71    NPE_CHECK_RETURN_VOID(env, movie);
72    NPE_CHECK_RETURN_VOID(env, canvas);
73    // its OK for paint to be null
74
75    SkMovie* m = J2Movie(env, movie);
76    SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas);
77    SkScalar sx = SkFloatToScalar(fx);
78    SkScalar sy = SkFloatToScalar(fy);
79    const SkBitmap& b = m->bitmap();
80    const SkPaint* p = jpaint ? GraphicsJNI::getNativePaint(env, jpaint) : NULL;
81
82    c->drawBitmap(b, sx, sy, p);
83}
84
85static jobject movie_decodeAsset(JNIEnv* env, jobject clazz, jlong native_asset) {
86    android::Asset* asset = reinterpret_cast<android::Asset*>(native_asset);
87    if (asset == NULL) return NULL;
88    SkAutoTUnref<SkStreamRewindable> stream (new android::AssetStreamAdaptor(asset));
89    SkMovie* moov = SkMovie::DecodeStream(stream.get());
90    return create_jmovie(env, moov);
91}
92
93static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) {
94
95    NPE_CHECK_RETURN_ZERO(env, istream);
96
97    jbyteArray byteArray = env->NewByteArray(16*1024);
98    ScopedLocalRef<jbyteArray> scoper(env, byteArray);
99    SkStream* strm = CreateJavaInputStreamAdaptor(env, istream, byteArray);
100    if (NULL == strm) {
101        return 0;
102    }
103
104    // Need to buffer enough input to be able to rewind as much as might be read by a decoder
105    // trying to determine the stream's format. The only decoder for movies is GIF, which
106    // will only read 6.
107    // FIXME: Get this number from SkImageDecoder
108    SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(strm, 6));
109    SkASSERT(bufferedStream.get() != NULL);
110
111    SkMovie* moov = SkMovie::DecodeStream(bufferedStream);
112    strm->unref();
113    return create_jmovie(env, moov);
114}
115
116static jobject movie_decodeByteArray(JNIEnv* env, jobject clazz,
117                                     jbyteArray byteArray,
118                                     jint offset, jint length) {
119
120    NPE_CHECK_RETURN_ZERO(env, byteArray);
121
122    int totalLength = env->GetArrayLength(byteArray);
123    if ((offset | length) < 0 || offset + length > totalLength) {
124        doThrowAIOOBE(env);
125        return 0;
126    }
127
128    AutoJavaByteArray   ar(env, byteArray);
129    SkMovie* moov = SkMovie::DecodeMemory(ar.ptr() + offset, length);
130    return create_jmovie(env, moov);
131}
132
133static void movie_destructor(JNIEnv* env, jobject, jlong movieHandle) {
134    SkMovie* movie = (SkMovie*) movieHandle;
135    delete movie;
136}
137
138//////////////////////////////////////////////////////////////////////////////////////////////
139
140#include <android_runtime/AndroidRuntime.h>
141
142static JNINativeMethod gMethods[] = {
143    {   "width",    "()I",  (void*)movie_width  },
144    {   "height",   "()I",  (void*)movie_height  },
145    {   "isOpaque", "()Z",  (void*)movie_isOpaque  },
146    {   "duration", "()I",  (void*)movie_duration  },
147    {   "setTime",  "(I)Z", (void*)movie_setTime  },
148    {   "draw",     "(Landroid/graphics/Canvas;FFLandroid/graphics/Paint;)V",
149                            (void*)movie_draw  },
150    { "nativeDecodeAsset", "(J)Landroid/graphics/Movie;",
151                            (void*)movie_decodeAsset },
152    { "nativeDecodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
153                            (void*)movie_decodeStream },
154    { "nativeDestructor","(J)V", (void*)movie_destructor },
155    { "decodeByteArray", "([BII)Landroid/graphics/Movie;",
156                            (void*)movie_decodeByteArray },
157};
158
159#define kClassPathName  "android/graphics/Movie"
160
161#define RETURN_ERR_IF_NULL(value)   do { if (!(value)) { assert(0); return -1; } } while (false)
162
163int register_android_graphics_Movie(JNIEnv* env)
164{
165    gMovie_class = env->FindClass(kClassPathName);
166    RETURN_ERR_IF_NULL(gMovie_class);
167    gMovie_class = (jclass)env->NewGlobalRef(gMovie_class);
168
169    gMovie_constructorMethodID = env->GetMethodID(gMovie_class, "<init>", "(J)V");
170    RETURN_ERR_IF_NULL(gMovie_constructorMethodID);
171
172    gMovie_nativeInstanceID = env->GetFieldID(gMovie_class, "mNativeMovie", "J");
173    RETURN_ERR_IF_NULL(gMovie_nativeInstanceID);
174
175    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
176                                                       gMethods, SK_ARRAY_COUNT(gMethods));
177}
178