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