summaryrefslogtreecommitdiff
path: root/tvapi/android/jni/android_amlogic_tv.cpp (plain)
blob: ec531ef87b571562ac09531916465b2ddcadb217
1#define LOG_TAG "Tv-JNI"
2#include <utils/Log.h>
3
4#include "jni.h"
5#include "JNIHelp.h"
6#include "android_runtime/AndroidRuntime.h"
7#include <utils/Vector.h>
8#include <include/Tv.h>
9#include <binder/IMemory.h>
10#include <binder/Parcel.h>
11#include <binder/MemoryHeapBase.h>
12#include <binder/MemoryBase.h>
13#include <core/SkBitmap.h>
14#include "android_util_Binder.h"
15#include "android_os_Parcel.h"
16using namespace android;
17
18struct fields_t {
19 jfieldID context;
20 jmethodID post_event;
21};
22
23#ifdef LOG_TAG
24#undef LOG_TAG
25#define LOG_TAG "TvJNI"
26#endif
27
28static fields_t fields;
29static Mutex sLock;
30class JNITvContext: public TvListener
31{
32public:
33 JNITvContext(JNIEnv *env, jobject weak_this, jclass clazz, const sp<Tv> &tv);
34 ~JNITvContext()
35 {
36 release();
37 }
38 virtual void notify(int32_t msgType, const Parcel &p);
39 void addCallbackBuffer(JNIEnv *env, jbyteArray cbb);
40 sp<Tv> getTv()
41 {
42 Mutex::Autolock _l(mLock);
43 return mTv;
44 }
45 void release();
46 Parcel *mExtParcel;
47private:
48 jobject mTvJObjectWeak; // weak reference to java object
49 jclass mTvJClass; // strong reference to java class
50 sp<Tv> mTv; // strong reference to native object
51 Mutex mLock;
52
53 Vector<jbyteArray> mCallbackBuffers; // Global reference application managed byte[]
54 bool mManualBufferMode; // Whether to use application managed buffers.
55 bool mManualTvCallbackSet; // Whether the callback has been set, used to reduce unnecessary calls to set the callback.
56};
57
58sp<Tv> get_native_tv(JNIEnv *env, jobject thiz, JNITvContext **pContext)
59{
60 sp<Tv> tv;
61 Mutex::Autolock _l(sLock);
62 JNITvContext *context = reinterpret_cast<JNITvContext *>(env->GetIntField(thiz, fields.context));
63 if (context != NULL) {
64 tv = context->getTv();
65 }
66 if (tv == 0) {
67 jniThrowException(env, "java/lang/RuntimeException", "Method called after release()");
68 }
69
70 if (pContext != NULL) *pContext = context;
71 return tv;
72}
73
74JNITvContext::JNITvContext(JNIEnv *env, jobject weak_this, jclass clazz, const sp<Tv> &tv)
75{
76 mTvJObjectWeak = env->NewGlobalRef(weak_this);
77 mTvJClass = (jclass)env->NewGlobalRef(clazz);
78 mTv = tv;
79 ALOGD("tvjni----------------------JNITvContext::JNITvContext(");
80 mManualBufferMode = false;
81 mManualTvCallbackSet = false;
82 //mExtParcel = parcelForJavaObject(env, ext_parcel);
83}
84
85void JNITvContext::release()
86{
87 ALOGD("release");
88 Mutex::Autolock _l(mLock);
89 JNIEnv *env = AndroidRuntime::getJNIEnv();
90
91 if (mTvJObjectWeak != NULL) {
92 env->DeleteGlobalRef(mTvJObjectWeak);
93 mTvJObjectWeak = NULL;
94 }
95 if (mTvJClass != NULL) {
96 env->DeleteGlobalRef(mTvJClass);
97 mTvJClass = NULL;
98 }
99 mTv.clear();
100}
101
102// connect to tv service
103static void android_amlogic_Tv_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
104{
105 sp<Tv> tv = Tv::connect();
106
107 ALOGD("android_amlogic_Tv_native_setup.");
108
109 if (tv == NULL) {
110 jniThrowException(env, "java/lang/RuntimeException", "Fail to connect to tv service");
111 return;
112 }
113
114 // make sure tv amlogic is alive
115 if (tv->getStatus() != NO_ERROR) {
116 jniThrowException(env, "java/lang/RuntimeException", "Tv initialization failed!");
117 return;
118 }
119
120 jclass clazz = env->GetObjectClass(thiz);
121 if (clazz == NULL) {
122 jniThrowException(env, "java/lang/RuntimeException", "Can't find android/amlogic/Tv!");
123 return;
124 }
125
126 sp<JNITvContext> context = new JNITvContext(env, weak_this, clazz, tv);
127 context->incStrong(thiz);
128 tv->setListener(context);
129
130 env->SetIntField(thiz, fields.context, (int)context.get());
131}
132
133
134static void android_amlogic_Tv_release(JNIEnv *env, jobject thiz)
135{
136 // TODO: Change to LOGE
137 JNITvContext *context = NULL;
138 sp<Tv> tv;
139 {
140 Mutex::Autolock _l(sLock);
141 context = reinterpret_cast<JNITvContext *>(env->GetIntField(thiz, fields.context));
142
143 // Make sure we do not attempt to callback on a deleted Java object.
144 env->SetIntField(thiz, fields.context, 0);
145 }
146
147 ALOGD("release tv");
148
149 // clean up if release has not been called before
150 if (context != NULL) {
151 tv = context->getTv();
152 context->release();
153 ALOGD("native_release: context=%p tv=%p", context, tv.get());
154
155 // clear callbacks
156 if (tv != NULL) {
157 //tv->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
158 tv->disconnect();
159 }
160
161 // remove context to prevent further Java access
162 context->decStrong(thiz);
163 }
164}
165
166void JNITvContext::notify(int32_t msgType, const Parcel &p)
167{
168 // VM pointer will be NULL if object is released
169 Mutex::Autolock _l(mLock);
170 if (mTvJObjectWeak == NULL) {
171 ALOGW("callback on dead tv object");
172 return;
173 }
174
175 JNIEnv *env = AndroidRuntime::getJNIEnv();
176
177 jobject jParcel = createJavaParcelObject(env);
178 if (jParcel != NULL) {
179 Parcel *nativeParcel = parcelForJavaObject(env, jParcel);
180 nativeParcel->write(p.data(), p.dataSize());
181 env->CallStaticVoidMethod(mTvJClass, fields.post_event, mTvJObjectWeak, msgType, jParcel);
182 env->DeleteLocalRef(jParcel);
183 }
184}
185
186
187void JNITvContext::addCallbackBuffer(JNIEnv *env, jbyteArray cbb)
188{
189 if (cbb != NULL) {
190 Mutex::Autolock _l(mLock);
191 jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb);
192 mCallbackBuffers.push(cbb);
193 ALOGD("Adding callback buffer to queue, %d total", mCallbackBuffers.size());
194 } else {
195 ALOGE("Null byte array!");
196 }
197}
198
199static jint android_amlogic_Tv_processCmd(JNIEnv *env, jobject thiz, jobject pObj, jobject rObj)
200{
201 sp<Tv> tv = get_native_tv(env, thiz, NULL);
202 if (tv == 0) return -1;
203
204 Parcel *p = parcelForJavaObject(env, pObj);
205 //jclass clazz;
206 //clazz = env->FindClass("android/os/Parcel");
207 //LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Parcel");
208
209
210 //jmethodID mConstructor = env->GetMethodID(clazz, "<init>", "(I)V");
211 //jobject replayobj = env->NewObject(clazz, mConstructor, 0);
212 Parcel *r = parcelForJavaObject(env, rObj);
213
214
215 return tv->processCmd(*p, r);
216 //if ( != NO_ERROR) {
217 // jniThrowException(env, "java/lang/RuntimeException", "StartTv failed");
218 // return -1;
219 // }
220 //return 0;
221}
222
223static void android_amlogic_Tv_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes)
224{
225 JNITvContext *context = reinterpret_cast<JNITvContext *>(env->GetIntField(thiz, fields.context));
226
227 ALOGD("addCallbackBuffer");
228 if (context != NULL) {
229 context->addCallbackBuffer(env, bytes);
230 }
231}
232
233static void android_amlogic_Tv_reconnect(JNIEnv *env, jobject thiz)
234{
235 sp<Tv> tv = get_native_tv(env, thiz, NULL);
236 if (tv == 0) return;
237
238 if (tv->reconnect() != NO_ERROR) {
239 jniThrowException(env, "java/io/IOException", "reconnect failed");
240 return;
241 }
242}
243
244static void android_amlogic_Tv_lock(JNIEnv *env, jobject thiz)
245{
246 sp<Tv> tv = get_native_tv(env, thiz, NULL);
247 if (tv == 0) return;
248
249 ALOGD("lock");
250
251 if (tv->lock() != NO_ERROR) {
252 jniThrowException(env, "java/lang/RuntimeException", "lock failed");
253 }
254}
255
256static void android_amlogic_Tv_unlock(JNIEnv *env, jobject thiz)
257{
258 sp<Tv> tv = get_native_tv(env, thiz, NULL);
259 if (tv == 0) return;
260
261 ALOGD("unlock");
262
263 if (tv->unlock() != NO_ERROR) {
264 jniThrowException(env, "java/lang/RuntimeException", "unlock failed");
265 }
266}
267
268static void android_amlogic_Tv_create_subtitle_bitmap(JNIEnv *env, jobject thiz, jobject bmpobj)
269{
270 ALOGD("create subtitle bmp");
271 sp<Tv> tv = get_native_tv(env, thiz, NULL);
272 if (tv == 0) return;
273
274 //get skbitmap
275 jclass bmp_clazz;
276 jfieldID skbmp_fid;
277 jint hbmp;
278 bmp_clazz = env->FindClass("android/graphics/Bitmap");
279 skbmp_fid = env->GetFieldID(bmp_clazz, "mNativeBitmap", "I");
280 hbmp = env->GetIntField(bmpobj, skbmp_fid);
281 SkBitmap *pSkBmp = reinterpret_cast<SkBitmap *>(hbmp);
282 ALOGD("pSkBmp = %d", hbmp);
283 ALOGD("bmp width = %d height = %d", pSkBmp->width(), pSkBmp->height());
284 env->DeleteLocalRef(bmp_clazz);
285
286 //alloc share mem
287 sp<MemoryHeapBase> MemHeap = new MemoryHeapBase(1920 * 1080 * 4, 0, "subtitle bmp");
288 ALOGD("heap id = %d", MemHeap->getHeapID());
289 if (MemHeap->getHeapID() < 0) {
290 return;
291 }
292 sp<MemoryBase> MemBase = new MemoryBase(MemHeap, 0, 1920 * 1080 * 4);
293 pSkBmp->setPixels(MemBase->pointer());
294
295
296 //send share mem to server
297 tv->createSubtitle(MemBase);
298 return;
299}
300
301static void android_amlogic_Tv_create_video_frame_bitmap(JNIEnv *env, jobject thiz, jobject bmpobj )
302{
303 ALOGD("create video frame bmp");
304 sp<Tv> tv = get_native_tv(env, thiz, NULL);
305 if (tv == 0) return;
306
307 //get skbitmap
308 jclass bmp_clazz;
309 jfieldID skbmp_fid;
310 jint hbmp;
311 bmp_clazz = env->FindClass("android/graphics/Bitmap");
312 skbmp_fid = env->GetFieldID(bmp_clazz, "mNativeBitmap", "I");
313 hbmp = env->GetIntField(bmpobj, skbmp_fid);
314 SkBitmap *pSkBmp = reinterpret_cast<SkBitmap *>(hbmp);
315 ALOGD("pSkBmp = %d", hbmp);
316 ALOGD("bmp width = %d height = %d", pSkBmp->width(), pSkBmp->height());
317 env->DeleteLocalRef(bmp_clazz);
318
319 //alloc share mem
320 sp<MemoryHeapBase> MemHeap = new MemoryHeapBase(1280 * 720 * 4 + 1, 0, "video frame bmp");
321 ALOGD("heap id = %d", MemHeap->getHeapID());
322 if (MemHeap->getHeapID() < 0) {
323 return;
324 }
325 sp<MemoryBase> MemBase = new MemoryBase(MemHeap, 0, 1280 * 720 * 4 + 1);
326 pSkBmp->setPixels(MemBase->pointer());
327
328
329 //send share mem to server
330 tv->createVideoFrame(MemBase);
331 return;
332}
333
334//-------------------------------------------------
335
336static JNINativeMethod camMethods[] = {
337 {
338 "native_setup",
339 "(Ljava/lang/Object;)V",
340 (void *)android_amlogic_Tv_native_setup
341 },
342 {
343 "native_release",
344 "()V",
345 (void *)android_amlogic_Tv_release
346 },
347 {
348 "processCmd",
349 "(Landroid/os/Parcel;Landroid/os/Parcel;)I",
350 (void *)android_amlogic_Tv_processCmd
351 },
352 {
353 "addCallbackBuffer",
354 "([B)V",
355 (void *)android_amlogic_Tv_addCallbackBuffer
356 },
357 {
358 "reconnect",
359 "()V",
360 (void *)android_amlogic_Tv_reconnect
361 },
362 {
363 "lock",
364 "()V",
365 (void *)android_amlogic_Tv_lock
366 },
367 {
368 "unlock",
369 "()V",
370 (void *)android_amlogic_Tv_unlock
371 },
372 {
373 "native_create_subtitle_bitmap",
374 "(Ljava/lang/Object;)V",
375 (void *)android_amlogic_Tv_create_subtitle_bitmap
376 },
377 {
378 "native_create_video_frame_bitmap",
379 "(Ljava/lang/Object;)V",
380 (void *)android_amlogic_Tv_create_video_frame_bitmap
381 },
382
383};
384
385struct field {
386 const char *class_name;
387 const char *field_name;
388 const char *field_type;
389 jfieldID *jfield;
390};
391
392static int find_fields(JNIEnv *env, field *fields, int count)
393{
394 for (int i = 0; i < count; i++) {
395 field *f = &fields[i];
396 jclass clazz = env->FindClass(f->class_name);
397 if (clazz == NULL) {
398 ALOGE("Can't find %s", f->class_name);
399 return -1;
400 }
401
402 jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type);
403 if (field == NULL) {
404 ALOGE("Can't find %s.%s", f->class_name, f->field_name);
405 return -1;
406 }
407
408 *(f->jfield) = field;
409 }
410
411 return 0;
412}
413
414// Get all the required offsets in java class and register native functions
415int register_android_amlogic_Tv(JNIEnv *env)
416{
417 field fields_to_find[] = {
418 { "android/amlogic/Tv", "mNativeContext", "I", &fields.context }
419 };
420
421 ALOGD("register_android_amlogic_Tv.");
422
423 if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
424 return -1;
425
426 jclass clazz = env->FindClass("android/amlogic/Tv");
427 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", "(Ljava/lang/Object;ILandroid/os/Parcel;)V");
428 if (fields.post_event == NULL) {
429 ALOGE("Can't find android/amlogic/Tv.postEventFromNative");
430 return -1;
431 }
432
433 // Register native functions
434 return AndroidRuntime::registerNativeMethods(env, "android/amlogic/Tv", camMethods, NELEM(camMethods));
435}
436
437
438jint JNI_OnLoad(JavaVM *vm, void *reserved)
439{
440 JNIEnv *env = NULL;
441 jint result = -1;
442
443 if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
444 ALOGE("ERROR: GetEnv failed\n");
445 goto bail;
446 }
447 assert(env != NULL);
448
449 register_android_amlogic_Tv(env);
450
451 /* success -- return valid version number */
452 result = JNI_VERSION_1_4;
453bail:
454 return result;
455}
456
457