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