Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 78be65d5 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Tuner JNI: Dvr and DvrCallback" into rvc-dev am: d9f9a8d7 am: 8611c84a

Change-Id: I51ec433f010fe894592522744ca97fa6ffedf9af
parents 11a75c9e 8611c84a
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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;
    }

+22 −1
Original line number Diff line number Diff line
@@ -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");
        }
    }

    /**
+27 −1
Original line number Diff line number Diff line
@@ -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);
    }
}
+163 −74
Original line number Diff line number Diff line
@@ -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<ILnb> Lnb::getILnb() {
}

/////////////// DvrCallback ///////////////////////
Return<void> DvrCallback::onRecordStatus(RecordStatus /*status*/) {
Return<void> DvrCallback::onRecordStatus(RecordStatus status) {
    ALOGD("DvrCallback::onRecordStatus");
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    env->CallVoidMethod(
            mDvr,
            gFields.onDvrRecordStatusID,
            (jint) status);
    return Void();
}

Return<void> DvrCallback::onPlaybackStatus(PlaybackStatus /*status*/) {
Return<void> 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);
}

DvrCallback::~DvrCallback() {
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    if (mDvr != NULL) {
        env->DeleteWeakGlobalRef(mDvr);
        mDvr = NULL;
    }
}

/////////////// Dvr ///////////////////////

Dvr::Dvr(sp<IDvr> sp, jweak obj) : mDvrSp(sp), mDvrObj(obj), mDvrMQEventFlag(nullptr) {}
Dvr::Dvr(sp<IDvr> sp, jobject obj) : mDvrSp(sp), mDvrMQEventFlag(nullptr) {
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    mDvrObj = env->NewWeakGlobalRef(obj);
}

Dvr::~Dvr() {
    EventFlag::deleteEventFlag(&mDvrMQEventFlag);
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    env->DeleteWeakGlobalRef(mDvrObj);
    mDvrObj = NULL;
}

