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