Merge "Tuner JNI: use linearblock for media event"
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 012b8d6..73769be 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -652,7 +652,7 @@
         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 a98183b..cfb943b 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 java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
 
 /**
  * Tuner data filter.
@@ -177,6 +178,7 @@
 
     private long mNativeContext;
     private FilterCallback mCallback;
+    private Executor mExecutor;
     private final int mId;
     private int mMainType;
     private int mSubtype;
@@ -199,6 +201,12 @@
     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 @@
     }
 
     /** @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 47ec7e6..d2294b3 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -136,17 +136,23 @@
     ],
 
     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 71ba59c..893e516 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 @@
 static fields_t gFields;
 static const void *sRefBaseOwner;
 
-struct JMediaCodecLinearBlock {
-    std::shared_ptr<C2Buffer> mBuffer;
-    std::shared_ptr<C2ReadView> mReadonlyMapping;
-
-    std::shared_ptr<C2LinearBlock> mBlock;
-    std::shared_ptr<C2WriteView> mReadWriteMapping;
-
-    sp<IMemoryHeap> mHeap;
-    sp<hardware::HidlMemory> mMemory;
-
-    sp<MediaCodecBuffer> mLegacyBuffer;
-
-    std::once_flag mCopyWarningFlag;
-
-    std::shared_ptr<C2Buffer> 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<hardware::HidlMemory> toHidlMemory() {
-        if (mMemory) {
-            return mMemory;
-        }
-        return nullptr;
-    }
-};
 
 struct JMediaCodecGraphicBlock {
     std::shared_ptr<C2Buffer> mBuffer;
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 1d12e77..8899fee 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -21,6 +21,9 @@
 
 #include "jni.h"
 
+#include <C2Buffer.h>
+#include <binder/MemoryHeapBase.h>
+#include <media/MediaCodecBuffer.h>
 #include <media/MediaMetricsItem.h>
 #include <media/hardware/CryptoAPI.h>
 #include <media/stagefright/foundation/ABase.h>
diff --git a/media/jni/android_media_MediaCodecLinearBlock.h b/media/jni/android_media_MediaCodecLinearBlock.h
new file mode 100644
index 0000000..0843834
--- /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 <C2Buffer.h>
+#include <binder/MemoryHeapBase.h>
+#include <hidl/HidlSupport.h>
+#include <media/MediaCodecBuffer.h>
+
+namespace android {
+
+struct JMediaCodecLinearBlock {
+    std::shared_ptr<C2Buffer> mBuffer;
+    std::shared_ptr<C2ReadView> mReadonlyMapping;
+
+    std::shared_ptr<C2LinearBlock> mBlock;
+    std::shared_ptr<C2WriteView> mReadWriteMapping;
+
+    sp<IMemoryHeap> mHeap;
+    sp<hardware::HidlMemory> mMemory;
+
+    sp<MediaCodecBuffer> mLegacyBuffer;
+
+    std::once_flag mCopyWarningFlag;
+
+    std::shared_ptr<C2Buffer> 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<hardware::HidlMemory> 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 4f31f6c..5c39f29 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 <utils/Log.h>
 
+#include "android_media_MediaCodecLinearBlock.h"
 #include "android_media_tv_Tuner.h"
 #include "android_runtime/AndroidRuntime.h"
 
+#include <C2BlockInternal.h>
+#include <C2HandleIonInternal.h>
 #include <android/hardware/tv/tuner/1.0/ITuner.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <utils/NativeHandle.h>
 
 #pragma GCC diagnostic ignored "-Wunused-function"
 
@@ -36,6 +41,7 @@
 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;
@@ -130,10 +136,13 @@
     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;
 
@@ -198,8 +207,66 @@
 
 /////////////// FilterCallback ///////////////////////
 //TODO: implement filter callback
-Return<void> 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<C2LinearBlock> block = _C2BlockFactory::CreateLinearBlock(ion);
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    std::unique_ptr<JMediaCodecLinearBlock> 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,
+            "<init>",
+            "(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<void> FilterCallback::onFilterEvent(const DemuxFilterEvent& filterEvent) {
     ALOGD("FilterCallback::onFilterEvent");
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass clazz = env->FindClass("android/media/tv/tuner/filter/Filter");
+
+    std::vector<DemuxFilterEvent::Event> 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();
 }
 
@@ -1483,6 +1550,11 @@
     jclass dvrClazz = env->FindClass("android/media/tv/tuner/dvr/Dvr");
     gFields.dvrContext = env->GetFieldID(dvrClazz, "mNativeContext", "J");
     gFields.dvrInitID = env->GetMethodID(dvrClazz, "<init>", "()V");
+
+    jclass linearBlockClazz = env->FindClass("android/media/MediaCodec$LinearBlock");
+    gFields.linearBlockInitID = env->GetMethodID(linearBlockClazz, "<init>", "()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 c5590b9..32d4899 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -102,8 +102,10 @@
     virtual Return<void> 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 {
@@ -168,7 +170,7 @@
     hidl_vec<LnbId> mLnbIds;
     sp<ILnb> mLnb;
     sp<IDemux> 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);