diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 012b8d639fccb..73769be3d6ad0 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -652,7 +652,7 @@ public class Tuner implements AutoCloseable { if (filter != null) { filter.setMainType(mainType); filter.setSubtype(subType); - filter.setCallback(cb); + filter.setCallback(cb, executor); if (mHandler == null) { mHandler = createEventHandler(); } diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java index a98183bbf1a3d..cfb943b10d17b 100644 --- a/media/java/android/media/tv/tuner/filter/Filter.java +++ b/media/java/android/media/tv/tuner/filter/Filter.java @@ -27,6 +27,7 @@ import android.media.tv.tuner.TunerUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.Executor; /** * Tuner data filter. @@ -177,6 +178,7 @@ public class Filter implements AutoCloseable { private long mNativeContext; private FilterCallback mCallback; + private Executor mExecutor; private final int mId; private int mMainType; private int mSubtype; @@ -199,6 +201,12 @@ public class Filter implements AutoCloseable { private void onFilterStatus(int status) { } + private void onFilterEvent(FilterEvent[] events) { + if (mCallback != null && mExecutor != null) { + mExecutor.execute(() -> mCallback.onFilterEvent(this, events)); + } + } + /** @hide */ public void setMainType(@Type int mainType) { mMainType = mainType; @@ -209,8 +217,9 @@ public class Filter implements AutoCloseable { } /** @hide */ - public void setCallback(FilterCallback cb) { + public void setCallback(FilterCallback cb, Executor executor) { mCallback = cb; + mExecutor = executor; } /** @hide */ public FilterCallback getCallback() { diff --git a/media/jni/Android.bp b/media/jni/Android.bp index c17b1b773bd52..64ea463a87577 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -136,17 +136,23 @@ cc_library_shared { ], shared_libs: [ + "android.hardware.graphics.bufferqueue@2.0", "android.hardware.tv.tuner@1.0", "libandroid_runtime", "libcutils", "libfmq", "libhidlbase", "liblog", + "libmedia", "libnativehelper", "libutils", ], + defaults: [ + "libcodec2-impl-defaults", + ], header_libs: [ + "libcodec2_internal", "libstagefright_foundation_headers", ], diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 71ba59c8a7078..893e51654b682 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -22,6 +22,7 @@ #include "android_media_MediaCodec.h" +#include "android_media_MediaCodecLinearBlock.h" #include "android_media_MediaCrypto.h" #include "android_media_MediaDescrambler.h" #include "android_media_MediaMetricsJNI.h" @@ -174,44 +175,6 @@ struct fields_t { static fields_t gFields; static const void *sRefBaseOwner; -struct JMediaCodecLinearBlock { - std::shared_ptr mBuffer; - std::shared_ptr mReadonlyMapping; - - std::shared_ptr mBlock; - std::shared_ptr mReadWriteMapping; - - sp mHeap; - sp mMemory; - - sp mLegacyBuffer; - - std::once_flag mCopyWarningFlag; - - std::shared_ptr toC2Buffer(size_t offset, size_t size) { - if (mBuffer) { - if (mBuffer->data().type() != C2BufferData::LINEAR) { - return nullptr; - } - C2ConstLinearBlock block = mBuffer->data().linearBlocks().front(); - if (offset == 0 && size == block.capacity()) { - return mBuffer; - } - return C2Buffer::CreateLinearBuffer(block.subBlock(offset, size)); - } - if (mBlock) { - return C2Buffer::CreateLinearBuffer(mBlock->share(offset, size, C2Fence{})); - } - return nullptr; - } - - sp toHidlMemory() { - if (mMemory) { - return mMemory; - } - return nullptr; - } -}; struct JMediaCodecGraphicBlock { std::shared_ptr mBuffer; diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h index 1d12e776d43e1..8899fee7a73d2 100644 --- a/media/jni/android_media_MediaCodec.h +++ b/media/jni/android_media_MediaCodec.h @@ -21,6 +21,9 @@ #include "jni.h" +#include +#include +#include #include #include #include diff --git a/media/jni/android_media_MediaCodecLinearBlock.h b/media/jni/android_media_MediaCodecLinearBlock.h new file mode 100644 index 0000000000000..08438340d8031 --- /dev/null +++ b/media/jni/android_media_MediaCodecLinearBlock.h @@ -0,0 +1,68 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ANDROID_MEDIA_MEDIACODECLINEARBLOCK_H_ +#define _ANDROID_MEDIA_MEDIACODECLINEARBLOCK_H_ + +#include +#include +#include +#include + +namespace android { + +struct JMediaCodecLinearBlock { + std::shared_ptr mBuffer; + std::shared_ptr mReadonlyMapping; + + std::shared_ptr mBlock; + std::shared_ptr mReadWriteMapping; + + sp mHeap; + sp mMemory; + + sp mLegacyBuffer; + + std::once_flag mCopyWarningFlag; + + std::shared_ptr toC2Buffer(size_t offset, size_t size) { + if (mBuffer) { + if (mBuffer->data().type() != C2BufferData::LINEAR) { + return nullptr; + } + C2ConstLinearBlock block = mBuffer->data().linearBlocks().front(); + if (offset == 0 && size == block.capacity()) { + return mBuffer; + } + return C2Buffer::CreateLinearBuffer(block.subBlock(offset, size)); + } + if (mBlock) { + return C2Buffer::CreateLinearBuffer(mBlock->share(offset, size, C2Fence{})); + } + return nullptr; + } + + sp toHidlMemory() { + if (mMemory) { + return mMemory; + } + return nullptr; + } +}; + +} // namespace android + +#endif // _ANDROID_MEDIA_MEDIACODECLINEARBLOCK_H_ \ No newline at end of file diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index f4d2d030c6f1b..28f55ca4ca14c 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -17,12 +17,17 @@ #define LOG_TAG "TvTuner-JNI" #include +#include "android_media_MediaCodecLinearBlock.h" #include "android_media_tv_Tuner.h" #include "android_runtime/AndroidRuntime.h" +#include +#include #include #include #include +#include +#include #pragma GCC diagnostic ignored "-Wunused-function" @@ -36,6 +41,7 @@ using ::android::hardware::tv::tuner::V1_0::DemuxAlpLengthType; using ::android::hardware::tv::tuner::V1_0::DemuxFilterAvSettings; using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadSettings; using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType; +using ::android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent; using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; using ::android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings; using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionBits; @@ -128,10 +134,13 @@ struct fields_t { jmethodID lnbInitID; jmethodID onLnbEventID; jmethodID descramblerInitID; + jmethodID linearBlockInitID; + jmethodID linearBlockSetInternalStateID; }; static fields_t gFields; + static int IP_V4_LENGTH = 4; static int IP_V6_LENGTH = 16; @@ -196,8 +205,66 @@ DvrMQ& Dvr::getDvrMQ() { /////////////// FilterCallback /////////////////////// //TODO: implement filter callback -Return FilterCallback::onFilterEvent(const DemuxFilterEvent& /*filterEvent*/) { +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 block = _C2BlockFactory::CreateLinearBlock(ion); + + JNIEnv *env = AndroidRuntime::getJNIEnv(); + std::unique_ptr context{new JMediaCodecLinearBlock}; + context->mBlock = block; + + jobject linearBlock = + env->NewObject( + env->FindClass("android/media/MediaCodec$LinearBlock"), + gFields.linearBlockInitID); + env->CallVoidMethod( + linearBlock, + gFields.linearBlockSetInternalStateID, + (jlong)context.release(), + true); + return linearBlock; +} + +jobject FilterCallback::getMediaEvent(const DemuxFilterEvent::Event& event) { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + jclass clazz = env->FindClass("android/media/tv/tuner/filter/MediaEvent"); + jmethodID eventInit = env->GetMethodID(clazz, + "", + "(IZJJJLandroid/media/MediaCodec$LinearBlock;" + "ZJIZLandroid/media/tv/tuner/filter/AudioDescriptor;)V"); + + DemuxFilterMediaEvent mediaEvent = event.media(); + uint32_t dataLength = mediaEvent.dataLength; + const native_handle_t* h = mediaEvent.avMemory.getNativeHandle(); + jobject block = handleToLinearBlock(h, dataLength); + // TODO: handle other fields + + return env->NewObject(clazz, eventInit, (jint) 0, (jboolean) 0, (jlong) 0, (jlong) 0, (jlong) 0, + block, (jboolean) 0, (jlong) 0, (jint) 0, (jboolean) 0, NULL); +} + +Return FilterCallback::onFilterEvent(const DemuxFilterEvent& filterEvent) { ALOGD("FilterCallback::onFilterEvent"); + + JNIEnv *env = AndroidRuntime::getJNIEnv(); + jclass clazz = env->FindClass("android/media/tv/tuner/filter/Filter"); + + std::vector events = filterEvent.events; + jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/FilterEvent"); + jobjectArray array = env->NewObjectArray(events.size(), eventClazz, NULL); + + for (int i = 0; i < events.size(); i++) { + auto event = events[i]; + if (event.getDiscriminator() == DemuxFilterEvent::Event::hidl_discriminator::media) { + env->SetObjectArrayElement(array, i, getMediaEvent(event)); + } + } + env->CallVoidMethod( + mFilter, + env->GetMethodID(clazz, "onFilterEvent", + "([Landroid/media/tv/tuner/filter/FilterEvent;)V"), + array); return Void(); } @@ -1428,6 +1495,11 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) { jclass dvrClazz = env->FindClass("android/media/tv/tuner/dvr/Dvr"); gFields.dvrContext = env->GetFieldID(dvrClazz, "mNativeContext", "J"); gFields.dvrInitID = env->GetMethodID(dvrClazz, "", "()V"); + + jclass linearBlockClazz = env->FindClass("android/media/MediaCodec$LinearBlock"); + gFields.linearBlockInitID = env->GetMethodID(linearBlockClazz, "", "()V"); + gFields.linearBlockSetInternalStateID = + env->GetMethodID(linearBlockClazz, "setInternalStateLocked", "(JZ)V"); } static void android_media_tv_Tuner_native_setup(JNIEnv *env, jobject thiz) { diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index d899bbd6467fb..33b569e9dcc5a 100644 --- a/media/jni/android_media_tv_Tuner.h +++ b/media/jni/android_media_tv_Tuner.h @@ -101,8 +101,10 @@ struct FilterCallback : public IFilterCallback { virtual Return onFilterStatus(const DemuxFilterStatus status); void setFilter(const jobject filter); + jobject handleToLinearBlock(const native_handle_t* handle, uint32_t size); private: jweak mFilter; + jobject getMediaEvent(const DemuxFilterEvent::Event& event); }; struct FrontendCallback : public IFrontendCallback { @@ -158,7 +160,7 @@ private: hidl_vec mLnbIds; sp mLnb; sp mDemux; - int mDemuxId; + uint32_t mDemuxId; static jobject getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); static jobject getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); static jobject getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps);