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