From 431e561fdaad27b1c7e3784f864e47e583adf0ae Mon Sep 17 00:00:00 2001 From: shubang Date: Mon, 30 Mar 2020 21:24:56 -0700 Subject: [PATCH] Tuner JNI: Dvr and DvrCallback Bug: 139308734 Test: mmm Change-Id: I2ea2d2e8b8309a70f9aa3dfeb6a3025c7e515afd --- media/java/android/media/tv/tuner/Tuner.java | 2 + .../media/tv/tuner/dvr/DvrPlayback.java | 23 +- .../media/tv/tuner/dvr/DvrRecorder.java | 28 +- media/jni/android_media_tv_Tuner.cpp | 257 ++++++++++++------ media/jni/android_media_tv_Tuner.h | 13 +- 5 files changed, 231 insertions(+), 92 deletions(-) diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 894882f07b5b3..d4494acb7e7ab 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -906,6 +906,7 @@ public class Tuner implements AutoCloseable { Objects.requireNonNull(l, "OnRecordStatusChangedListener must not be null"); checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX); DvrRecorder dvr = nativeOpenDvrRecorder(bufferSize); + dvr.setListener(executor, l); return dvr; } @@ -928,6 +929,7 @@ public class Tuner implements AutoCloseable { Objects.requireNonNull(l, "OnPlaybackStatusChangedListener must not be null"); checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX); DvrPlayback dvr = nativeOpenDvrPlayback(bufferSize); + dvr.setListener(executor, l); return dvr; } diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java index 0d10d941a15d0..9971c847dd54d 100644 --- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java +++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java @@ -21,12 +21,15 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.hardware.tv.tuner.V1_0.Constants; +import android.media.tv.tuner.Tuner; import android.media.tv.tuner.Tuner.Result; +import android.media.tv.tuner.TunerUtils; import android.media.tv.tuner.filter.Filter; import android.os.ParcelFileDescriptor; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.Executor; /** * Digital Video Record (DVR) class which provides playback control on Demux's input buffer. @@ -70,6 +73,8 @@ public class DvrPlayback implements AutoCloseable { public static final int PLAYBACK_STATUS_FULL = Constants.PlaybackStatus.SPACE_FULL; private long mNativeContext; + private OnPlaybackStatusChangedListener mListener; + private Executor mExecutor; private native int nativeAttachFilter(Filter filter); private native int nativeDetachFilter(Filter filter); @@ -85,6 +90,19 @@ public class DvrPlayback implements AutoCloseable { private DvrPlayback() { } + /** @hide */ + public void setListener( + @NonNull Executor executor, @NonNull OnPlaybackStatusChangedListener listener) { + mExecutor = executor; + mListener = listener; + } + + private void onPlaybackStatusChanged(int status) { + if (mExecutor != null && mListener != null) { + mExecutor.execute(() -> mListener.onPlaybackStatusChanged(status)); + } + } + /** * Attaches a filter to DVR interface for recording. @@ -164,7 +182,10 @@ public class DvrPlayback implements AutoCloseable { */ @Override public void close() { - nativeClose(); + int res = nativeClose(); + if (res != Tuner.RESULT_SUCCESS) { + TunerUtils.throwExceptionForResult(res, "failed to close DVR playback"); + } } /** diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java index dbda7bbad5f2f..198bd0f4e78e4 100644 --- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java +++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java @@ -19,10 +19,14 @@ package android.media.tv.tuner.dvr; import android.annotation.BytesLong; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.media.tv.tuner.Tuner; import android.media.tv.tuner.Tuner.Result; +import android.media.tv.tuner.TunerUtils; import android.media.tv.tuner.filter.Filter; import android.os.ParcelFileDescriptor; +import java.util.concurrent.Executor; + /** * Digital Video Record (DVR) recorder class which provides record control on Demux's output buffer. * @@ -31,6 +35,8 @@ import android.os.ParcelFileDescriptor; @SystemApi public class DvrRecorder implements AutoCloseable { private long mNativeContext; + private OnRecordStatusChangedListener mListener; + private Executor mExecutor; private native int nativeAttachFilter(Filter filter); private native int nativeDetachFilter(Filter filter); @@ -46,6 +52,19 @@ public class DvrRecorder implements AutoCloseable { private DvrRecorder() { } + /** @hide */ + public void setListener( + @NonNull Executor executor, @NonNull OnRecordStatusChangedListener listener) { + mExecutor = executor; + mListener = listener; + } + + private void onRecordStatusChanged(int status) { + if (mExecutor != null && mListener != null) { + mExecutor.execute(() -> mListener.onRecordStatusChanged(status)); + } + } + /** * Attaches a filter to DVR interface for recording. @@ -125,7 +144,10 @@ public class DvrRecorder implements AutoCloseable { */ @Override public void close() { - nativeClose(); + int res = nativeClose(); + if (res != Tuner.RESULT_SUCCESS) { + TunerUtils.throwExceptionForResult(res, "failed to close DVR recorder"); + } } /** @@ -163,6 +185,10 @@ public class DvrRecorder implements AutoCloseable { */ @BytesLong public long write(@NonNull byte[] bytes, @BytesLong long offset, @BytesLong long size) { + if (size + offset > bytes.length) { + throw new ArrayIndexOutOfBoundsException( + "Array length=" + bytes.length + ", offset=" + offset + ", size=" + size); + } return nativeWrite(bytes, offset, size); } } diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index 9310d38c3bd14..4a7e8e1fa1516 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -151,6 +151,8 @@ struct fields_t { jmethodID onFilterEventID; jmethodID lnbInitID; jmethodID onLnbEventID; + jmethodID onDvrRecordStatusID; + jmethodID onDvrPlaybackStatusID; jmethodID descramblerInitID; jmethodID linearBlockInitID; jmethodID linearBlockSetInternalStateID; @@ -198,13 +200,23 @@ sp Lnb::getILnb() { } /////////////// DvrCallback /////////////////////// -Return DvrCallback::onRecordStatus(RecordStatus /*status*/) { +Return DvrCallback::onRecordStatus(RecordStatus status) { ALOGD("DvrCallback::onRecordStatus"); + JNIEnv *env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod( + mDvr, + gFields.onDvrRecordStatusID, + (jint) status); return Void(); } -Return DvrCallback::onPlaybackStatus(PlaybackStatus /*status*/) { +Return DvrCallback::onPlaybackStatus(PlaybackStatus status) { ALOGD("DvrCallback::onPlaybackStatus"); + JNIEnv *env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod( + mDvr, + gFields.onDvrPlaybackStatusID, + (jint) status); return Void(); } @@ -214,27 +226,40 @@ void DvrCallback::setDvr(const jobject dvr) { mDvr = env->NewWeakGlobalRef(dvr); } -/////////////// Dvr /////////////////////// - -Dvr::Dvr(sp sp, jweak obj) : mDvrSp(sp), mDvrObj(obj), mDvrMQEventFlag(nullptr) {} - -Dvr::~Dvr() { - EventFlag::deleteEventFlag(&mDvrMQEventFlag); +DvrCallback::~DvrCallback() { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + if (mDvr != NULL) { + env->DeleteWeakGlobalRef(mDvr); + mDvr = NULL; + } } -int Dvr::close() { +/////////////// Dvr /////////////////////// + +Dvr::Dvr(sp sp, jobject obj) : mDvrSp(sp), mDvrMQEventFlag(nullptr) { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + mDvrObj = env->NewWeakGlobalRef(obj); +} + +Dvr::~Dvr() { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + env->DeleteWeakGlobalRef(mDvrObj); + mDvrObj = NULL; +} + +jint Dvr::close() { Result r = mDvrSp->close(); if (r == Result::SUCCESS) { EventFlag::deleteEventFlag(&mDvrMQEventFlag); } - return (int)r; + return (jint) r; } sp Dvr::getIDvr() { return mDvrSp; } -DvrMQ& Dvr::getDvrMQ() { +MQ& Dvr::getDvrMQ() { return *mDvrMQ; } @@ -558,6 +583,14 @@ void FilterCallback::setFilter(const jobject filter) { mFilter = env->NewWeakGlobalRef(filter); } +FilterCallback::~FilterCallback() { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + if (mFilter != NULL) { + env->DeleteWeakGlobalRef(mFilter); + mFilter = NULL; + } +} + /////////////// Filter /////////////////////// Filter::Filter(sp sp, jobject obj) : mFilterSp(sp) { @@ -785,6 +818,7 @@ JTuner::JTuner(JNIEnv *env, jobject thiz) JTuner::~JTuner() { JNIEnv *env = AndroidRuntime::getJNIEnv(); + env->DeleteWeakGlobalRef(mObject); env->DeleteGlobalRef(mClass); mTuner = NULL; mClass = NULL; @@ -1988,10 +2022,14 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) { jclass dvrRecorderClazz = env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"); gFields.dvrRecorderContext = env->GetFieldID(dvrRecorderClazz, "mNativeContext", "J"); gFields.dvrRecorderInitID = env->GetMethodID(dvrRecorderClazz, "", "()V"); + gFields.onDvrRecordStatusID = + env->GetMethodID(dvrRecorderClazz, "onRecordStatusChanged", "(I)V"); jclass dvrPlaybackClazz = env->FindClass("android/media/tv/tuner/dvr/DvrPlayback"); gFields.dvrPlaybackContext = env->GetFieldID(dvrPlaybackClazz, "mNativeContext", "J"); gFields.dvrPlaybackInitID = env->GetMethodID(dvrPlaybackClazz, "", "()V"); + gFields.onDvrPlaybackStatusID = + env->GetMethodID(dvrRecorderClazz, "onPlaybackStatusChanged", "(I)V"); jclass linearBlockClazz = env->FindClass("android/media/MediaCodec$LinearBlock"); gFields.linearBlockInitID = env->GetMethodID(linearBlockClazz, "", "()V"); @@ -2485,10 +2523,11 @@ static DemuxFilterSettings getFilterConfiguration( return filterSettings; } -static jint copyData(JNIEnv *env, sp filter, jbyteArray buffer, jlong offset, jlong size) { +static jint copyData(JNIEnv *env, std::unique_ptr& mq, EventFlag* flag, jbyteArray buffer, + jlong offset, jlong size) { ALOGD("copyData, size=%ld, offset=%ld", (long) size, (long) offset); - jlong available = filter->mFilterMQ->availableToRead(); + jlong available = mq->availableToRead(); ALOGD("copyData, available=%ld", (long) available); size = std::min(size, available); @@ -2500,9 +2539,9 @@ static jint copyData(JNIEnv *env, sp filter, jbyteArray buffer, jlong of return 0; } - if (filter->mFilterMQ->read(reinterpret_cast(dst) + offset, size)) { + if (mq->read(reinterpret_cast(dst) + offset, size)) { env->ReleaseByteArrayElements(buffer, dst, 0); - filter->mFilterMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); + flag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); } else { ALOGD("Failed to read FMQ"); env->ReleaseByteArrayElements(buffer, dst, 0); @@ -2537,7 +2576,7 @@ static jint android_media_tv_Tuner_configure_filter( ALOGD("getFilterQueueDesc"); }); if (getQueueDescResult == Result::SUCCESS) { - filterSp->mFilterMQ = std::make_unique(filterMQDesc, true); + filterSp->mFilterMQ = std::make_unique(filterMQDesc, true); EventFlag::createEventFlag( filterSp->mFilterMQ->getEventFlagWord(), &(filterSp->mFilterMQEventFlag)); } @@ -2622,7 +2661,7 @@ static jint android_media_tv_Tuner_read_filter_fmq( ALOGD("Failed to read filter FMQ: filter not found"); return (jint) Result::INVALID_STATE; } - return copyData(env, filterSp, buffer, offset, size); + return copyData(env, filterSp->mFilterMQ, filterSp->mFilterMQEventFlag, buffer, offset, size); } static jint android_media_tv_Tuner_close_filter(JNIEnv *env, jobject filter) { @@ -2781,86 +2820,103 @@ static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv* env, jobject thiz) return tuner->getDemuxCaps(); } -static int android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) { - sp dvrSp = getDvr(env, dvr)->getIDvr(); - sp iFilterSp = getFilter(env, filter)->getIFilter(); - if (dvrSp == NULL || iFilterSp == NULL) { - return false; - } - Result result = dvrSp->attachFilter(iFilterSp); - return (int) result; -} - -static int android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) { - sp dvrSp = getDvr(env, dvr)->getIDvr(); - sp iFilterSp = getFilter(env, filter)->getIFilter(); - if (dvrSp == NULL || iFilterSp == NULL) { - return false; - } - Result result = dvrSp->detachFilter(iFilterSp); - return (int) result; -} - -static int android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobject settings) { +static jint android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp dvrSp = getDvr(env, dvr); + if (dvrSp == NULL) { + return (jint) Result::NOT_INITIALIZED; + } + sp filterSp = getFilter(env, filter); + if (filterSp == NULL) { + return (jint) Result::INVALID_ARGUMENT; + } sp iDvrSp = dvrSp->getIDvr(); + sp iFilterSp = filterSp->getIFilter(); + Result result = iDvrSp->attachFilter(iFilterSp); + return (jint) result; +} + +static jint android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) { + sp dvrSp = getDvr(env, dvr); + if (dvrSp == NULL) { + return (jint) Result::NOT_INITIALIZED; + } + sp filterSp = getFilter(env, filter); + if (filterSp == NULL) { + return (jint) Result::INVALID_ARGUMENT; + } + sp iDvrSp = dvrSp->getIDvr(); + sp iFilterSp = filterSp->getIFilter(); + Result result = iDvrSp->detachFilter(iFilterSp); + return (jint) result; +} + +static jint android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobject settings) { + sp dvrSp = getDvr(env, dvr); if (dvrSp == NULL) { ALOGD("Failed to configure dvr: dvr not found"); - return (int)Result::INVALID_STATE; + return (int)Result::NOT_INITIALIZED; } + sp iDvrSp = dvrSp->getIDvr(); Result result = iDvrSp->configure(getDvrSettings(env, settings)); - MQDescriptorSync dvrMQDesc; - if (result == Result::SUCCESS) { - Result getQueueDescResult = Result::UNKNOWN_ERROR; - iDvrSp->getQueueDesc( - [&](Result r, const MQDescriptorSync& desc) { - dvrMQDesc = desc; - getQueueDescResult = r; - ALOGD("getDvrQueueDesc"); - }); - if (getQueueDescResult == Result::SUCCESS) { - dvrSp->mDvrMQ = std::make_unique(dvrMQDesc, true); - EventFlag::createEventFlag( - dvrSp->mDvrMQ->getEventFlagWord(), &(dvrSp->mDvrMQEventFlag)); - } + if (result != Result::SUCCESS) { + return (jint) result; } - return (int)result; + MQDescriptorSync dvrMQDesc; + Result getQueueDescResult = Result::UNKNOWN_ERROR; + iDvrSp->getQueueDesc( + [&](Result r, const MQDescriptorSync& desc) { + dvrMQDesc = desc; + getQueueDescResult = r; + ALOGD("getDvrQueueDesc"); + }); + if (getQueueDescResult == Result::SUCCESS) { + dvrSp->mDvrMQ = std::make_unique(dvrMQDesc, true); + EventFlag::createEventFlag( + dvrSp->mDvrMQ->getEventFlagWord(), &(dvrSp->mDvrMQEventFlag)); + } + return (jint) getQueueDescResult; } -static int android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) { - - sp dvrSp = getDvr(env, dvr)->getIDvr(); +static jint android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) { + sp dvrSp = getDvr(env, dvr); if (dvrSp == NULL) { ALOGD("Failed to start dvr: dvr not found"); - return false; + return (jint) Result::NOT_INITIALIZED; } - - Result result = dvrSp->start(); - return (int) result; + sp iDvrSp = dvrSp->getIDvr(); + Result result = iDvrSp->start(); + return (jint) result; } -static int android_media_tv_Tuner_stop_dvr(JNIEnv *env, jobject dvr) { - sp dvrSp = getDvr(env, dvr)->getIDvr(); +static jint android_media_tv_Tuner_stop_dvr(JNIEnv *env, jobject dvr) { + sp dvrSp = getDvr(env, dvr); if (dvrSp == NULL) { ALOGD("Failed to stop dvr: dvr not found"); - return false; + return (jint) Result::NOT_INITIALIZED; } - Result result = dvrSp->stop(); - return (int) result; + sp iDvrSp = dvrSp->getIDvr(); + Result result = iDvrSp->stop(); + return (jint) result; } -static int android_media_tv_Tuner_flush_dvr(JNIEnv *env, jobject dvr) { - sp dvrSp = getDvr(env, dvr)->getIDvr(); +static jint android_media_tv_Tuner_flush_dvr(JNIEnv *env, jobject dvr) { + sp dvrSp = getDvr(env, dvr); if (dvrSp == NULL) { ALOGD("Failed to flush dvr: dvr not found"); - return false; + return (jint) Result::NOT_INITIALIZED; } - Result result = dvrSp->flush(); - return (int) result; + sp iDvrSp = dvrSp->getIDvr(); + Result result = iDvrSp->flush(); + return (jint) result; } -static int android_media_tv_Tuner_close_dvr(JNIEnv*, jobject) { - return 0; +static jint android_media_tv_Tuner_close_dvr(JNIEnv* env, jobject dvr) { + sp dvrSp = getDvr(env, dvr); + if (dvrSp == NULL) { + ALOGD("Failed to close dvr: dvr not found"); + return (jint) Result::NOT_INITIALIZED; + } + return dvrSp->close(); } static sp getLnb(JNIEnv *env, jobject lnb) { @@ -2916,7 +2972,7 @@ static jlong android_media_tv_Tuner_read_dvr(JNIEnv *env, jobject dvr, jlong siz long available = dvrSp->mDvrMQ->availableToWrite(); long write = std::min((long) size, available); - DvrMQ::MemTransaction tx; + MQ::MemTransaction tx; long ret = 0; if (dvrSp->mDvrMQ->beginWrite(write, &tx)) { auto first = tx.getFirstRegion(); @@ -2947,10 +3003,36 @@ static jlong android_media_tv_Tuner_read_dvr(JNIEnv *env, jobject dvr, jlong siz } static jlong android_media_tv_Tuner_read_dvr_from_array( - JNIEnv /* *env */, jobject /* dvr */, jbyteArray /* bytes */, jlong /* offset */, - jlong /* size */) { - //TODO: impl - return 0; + JNIEnv* env, jobject dvr, jbyteArray buffer, jlong offset, jlong size) { + sp dvrSp = getDvr(env, dvr); + if (dvrSp == NULL) { + ALOGW("Failed to read dvr: dvr not found"); + return 0; + } + if (dvrSp->mDvrMQ == NULL) { + ALOGW("Failed to read dvr: dvr not configured"); + return 0; + } + + jlong available = dvrSp->mDvrMQ->availableToWrite(); + size = std::min(size, available); + + jboolean isCopy; + jbyte *src = env->GetByteArrayElements(buffer, &isCopy); + if (src == nullptr) { + ALOGD("Failed to GetByteArrayElements"); + return 0; + } + + if (dvrSp->mDvrMQ->write(reinterpret_cast(src) + offset, size)) { + env->ReleaseByteArrayElements(buffer, src, 0); + dvrSp->mDvrMQEventFlag->wake(static_cast(DemuxQueueNotifyBits::DATA_CONSUMED)); + } else { + ALOGD("Failed to write FMQ"); + env->ReleaseByteArrayElements(buffer, src, 0); + return 0; + } + return size; } static jlong android_media_tv_Tuner_write_dvr(JNIEnv *env, jobject dvr, jlong size) { @@ -2965,13 +3047,13 @@ static jlong android_media_tv_Tuner_write_dvr(JNIEnv *env, jobject dvr, jlong si return 0; } - DvrMQ& dvrMq = dvrSp->getDvrMQ(); + MQ& dvrMq = dvrSp->getDvrMQ(); long available = dvrMq.availableToRead(); long toRead = std::min((long) size, available); long ret = 0; - DvrMQ::MemTransaction tx; + MQ::MemTransaction tx; if (dvrMq.beginRead(toRead, &tx)) { auto first = tx.getFirstRegion(); auto data = first.getAddress(); @@ -3001,10 +3083,17 @@ static jlong android_media_tv_Tuner_write_dvr(JNIEnv *env, jobject dvr, jlong si } static jlong android_media_tv_Tuner_write_dvr_to_array( - JNIEnv /* *env */, jobject /* dvr */, jbyteArray /* bytes */, jlong /* offset */, - jlong /* size */) { - //TODO: impl - return 0; + JNIEnv *env, jobject dvr, jbyteArray buffer, jlong offset, jlong size) { + sp dvrSp = getDvr(env, dvr); + if (dvrSp == NULL) { + ALOGW("Failed to write dvr: dvr not found"); + return 0; + } + if (dvrSp->mDvrMQ == NULL) { + ALOGW("Failed to write dvr: dvr not configured"); + return 0; + } + return copyData(env, dvrSp->mDvrMQ, dvrSp->mDvrMQEventFlag, buffer, offset, size); } static const JNINativeMethod gTunerMethods[] = { diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index 18aac285e7c08..7e860b9c872f6 100644 --- a/media/jni/android_media_tv_Tuner.h +++ b/media/jni/android_media_tv_Tuner.h @@ -62,8 +62,7 @@ using ::android::hardware::tv::tuner::V1_0::PlaybackStatus; using ::android::hardware::tv::tuner::V1_0::RecordStatus; using ::android::hardware::tv::tuner::V1_0::Result; -using FilterMQ = MessageQueue; -using DvrMQ = MessageQueue; +using MQ = MessageQueue; namespace android { @@ -84,6 +83,7 @@ struct Lnb : public RefBase { }; struct DvrCallback : public IDvrCallback { + ~DvrCallback(); virtual Return onRecordStatus(RecordStatus status); virtual Return onPlaybackStatus(PlaybackStatus status); @@ -95,18 +95,19 @@ private: struct Dvr : public RefBase { Dvr(sp sp, jweak obj); ~Dvr(); - int close(); - DvrMQ& getDvrMQ(); + jint close(); + MQ& getDvrMQ(); sp getIDvr(); sp mDvrSp; jweak mDvrObj; - std::unique_ptr mDvrMQ; + std::unique_ptr mDvrMQ; EventFlag* mDvrMQEventFlag; std::string mFilePath; int mFd; }; struct FilterCallback : public IFilterCallback { + ~FilterCallback(); virtual Return onFilterEvent(const DemuxFilterEvent& filterEvent); virtual Return onFilterStatus(const DemuxFilterStatus status); @@ -149,7 +150,7 @@ struct Filter : public RefBase { int close(); sp getIFilter(); sp mFilterSp; - std::unique_ptr mFilterMQ; + std::unique_ptr mFilterMQ; EventFlag* mFilterMQEventFlag; jweak mFilterObj; };