Tuner JNI: linearBlock and OnDestroyNotify
referred to ag/10877916 by Henry quxiangfang@
Bug: 139308734
Test: mmm
Change-Id: I7574d27cb1f582a5556e22eac4fff87335230b00
diff --git a/media/java/android/media/tv/tuner/filter/MediaEvent.java b/media/java/android/media/tv/tuner/filter/MediaEvent.java
index 247c1c4..af63070 100644
--- a/media/java/android/media/tv/tuner/filter/MediaEvent.java
+++ b/media/java/android/media/tv/tuner/filter/MediaEvent.java
@@ -28,14 +28,19 @@
*/
@SystemApi
public class MediaEvent extends FilterEvent {
- private native int nativeGetAudioHandle();
+ private long mNativeContext;
+ private final Object mLock = new Object();
+
+ private native Long nativeGetAudioHandle();
+ private native LinearBlock nativeGetLinearBlock();
+ private native void nativeFinalize();
private final int mStreamId;
private final boolean mIsPtsPresent;
private final long mPts;
private final long mDataLength;
private final long mOffset;
- private final LinearBlock mLinearBlock;
+ private LinearBlock mLinearBlock;
private final boolean mIsSecureMemory;
private final long mDataId;
private final int mMpuSequenceNumber;
@@ -103,7 +108,12 @@
*/
@Nullable
public LinearBlock getLinearBlock() {
- return mLinearBlock;
+ synchronized (mLock) {
+ if (mLinearBlock == null) {
+ mLinearBlock = nativeGetLinearBlock();
+ }
+ return mLinearBlock;
+ }
}
/**
@@ -163,4 +173,15 @@
public AudioDescriptor getExtraMetaData() {
return mExtraMetaData;
}
+
+
+ /**
+ * Finalize the MediaEvent object.
+ * @hide
+ */
+ @Override
+ protected void finalize() {
+ nativeFinalize();
+ mNativeContext = 0;
+ }
}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index ab311c0e..8058314 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -21,8 +21,7 @@
#include "android_media_tv_Tuner.h"
#include "android_runtime/AndroidRuntime.h"
-#include <C2BlockInternal.h>
-#include <C2HandleIonInternal.h>
+#include <android-base/logging.h>
#include <android/hardware/tv/tuner/1.0/ITuner.h>
#include <media/stagefright/foundation/ADebug.h>
#include <nativehelper/JNIHelp.h>
@@ -145,6 +144,7 @@
jfieldID descramblerContext;
jfieldID dvrRecorderContext;
jfieldID dvrPlaybackContext;
+ jfieldID mediaEventContext;
jmethodID frontendInitID;
jmethodID filterInitID;
jmethodID timeFilterInitID;
@@ -169,6 +169,12 @@
static int IP_V4_LENGTH = 4;
static int IP_V6_LENGTH = 16;
+void DestroyCallback(const C2Buffer * /* buf */, void *arg) {
+ android::sp<android::MediaEvent> event = (android::MediaEvent *)arg;
+ event->mAvHandleRefCnt--;
+ event->finalize();
+}
+
namespace android {
/////////////// LnbCallback ///////////////////////
LnbCallback::LnbCallback(jobject lnbObj, LnbId id) : mId(id) {
@@ -280,17 +286,69 @@
return *mDvrMQ;
}
-/////////////// FilterCallback ///////////////////////
-//TODO: implement filter callback
-jobject FilterCallback::handleToLinearBlock(const native_handle_t* handle, uint32_t size) {
- ALOGD("FilterCallback::handleToLinearBlock");
- C2HandleIon* ion = new C2HandleIon(handle->data[0], size);
- std::shared_ptr<C2LinearBlock> block = _C2BlockFactory::CreateLinearBlock(ion);
+/////////////// C2DataIdInfo ///////////////////////
+
+C2DataIdInfo::C2DataIdInfo(uint32_t index, uint64_t value) : C2Param(kParamSize, index) {
+ CHECK(isGlobal());
+ CHECK_EQ(C2Param::INFO, kind());
+ DummyInfo info{value};
+ memcpy(this + 1, static_cast<C2Param *>(&info) + 1, kParamSize - sizeof(C2Param));
+}
+
+/////////////// MediaEvent ///////////////////////
+
+MediaEvent::MediaEvent(sp<IFilter> iFilter, hidl_handle avHandle,
+ uint64_t dataId, uint64_t dataLength, jobject obj) : mIFilter(iFilter),
+ mDataId(dataId), mDataLength(dataLength), mBuffer(nullptr),
+ mDataIdRefCnt(0), mAvHandleRefCnt(0), mIonHandle(nullptr) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ mMediaEventObj = env->NewWeakGlobalRef(obj);
+ mAvHandle = native_handle_clone(avHandle.getNativeHandle());
+}
+
+MediaEvent::~MediaEvent() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->DeleteWeakGlobalRef(mMediaEventObj);
+ mMediaEventObj = NULL;
+ native_handle_delete(mAvHandle);
+ if (mIonHandle != NULL) {
+ delete mIonHandle;
+ }
+ if (mC2Buffer != NULL) {
+ mC2Buffer->unregisterOnDestroyNotify(&DestroyCallback, this);
+ }
+}
+
+void MediaEvent::finalize() {
+ if (mAvHandleRefCnt == 0) {
+ mIFilter->releaseAvHandle(hidl_handle(mAvHandle), mDataIdRefCnt == 0 ? mDataId : 0);
+ native_handle_close(mAvHandle);
+ }
+}
+
+jobject MediaEvent::getLinearBlock() {
+ ALOGD("MediaEvent::getLinearBlock");
+ if (mAvHandle == NULL) {
+ return NULL;
+ }
+ if (mLinearBlockObj != NULL) {
+ return mLinearBlockObj;
+ }
+ mIonHandle = new C2HandleIon(mAvHandle->data[0], mDataLength);
+ std::shared_ptr<C2LinearBlock> block = _C2BlockFactory::CreateLinearBlock(mIonHandle);
JNIEnv *env = AndroidRuntime::getJNIEnv();
std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
context->mBlock = block;
-
+ mC2Buffer = context->toC2Buffer(0, mDataLength);
+ if (mAvHandle->numInts > 0) {
+ // use first int in the native_handle as the index
+ int index = mAvHandle->data[mAvHandle->numFds];
+ std::shared_ptr<C2Param> c2param = std::make_shared<C2DataIdInfo>(index, mDataId);
+ std::shared_ptr<C2Info> info(std::static_pointer_cast<C2Info>(c2param));
+ mC2Buffer->setInfo(info);
+ }
+ mC2Buffer->registerOnDestroyNotify(&DestroyCallback, this);
jobject linearBlock =
env->NewObject(
env->FindClass("android/media/MediaCodec$LinearBlock"),
@@ -300,9 +358,18 @@
gFields.linearBlockSetInternalStateID,
(jlong)context.release(),
true);
- return linearBlock;
+ mLinearBlockObj = env->NewWeakGlobalRef(linearBlock);
+ mAvHandleRefCnt++;
+ return mLinearBlockObj;
}
+uint64_t MediaEvent::getAudioHandle() {
+ mDataIdRefCnt++;
+ return mDataId;
+}
+
+/////////////// FilterCallback ///////////////////////
+
jobjectArray FilterCallback::getSectionEvent(
jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -333,6 +400,7 @@
"<init>",
"(IZJJJLandroid/media/MediaCodec$LinearBlock;"
"ZJIZLandroid/media/tv/tuner/filter/AudioDescriptor;)V");
+ jfieldID eventContext = env->GetFieldID(eventClazz, "mNativeContext", "J");
for (int i = 0; i < events.size(); i++) {
auto event = events[i];
@@ -358,12 +426,6 @@
}
jlong dataLength = static_cast<jlong>(mediaEvent.dataLength);
- const native_handle_t* h = NULL;
- jobject block = NULL;
- if (mediaEvent.avMemory != NULL) {
- h = mediaEvent.avMemory.getNativeHandle();
- block = handleToLinearBlock(h, dataLength);
- }
jint streamId = static_cast<jint>(mediaEvent.streamId);
jboolean isPtsPresent = static_cast<jboolean>(mediaEvent.isPtsPresent);
@@ -376,8 +438,18 @@
jobject obj =
env->NewObject(eventClazz, eventInit, streamId, isPtsPresent, pts, dataLength,
- offset, block, isSecureMemory, avDataId, mpuSequenceNumber, isPesPrivateData,
+ offset, NULL, isSecureMemory, avDataId, mpuSequenceNumber, isPesPrivateData,
audioDescriptor);
+
+ if (mediaEvent.avMemory.getNativeHandle() != NULL || mediaEvent.avDataId != 0) {
+ sp<MediaEvent> mediaEventSp =
+ new MediaEvent(mIFilter, mediaEvent.avMemory,
+ mediaEvent.avDataId, dataLength, obj);
+ mediaEventSp->mAvHandleRefCnt++;
+ env->SetLongField(obj, eventContext, (jlong) mediaEventSp.get());
+ mediaEventSp->incStrong(obj);
+ }
+
env->SetObjectArrayElement(arr, i, obj);
}
return arr;
@@ -594,10 +666,10 @@
return Void();
}
-void FilterCallback::setFilter(const jobject filter) {
+void FilterCallback::setFilter(const sp<Filter> filter) {
ALOGD("FilterCallback::setFilter");
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- mFilter = env->NewWeakGlobalRef(filter);
+ mFilter = filter->mFilterObj;
+ mIFilter = filter->mFilterSp;
}
FilterCallback::~FilterCallback() {
@@ -1431,7 +1503,7 @@
filterSp->incStrong(filterObj);
env->SetLongField(filterObj, gFields.filterContext, (jlong)filterSp.get());
- callback->setFilter(filterObj);
+ callback->setFilter(filterSp);
return filterObj;
}
@@ -2390,6 +2462,9 @@
gFields.onDvrPlaybackStatusID =
env->GetMethodID(dvrPlaybackClazz, "onPlaybackStatusChanged", "(I)V");
+ jclass mediaEventClazz = env->FindClass("android/media/tv/tuner/filter/MediaEvent");
+ gFields.mediaEventContext = env->GetFieldID(mediaEventClazz, "mNativeContext", "J");
+
jclass linearBlockClazz = env->FindClass("android/media/MediaCodec$LinearBlock");
gFields.linearBlockInitID = env->GetMethodID(linearBlockClazz, "<init>", "()V");
gFields.linearBlockSetInternalStateID =
@@ -3507,6 +3582,52 @@
return copyData(env, dvrSp->mDvrMQ, dvrSp->mDvrMQEventFlag, buffer, offset, size);
}
+static sp<MediaEvent> getMediaEventSp(JNIEnv *env, jobject mediaEventObj) {
+ return (MediaEvent *)env->GetLongField(mediaEventObj, gFields.mediaEventContext);
+}
+
+static jobject android_media_tv_Tuner_media_event_get_linear_block(
+ JNIEnv* env, jobject mediaEventObj) {
+ sp<MediaEvent> mediaEventSp = getMediaEventSp(env, mediaEventObj);
+ if (mediaEventSp == NULL) {
+ ALOGD("Failed get MediaEvent");
+ return NULL;
+ }
+
+ return mediaEventSp->getLinearBlock();
+}
+
+static jobject android_media_tv_Tuner_media_event_get_audio_handle(
+ JNIEnv* env, jobject mediaEventObj) {
+ sp<MediaEvent> mediaEventSp = getMediaEventSp(env, mediaEventObj);
+ if (mediaEventSp == NULL) {
+ ALOGD("Failed get MediaEvent");
+ return NULL;
+ }
+
+ android::Mutex::Autolock autoLock(mediaEventSp->mLock);
+ uint64_t audioHandle = mediaEventSp->getAudioHandle();
+ jclass longClazz = env->FindClass("java/lang/Long");
+ jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V");
+
+ jobject longObj = env->NewObject(longClazz, longInit, static_cast<jlong>(audioHandle));
+ return longObj;
+}
+
+static void android_media_tv_Tuner_media_event_finalize(JNIEnv* env, jobject mediaEventObj) {
+ sp<MediaEvent> mediaEventSp = getMediaEventSp(env, mediaEventObj);
+ if (mediaEventSp == NULL) {
+ ALOGD("Failed get MediaEvent");
+ return;
+ }
+
+ android::Mutex::Autolock autoLock(mediaEventSp->mLock);
+ mediaEventSp->mAvHandleRefCnt--;
+ mediaEventSp->finalize();
+
+ mediaEventSp->decStrong(mediaEventObj);
+}
+
static const JNINativeMethod gTunerMethods[] = {
{ "nativeInit", "()V", (void *)android_media_tv_Tuner_native_init },
{ "nativeSetup", "()V", (void *)android_media_tv_Tuner_native_setup },
@@ -3629,6 +3750,15 @@
{ "nativeClose", "()I", (void *)android_media_tv_Tuner_close_lnb },
};
+static const JNINativeMethod gMediaEventMethods[] = {
+ { "nativeGetLinearBlock", "()Landroid/media/MediaCodec$LinearBlock;",
+ (void *)android_media_tv_Tuner_media_event_get_linear_block },
+ { "nativeGetAudioHandle", "()Ljava/lang/Long;",
+ (void *)android_media_tv_Tuner_media_event_get_audio_handle },
+ { "nativeFinalize", "()V",
+ (void *)android_media_tv_Tuner_media_event_finalize },
+};
+
static bool register_android_media_tv_Tuner(JNIEnv *env) {
if (AndroidRuntime::registerNativeMethods(
env, "android/media/tv/tuner/Tuner", gTunerMethods, NELEM(gTunerMethods)) != JNI_OK) {
@@ -3677,6 +3807,13 @@
ALOGE("Failed to register lnb native methods");
return false;
}
+ if (AndroidRuntime::registerNativeMethods(
+ env, "android/media/tv/tuner/filter/MediaEvent",
+ gMediaEventMethods,
+ NELEM(gMediaEventMethods)) != JNI_OK) {
+ ALOGE("Failed to register MediaEvent native methods");
+ return false;
+ }
return true;
}
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 3da78ac..c469a3a 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -18,10 +18,14 @@
#define _ANDROID_MEDIA_TV_TUNER_H_
#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <C2BlockInternal.h>
+#include <C2HandleIonInternal.h>
+#include <C2ParamDef.h>
#include <fmq/MessageQueue.h>
#include <fstream>
#include <string>
#include <unordered_map>
+#include <utils/Mutex.h>
#include <utils/RefBase.h>
#include "jni.h"
@@ -30,6 +34,7 @@
using ::android::hardware::MQDescriptorSync;
using ::android::hardware::MessageQueue;
using ::android::hardware::Return;
+using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_vec;
using ::android::hardware::kSynchronizedReadWrite;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
@@ -106,15 +111,48 @@
int mFd;
};
+struct MediaEvent : public RefBase {
+ MediaEvent(sp<IFilter> iFilter, hidl_handle avHandle, uint64_t dataId,
+ uint64_t dataLength, jobject obj);
+ ~MediaEvent();
+ jobject getLinearBlock();
+ uint64_t getAudioHandle();
+ void finalize();
+
+ sp<IFilter> mIFilter;
+ native_handle_t* mAvHandle;
+ uint64_t mDataId;
+ uint64_t mDataLength;
+ uint8_t* mBuffer;
+ android::Mutex mLock;
+ int mDataIdRefCnt;
+ int mAvHandleRefCnt;
+ jweak mMediaEventObj;
+ jweak mLinearBlockObj;
+ C2HandleIon* mIonHandle;
+ std::shared_ptr<C2Buffer> mC2Buffer;
+};
+
+struct Filter : public RefBase {
+ Filter(sp<IFilter> sp, jobject obj);
+ ~Filter();
+ int close();
+ sp<IFilter> getIFilter();
+ sp<IFilter> mFilterSp;
+ std::unique_ptr<MQ> mFilterMQ;
+ EventFlag* mFilterMQEventFlag;
+ jweak mFilterObj;
+};
+
struct FilterCallback : public IFilterCallback {
~FilterCallback();
virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent);
virtual Return<void> onFilterStatus(const DemuxFilterStatus status);
- void setFilter(const jobject filter);
- jobject handleToLinearBlock(const native_handle_t* handle, uint32_t size);
+ void setFilter(const sp<Filter> filter);
private:
jweak mFilter;
+ sp<IFilter> mIFilter;
jobjectArray getSectionEvent(
jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
jobjectArray getMediaEvent(
@@ -144,17 +182,6 @@
FrontendId mId;
};
-struct Filter : public RefBase {
- Filter(sp<IFilter> sp, jobject obj);
- ~Filter();
- int close();
- sp<IFilter> getIFilter();
- sp<IFilter> mFilterSp;
- std::unique_ptr<MQ> mFilterMQ;
- EventFlag* mFilterMQEventFlag;
- jweak mFilterObj;
-};
-
struct TimeFilter : public RefBase {
TimeFilter(sp<ITimeFilter> sp, jweak obj);
~TimeFilter();
@@ -219,6 +246,14 @@
static jobject getIsdbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps);
};
+class C2DataIdInfo : public C2Param {
+public:
+ C2DataIdInfo(uint32_t index, uint64_t value);
+private:
+ typedef C2GlobalParam<C2Info, C2Int64Value, 0> DummyInfo;
+ static const size_t kParamSize = sizeof(DummyInfo);
+};
+
} // namespace android
#endif // _ANDROID_MEDIA_TV_TUNER_H_