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