blob: c69beca12b10ae82aad636030b38f0bbd4725cad [file] [log] [blame]
/*
* 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.
*/
#define LOG_TAG "android.hardware.tv.tuner@1.1-Filter"
#include "Filter.h"
#include <utils/Log.h>
namespace android {
namespace hardware {
namespace tv {
namespace tuner {
namespace V1_0 {
namespace implementation {
#define WAIT_TIMEOUT 3000000000
Filter::Filter() {}
Filter::Filter(DemuxFilterType type, uint64_t filterId, uint32_t bufferSize,
const sp<IFilterCallback>& cb, sp<Demux> demux) {
mType = type;
mFilterId = filterId;
mBufferSize = bufferSize;
mDemux = demux;
switch (mType.mainType) {
case DemuxFilterMainType::TS:
if (mType.subType.tsFilterType() == DemuxTsFilterType::AUDIO ||
mType.subType.tsFilterType() == DemuxTsFilterType::VIDEO) {
mIsMediaFilter = true;
}
if (mType.subType.tsFilterType() == DemuxTsFilterType::PCR) {
mIsPcrFilter = true;
}
if (mType.subType.tsFilterType() == DemuxTsFilterType::RECORD) {
mIsRecordFilter = true;
}
break;
case DemuxFilterMainType::MMTP:
if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO ||
mType.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) {
mIsMediaFilter = true;
}
if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::RECORD) {
mIsRecordFilter = true;
}
break;
case DemuxFilterMainType::IP:
break;
case DemuxFilterMainType::TLV:
break;
case DemuxFilterMainType::ALP:
break;
default:
break;
}
sp<V1_1::IFilterCallback> filterCallback_v1_1 = V1_1::IFilterCallback::castFrom(cb);
if (filterCallback_v1_1 != NULL) {
mCallback_1_1 = filterCallback_v1_1;
} else {
mCallback = cb;
}
}
Filter::~Filter() {}
Return<void> Filter::getId64Bit(getId64Bit_cb _hidl_cb) {
ALOGV("%s", __FUNCTION__);
_hidl_cb(Result::SUCCESS, mFilterId);
return Void();
}
Return<void> Filter::getId(getId_cb _hidl_cb) {
ALOGV("%s", __FUNCTION__);
_hidl_cb(Result::SUCCESS, static_cast<uint32_t>(mFilterId));
return Void();
}
Return<Result> Filter::setDataSource(const sp<V1_0::IFilter>& filter) {
ALOGV("%s", __FUNCTION__);
mDataSource = filter;
mIsDataSourceDemux = false;
return Result::SUCCESS;
}
Return<void> Filter::getQueueDesc(getQueueDesc_cb _hidl_cb) {
ALOGV("%s", __FUNCTION__);
mIsUsingFMQ = mIsRecordFilter ? false : true;
_hidl_cb(Result::SUCCESS, *mFilterMQ->getDesc());
return Void();
}
Return<Result> Filter::configure(const DemuxFilterSettings& settings) {
ALOGV("%s", __FUNCTION__);
mFilterSettings = settings;
switch (mType.mainType) {
case DemuxFilterMainType::TS:
mTpid = settings.ts().tpid;
break;
case DemuxFilterMainType::MMTP:
break;
case DemuxFilterMainType::IP:
break;
case DemuxFilterMainType::TLV:
break;
case DemuxFilterMainType::ALP:
break;
default:
break;
}
return Result::SUCCESS;
}
Return<Result> Filter::start() {
ALOGV("%s", __FUNCTION__);
return startFilterLoop();
}
Return<Result> Filter::stop() {
ALOGV("%s", __FUNCTION__);
mFilterThreadRunning = false;
std::lock_guard<std::mutex> lock(mFilterThreadLock);
return Result::SUCCESS;
}
Return<Result> Filter::flush() {
ALOGV("%s", __FUNCTION__);
// temp implementation to flush the FMQ
int size = mFilterMQ->availableToRead();
char* buffer = new char[size];
mFilterMQ->read((unsigned char*)&buffer[0], size);
delete[] buffer;
mFilterStatus = DemuxFilterStatus::DATA_READY;
return Result::SUCCESS;
}
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;
}
::close(mDataId2Avfd[avDataId]);
return Result::SUCCESS;
}
Return<Result> Filter::close() {
ALOGV("%s", __FUNCTION__);
return mDemux->removeFilter(mFilterId);
}
Return<Result> Filter::configureIpCid(uint32_t ipCid) {
ALOGV("%s", __FUNCTION__);
if (mType.mainType != DemuxFilterMainType::IP) {
return Result::INVALID_STATE;
}
mCid = 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__);
// Create a synchronized FMQ that supports blocking read/write
std::unique_ptr<FilterMQ> tmpFilterMQ =
std::unique_ptr<FilterMQ>(new (std::nothrow) FilterMQ(mBufferSize, true));
if (!tmpFilterMQ->isValid()) {
ALOGW("[Filter] Failed to create FMQ of filter with id: %" PRIu64, mFilterId);
return false;
}
mFilterMQ = std::move(tmpFilterMQ);
if (EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterEventFlag) != OK) {
return false;
}
return true;
}
Result Filter::startFilterLoop() {
pthread_create(&mFilterThread, NULL, __threadLoopFilter, this);
pthread_setname_np(mFilterThread, "filter_waiting_loop");
return Result::SUCCESS;
}
void* Filter::__threadLoopFilter(void* user) {
Filter* const self = static_cast<Filter*>(user);
self->filterThreadLoop();
return 0;
}
void Filter::filterThreadLoop() {
ALOGD("[Filter] filter %" PRIu64 " threadLoop start.", mFilterId);
std::lock_guard<std::mutex> lock(mFilterThreadLock);
mFilterThreadRunning = true;
// For the first time of filter output, implementation needs to send the filter
// Event Callback without waiting for the DATA_CONSUMED to init the process.
while (mFilterThreadRunning) {
if (mFilterEvent.events.size() == 0 && mFilterEventExt.events.size() == 0) {
if (DEBUG_FILTER) {
ALOGD("[Filter] wait for filter data output.");
}
usleep(1000 * 1000);
continue;
}
// After successfully write, send a callback and wait for the read to be done
if (mCallback_1_1 != nullptr) {
mCallback_1_1->onFilterEvent_1_1(mFilterEvent, mFilterEventExt);
mFilterEventExt.events.resize(0);
} else if (mCallback != nullptr) {
mCallback->onFilterEvent(mFilterEvent);
} else {
ALOGD("[Filter] filter callback is not configured yet.");
mFilterThreadRunning = false;
return;
}
mFilterEvent.events.resize(0);
freeAvHandle();
mFilterStatus = DemuxFilterStatus::DATA_READY;
if (mCallback != nullptr) {
mCallback->onFilterStatus(mFilterStatus);
} else if (mCallback_1_1 != nullptr) {
mCallback_1_1->onFilterStatus(mFilterStatus);
}
break;
}
while (mFilterThreadRunning) {
uint32_t efState = 0;
// We do not wait for the last round of written data to be read to finish the thread
// because the VTS can verify the reading itself.
for (int i = 0; i < SECTION_WRITE_COUNT; i++) {
while (mFilterThreadRunning && mIsUsingFMQ) {
status_t status = mFilterEventFlag->wait(
static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED), &efState,
WAIT_TIMEOUT, true /* retry on spurious wake */);
if (status != OK) {
ALOGD("[Filter] wait for data consumed");
continue;
}
break;
}
maySendFilterStatusCallback();
while (mFilterThreadRunning) {
std::lock_guard<std::mutex> lock(mFilterEventLock);
if (mFilterEvent.events.size() == 0) {
continue;
}
// After successfully write, send a callback and wait for the read to be done
if (mCallback != nullptr) {
mCallback->onFilterEvent(mFilterEvent);
mFilterEvent.events.resize(0);
} else if (mCallback_1_1 != nullptr) {
mCallback_1_1->onFilterEvent_1_1(mFilterEvent, mFilterEventExt);
mFilterEventExt.events.resize(0);
}
break;
}
// We do not wait for the last read to be done
// VTS can verify the read result itself.
if (i == SECTION_WRITE_COUNT - 1) {
ALOGD("[Filter] filter %" PRIu64 " writing done. Ending thread", mFilterId);
break;
}
}
mFilterThreadRunning = false;
}
ALOGD("[Filter] filter thread ended.");
}
void Filter::freeAvHandle() {
if (!mIsMediaFilter) {
return;
}
for (int i = 0; i < mFilterEvent.events.size(); i++) {
::close(mFilterEvent.events[i].media().avMemory.getNativeHandle()->data[0]);
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() {
if (!mIsUsingFMQ) {
return;
}
std::lock_guard<std::mutex> lock(mFilterStatusLock);
int availableToRead = mFilterMQ->availableToRead();
int availableToWrite = mFilterMQ->availableToWrite();
int fmqSize = mFilterMQ->getQuantumCount();
DemuxFilterStatus newStatus = checkFilterStatusChange(
availableToWrite, availableToRead, ceil(fmqSize * 0.75), ceil(fmqSize * 0.25));
if (mFilterStatus != newStatus) {
if (mCallback != nullptr) {
mCallback->onFilterStatus(newStatus);
} else if (mCallback_1_1 != nullptr) {
mCallback_1_1->onFilterStatus(newStatus);
}
mFilterStatus = newStatus;
}
}
DemuxFilterStatus Filter::checkFilterStatusChange(uint32_t availableToWrite,
uint32_t availableToRead, uint32_t highThreshold,
uint32_t lowThreshold) {
if (availableToWrite == 0) {
return DemuxFilterStatus::OVERFLOW;
} else if (availableToRead > highThreshold) {
return DemuxFilterStatus::HIGH_WATER;
} else if (availableToRead < lowThreshold) {
return DemuxFilterStatus::LOW_WATER;
}
return mFilterStatus;
}
uint16_t Filter::getTpid() {
return mTpid;
}
void Filter::updateFilterOutput(vector<uint8_t> data) {
std::lock_guard<std::mutex> lock(mFilterOutputLock);
mFilterOutput.insert(mFilterOutput.end(), data.begin(), data.end());
}
void Filter::updatePts(uint64_t pts) {
std::lock_guard<std::mutex> lock(mFilterOutputLock);
mPts = pts;
}
void Filter::updateRecordOutput(vector<uint8_t> data) {
std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
mRecordFilterOutput.insert(mRecordFilterOutput.end(), data.begin(), data.end());
}
Result Filter::startFilterHandler() {
std::lock_guard<std::mutex> lock(mFilterOutputLock);
switch (mType.mainType) {
case DemuxFilterMainType::TS:
switch (mType.subType.tsFilterType()) {
case DemuxTsFilterType::UNDEFINED:
break;
case DemuxTsFilterType::SECTION:
startSectionFilterHandler();
break;
case DemuxTsFilterType::PES:
startPesFilterHandler();
break;
case DemuxTsFilterType::TS:
startTsFilterHandler();
break;
case DemuxTsFilterType::AUDIO:
case DemuxTsFilterType::VIDEO:
startMediaFilterHandler();
break;
case DemuxTsFilterType::PCR:
startPcrFilterHandler();
break;
case DemuxTsFilterType::TEMI:
startTemiFilterHandler();
break;
default:
break;
}
break;
case DemuxFilterMainType::MMTP:
/*mmtpSettings*/
break;
case DemuxFilterMainType::IP:
/*ipSettings*/
break;
case DemuxFilterMainType::TLV:
/*tlvSettings*/
break;
case DemuxFilterMainType::ALP:
/*alpSettings*/
break;
default:
break;
}
return Result::SUCCESS;
}
Result Filter::startSectionFilterHandler() {
if (mFilterOutput.empty()) {
return Result::SUCCESS;
}
if (!writeSectionsAndCreateEvent(mFilterOutput)) {
ALOGD("[Filter] filter %" PRIu64 " fails to write into FMQ. Ending thread", mFilterId);
return Result::UNKNOWN_ERROR;
}
mFilterOutput.clear();
return Result::SUCCESS;
}
Result Filter::startPesFilterHandler() {
std::lock_guard<std::mutex> lock(mFilterEventLock);
if (mFilterOutput.empty()) {
return Result::SUCCESS;
}
for (int i = 0; i < mFilterOutput.size(); i += 188) {
if (mPesSizeLeft == 0) {
uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
mFilterOutput[i + 6];
if (DEBUG_FILTER) {
ALOGD("[Filter] prefix %d", prefix);
}
if (prefix == 0x000001) {
// TODO handle mulptiple Pes filters
mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9];
mPesSizeLeft += 6;
if (DEBUG_FILTER) {
ALOGD("[Filter] pes data length %d", mPesSizeLeft);
}
} else {
continue;
}
}
int endPoint = min(184, mPesSizeLeft);
// append data and check size
vector<uint8_t>::const_iterator first = mFilterOutput.begin() + i + 4;
vector<uint8_t>::const_iterator last = mFilterOutput.begin() + i + 4 + endPoint;
mPesOutput.insert(mPesOutput.end(), first, last);
// size does not match then continue
mPesSizeLeft -= endPoint;
if (DEBUG_FILTER) {
ALOGD("[Filter] pes data left %d", mPesSizeLeft);
}
if (mPesSizeLeft > 0) {
continue;
}
// size match then create event
if (!writeDataToFilterMQ(mPesOutput)) {
ALOGD("[Filter] pes data write failed");
mFilterOutput.clear();
return Result::INVALID_STATE;
}
maySendFilterStatusCallback();
DemuxFilterPesEvent pesEvent;
pesEvent = {
// temp dump meta data
.streamId = mPesOutput[3],
.dataLength = static_cast<uint16_t>(mPesOutput.size()),
};
if (DEBUG_FILTER) {
ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength);
}
int size = mFilterEvent.events.size();
mFilterEvent.events.resize(size + 1);
mFilterEvent.events[size].pes(pesEvent);
mPesOutput.clear();
}
mFilterOutput.clear();
return Result::SUCCESS;
}
Result Filter::startTsFilterHandler() {
// TODO handle starting TS filter
return Result::SUCCESS;
}
Result Filter::startMediaFilterHandler() {
std::lock_guard<std::mutex> lock(mFilterEventLock);
if (mFilterOutput.empty()) {
return Result::SUCCESS;
}
Result result;
if (mPts) {
result = createMediaFilterEventWithIon(mFilterOutput);
if (result == Result::SUCCESS) {
mFilterOutput.clear();
}
return result;
}
for (int i = 0; i < mFilterOutput.size(); i += 188) {
if (mPesSizeLeft == 0) {
uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
mFilterOutput[i + 6];
if (DEBUG_FILTER) {
ALOGD("[Filter] prefix %d", prefix);
}
if (prefix == 0x000001) {
// TODO handle mulptiple Pes filters
mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9];
mPesSizeLeft += 6;
if (DEBUG_FILTER) {
ALOGD("[Filter] pes data length %d", mPesSizeLeft);
}
} else {
continue;
}
}
int endPoint = min(184, mPesSizeLeft);
// append data and check size
vector<uint8_t>::const_iterator first = mFilterOutput.begin() + i + 4;
vector<uint8_t>::const_iterator last = mFilterOutput.begin() + i + 4 + endPoint;
mPesOutput.insert(mPesOutput.end(), first, last);
// size does not match then continue
mPesSizeLeft -= endPoint;
if (DEBUG_FILTER) {
ALOGD("[Filter] pes data left %d", mPesSizeLeft);
}
if (mPesSizeLeft > 0 || mAvBufferCopyCount++ < 10) {
continue;
}
result = createMediaFilterEventWithIon(mPesOutput);
if (result != Result::SUCCESS) {
return result;
}
}
mFilterOutput.clear();
return Result::SUCCESS;
}
Result Filter::createMediaFilterEventWithIon(vector<uint8_t> output) {
if (mUsingSharedAvMem) {
if (mSharedAvMemHandle.getNativeHandle() == nullptr) {
return Result::UNKNOWN_ERROR;
}
return createShareMemMediaEvents(output);
}
return createIndependentMediaEvents(output);
}
Result Filter::startRecordFilterHandler() {
std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
if (mRecordFilterOutput.empty()) {
return Result::SUCCESS;
}
if (mDvr == nullptr || !mDvr->writeRecordFMQ(mRecordFilterOutput)) {
ALOGD("[Filter] dvr fails to write into record FMQ.");
return Result::UNKNOWN_ERROR;
}
V1_0::DemuxFilterTsRecordEvent recordEvent;
recordEvent = {
.byteNumber = mRecordFilterOutput.size(),
};
V1_1::DemuxFilterRecordEventExt recordEventExt;
recordEventExt = {
.pts = (mPts == 0) ? time(NULL) * 900000 : mPts,
};
int size;
size = mFilterEventExt.events.size();
mFilterEventExt.events.resize(size + 1);
mFilterEventExt.events[size].tsRecord(recordEventExt);
size = mFilterEvent.events.size();
mFilterEvent.events.resize(size + 1);
mFilterEvent.events[size].tsRecord(recordEvent);
mRecordFilterOutput.clear();
return Result::SUCCESS;
}
Result Filter::startPcrFilterHandler() {
// TODO handle starting PCR filter
return Result::SUCCESS;
}
Result Filter::startTemiFilterHandler() {
// TODO handle starting TEMI filter
return Result::SUCCESS;
}
bool Filter::writeSectionsAndCreateEvent(vector<uint8_t> data) {
// TODO check how many sections has been read
ALOGD("[Filter] section handler");
std::lock_guard<std::mutex> lock(mFilterEventLock);
if (!writeDataToFilterMQ(data)) {
return false;
}
int size = mFilterEvent.events.size();
mFilterEvent.events.resize(size + 1);
DemuxFilterSectionEvent secEvent;
secEvent = {
// temp dump meta data
.tableId = 0,
.version = 1,
.sectionNum = 1,
.dataLength = static_cast<uint16_t>(data.size()),
};
mFilterEvent.events[size].section(secEvent);
return true;
}
bool Filter::writeDataToFilterMQ(const std::vector<uint8_t>& data) {
std::lock_guard<std::mutex> lock(mWriteLock);
if (mFilterMQ->write(data.data(), data.size())) {
return true;
}
return false;
}
void Filter::attachFilterToRecord(const sp<Dvr> dvr) {
mDvr = dvr;
}
void Filter::detachFilterFromRecord() {
mDvr = nullptr;
}
int Filter::createAvIonFd(int size) {
// Create an ion fd and allocate an av fd mapped to a buffer to it.
int ion_fd = ion_open();
if (ion_fd == -1) {
ALOGE("[Filter] Failed to open ion fd %d", errno);
return -1;
}
int av_fd = -1;
ion_alloc_fd(dup(ion_fd), size, 0 /*align*/, ION_HEAP_SYSTEM_MASK, 0 /*flags*/, &av_fd);
if (av_fd == -1) {
ALOGE("[Filter] Failed to create av fd %d", errno);
return -1;
}
return av_fd;
}
uint8_t* Filter::getIonBuffer(int fd, int size) {
uint8_t* avBuf = static_cast<uint8_t*>(
mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 /*offset*/));
if (avBuf == MAP_FAILED) {
ALOGE("[Filter] fail to allocate buffer %d", errno);
return NULL;
}
return avBuf;
}
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.
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
} // namespace tv
} // namespace hardware
} // namespace android