int Dvr::close() {
jint Dvr::close() {
    Result r = mDvrSp->close();
    if (r == Result::SUCCESS) {
        EventFlag::deleteEventFlag(&mDvrMQEventFlag);
    }
    return (int)r;
    return (jint) r;
}

sp<IDvr> 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<IFilter> 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, "<init>", "()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, "<init>", "()V");
    gFields.onDvrPlaybackStatusID =
            env->GetMethodID(dvrRecorderClazz, "onPlaybackStatusChanged", "(I)V");

    jclass linearBlockClazz = env->FindClass("android/media/MediaCodec$LinearBlock");
    gFields.linearBlockInitID = env->GetMethodID(linearBlockClazz, "<init>", "()V");
@@ -2485,10 +2523,11 @@ static DemuxFilterSettings getFilterConfiguration(
    return filterSettings;
}

static jint copyData(JNIEnv *env, sp<Filter> filter, jbyteArray buffer, jlong offset, jlong size) {
static jint copyData(JNIEnv *env, std::unique_ptr<MQ>& 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> filter, jbyteArray buffer, jlong of
        return 0;
    }

    if (filter->mFilterMQ->read(reinterpret_cast<unsigned char*>(dst) + offset, size)) {
    if (mq->read(reinterpret_cast<unsigned char*>(dst) + offset, size)) {
        env->ReleaseByteArrayElements(buffer, dst, 0);
        filter->mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
        flag->wake(static_cast<uint32_t>(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<FilterMQ>(filterMQDesc, true);
            filterSp->mFilterMQ = std::make_unique<MQ>(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,36 +2820,48 @@ 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<IDvr> dvrSp = getDvr(env, dvr)->getIDvr();
    sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
    if (dvrSp == NULL || iFilterSp == NULL) {
        return false;
static jint android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) {
    sp<Dvr> dvrSp = getDvr(env, dvr);
    if (dvrSp == NULL) {
        return (jint) Result::NOT_INITIALIZED;
    }
    Result result = dvrSp->attachFilter(iFilterSp);
    return (int) result;
    sp<Filter> filterSp = getFilter(env, filter);
    if (filterSp == NULL) {
        return (jint) Result::INVALID_ARGUMENT;
    }
    sp<IDvr> iDvrSp = dvrSp->getIDvr();
    sp<IFilter> iFilterSp = filterSp->getIFilter();
    Result result = iDvrSp->attachFilter(iFilterSp);
    return (jint) result;
}

static int android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) {
    sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr();
    sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
    if (dvrSp == NULL || iFilterSp == NULL) {
        return false;
static jint android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) {
    sp<Dvr> dvrSp = getDvr(env, dvr);
    if (dvrSp == NULL) {
        return (jint) Result::NOT_INITIALIZED;
    }
    Result result = dvrSp->detachFilter(iFilterSp);
    return (int) result;
    sp<Filter> filterSp = getFilter(env, filter);
    if (filterSp == NULL) {
        return (jint) Result::INVALID_ARGUMENT;
    }
    sp<IDvr> iDvrSp = dvrSp->getIDvr();
    sp<IFilter> iFilterSp = filterSp->getIFilter();
    Result result = iDvrSp->detachFilter(iFilterSp);
    return (jint) result;
}

static int android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobject settings) {
static jint android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobject settings) {
    sp<Dvr> dvrSp = getDvr(env, dvr);
    sp<IDvr> iDvrSp = dvrSp->getIDvr();
    if (dvrSp == NULL) {
        ALOGD("Failed to configure dvr: dvr not found");
        return (int)Result::INVALID_STATE;
        return (int)Result::NOT_INITIALIZED;
    }
    sp<IDvr> iDvrSp = dvrSp->getIDvr();
    Result result = iDvrSp->configure(getDvrSettings(env, settings));
    if (result != Result::SUCCESS) {
        return (jint) result;
    }
    MQDescriptorSync<uint8_t> dvrMQDesc;
    if (result == Result::SUCCESS) {
    Result getQueueDescResult = Result::UNKNOWN_ERROR;
    iDvrSp->getQueueDesc(
            [&](Result r, const MQDescriptorSync<uint8_t>& desc) {
@@ -2819,48 +2870,53 @@ static int android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobjec
                ALOGD("getDvrQueueDesc");
            });
    if (getQueueDescResult == Result::SUCCESS) {
            dvrSp->mDvrMQ = std::make_unique<DvrMQ>(dvrMQDesc, true);
        dvrSp->mDvrMQ = std::make_unique<MQ>(dvrMQDesc, true);
        EventFlag::createEventFlag(
                dvrSp->mDvrMQ->getEventFlagWord(), &(dvrSp->mDvrMQEventFlag));
    }
    return (jint) getQueueDescResult;
}
    return (int)result;
}

static int android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) {

    sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr();
static jint android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) {
    sp<Dvr> 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<IDvr> iDvrSp = dvrSp->getIDvr();
    Result result = iDvrSp->start();
    return (jint) result;
}

static int android_media_tv_Tuner_stop_dvr(JNIEnv *env, jobject dvr) {
    sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr();
static jint android_media_tv_Tuner_stop_dvr(JNIEnv *env, jobject dvr) {
    sp<Dvr> 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<IDvr> iDvrSp = dvrSp->getIDvr();
    Result result = iDvrSp->stop();
    return (jint) result;
}

static int android_media_tv_Tuner_flush_dvr(JNIEnv *env, jobject dvr) {
    sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr();
static jint android_media_tv_Tuner_flush_dvr(JNIEnv *env, jobject dvr) {
    sp<Dvr> 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<IDvr> 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<Dvr> 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<Lnb> 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,11 +3003,37 @@ 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
        JNIEnv* env, jobject dvr, jbyteArray buffer, jlong offset, jlong size) {
    sp<Dvr> 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<unsigned char*>(src) + offset, size)) {
        env->ReleaseByteArrayElements(buffer, src, 0);
        dvrSp->mDvrMQEventFlag->wake(static_cast<uint32_t>(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) {
    sp<Dvr> dvrSp = getDvr(env, dvr);
@@ -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,11 +3083,18 @@ 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
        JNIEnv *env, jobject dvr, jbyteArray buffer, jlong offset, jlong size) {
    sp<Dvr> 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[] = {
    { "nativeInit", "()V", (void *)android_media_tv_Tuner_native_init },
+7 −6
Original line number Diff line number Diff line
@@ -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<uint8_t, kSynchronizedReadWrite>;
using DvrMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
using MQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;

namespace android {

@@ -84,6 +83,7 @@ struct Lnb : public RefBase {
};

struct DvrCallback : public IDvrCallback {
    ~DvrCallback();
    virtual Return<void> onRecordStatus(RecordStatus status);
    virtual Return<void> onPlaybackStatus(PlaybackStatus status);

@@ -95,18 +95,19 @@ private:
struct Dvr : public RefBase {
    Dvr(sp<IDvr> sp, jweak obj);
    ~Dvr();
    int close();
    DvrMQ& getDvrMQ();
    jint close();
    MQ& getDvrMQ();
    sp<IDvr> getIDvr();
    sp<IDvr> mDvrSp;
    jweak mDvrObj;
    std::unique_ptr<DvrMQ> mDvrMQ;
    std::unique_ptr<MQ> mDvrMQ;
    EventFlag* mDvrMQEventFlag;
    std::string mFilePath;
    int mFd;
};

struct FilterCallback : public IFilterCallback {
    ~FilterCallback();
    virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent);
    virtual Return<void> onFilterStatus(const DemuxFilterStatus status);

@@ -149,7 +150,7 @@ struct Filter : public RefBase {
    int close();
    sp<IFilter> getIFilter();
    sp<IFilter> mFilterSp;
    std::unique_ptr<FilterMQ> mFilterMQ;
    std::unique_ptr<MQ> mFilterMQ;
    EventFlag* mFilterMQEventFlag;
    jweak mFilterObj;
};