Tuner JNI: linearBlock and OnDestroyNotify

referred to ag/10877916 by Henry quxiangfang@

Bug: 139308734
Test: mmm
Change-Id: I7574d27cb1f582a5556e22eac4fff87335230b00
This commit is contained in:
shubang
2020-04-01 16:51:04 -07:00
parent b344e0ac95
commit 3aef4fe424
3 changed files with 230 additions and 37 deletions

View File

@@ -28,14 +28,19 @@ import android.media.MediaCodec.LinearBlock;
*/
@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 @@ public class MediaEvent extends FilterEvent {
*/
@Nullable
public LinearBlock getLinearBlock() {
return mLinearBlock;
synchronized (mLock) {
if (mLinearBlock == null) {
mLinearBlock = nativeGetLinearBlock();
}
return mLinearBlock;
}
}
/**
@@ -163,4 +173,15 @@ public class MediaEvent extends FilterEvent {
public AudioDescriptor getExtraMetaData() {
return mExtraMetaData;
}
/**
* Finalize the MediaEvent object.
* @hide
*/
@Override
protected void finalize() {
nativeFinalize();
mNativeContext = 0;
}
}

View File

@@ -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 @@ struct fields_t {
jfieldID descramblerContext;
jfieldID dvrRecorderContext;
jfieldID dvrPlaybackContext;
jfieldID mediaEventContext;
jmethodID frontendInitID;
jmethodID filterInitID;
jmethodID timeFilterInitID;
@@ -169,6 +169,12 @@ static fields_t gFields;
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 @@ MQ& Dvr::getDvrMQ() {
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 @@ jobject FilterCallback::handleToLinearBlock(const native_handle_t* handle, uint3
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 @@ jobjectArray FilterCallback::getMediaEvent(
"<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 @@ jobjectArray FilterCallback::getMediaEvent(
}
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 @@ jobjectArray FilterCallback::getMediaEvent(
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> FilterCallback::onFilterStatus(const DemuxFilterStatus status) {
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 @@ jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) {
filterSp->incStrong(filterObj);
env->SetLongField(filterObj, gFields.filterContext, (jlong)filterSp.get());
callback->setFilter(filterObj);
callback->setFilter(filterSp);
return filterObj;
}
@@ -2390,6 +2462,9 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) {
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 @@ static jlong android_media_tv_Tuner_write_dvr_to_array(
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 @@ static const JNINativeMethod gLnbMethods[] = {
{ "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 @@ static bool register_android_media_tv_Tuner(JNIEnv *env) {
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;
}

View File

@@ -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::EventFlag;
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 @@ struct Dvr : public RefBase {
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 @@ struct FrontendCallback : public IFrontendCallback {
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 @@ private:
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_