summaryrefslogtreecommitdiffstats
path: root/core/jni/android/graphics/Movie.cpp
blob: b25fa848b77727a749147e44c7a8024786913e61 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include "ScopedLocalRef.h"
#include "SkFrontBufferedStream.h"
#include "SkMovie.h"
#include "SkStream.h"
#include "GraphicsJNI.h"
#include "SkTemplates.h"
#include "SkUtils.h"
#include "Utils.h"
#include "CreateJavaOutputStreamAdaptor.h"
#include "Paint.h"

#include <androidfw/Asset.h>
#include <androidfw/ResourceTypes.h>
#include <netinet/in.h>

#include "core_jni_helpers.h"

static jclass       gMovie_class;
static jmethodID    gMovie_constructorMethodID;
static jfieldID     gMovie_nativeInstanceID;

jobject create_jmovie(JNIEnv* env, SkMovie* moov) {
    if (NULL == moov) {
        return NULL;
    }
    return env->NewObject(gMovie_class, gMovie_constructorMethodID,
            static_cast<jlong>(reinterpret_cast<uintptr_t>(moov)));
}

static SkMovie* J2Movie(JNIEnv* env, jobject movie) {
    SkASSERT(env);
    SkASSERT(movie);
    SkASSERT(env->IsInstanceOf(movie, gMovie_class));
    SkMovie* m = (SkMovie*)env->GetLongField(movie, gMovie_nativeInstanceID);
    SkASSERT(m);
    return m;
}

///////////////////////////////////////////////////////////////////////////////

static jint movie_width(JNIEnv* env, jobject movie) {
    NPE_CHECK_RETURN_ZERO(env, movie);
    return static_cast<jint>(J2Movie(env, movie)->width());
}

static jint movie_height(JNIEnv* env, jobject movie) {
    NPE_CHECK_RETURN_ZERO(env, movie);
    return static_cast<jint>(J2Movie(env, movie)->height());
}

static jboolean movie_isOpaque(JNIEnv* env, jobject movie) {
    NPE_CHECK_RETURN_ZERO(env, movie);
    return J2Movie(env, movie)->isOpaque() ? JNI_TRUE : JNI_FALSE;
}

static jint movie_duration(JNIEnv* env, jobject movie) {
    NPE_CHECK_RETURN_ZERO(env, movie);
    return static_cast<jint>(J2Movie(env, movie)->duration());
}

static jboolean movie_setTime(JNIEnv* env, jobject movie, jint ms) {
    NPE_CHECK_RETURN_ZERO(env, movie);
    return J2Movie(env, movie)->setTime(ms) ? JNI_TRUE : JNI_FALSE;
}

static void movie_draw(JNIEnv* env, jobject movie, jobject canvas,
                       jfloat fx, jfloat fy, jobject jpaint) {
    NPE_CHECK_RETURN_VOID(env, movie);
    NPE_CHECK_RETURN_VOID(env, canvas);
    // its OK for paint to be null

    SkMovie* m = J2Movie(env, movie);
    SkCanvas* c = GraphicsJNI::getNativeCanvas(env, canvas);
    const SkBitmap& b = m->bitmap();
    const SkPaint* p = jpaint ? GraphicsJNI::getNativePaint(env, jpaint) : NULL;

    c->drawBitmap(b, fx, fy, p);
}

static jobject movie_decodeAsset(JNIEnv* env, jobject clazz, jlong native_asset) {
    android::Asset* asset = reinterpret_cast<android::Asset*>(native_asset);
    if (asset == NULL) return NULL;
    SkAutoTUnref<SkStreamRewindable> stream (new android::AssetStreamAdaptor(asset,
            android::AssetStreamAdaptor::kNo_OwnAsset,
            android::AssetStreamAdaptor::kNo_HasMemoryBase));
    SkMovie* moov = SkMovie::DecodeStream(stream.get());
    return create_jmovie(env, moov);
}

static jobject movie_decodeStream(JNIEnv* env, jobject clazz, jobject istream) {

    NPE_CHECK_RETURN_ZERO(env, istream);

    jbyteArray byteArray = env->NewByteArray(16*1024);
    ScopedLocalRef<jbyteArray> scoper(env, byteArray);
    SkStream* strm = CreateJavaInputStreamAdaptor(env, istream, byteArray);
    if (NULL == strm) {
        return 0;
    }

    // Need to buffer enough input to be able to rewind as much as might be read by a decoder
    // trying to determine the stream's format. The only decoder for movies is GIF, which
    // will only read 6.
    // FIXME: Get this number from SkImageDecoder
    SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(strm, 6));
    SkASSERT(bufferedStream.get() != NULL);

    SkMovie* moov = SkMovie::DecodeStream(bufferedStream);
    strm->unref();
    return create_jmovie(env, moov);
}

static jobject movie_decodeByteArray(JNIEnv* env, jobject clazz,
                                     jbyteArray byteArray,
                                     jint offset, jint length) {

    NPE_CHECK_RETURN_ZERO(env, byteArray);

    int totalLength = env->GetArrayLength(byteArray);
    if ((offset | length) < 0 || offset + length > totalLength) {
        doThrowAIOOBE(env);
        return 0;
    }

    AutoJavaByteArray   ar(env, byteArray);
    SkMovie* moov = SkMovie::DecodeMemory(ar.ptr() + offset, length);
    return create_jmovie(env, moov);
}

static void movie_destructor(JNIEnv* env, jobject, jlong movieHandle) {
    SkMovie* movie = (SkMovie*) movieHandle;
    delete movie;
}

//////////////////////////////////////////////////////////////////////////////////////////////

static JNINativeMethod gMethods[] = {
    {   "width",    "()I",  (void*)movie_width  },
    {   "height",   "()I",  (void*)movie_height  },
    {   "isOpaque", "()Z",  (void*)movie_isOpaque  },
    {   "duration", "()I",  (void*)movie_duration  },
    {   "setTime",  "(I)Z", (void*)movie_setTime  },
    {   "draw",     "(Landroid/graphics/Canvas;FFLandroid/graphics/Paint;)V",
                            (void*)movie_draw  },
    { "nativeDecodeAsset", "(J)Landroid/graphics/Movie;",
                            (void*)movie_decodeAsset },
    { "nativeDecodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
                            (void*)movie_decodeStream },
    { "nativeDestructor","(J)V", (void*)movie_destructor },
    { "decodeByteArray", "([BII)Landroid/graphics/Movie;",
                            (void*)movie_decodeByteArray },
};

int register_android_graphics_Movie(JNIEnv* env)
{
    gMovie_class = android::FindClassOrDie(env, "android/graphics/Movie");
    gMovie_class = android::MakeGlobalRefOrDie(env, gMovie_class);

    gMovie_constructorMethodID = android::GetMethodIDOrDie(env, gMovie_class, "<init>", "(J)V");

    gMovie_nativeInstanceID = android::GetFieldIDOrDie(env, gMovie_class, "mNativeMovie", "J");

    return android::RegisterMethodsOrDie(env, "android/graphics/Movie", gMethods, NELEM(gMethods));
}