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

Commit f2659f5f authored by Amy Zhang's avatar Amy Zhang Committed by Android (Google) Code Review
Browse files

Merge "Add API to get the shared memory Audio/Video handle"

parents 14072bb9 976c6404
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -51,4 +51,23 @@ interface IFilter extends @1.0::IFilter {
     *         UNKNOWN_ERROR if failed for other reasons.
     */
    configureIpCid(uint32_t ipCid) generates (Result result);

    /**
     * Get the shared AV memory handle. Use IFilter.releaseAvHandle to release the handle.
     *
     * When media filters are opened, call this API to initialize the share memory handle if it's
     * needed.
     *
     * If DemuxFilterMediaEvent.avMemory contains file descriptor, share memory should be ignored.
     *
     * @return avMemory A handle associated to the shared memory for audio or video.
     *         avMemory.data[0] is normally an fd for ION memory. When the avMemory->numFd is 0, the
     *         share memory is not initialized and does not contain valid fd.
     *         avMemory.data[avMemory.numFds] is an index used as a parameter of
     *         C2DataIdInfo to build C2 buffer in Codec. No C2 buffer would be created if the index
     *         does not exist.
     * @return avMemSize the size of the shared av memory. It should be ignored when the share
     *         memory is not initialized.
     */
    getAvSharedHandle() generates (Result result, handle avMemory, uint64_t avMemSize);
};
+167 −50
Original line number Diff line number Diff line
@@ -163,8 +163,17 @@ Return<Result> Filter::flush() {
    return Result::SUCCESS;
}

