diff options
| -rw-r--r-- | media/java/android/media/tv/tuner/filter/MediaEvent.java | 27 | ||||
| -rw-r--r-- | media/jni/android_media_tv_Tuner.cpp | 179 | ||||
| -rw-r--r-- | media/jni/android_media_tv_Tuner.h | 61 |
3 files changed, 230 insertions, 37 deletions
diff --git a/media/java/android/media/tv/tuner/filter/MediaEvent.java b/media/java/android/media/tv/tuner/filter/MediaEvent.java index 247c1c47560a..af63070027a2 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 @@ 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; + } } diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index ab311c0e245a..805831442756 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 @@ 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; } diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index 3da78acb2f90..c469a3ad8b76 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::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_ |