Tuner JNI: linearBlock and OnDestroyNotify
referred to ag/10877916 by Henry quxiangfang@ Bug: 139308734 Test: mmm Change-Id: I7574d27cb1f582a5556e22eac4fff87335230b00
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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_
|
||||
|
||||
Reference in New Issue
Block a user