mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:23:37 +00:00
Implement ES data process in Tuner default impl to support Sample TIS
This CL also provides a new VTS case to test ES input stream. Please see the test.es https://drive.google.com/file/d/13ZDT9uhEO1LXDT2GcOhB91iIK6m_KEER/view?usp=sharing ES Format(all the numbers are in decimal): 1. First line is a general meta data to describe the whole file m:meta data size in bytes, l:ES frame line count X, V:video raw data size int bytes, A:audio raw data size in bytes, pv:video pid, pa:audio pid 2. The following X lines(equals to the ES frame line count) are the size/pts information of the video or audio ES frames. Starting with v means video, a means audio. They are printed in the same order as how they presented in the original ts. v, Len:current ES frame size in bytes, PTS: current ES frame PTS 3. After the X lines of ES frame descriptions, there are the video ES raw data connected with the audio ES raw data. Test: atest VtsHalTvTunerV1_0TargetTest Bug: 159027928 Change-Id: I56bd799fd6eda867df54d593235510a5e4758257
This commit is contained in:
@@ -294,6 +294,11 @@ void Demux::updateFilterOutput(uint16_t filterId, vector<uint8_t> data) {
|
||||
mFilters[filterId]->updateFilterOutput(data);
|
||||
}
|
||||
|
||||
void Demux::updateMediaFilterOutput(uint16_t filterId, vector<uint8_t> data, uint64_t pts) {
|
||||
updateFilterOutput(filterId, data);
|
||||
mFilters[filterId]->updatePts(pts);
|
||||
}
|
||||
|
||||
uint16_t Demux::getFilterTpid(uint32_t filterId) {
|
||||
return mFilters[filterId]->getTpid();
|
||||
}
|
||||
@@ -322,6 +327,12 @@ void Demux::frontendInputThreadLoop() {
|
||||
ALOGD("[Demux] wait for data ready on the playback FMQ");
|
||||
continue;
|
||||
}
|
||||
if (mDvrPlayback->getSettings().playback().dataFormat == DataFormat::ES) {
|
||||
if (!mDvrPlayback->processEsDataOnPlayback(true /*isVirtualFrontend*/, mIsRecording)) {
|
||||
ALOGE("[Demux] playback es data failed to be filtered. Ending thread");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Our current implementation filter the data and write it into the filter FMQ immediately
|
||||
// after the DATA_READY from the VTS/framework
|
||||
if (!mDvrPlayback->readPlaybackFMQ(true /*isVirtualFrontend*/, mIsRecording) ||
|
||||
|
||||
@@ -87,6 +87,7 @@ class Demux : public IDemux {
|
||||
bool detachRecordFilter(int filterId);
|
||||
Result startFilterHandler(uint32_t filterId);
|
||||
void updateFilterOutput(uint16_t filterId, vector<uint8_t> data);
|
||||
void updateMediaFilterOutput(uint16_t filterId, vector<uint8_t> data, uint64_t pts);
|
||||
uint16_t getFilterTpid(uint32_t filterId);
|
||||
void setIsRecording(bool isRecording);
|
||||
void startFrontendInputLoop();
|
||||
|
||||
@@ -129,7 +129,7 @@ Return<Result> Dvr::stop() {
|
||||
|
||||
mDvrThreadRunning = false;
|
||||
|
||||
std::lock_guard<std::mutex> lock(mDvrThreadLock);
|
||||
lock_guard<mutex> lock(mDvrThreadLock);
|
||||
|
||||
mIsRecordStarted = false;
|
||||
mDemux->setIsRecording(false);
|
||||
@@ -155,14 +155,13 @@ bool Dvr::createDvrMQ() {
|
||||
ALOGV("%s", __FUNCTION__);
|
||||
|
||||
// Create a synchronized FMQ that supports blocking read/write
|
||||
std::unique_ptr<DvrMQ> tmpDvrMQ =
|
||||
std::unique_ptr<DvrMQ>(new (std::nothrow) DvrMQ(mBufferSize, true));
|
||||
unique_ptr<DvrMQ> tmpDvrMQ = unique_ptr<DvrMQ>(new (nothrow) DvrMQ(mBufferSize, true));
|
||||
if (!tmpDvrMQ->isValid()) {
|
||||
ALOGW("[Dvr] Failed to create FMQ of DVR");
|
||||
return false;
|
||||
}
|
||||
|
||||
mDvrMQ = std::move(tmpDvrMQ);
|
||||
mDvrMQ = move(tmpDvrMQ);
|
||||
|
||||
if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) {
|
||||
return false;
|
||||
@@ -183,7 +182,7 @@ void* Dvr::__threadLoopPlayback(void* user) {
|
||||
|
||||
void Dvr::playbackThreadLoop() {
|
||||
ALOGD("[Dvr] playback threadLoop start.");
|
||||
std::lock_guard<std::mutex> lock(mDvrThreadLock);
|
||||
lock_guard<mutex> lock(mDvrThreadLock);
|
||||
mDvrThreadRunning = true;
|
||||
|
||||
while (mDvrThreadRunning) {
|
||||
@@ -195,6 +194,14 @@ void Dvr::playbackThreadLoop() {
|
||||
ALOGD("[Dvr] wait for data ready on the playback FMQ");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mDvrSettings.playback().dataFormat == DataFormat::ES) {
|
||||
if (!processEsDataOnPlayback(false /*isVirtualFrontend*/, false /*isRecording*/)) {
|
||||
ALOGE("[Dvr] playback es data failed to be filtered. Ending thread");
|
||||
break;
|
||||
}
|
||||
maySendPlaybackStatusCallback();
|
||||
}
|
||||
// Our current implementation filter the data and write it into the filter FMQ immediately
|
||||
// after the DATA_READY from the VTS/framework
|
||||
if (!readPlaybackFMQ(false /*isVirtualFrontend*/, false /*isRecording*/) ||
|
||||
@@ -211,7 +218,7 @@ void Dvr::playbackThreadLoop() {
|
||||
}
|
||||
|
||||
void Dvr::maySendPlaybackStatusCallback() {
|
||||
std::lock_guard<std::mutex> lock(mPlaybackStatusLock);
|
||||
lock_guard<mutex> lock(mPlaybackStatusLock);
|
||||
int availableToRead = mDvrMQ->availableToRead();
|
||||
int availableToWrite = mDvrMQ->availableToWrite();
|
||||
|
||||
@@ -263,8 +270,128 @@ bool Dvr::readPlaybackFMQ(bool isVirtualFrontend, bool isRecording) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Dvr::processEsDataOnPlayback(bool isVirtualFrontend, bool isRecording) {
|
||||
// Read ES from the DVR FMQ
|
||||
// Note that currently we only provides ES with metaData in a specific format to be parsed.
|
||||
// The ES size should be smaller than the Playback FMQ size to avoid reading truncated data.
|
||||
int size = mDvrMQ->availableToRead();
|
||||
vector<uint8_t> dataOutputBuffer;
|
||||
dataOutputBuffer.resize(size);
|
||||
if (!mDvrMQ->read(dataOutputBuffer.data(), size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int metaDataSize = size;
|
||||
int totalFrames = 0;
|
||||
int videoEsDataSize = 0;
|
||||
int audioEsDataSize = 0;
|
||||
int audioPid = 0;
|
||||
int videoPid = 0;
|
||||
|
||||
vector<MediaEsMetaData> esMeta;
|
||||
int videoReadPointer = 0;
|
||||
int audioReadPointer = 0;
|
||||
int frameCount = 0;
|
||||
// Get meta data from the es
|
||||
for (int i = 0; i < metaDataSize; i++) {
|
||||
switch (dataOutputBuffer[i]) {
|
||||
case 'm':
|
||||
metaDataSize = 0;
|
||||
getMetaDataValue(i, dataOutputBuffer.data(), metaDataSize);
|
||||
videoReadPointer = metaDataSize;
|
||||
continue;
|
||||
case 'l':
|
||||
getMetaDataValue(i, dataOutputBuffer.data(), totalFrames);
|
||||
esMeta.resize(totalFrames);
|
||||
continue;
|
||||
case 'V':
|
||||
getMetaDataValue(i, dataOutputBuffer.data(), videoEsDataSize);
|
||||
audioReadPointer = metaDataSize + videoEsDataSize;
|
||||
continue;
|
||||
case 'A':
|
||||
getMetaDataValue(i, dataOutputBuffer.data(), audioEsDataSize);
|
||||
continue;
|
||||
case 'p':
|
||||
if (dataOutputBuffer[++i] == 'a') {
|
||||
getMetaDataValue(i, dataOutputBuffer.data(), audioPid);
|
||||
} else if (dataOutputBuffer[i] == 'v') {
|
||||
getMetaDataValue(i, dataOutputBuffer.data(), videoPid);
|
||||
}
|
||||
continue;
|
||||
case 'v':
|
||||
case 'a':
|
||||
if (dataOutputBuffer[i + 1] != ',') {
|
||||
ALOGE("[Dvr] Invalid format meta data.");
|
||||
return false;
|
||||
}
|
||||
esMeta[frameCount] = {
|
||||
.isAudio = dataOutputBuffer[i] == 'a' ? true : false,
|
||||
};
|
||||
i += 5; // Move to Len
|
||||
getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].len);
|
||||
if (esMeta[frameCount].isAudio) {
|
||||
esMeta[frameCount].startIndex = audioReadPointer;
|
||||
audioReadPointer += esMeta[frameCount].len;
|
||||
} else {
|
||||
esMeta[frameCount].startIndex = videoReadPointer;
|
||||
videoReadPointer += esMeta[frameCount].len;
|
||||
}
|
||||
i += 4; // move to PTS
|
||||
getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].pts);
|
||||
frameCount++;
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (frameCount != totalFrames) {
|
||||
ALOGE("[Dvr] Invalid meta data, frameCount=%d, totalFrames reported=%d", frameCount,
|
||||
totalFrames);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (metaDataSize + audioEsDataSize + videoEsDataSize != size) {
|
||||
ALOGE("[Dvr] Invalid meta data, metaSize=%d, videoSize=%d, audioSize=%d, totolSize=%d",
|
||||
metaDataSize, videoEsDataSize, audioEsDataSize, size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read es raw data from the FMQ per meta data built previously
|
||||
vector<uint8_t> frameData;
|
||||
map<uint32_t, sp<IFilter>>::iterator it;
|
||||
int pid = 0;
|
||||
for (int i = 0; i < totalFrames; i++) {
|
||||
frameData.resize(esMeta[i].len);
|
||||
pid = esMeta[i].isAudio ? audioPid : videoPid;
|
||||
memcpy(dataOutputBuffer.data() + esMeta[i].startIndex, frameData.data(), esMeta[i].len);
|
||||
// Send to the media filter
|
||||
if (isVirtualFrontend && isRecording) {
|
||||
// TODO validate record
|
||||
mDemux->sendFrontendInputToRecord(frameData);
|
||||
} else {
|
||||
for (it = mFilters.begin(); it != mFilters.end(); it++) {
|
||||
if (pid == mDemux->getFilterTpid(it->first)) {
|
||||
mDemux->updateMediaFilterOutput(it->first, frameData,
|
||||
static_cast<uint64_t>(esMeta[i].pts));
|
||||
startFilterDispatcher(isVirtualFrontend, isRecording);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Dvr::getMetaDataValue(int& index, uint8_t* dataOutputBuffer, int& value) {
|
||||
index += 2; // Move the pointer across the ":" to the value
|
||||
while (dataOutputBuffer[index] != ',' && dataOutputBuffer[index] != '\n') {
|
||||
value = ((dataOutputBuffer[index++] - 48) + value * 10);
|
||||
}
|
||||
}
|
||||
|
||||
void Dvr::startTpidFilter(vector<uint8_t> data) {
|
||||
std::map<uint32_t, sp<IFilter>>::iterator it;
|
||||
map<uint32_t, sp<IFilter>>::iterator it;
|
||||
for (it = mFilters.begin(); it != mFilters.end(); it++) {
|
||||
uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
|
||||
if (DEBUG_DVR) {
|
||||
@@ -285,7 +412,7 @@ bool Dvr::startFilterDispatcher(bool isVirtualFrontend, bool isRecording) {
|
||||
}
|
||||
}
|
||||
|
||||
std::map<uint32_t, sp<IFilter>>::iterator it;
|
||||
map<uint32_t, sp<IFilter>>::iterator it;
|
||||
// Handle the output data per filter type
|
||||
for (it = mFilters.begin(); it != mFilters.end(); it++) {
|
||||
if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) {
|
||||
@@ -296,8 +423,8 @@ bool Dvr::startFilterDispatcher(bool isVirtualFrontend, bool isRecording) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Dvr::writeRecordFMQ(const std::vector<uint8_t>& data) {
|
||||
std::lock_guard<std::mutex> lock(mWriteLock);
|
||||
bool Dvr::writeRecordFMQ(const vector<uint8_t>& data) {
|
||||
lock_guard<mutex> lock(mWriteLock);
|
||||
if (mRecordStatus == RecordStatus::OVERFLOW) {
|
||||
ALOGW("[Dvr] stops writing and wait for the client side flushing.");
|
||||
return true;
|
||||
@@ -313,7 +440,7 @@ bool Dvr::writeRecordFMQ(const std::vector<uint8_t>& data) {
|
||||
}
|
||||
|
||||
void Dvr::maySendRecordStatusCallback() {
|
||||
std::lock_guard<std::mutex> lock(mRecordStatusLock);
|
||||
lock_guard<mutex> lock(mRecordStatusLock);
|
||||
int availableToRead = mDvrMQ->availableToRead();
|
||||
int availableToWrite = mDvrMQ->availableToWrite();
|
||||
|
||||
|
||||
@@ -44,6 +44,13 @@ using ::android::hardware::tv::tuner::V1_0::Result;
|
||||
|
||||
using DvrMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
|
||||
|
||||
struct MediaEsMetaData {
|
||||
bool isAudio;
|
||||
int startIndex;
|
||||
int len;
|
||||
int pts;
|
||||
};
|
||||
|
||||
class Demux;
|
||||
class Filter;
|
||||
class Frontend;
|
||||
@@ -84,8 +91,10 @@ class Dvr : public IDvr {
|
||||
bool addPlaybackFilter(uint32_t filterId, sp<IFilter> filter);
|
||||
bool removePlaybackFilter(uint32_t filterId);
|
||||
bool readPlaybackFMQ(bool isVirtualFrontend, bool isRecording);
|
||||
bool processEsDataOnPlayback(bool isVirtualFrontend, bool isRecording);
|
||||
bool startFilterDispatcher(bool isVirtualFrontend, bool isRecording);
|
||||
EventFlag* getDvrEventFlag();
|
||||
DvrSettings getSettings() { return mDvrSettings; }
|
||||
|
||||
private:
|
||||
// Demux service
|
||||
@@ -98,6 +107,7 @@ class Dvr : public IDvr {
|
||||
|
||||
void deleteEventFlag();
|
||||
bool readDataFromMQ();
|
||||
void getMetaDataValue(int& index, uint8_t* dataOutputBuffer, int& value);
|
||||
void maySendPlaybackStatusCallback();
|
||||
void maySendRecordStatusCallback();
|
||||
PlaybackStatus checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
|
||||
|
||||
@@ -317,6 +317,11 @@ void Filter::updateFilterOutput(vector<uint8_t> data) {
|
||||
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());
|
||||
@@ -460,6 +465,11 @@ Result Filter::startMediaFilterHandler() {
|
||||
if (mFilterOutput.empty()) {
|
||||
return Result::SUCCESS;
|
||||
}
|
||||
|
||||
if (mPts) {
|
||||
return createMediaFilterEventWithIon(mFilterOutput);
|
||||
}
|
||||
|
||||
for (int i = 0; i < mFilterOutput.size(); i += 188) {
|
||||
if (mPesSizeLeft == 0) {
|
||||
uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
|
||||
@@ -493,46 +503,7 @@ Result Filter::startMediaFilterHandler() {
|
||||
continue;
|
||||
}
|
||||
|
||||
int av_fd = createAvIonFd(mPesOutput.size());
|
||||
if (av_fd == -1) {
|
||||
return Result::UNKNOWN_ERROR;
|
||||
}
|
||||
// copy the filtered data to the buffer
|
||||
uint8_t* avBuffer = getIonBuffer(av_fd, mPesOutput.size());
|
||||
if (avBuffer == NULL) {
|
||||
return Result::UNKNOWN_ERROR;
|
||||
}
|
||||
memcpy(avBuffer, mPesOutput.data(), mPesOutput.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>(mPesOutput.size()),
|
||||
.avDataId = dataId,
|
||||
};
|
||||
int size = mFilterEvent.events.size();
|
||||
mFilterEvent.events.resize(size + 1);
|
||||
mFilterEvent.events[size].media(mediaEvent);
|
||||
|
||||
// Clear and log
|
||||
mPesOutput.clear();
|
||||
mAvBufferCopyCount = 0;
|
||||
::close(av_fd);
|
||||
if (DEBUG_FILTER) {
|
||||
ALOGD("[Filter] assembled av data length %d", mediaEvent.dataLength);
|
||||
}
|
||||
createMediaFilterEventWithIon(mPesOutput);
|
||||
}
|
||||
|
||||
mFilterOutput.clear();
|
||||
@@ -540,6 +511,54 @@ Result Filter::startMediaFilterHandler() {
|
||||
return Result::SUCCESS;
|
||||
}
|
||||
|
||||
Result Filter::createMediaFilterEventWithIon(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::startRecordFilterHandler() {
|
||||
std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
|
||||
if (mRecordFilterOutput.empty()) {
|
||||
|
||||
@@ -84,6 +84,7 @@ class Filter : public IFilter {
|
||||
uint16_t getTpid();
|
||||
void updateFilterOutput(vector<uint8_t> data);
|
||||
void updateRecordOutput(vector<uint8_t> data);
|
||||
void updatePts(uint64_t pts);
|
||||
Result startFilterHandler();
|
||||
Result startRecordFilterHandler();
|
||||
void attachFilterToRecord(const sp<Dvr> dvr);
|
||||
@@ -116,6 +117,7 @@ class Filter : public IFilter {
|
||||
bool mIsDataSourceDemux = true;
|
||||
vector<uint8_t> mFilterOutput;
|
||||
vector<uint8_t> mRecordFilterOutput;
|
||||
uint64_t mPts = 0;
|
||||
unique_ptr<FilterMQ> mFilterMQ;
|
||||
bool mIsUsingFMQ = false;
|
||||
EventFlag* mFilterEventFlag;
|
||||
@@ -172,6 +174,7 @@ class Filter : public IFilter {
|
||||
int createAvIonFd(int size);
|
||||
uint8_t* getIonBuffer(int fd, int size);
|
||||
native_handle_t* createNativeHandle(int fd);
|
||||
Result createMediaFilterEventWithIon(vector<uint8_t> output);
|
||||
|
||||
/**
|
||||
* Lock to protect writes to the FMQs
|
||||
|
||||
@@ -370,13 +370,11 @@ AssertionResult FrontendTests::tuneFrontend(FrontendConfig config, bool testWith
|
||||
mIsSoftwareFe = config.isSoftwareFe;
|
||||
bool result = true;
|
||||
if (mIsSoftwareFe && testWithDemux) {
|
||||
DvrConfig dvrConfig;
|
||||
getSoftwareFrontendPlaybackConfig(dvrConfig);
|
||||
result &= mDvrTests.openDvrInDemux(dvrConfig.type, dvrConfig.bufferSize) == success();
|
||||
result &= mDvrTests.configDvrPlayback(dvrConfig.settings) == success();
|
||||
result &= mDvrTests.openDvrInDemux(mDvrConfig.type, mDvrConfig.bufferSize) == success();
|
||||
result &= mDvrTests.configDvrPlayback(mDvrConfig.settings) == success();
|
||||
result &= mDvrTests.getDvrPlaybackMQDescriptor() == success();
|
||||
mDvrTests.startPlaybackInputThread(dvrConfig.playbackInputFile,
|
||||
dvrConfig.settings.playback());
|
||||
mDvrTests.startPlaybackInputThread(mDvrConfig.playbackInputFile,
|
||||
mDvrConfig.settings.playback());
|
||||
if (!result) {
|
||||
ALOGW("[vts] Software frontend dvr configure failed.");
|
||||
return failure();
|
||||
|
||||
@@ -104,6 +104,7 @@ class FrontendTests {
|
||||
void setService(sp<ITuner> tuner) {
|
||||
mService = tuner;
|
||||
mDvrTests.setService(tuner);
|
||||
getDefaultSoftwareFrontendPlaybackConfig(mDvrConfig);
|
||||
}
|
||||
|
||||
AssertionResult getFrontendIds();
|
||||
@@ -125,12 +126,13 @@ class FrontendTests {
|
||||
|
||||
void setDvrTests(DvrTests dvrTests) { mDvrTests = dvrTests; }
|
||||
void setDemux(sp<IDemux> demux) { mDvrTests.setDemux(demux); }
|
||||
void setSoftwareFrontendDvrConfig(DvrConfig conf) { mDvrConfig = conf; }
|
||||
|
||||
protected:
|
||||
static AssertionResult failure() { return ::testing::AssertionFailure(); }
|
||||
static AssertionResult success() { return ::testing::AssertionSuccess(); }
|
||||
|
||||
void getSoftwareFrontendPlaybackConfig(DvrConfig& dvrConfig) {
|
||||
void getDefaultSoftwareFrontendPlaybackConfig(DvrConfig& dvrConfig) {
|
||||
PlaybackSettings playbackSettings{
|
||||
.statusMask = 0xf,
|
||||
.lowThreshold = 0x1000,
|
||||
@@ -151,4 +153,5 @@ class FrontendTests {
|
||||
|
||||
DvrTests mDvrTests;
|
||||
bool mIsSoftwareFe = false;
|
||||
DvrConfig mDvrConfig;
|
||||
};
|
||||
|
||||
@@ -486,6 +486,62 @@ TEST_P(TunerBroadcastHidlTest, LnbBroadcastDataFlowVideoFilterTest) {
|
||||
broadcastSingleFilterTest(filterArray[TS_VIDEO0], frontendArray[DVBS]);
|
||||
}
|
||||
|
||||
TEST_P(TunerBroadcastHidlTest, BroadcastEsDataFlowMediaFiltersTest) {
|
||||
description("Test Meida Filters functionality in Broadcast use case with ES input.");
|
||||
uint32_t feId;
|
||||
uint32_t demuxId;
|
||||
sp<IDemux> demux;
|
||||
uint32_t filterId;
|
||||
|
||||
mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId);
|
||||
if (feId == INVALID_ID) {
|
||||
// TODO broadcast test on Cuttlefish needs licensed ts input,
|
||||
// these tests are runnable on vendor device with real frontend module
|
||||
// or with manual ts installing and use DVBT frontend.
|
||||
return;
|
||||
}
|
||||
ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
|
||||
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
|
||||
ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
|
||||
ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
|
||||
mFrontendTests.setDemux(demux);
|
||||
mFilterTests.setDemux(demux);
|
||||
ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_AUDIO1].type,
|
||||
filterArray[TS_AUDIO1].bufferSize));
|
||||
ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
|
||||
ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_AUDIO1].settings, filterId));
|
||||
ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
|
||||
ASSERT_TRUE(mFilterTests.startFilter(filterId));
|
||||
ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_VIDEO1].type,
|
||||
filterArray[TS_VIDEO1].bufferSize));
|
||||
ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
|
||||
ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_VIDEO1].settings, filterId));
|
||||
ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
|
||||
ASSERT_TRUE(mFilterTests.startFilter(filterId));
|
||||
// tune test
|
||||
PlaybackSettings playbackSettings{
|
||||
.statusMask = 0xf,
|
||||
.lowThreshold = 0x1000,
|
||||
.highThreshold = 0x07fff,
|
||||
.dataFormat = DataFormat::ES,
|
||||
.packetSize = 188,
|
||||
};
|
||||
DvrConfig dvrConfig{
|
||||
.type = DvrType::PLAYBACK,
|
||||
.playbackInputFile = "/data/local/tmp/test.es",
|
||||
.bufferSize = FMQ_SIZE_4M,
|
||||
};
|
||||
dvrConfig.settings.playback(playbackSettings);
|
||||
mFrontendTests.setSoftwareFrontendDvrConfig(dvrConfig);
|
||||
ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendArray[DVBT], true /*testWithDemux*/));
|
||||
ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles));
|
||||
ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
|
||||
ASSERT_TRUE(mFilterTests.stopFilter(filterId));
|
||||
ASSERT_TRUE(mFilterTests.closeFilter(filterId));
|
||||
ASSERT_TRUE(mDemuxTests.closeDemux());
|
||||
ASSERT_TRUE(mFrontendTests.closeFrontend());
|
||||
}
|
||||
|
||||
TEST_P(TunerPlaybackHidlTest, PlaybackDataFlowWithTsSectionFilterTest) {
|
||||
description("Feed ts data from playback and configure Ts section filter to get output");
|
||||
playbackSingleFilterTest(filterArray[TS_SECTION0], dvrArray[DVR_PLAYBACK0]);
|
||||
|
||||
@@ -77,6 +77,7 @@ typedef enum {
|
||||
TS_VIDEO0,
|
||||
TS_VIDEO1,
|
||||
TS_AUDIO0,
|
||||
TS_AUDIO1,
|
||||
TS_PES0,
|
||||
TS_PCR0,
|
||||
TS_SECTION0,
|
||||
@@ -121,7 +122,6 @@ typedef enum {
|
||||
typedef enum {
|
||||
DVR_RECORD0,
|
||||
DVR_PLAYBACK0,
|
||||
DVR_SOFTWARE_FE,
|
||||
DVR_MAX,
|
||||
} Dvr;
|
||||
|
||||
@@ -274,6 +274,11 @@ inline void initFilterConfig() {
|
||||
filterArray[TS_AUDIO0].bufferSize = FMQ_SIZE_16M;
|
||||
filterArray[TS_AUDIO0].settings.ts().tpid = 256;
|
||||
filterArray[TS_AUDIO0].settings.ts().filterSettings.av({.isPassthrough = false});
|
||||
filterArray[TS_AUDIO1].type.mainType = DemuxFilterMainType::TS;
|
||||
filterArray[TS_AUDIO1].type.subType.tsFilterType(DemuxTsFilterType::AUDIO);
|
||||
filterArray[TS_AUDIO1].bufferSize = FMQ_SIZE_16M;
|
||||
filterArray[TS_AUDIO1].settings.ts().tpid = 257;
|
||||
filterArray[TS_AUDIO1].settings.ts().filterSettings.av({.isPassthrough = false});
|
||||
// TS PES filter setting
|
||||
filterArray[TS_PES0].type.mainType = DemuxFilterMainType::TS;
|
||||
filterArray[TS_PES0].type.subType.tsFilterType(DemuxTsFilterType::PES);
|
||||
@@ -362,17 +367,6 @@ inline void initDvrConfig() {
|
||||
dvrArray[DVR_PLAYBACK0].playbackInputFile = "/data/local/tmp/segment000000.ts";
|
||||
dvrArray[DVR_PLAYBACK0].bufferSize = FMQ_SIZE_4M;
|
||||
dvrArray[DVR_PLAYBACK0].settings.playback(playbackSettings);
|
||||
PlaybackSettings softwareFePlaybackSettings{
|
||||
.statusMask = 0xf,
|
||||
.lowThreshold = 0x1000,
|
||||
.highThreshold = 0x07fff,
|
||||
.dataFormat = DataFormat::TS,
|
||||
.packetSize = 188,
|
||||
};
|
||||
dvrArray[DVR_SOFTWARE_FE].type = DvrType::PLAYBACK;
|
||||
dvrArray[DVR_SOFTWARE_FE].playbackInputFile = "/data/local/tmp/segment000000.ts";
|
||||
dvrArray[DVR_SOFTWARE_FE].bufferSize = FMQ_SIZE_4M;
|
||||
dvrArray[DVR_SOFTWARE_FE].settings.playback(softwareFePlaybackSettings);
|
||||
};
|
||||
|
||||
/** Configuration array for the descrambler test */
|
||||
|
||||
Reference in New Issue
Block a user