Return<Result> Filter::releaseAvHandle(const hidl_handle& /*avMemory*/, uint64_t avDataId) {
Return<Result> Filter::releaseAvHandle(const hidl_handle& avMemory, uint64_t avDataId) {
    ALOGV("%s", __FUNCTION__);

    if ((avMemory.getNativeHandle()->numFds > 0) &&
        (mSharedAvMemHandle.getNativeHandle()->numFds > 0) &&
        (sameFile(avMemory.getNativeHandle()->data[0],
                  mSharedAvMemHandle.getNativeHandle()->data[0]))) {
        freeSharedAvHandle();
        return Result::SUCCESS;
    }

    if (mDataId2Avfd.find(avDataId) == mDataId2Avfd.end()) {
        return Result::INVALID_ARGUMENT;
    }
@@ -190,6 +199,35 @@ Return<Result> Filter::configureIpCid(uint32_t ipCid) {
    return Result::SUCCESS;
}

Return<void> Filter::getAvSharedHandle(getAvSharedHandle_cb _hidl_cb) {
    ALOGV("%s", __FUNCTION__);

    if (!mIsMediaFilter) {
        _hidl_cb(Result::INVALID_STATE, NULL, BUFFER_SIZE_16M);
        return Void();
    }

    if (mSharedAvMemHandle.getNativeHandle() != nullptr) {
        _hidl_cb(Result::SUCCESS, mSharedAvMemHandle, BUFFER_SIZE_16M);
        return Void();
    }

    int av_fd = createAvIonFd(BUFFER_SIZE_16M);
    if (av_fd == -1) {
        _hidl_cb(Result::UNKNOWN_ERROR, NULL, 0);
    }

    native_handle_t* nativeHandle = createNativeHandle(av_fd);
    if (nativeHandle == NULL) {
        _hidl_cb(Result::UNKNOWN_ERROR, NULL, 0);
    }
    mSharedAvMemHandle.setTo(nativeHandle, /*shouldOwn=*/true);
    ::close(av_fd);

    _hidl_cb(Result::SUCCESS, mSharedAvMemHandle, BUFFER_SIZE_16M);
    return Void();
}

bool Filter::createFilterMQ() {
    ALOGV("%s", __FUNCTION__);

@@ -313,8 +351,17 @@ void Filter::freeAvHandle() {
    }
    for (int i = 0; i < mFilterEvent.events.size(); i++) {
        ::close(mFilterEvent.events[i].media().avMemory.getNativeHandle()->data[0]);
        native_handle_close(mFilterEvent.events[i].media().avMemory.getNativeHandle());
        native_handle_delete(const_cast<native_handle_t*>(
                mFilterEvent.events[i].media().avMemory.getNativeHandle()));
    }
}

void Filter::freeSharedAvHandle() {
    if (!mIsMediaFilter) {
        return;
    }
    ::close(mSharedAvMemHandle.getNativeHandle()->data[0]);
    native_handle_delete(const_cast<native_handle_t*>(mSharedAvMemHandle.getNativeHandle()));
}

void Filter::maySendFilterStatusCallback() {
@@ -509,8 +556,8 @@ Result Filter::startMediaFilterHandler() {
        return Result::SUCCESS;
    }

    if (mPts) {
    Result result;
    if (mPts) {
        result = createMediaFilterEventWithIon(mFilterOutput);
        if (result == Result::SUCCESS) {
            mFilterOutput.clear();
@@ -551,7 +598,10 @@ Result Filter::startMediaFilterHandler() {
            continue;
        }

        createMediaFilterEventWithIon(mPesOutput);
        result = createMediaFilterEventWithIon(mPesOutput);
        if (result != Result::SUCCESS) {
            return result;
        }
    }

    mFilterOutput.clear();
@@ -560,51 +610,14 @@ Result Filter::startMediaFilterHandler() {
}

Result Filter::createMediaFilterEventWithIon(vector<uint8_t> output) {
    int av_fd = createAvIonFd(output.size());
    if (av_fd == -1) {
    if (mUsingSharedAvMem) {
        if (mSharedAvMemHandle.getNativeHandle() == nullptr) {
            return Result::UNKNOWN_ERROR;
        }
    // copy the filtered data to the buffer
    uint8_t* avBuffer = getIonBuffer(av_fd, output.size());
    if (avBuffer == NULL) {
        return Result::UNKNOWN_ERROR;
        return createShareMemMediaEvents(output);
    }
    memcpy(avBuffer, output.data(), output.size() * sizeof(uint8_t));

    native_handle_t* nativeHandle = createNativeHandle(av_fd);
    if (nativeHandle == NULL) {
        return Result::UNKNOWN_ERROR;
    }
    hidl_handle handle;
    handle.setTo(nativeHandle, /*shouldOwn=*/true);

    // Create a dataId and add a <dataId, av_fd> pair into the dataId2Avfd map
    uint64_t dataId = mLastUsedDataId++ /*createdUID*/;
    mDataId2Avfd[dataId] = dup(av_fd);

    // Create mediaEvent and send callback
    DemuxFilterMediaEvent mediaEvent;
    mediaEvent = {
            .avMemory = std::move(handle),
            .dataLength = static_cast<uint32_t>(output.size()),
            .avDataId = dataId,
    };
    if (mPts) {
        mediaEvent.pts = mPts;
        mPts = 0;
    }
    int size = mFilterEvent.events.size();
    mFilterEvent.events.resize(size + 1);
    mFilterEvent.events[size].media(mediaEvent);

    // Clear and log
    output.clear();
    mAvBufferCopyCount = 0;
    ::close(av_fd);
    if (DEBUG_FILTER) {
        ALOGD("[Filter] av data length %d", mediaEvent.dataLength);
    }
    return Result::SUCCESS;
    return createIndependentMediaEvents(output);
}

Result Filter::startRecordFilterHandler() {
@@ -713,15 +726,119 @@ uint8_t* Filter::getIonBuffer(int fd, int size) {
}

native_handle_t* Filter::createNativeHandle(int fd) {
    native_handle_t* nativeHandle;
    if (fd < 0) {
        nativeHandle = native_handle_create(/*numFd*/ 0, 0);
    } else {
        // Create a native handle to pass the av fd via the callback event.
    native_handle_t* nativeHandle = native_handle_create(/*numFd*/ 1, 0);
        nativeHandle = native_handle_create(/*numFd*/ 1, 0);
    }
    if (nativeHandle == NULL) {
        ALOGE("[Filter] Failed to create native_handle %d", errno);
        return NULL;
    }
    if (nativeHandle->numFds > 0) {
        nativeHandle->data[0] = dup(fd);
    }
    return nativeHandle;
}

Result Filter::createIndependentMediaEvents(vector<uint8_t> output) {
    int av_fd = createAvIonFd(output.size());
    if (av_fd == -1) {
        return Result::UNKNOWN_ERROR;
    }
    // copy the filtered data to the buffer
    uint8_t* avBuffer = getIonBuffer(av_fd, output.size());
    if (avBuffer == NULL) {
        return Result::UNKNOWN_ERROR;
    }
    memcpy(avBuffer, output.data(), output.size() * sizeof(uint8_t));

    native_handle_t* nativeHandle = createNativeHandle(av_fd);
    if (nativeHandle == NULL) {
        return Result::UNKNOWN_ERROR;
    }
    hidl_handle handle;
    handle.setTo(nativeHandle, /*shouldOwn=*/true);

    // Create a dataId and add a <dataId, av_fd> pair into the dataId2Avfd map
    uint64_t dataId = mLastUsedDataId++ /*createdUID*/;
    mDataId2Avfd[dataId] = dup(av_fd);

    // Create mediaEvent and send callback
    DemuxFilterMediaEvent mediaEvent;
    mediaEvent = {
            .avMemory = std::move(handle),
            .dataLength = static_cast<uint32_t>(output.size()),
            .avDataId = dataId,
    };
    if (mPts) {
        mediaEvent.pts = mPts;
        mPts = 0;
    }
    int size = mFilterEvent.events.size();
    mFilterEvent.events.resize(size + 1);
    mFilterEvent.events[size].media(mediaEvent);

    // Clear and log
    output.clear();
    mAvBufferCopyCount = 0;
    ::close(av_fd);
    if (DEBUG_FILTER) {
        ALOGD("[Filter] av data length %d", mediaEvent.dataLength);
    }
    return Result::SUCCESS;
}

Result Filter::createShareMemMediaEvents(vector<uint8_t> output) {
    // copy the filtered data to the shared buffer
    uint8_t* sharedAvBuffer = getIonBuffer(mSharedAvMemHandle.getNativeHandle()->data[0],
                                           output.size() + mSharedAvMemOffset);
    if (sharedAvBuffer == NULL) {
        return Result::UNKNOWN_ERROR;
    }
    memcpy(sharedAvBuffer + mSharedAvMemOffset, output.data(), output.size() * sizeof(uint8_t));

    // Create a memory handle with numFds == 0
    native_handle_t* nativeHandle = createNativeHandle(-1);
    if (nativeHandle == NULL) {
        return Result::UNKNOWN_ERROR;
    }
    hidl_handle handle;
    handle.setTo(nativeHandle, /*shouldOwn=*/true);

    // Create mediaEvent and send callback
    DemuxFilterMediaEvent mediaEvent;
    mediaEvent = {
            .offset = static_cast<uint32_t>(mSharedAvMemOffset),
            .dataLength = static_cast<uint32_t>(output.size()),
            .avMemory = handle,
    };
    mSharedAvMemOffset += output.size();
    if (mPts) {
        mediaEvent.pts = mPts;
        mPts = 0;
    }
    int size = mFilterEvent.events.size();
    mFilterEvent.events.resize(size + 1);
    mFilterEvent.events[size].media(mediaEvent);

    // Clear and log
    output.clear();
    if (DEBUG_FILTER) {
        ALOGD("[Filter] shared av data length %d", mediaEvent.dataLength);
    }
    return Result::SUCCESS;
}

bool Filter::sameFile(int fd1, int fd2) {
    struct stat stat1, stat2;
    if (fstat(fd1, &stat1) < 0 || fstat(fd2, &stat2) < 0) {
        return false;
    }
    return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino);
}
}  // namespace implementation
}  // namespace V1_0
}  // namespace tuner
+13 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <inttypes.h>
#include <ion/ion.h>
#include <math.h>
#include <sys/stat.h>
#include <set>
#include "Demux.h"
#include "Dvr.h"
@@ -43,6 +44,7 @@ using ::android::hardware::MessageQueue;
using ::android::hardware::MQDescriptorSync;

using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
const uint32_t BUFFER_SIZE_16M = 0x1000000;

class Demux;
class Dvr;
@@ -78,6 +80,8 @@ class Filter : public V1_1::IFilter {

    virtual Return<Result> configureIpCid(uint32_t ipCid) override;

    virtual Return<void> getAvSharedHandle(getAvSharedHandle_cb _hidl_cb) override;

    /**
     * To create a FilterMQ and its Event Flag.
     *
@@ -93,6 +97,7 @@ class Filter : public V1_1::IFilter {
    void attachFilterToRecord(const sp<Dvr> dvr);
    void detachFilterFromRecord();
    void freeAvHandle();
    void freeSharedAvHandle();
    bool isMediaFilter() { return mIsMediaFilter; };
    bool isPcrFilter() { return mIsPcrFilter; };
    bool isRecordFilter() { return mIsRecordFilter; };
@@ -185,6 +190,9 @@ class Filter : public V1_1::IFilter {
    uint8_t* getIonBuffer(int fd, int size);
    native_handle_t* createNativeHandle(int fd);
    Result createMediaFilterEventWithIon(vector<uint8_t> output);
    Result createIndependentMediaEvents(vector<uint8_t> output);
    Result createShareMemMediaEvents(vector<uint8_t> output);
    bool sameFile(int fd1, int fd2);

    /**
     * Lock to protect writes to the FMQs
@@ -212,6 +220,11 @@ class Filter : public V1_1::IFilter {
    std::map<uint64_t, int> mDataId2Avfd;
    uint64_t mLastUsedDataId = 1;
    int mAvBufferCopyCount = 0;

    // Shared A/V memory handle
    hidl_handle mSharedAvMemHandle;
    bool mUsingSharedAvMem = true;
    uint32_t mSharedAvMemOffset = 0;
};

}  // namespace implementation
+80 −5
Original line number Diff line number Diff line
@@ -16,22 +16,70 @@

#include "FilterTests.h"

bool FilterCallback::readFilterEventData() {
    bool result = false;
    ALOGW("[vts] reading from filter FMQ or buffer %d", mFilterId);
void FilterCallback::testFilterDataOutput() {
    android::Mutex::Autolock autoLock(mMsgLock);
    while (mPidFilterOutputCount < 1) {
        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
            EXPECT_TRUE(false) << "filter output matching pid does not output within timeout";
            return;
        }
    }
    mPidFilterOutputCount = 0;
    ALOGW("[vts] pass and stop");
}

void FilterCallback::readFilterEventData() {
    ALOGW("[vts] reading filter event");
    // todo separate filter handlers
    for (int i = 0; i < mFilterEvent.events.size(); i++) {
        auto event = mFilterEvent.events[i];
        switch (event.getDiscriminator()) {
            case DemuxFilterEvent::Event::hidl_discriminator::media:
                ALOGD("[vts] Media filter event, avMemHandle numFds=%d.",
                      event.media().avMemory.getNativeHandle()->numFds);
                dumpAvData(event.media());
                break;
            default:
                break;
        }
    }
    for (int i = 0; i < mFilterEventExt.events.size(); i++) {
        auto eventExt = mFilterEventExt.events[i];
        switch (eventExt.getDiscriminator()) {
            case DemuxFilterEventExt::Event::hidl_discriminator::tsRecord:
                ALOGW("[vts] Extended TS record filter event, pts=%" PRIu64 ".",
                ALOGD("[vts] Extended TS record filter event, pts=%" PRIu64 ".",
                      eventExt.tsRecord().pts);
                break;
            default:
                break;
        }
    }
    return result;
}

bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) {
    uint32_t length = event.dataLength;
    uint32_t offset = event.offset;
    // read data from buffer pointed by a handle
    hidl_handle handle = event.avMemory;
    if (handle.getNativeHandle()->numFds == 0) {
        if (mAvSharedHandle == NULL) {
            return false;
        }
        handle = mAvSharedHandle;
    }

    int av_fd = handle.getNativeHandle()->data[0];
    uint8_t* buffer =
            static_cast<uint8_t*>(mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0));
    if (buffer == MAP_FAILED) {
        ALOGE("[vts] fail to allocate av buffer, errno=%d", errno);
        return false;
    }
    uint8_t output[length + 1];
    memcpy(output, buffer + offset, length);
    // print buffer and check with golden output.
    ::close(av_fd);
    return true;
}

AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type, uint32_t bufferSize) {
@@ -81,6 +129,33 @@ AssertionResult FilterTests::getNewlyOpenedFilterId_64bit(uint64_t& filterId) {
    return AssertionResult(status == Result::SUCCESS);
}

AssertionResult FilterTests::getSharedAvMemoryHandle(uint64_t filterId) {
    EXPECT_TRUE(mFilters[filterId]) << "Open media filter first.";
    Result status = Result::UNKNOWN_ERROR;
    sp<android::hardware::tv::tuner::V1_1::IFilter> filter_v1_1 =
            android::hardware::tv::tuner::V1_1::IFilter::castFrom(mFilters[filterId]);
    if (filter_v1_1 != NULL) {
        filter_v1_1->getAvSharedHandle([&](Result r, hidl_handle avMemory, uint64_t avMemSize) {
            status = r;
            if (status == Result::SUCCESS) {
                mFilterCallbacks[mFilterId]->setSharedHandle(avMemory);
                mFilterCallbacks[mFilterId]->setMemSize(avMemSize);
                mAvSharedHandle = avMemory;
            }
        });
    }
    return AssertionResult(status == Result::SUCCESS);
}

AssertionResult FilterTests::releaseShareAvHandle(uint64_t filterId) {
    Result status;
    EXPECT_TRUE(mFilters[filterId]) << "Open media filter first.";
    EXPECT_TRUE(mAvSharedHandle) << "No shared av handle to release.";
    status = mFilters[filterId]->releaseAvHandle(mAvSharedHandle, 0 /*dataId*/);

    return AssertionResult(status == Result::SUCCESS);
}

AssertionResult FilterTests::configFilter(DemuxFilterSettings setting, uint64_t filterId) {
    Result status;
    EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
+25 −5
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ using android::hardware::Return;
using android::hardware::Void;
using android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
using android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent;
using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
using android::hardware::tv::tuner::V1_0::DemuxFilterType;
@@ -93,7 +94,14 @@ class FilterCallback : public IFilterCallback {
    }

    virtual Return<void> onFilterEvent(
            const android::hardware::tv::tuner::V1_0::DemuxFilterEvent& /*filterEvent*/) override {
            const android::hardware::tv::tuner::V1_0::DemuxFilterEvent& filterEvent) override {
        android::Mutex::Autolock autoLock(mMsgLock);
        // Temprarily we treat the first coming back filter data on the matching pid a success
        // once all of the MQ are cleared, means we got all the expected output
        mFilterEvent = filterEvent;
        readFilterEventData();
        mPidFilterOutputCount++;
        mMsgCondition.signal();
        return Void();
    }

@@ -104,8 +112,13 @@ class FilterCallback : public IFilterCallback {
    void setFilterId(uint32_t filterId) { mFilterId = filterId; }
    void setFilterInterface(sp<IFilter> filter) { mFilter = filter; }
    void setFilterEventType(FilterEventType type) { mFilterEventType = type; }
    void setSharedHandle(hidl_handle sharedHandle) { mAvSharedHandle = sharedHandle; }
    void setMemSize(uint64_t size) { mAvSharedMemSize = size; }

    void testFilterDataOutput();

    bool readFilterEventData();
    void readFilterEventData();
    bool dumpAvData(DemuxFilterMediaEvent event);

  private:
    uint32_t mFilterId;
@@ -114,6 +127,9 @@ class FilterCallback : public IFilterCallback {
    DemuxFilterEvent mFilterEvent;
    DemuxFilterEventExt mFilterEventExt;

    hidl_handle mAvSharedHandle = NULL;
    uint64_t mAvSharedMemSize = -1;

    android::Mutex mMsgLock;
    android::Mutex mFilterOutputLock;
    android::Condition mMsgCondition;
@@ -127,10 +143,12 @@ class FilterTests {
    void setDemux(sp<IDemux> demux) { mDemux = demux; }
    sp<IFilter> getFilterById(uint64_t filterId) { return mFilters[filterId]; }

    std::map<uint64_t, sp<FilterCallback>> getFilterCallbacks() { return mFilterCallbacks; }
    map<uint64_t, sp<FilterCallback>> getFilterCallbacks() { return mFilterCallbacks; }

    AssertionResult openFilterInDemux(DemuxFilterType type, uint32_t bufferSize);
    AssertionResult getNewlyOpenedFilterId_64bit(uint64_t& filterId);
    AssertionResult getSharedAvMemoryHandle(uint64_t filterId);
    AssertionResult releaseShareAvHandle(uint64_t filterId);
    AssertionResult configFilter(DemuxFilterSettings setting, uint64_t filterId);
    AssertionResult configIpFilterCid(uint32_t ipCid, uint64_t filterId);
    AssertionResult getFilterMQDescriptor(uint64_t filterId);
@@ -193,12 +211,14 @@ class FilterTests {
    sp<ITuner> mService;
    sp<IFilter> mFilter;
    sp<IDemux> mDemux;
    std::map<uint64_t, sp<IFilter>> mFilters;
    std::map<uint64_t, sp<FilterCallback>> mFilterCallbacks;
    map<uint64_t, sp<IFilter>> mFilters;
    map<uint64_t, sp<FilterCallback>> mFilterCallbacks;

    sp<FilterCallback> mFilterCallback;
    MQDesc mFilterMQDescriptor;
    vector<uint64_t> mUsedFilterIds;

    hidl_handle mAvSharedHandle = NULL;

    uint64_t mFilterId = -1;
};
Loading