Loading tv/tuner/1.0/default/Demux.cpp +69 −67 Original line number Original line Diff line number Diff line Loading @@ -48,8 +48,6 @@ Return<Result> Demux::setFrontendDataSource(uint32_t frontendId) { return Result::INVALID_STATE; return Result::INVALID_STATE; } } mFrontendSourceFile = mFrontend->getSourceFile(); mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId); mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId); return Result::SUCCESS; return Result::SUCCESS; Loading @@ -62,8 +60,6 @@ Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize, uint32_t filterId; uint32_t filterId; filterId = ++mLastUsedFilterId; filterId = ++mLastUsedFilterId; mUsedFilterIds.insert(filterId); if (cb == nullptr) { if (cb == nullptr) { ALOGW("[Demux] callback can't be null"); ALOGW("[Demux] callback can't be null"); _hidl_cb(Result::INVALID_ARGUMENT, new Filter()); _hidl_cb(Result::INVALID_ARGUMENT, new Filter()); Loading @@ -82,8 +78,13 @@ Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize, mPcrFilterIds.insert(filterId); mPcrFilterIds.insert(filterId); } } bool result = true; bool result = true; if (mDvr != nullptr && mDvr->getType() == DvrType::PLAYBACK) { if (!filter->isRecordFilter()) { result = mDvr->addPlaybackFilter(filter); // Only save non-record filters for now. Record filters are saved when the // IDvr.attacheFilter is called. mPlaybackFilterIds.insert(filterId); if (mDvrPlayback != nullptr) { result = mDvrPlayback->addPlaybackFilter(filterId, filter); } } } _hidl_cb(result ? Result::SUCCESS : Result::INVALID_ARGUMENT, filter); _hidl_cb(result ? Result::SUCCESS : Result::INVALID_ARGUMENT, filter); Loading Loading @@ -154,7 +155,13 @@ Return<void> Demux::getAvSyncTime(AvSyncHwId avSyncHwId, getAvSyncTime_cb _hidl_ Return<Result> Demux::close() { Return<Result> Demux::close() { ALOGV("%s", __FUNCTION__); ALOGV("%s", __FUNCTION__); mUsedFilterIds.clear(); set<uint32_t>::iterator it; for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) { mDvrPlayback->removePlaybackFilter(*it); } mPlaybackFilterIds.clear(); mRecordFilterIds.clear(); mFilters.clear(); mLastUsedFilterId = -1; mLastUsedFilterId = -1; return Result::SUCCESS; return Result::SUCCESS; Loading @@ -170,15 +177,38 @@ Return<void> Demux::openDvr(DvrType type, uint32_t bufferSize, const sp<IDvrCall return Void(); return Void(); } } mDvr = new Dvr(type, bufferSize, cb, this); set<uint32_t>::iterator it; switch (type) { case DvrType::PLAYBACK: mDvrPlayback = new Dvr(type, bufferSize, cb, this); if (!mDvrPlayback->createDvrMQ()) { _hidl_cb(Result::UNKNOWN_ERROR, mDvrPlayback); return Void(); } for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) { if (!mDvrPlayback->addPlaybackFilter(*it, mFilters[*it])) { ALOGE("[Demux] Can't get filter info for DVR playback"); _hidl_cb(Result::UNKNOWN_ERROR, mDvrPlayback); return Void(); } } if (!mDvr->createDvrMQ()) { _hidl_cb(Result::SUCCESS, mDvrPlayback); _hidl_cb(Result::UNKNOWN_ERROR, mDvr); return Void(); case DvrType::RECORD: mDvrRecord = new Dvr(type, bufferSize, cb, this); if (!mDvrRecord->createDvrMQ()) { _hidl_cb(Result::UNKNOWN_ERROR, mDvrRecord); return Void(); return Void(); } } _hidl_cb(Result::SUCCESS, mDvr); _hidl_cb(Result::SUCCESS, mDvrRecord); return Void(); return Void(); default: _hidl_cb(Result::INVALID_ARGUMENT, nullptr); return Void(); } } } Return<Result> Demux::connectCiCam(uint32_t ciCamId) { Return<Result> Demux::connectCiCam(uint32_t ciCamId) { Loading @@ -198,8 +228,10 @@ Return<Result> Demux::disconnectCiCam() { Result Demux::removeFilter(uint32_t filterId) { Result Demux::removeFilter(uint32_t filterId) { ALOGV("%s", __FUNCTION__); ALOGV("%s", __FUNCTION__); // resetFilterRecords(filterId); if (mDvrPlayback != nullptr) { mUsedFilterIds.erase(filterId); mDvrPlayback->removePlaybackFilter(filterId); } mPlaybackFilterIds.erase(filterId); mRecordFilterIds.erase(filterId); mRecordFilterIds.erase(filterId); mFilters.erase(filterId); mFilters.erase(filterId); Loading @@ -212,7 +244,7 @@ void Demux::startBroadcastTsFilter(vector<uint8_t> data) { if (DEBUG_DEMUX) { if (DEBUG_DEMUX) { ALOGW("[Demux] start ts filter pid: %d", pid); ALOGW("[Demux] start ts filter pid: %d", pid); } } for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) { if (pid == mFilters[*it]->getTpid()) { if (pid == mFilters[*it]->getTpid()) { mFilters[*it]->updateFilterOutput(data); mFilters[*it]->updateFilterOutput(data); } } Loading @@ -233,7 +265,7 @@ bool Demux::startBroadcastFilterDispatcher() { set<uint32_t>::iterator it; set<uint32_t>::iterator it; // Handle the output data per filter type // Handle the output data per filter type for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) { if (mFilters[*it]->startFilterHandler() != Result::SUCCESS) { if (mFilters[*it]->startFilterHandler() != Result::SUCCESS) { return false; return false; } } Loading Loading @@ -280,58 +312,27 @@ void* Demux::__threadLoopFrontend(void* user) { void Demux::frontendInputThreadLoop() { void Demux::frontendInputThreadLoop() { std::lock_guard<std::mutex> lock(mFrontendInputThreadLock); std::lock_guard<std::mutex> lock(mFrontendInputThreadLock); mFrontendInputThreadRunning = true; mFrontendInputThreadRunning = true; mKeepFetchingDataFromFrontend = true; // open the stream and get its length std::ifstream inputData(mFrontendSourceFile, std::ifstream::binary); // TODO take the packet size from the frontend setting int packetSize = 188; int writePacketAmount = 6; char* buffer = new char[packetSize]; ALOGW("[Demux] Frontend input thread loop start %s", mFrontendSourceFile.c_str()); if (!inputData.is_open()) { mFrontendInputThreadRunning = false; ALOGW("[Demux] Error %s", strerror(errno)); } while (mFrontendInputThreadRunning) { while (mFrontendInputThreadRunning) { // move the stream pointer for packet size * 6 every read until the end uint32_t efState = 0; while (mKeepFetchingDataFromFrontend) { status_t status = mDvrPlayback->getDvrEventFlag()->wait( for (int i = 0; i < writePacketAmount; i++) { static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT, inputData.read(buffer, packetSize); true /* retry on spurious wake */); if (!inputData) { if (status != OK) { mKeepFetchingDataFromFrontend = false; ALOGD("[Demux] wait for data ready on the playback FMQ"); mFrontendInputThreadRunning = false; continue; } // 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) || !mDvrPlayback->startFilterDispatcher(true /*isVirtualFrontend*/, mIsRecording)) { ALOGE("[Demux] playback data failed to be filtered. Ending thread"); break; break; } } // filter and dispatch filter output vector<uint8_t> byteBuffer; byteBuffer.resize(packetSize); for (int index = 0; index < byteBuffer.size(); index++) { byteBuffer[index] = static_cast<uint8_t>(buffer[index]); } if (mIsRecording) { // Feed the data into the Dvr recording input sendFrontendInputToRecord(byteBuffer); } else { // Feed the data into the broadcast demux filter startBroadcastTsFilter(byteBuffer); } } if (mIsRecording) { // Dispatch the data into the broadcasting filters. startRecordFilterDispatcher(); } else { // Dispatch the data into the broadcasting filters. startBroadcastFilterDispatcher(); } usleep(100); } } } mFrontendInputThreadRunning = false; ALOGW("[Demux] Frontend Input thread end."); ALOGW("[Demux] Frontend Input thread end."); delete[] buffer; inputData.close(); } } void Demux::stopFrontendInput() { void Demux::stopFrontendInput() { Loading @@ -346,18 +347,19 @@ void Demux::setIsRecording(bool isRecording) { } } bool Demux::attachRecordFilter(int filterId) { bool Demux::attachRecordFilter(int filterId) { if (mFilters[filterId] == nullptr || mDvr == nullptr) { if (mFilters[filterId] == nullptr || mDvrRecord == nullptr || !mFilters[filterId]->isRecordFilter()) { return false; return false; } } mRecordFilterIds.insert(filterId); mRecordFilterIds.insert(filterId); mFilters[filterId]->attachFilterToRecord(mDvr); mFilters[filterId]->attachFilterToRecord(mDvrRecord); return true; return true; } } bool Demux::detachRecordFilter(int filterId) { bool Demux::detachRecordFilter(int filterId) { if (mFilters[filterId] == nullptr || mDvr == nullptr) { if (mFilters[filterId] == nullptr || mDvrRecord == nullptr) { return false; return false; } } Loading tv/tuner/1.0/default/Demux.h +16 −15 Original line number Original line Diff line number Diff line Loading @@ -91,13 +91,23 @@ class Demux : public IDemux { void setIsRecording(bool isRecording); void setIsRecording(bool isRecording); void startFrontendInputLoop(); void startFrontendInputLoop(); /** * A dispatcher to read and dispatch input data to all the started filters. * Each filter handler handles the data filtering/output writing/filterEvent updating. * Note that recording filters are not included. */ bool startBroadcastFilterDispatcher(); void startBroadcastTsFilter(vector<uint8_t> data); void sendFrontendInputToRecord(vector<uint8_t> data); bool startRecordFilterDispatcher(); private: private: // Tuner service // Tuner service sp<Tuner> mTunerService; sp<Tuner> mTunerService; // Frontend source // Frontend source sp<Frontend> mFrontend; sp<Frontend> mFrontend; string mFrontendSourceFile; // A struct that passes the arguments to a newly created filter thread // A struct that passes the arguments to a newly created filter thread struct ThreadArgs { struct ThreadArgs { Loading @@ -117,16 +127,6 @@ class Demux : public IDemux { */ */ void deleteEventFlag(); void deleteEventFlag(); bool readDataFromMQ(); bool readDataFromMQ(); /** * A dispatcher to read and dispatch input data to all the started filters. * Each filter handler handles the data filtering/output writing/filterEvent updating. * Note that recording filters are not included. */ bool startBroadcastFilterDispatcher(); void startBroadcastTsFilter(vector<uint8_t> data); void sendFrontendInputToRecord(vector<uint8_t> data); bool startRecordFilterDispatcher(); uint32_t mDemuxId; uint32_t mDemuxId; uint32_t mCiCamId; uint32_t mCiCamId; Loading @@ -137,17 +137,17 @@ class Demux : public IDemux { */ */ uint32_t mLastUsedFilterId = -1; uint32_t mLastUsedFilterId = -1; /** /** * Record all the used filter Ids. * Record all the used playback filter Ids. * Any removed filter id should be removed from this set. * Any removed filter id should be removed from this set. */ */ set<uint32_t> mUsedFilterIds; set<uint32_t> mPlaybackFilterIds; /** /** * Record all the attached record filter Ids. * Record all the attached record filter Ids. * Any removed filter id should be removed from this set. * Any removed filter id should be removed from this set. */ */ set<uint32_t> mRecordFilterIds; set<uint32_t> mRecordFilterIds; /** /** * A list of created FilterMQ ptrs. * A list of created Filter sp. * The array number is the filter ID. * The array number is the filter ID. */ */ std::map<uint32_t, sp<Filter>> mFilters; std::map<uint32_t, sp<Filter>> mFilters; Loading @@ -160,7 +160,8 @@ class Demux : public IDemux { /** /** * Local reference to the opened DVR object. * Local reference to the opened DVR object. */ */ sp<Dvr> mDvr; sp<Dvr> mDvrPlayback; sp<Dvr> mDvrRecord; // Thread handlers // Thread handlers pthread_t mFrontendInputThread; pthread_t mFrontendInputThread; Loading tv/tuner/1.0/default/Dvr.cpp +33 −36 Original line number Original line Diff line number Diff line Loading @@ -70,8 +70,7 @@ Return<Result> Dvr::attachFilter(const sp<IFilter>& filter) { return status; return status; } } // check if the attached filter is a record filter // TODO check if the attached filter is a record filter mFilters[filterId] = filter; if (!mDemux->attachRecordFilter(filterId)) { if (!mDemux->attachRecordFilter(filterId)) { return Result::INVALID_ARGUMENT; return Result::INVALID_ARGUMENT; } } Loading @@ -94,20 +93,9 @@ Return<Result> Dvr::detachFilter(const sp<IFilter>& filter) { return status; return status; } } std::map<uint32_t, sp<IFilter>>::iterator it; it = mFilters.find(filterId); if (it != mFilters.end()) { mFilters.erase(filterId); if (!mDemux->detachRecordFilter(filterId)) { if (!mDemux->detachRecordFilter(filterId)) { return Result::INVALID_ARGUMENT; return Result::INVALID_ARGUMENT; } } } // If all the filters are detached, record can't be started if (mFilters.empty()) { mIsRecordFilterAttached = false; } return Result::SUCCESS; return Result::SUCCESS; } } Loading Loading @@ -183,6 +171,10 @@ bool Dvr::createDvrMQ() { return true; return true; } } EventFlag* Dvr::getDvrEventFlag() { return mDvrEventFlag; } void* Dvr::__threadLoopPlayback(void* user) { void* Dvr::__threadLoopPlayback(void* user) { Dvr* const self = static_cast<Dvr*>(user); Dvr* const self = static_cast<Dvr*>(user); self->playbackThreadLoop(); self->playbackThreadLoop(); Loading @@ -205,8 +197,9 @@ void Dvr::playbackThreadLoop() { } } // Our current implementation filter the data and write it into the filter FMQ immediately // Our current implementation filter the data and write it into the filter FMQ immediately // after the DATA_READY from the VTS/framework // after the DATA_READY from the VTS/framework if (!readPlaybackFMQ() || !startFilterDispatcher()) { if (!readPlaybackFMQ(false /*isVirtualFrontend*/, false /*isRecording*/) || ALOGD("[Dvr] playback data failed to be filtered. Ending thread"); !startFilterDispatcher(false /*isVirtualFrontend*/, false /*isRecording*/)) { ALOGE("[Dvr] playback data failed to be filtered. Ending thread"); break; break; } } Loading Loading @@ -245,7 +238,7 @@ PlaybackStatus Dvr::checkPlaybackStatusChange(uint32_t availableToWrite, uint32_ return mPlaybackStatus; return mPlaybackStatus; } } bool Dvr::readPlaybackFMQ() { bool Dvr::readPlaybackFMQ(bool isVirtualFrontend, bool isRecording) { // Read playback data from the input FMQ // Read playback data from the input FMQ int size = mDvrMQ->availableToRead(); int size = mDvrMQ->availableToRead(); int playbackPacketSize = mDvrSettings.playback().packetSize; int playbackPacketSize = mDvrSettings.playback().packetSize; Loading @@ -256,8 +249,16 @@ bool Dvr::readPlaybackFMQ() { if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) { if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) { return false; return false; } } if (isVirtualFrontend) { if (isRecording) { mDemux->sendFrontendInputToRecord(dataOutputBuffer); } else { mDemux->startBroadcastTsFilter(dataOutputBuffer); } } else { startTpidFilter(dataOutputBuffer); startTpidFilter(dataOutputBuffer); } } } return true; return true; } } Loading @@ -275,7 +276,15 @@ void Dvr::startTpidFilter(vector<uint8_t> data) { } } } } bool Dvr::startFilterDispatcher() { bool Dvr::startFilterDispatcher(bool isVirtualFrontend, bool isRecording) { if (isVirtualFrontend) { if (isRecording) { return mDemux->startRecordFilterDispatcher(); } else { return mDemux->startBroadcastFilterDispatcher(); } } std::map<uint32_t, sp<IFilter>>::iterator it; std::map<uint32_t, sp<IFilter>>::iterator it; // Handle the output data per filter type // Handle the output data per filter type for (it = mFilters.begin(); it != mFilters.end(); it++) { for (it = mFilters.begin(); it != mFilters.end(); it++) { Loading Loading @@ -329,27 +338,15 @@ RecordStatus Dvr::checkRecordStatusChange(uint32_t availableToWrite, uint32_t av return mRecordStatus; return mRecordStatus; } } bool Dvr::addPlaybackFilter(sp<IFilter> filter) { bool Dvr::addPlaybackFilter(uint32_t filterId, sp<IFilter> filter) { uint32_t filterId; Result status; filter->getId([&](Result result, uint32_t id) { filterId = id; status = result; }); if (status != Result::SUCCESS) { return false; } mFilters[filterId] = filter; mFilters[filterId] = filter; return true; return true; } } DvrType Dvr::getType() { bool Dvr::removePlaybackFilter(uint32_t filterId) { return mType; mFilters.erase(filterId); return true; } } } // namespace implementation } // namespace implementation } // namespace V1_0 } // namespace V1_0 } // namespace tuner } // namespace tuner Loading tv/tuner/1.0/default/Dvr.h +5 −8 Original line number Original line Diff line number Diff line Loading @@ -81,8 +81,11 @@ class Dvr : public IDvr { bool createDvrMQ(); bool createDvrMQ(); void sendBroadcastInputToDvrRecord(vector<uint8_t> byteBuffer); void sendBroadcastInputToDvrRecord(vector<uint8_t> byteBuffer); bool writeRecordFMQ(const std::vector<uint8_t>& data); bool writeRecordFMQ(const std::vector<uint8_t>& data); DvrType getType(); bool addPlaybackFilter(uint32_t filterId, sp<IFilter> filter); bool addPlaybackFilter(sp<IFilter> filter); bool removePlaybackFilter(uint32_t filterId); bool readPlaybackFMQ(bool isVirtualFrontend, bool isRecording); bool startFilterDispatcher(bool isVirtualFrontend, bool isRecording); EventFlag* getDvrEventFlag(); private: private: // Demux service // Demux service Loading @@ -105,9 +108,7 @@ class Dvr : public IDvr { * A dispatcher to read and dispatch input data to all the started filters. * A dispatcher to read and dispatch input data to all the started filters. * Each filter handler handles the data filtering/output writing/filterEvent updating. * Each filter handler handles the data filtering/output writing/filterEvent updating. */ */ bool readPlaybackFMQ(); void startTpidFilter(vector<uint8_t> data); void startTpidFilter(vector<uint8_t> data); bool startFilterDispatcher(); static void* __threadLoopPlayback(void* user); static void* __threadLoopPlayback(void* user); static void* __threadLoopRecord(void* user); static void* __threadLoopRecord(void* user); void playbackThreadLoop(); void playbackThreadLoop(); Loading @@ -123,7 +124,6 @@ class Dvr : public IDvr { // Thread handlers // Thread handlers pthread_t mDvrThread; pthread_t mDvrThread; pthread_t mBroadcastInputThread; // FMQ status local records // FMQ status local records PlaybackStatus mPlaybackStatus; PlaybackStatus mPlaybackStatus; Loading @@ -132,7 +132,6 @@ class Dvr : public IDvr { * If a specific filter's writing loop is still running * If a specific filter's writing loop is still running */ */ bool mDvrThreadRunning; bool mDvrThreadRunning; bool mBroadcastInputThreadRunning; bool mKeepFetchingDataFromFrontend; bool mKeepFetchingDataFromFrontend; /** /** * Lock to protect writes to the FMQs * Lock to protect writes to the FMQs Loading @@ -143,7 +142,6 @@ class Dvr : public IDvr { */ */ std::mutex mPlaybackStatusLock; std::mutex mPlaybackStatusLock; std::mutex mRecordStatusLock; std::mutex mRecordStatusLock; std::mutex mBroadcastInputThreadLock; std::mutex mDvrThreadLock; std::mutex mDvrThreadLock; const bool DEBUG_DVR = false; const bool DEBUG_DVR = false; Loading @@ -151,7 +149,6 @@ class Dvr : public IDvr { // Booleans to check if recording is running. // Booleans to check if recording is running. // Recording is ready when both of the following are set to true. // Recording is ready when both of the following are set to true. bool mIsRecordStarted = false; bool mIsRecordStarted = false; bool mIsRecordFilterAttached = false; }; }; } // namespace implementation } // namespace implementation Loading tv/tuner/1.0/default/Filter.cpp +7 −7 Original line number Original line Diff line number Diff line Loading @@ -47,12 +47,18 @@ Filter::Filter(DemuxFilterType type, uint32_t filterId, uint32_t bufferSize, if (mType.subType.tsFilterType() == DemuxTsFilterType::PCR) { if (mType.subType.tsFilterType() == DemuxTsFilterType::PCR) { mIsPcrFilter = true; mIsPcrFilter = true; } } if (mType.subType.tsFilterType() == DemuxTsFilterType::RECORD) { mIsRecordFilter = true; } break; break; case DemuxFilterMainType::MMTP: case DemuxFilterMainType::MMTP: if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO || if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO || mType.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) { mType.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) { mIsMediaFilter = true; mIsMediaFilter = true; } } if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::RECORD) { mIsRecordFilter = true; } break; break; case DemuxFilterMainType::IP: case DemuxFilterMainType::IP: break; break; Loading Loading @@ -535,12 +541,6 @@ Result Filter::startMediaFilterHandler() { } } Result Filter::startRecordFilterHandler() { Result Filter::startRecordFilterHandler() { /*DemuxFilterTsRecordEvent tsRecordEvent; tsRecordEvent.pid.tPid(0); tsRecordEvent.indexMask.tsIndexMask(0x01); mFilterEvent.events.resize(1); mFilterEvent.events[0].tsRecord(tsRecordEvent); */ std::lock_guard<std::mutex> lock(mRecordFilterOutputLock); std::lock_guard<std::mutex> lock(mRecordFilterOutputLock); if (mRecordFilterOutput.empty()) { if (mRecordFilterOutput.empty()) { return Result::SUCCESS; return Result::SUCCESS; Loading @@ -567,7 +567,7 @@ Result Filter::startTemiFilterHandler() { bool Filter::writeSectionsAndCreateEvent(vector<uint8_t> data) { bool Filter::writeSectionsAndCreateEvent(vector<uint8_t> data) { // TODO check how many sections has been read // TODO check how many sections has been read ALOGD("[Filter] section hander"); ALOGD("[Filter] section handler"); std::lock_guard<std::mutex> lock(mFilterEventLock); std::lock_guard<std::mutex> lock(mFilterEventLock); if (!writeDataToFilterMQ(data)) { if (!writeDataToFilterMQ(data)) { return false; return false; Loading Loading
tv/tuner/1.0/default/Demux.cpp +69 −67 Original line number Original line Diff line number Diff line Loading @@ -48,8 +48,6 @@ Return<Result> Demux::setFrontendDataSource(uint32_t frontendId) { return Result::INVALID_STATE; return Result::INVALID_STATE; } } mFrontendSourceFile = mFrontend->getSourceFile(); mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId); mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId); return Result::SUCCESS; return Result::SUCCESS; Loading @@ -62,8 +60,6 @@ Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize, uint32_t filterId; uint32_t filterId; filterId = ++mLastUsedFilterId; filterId = ++mLastUsedFilterId; mUsedFilterIds.insert(filterId); if (cb == nullptr) { if (cb == nullptr) { ALOGW("[Demux] callback can't be null"); ALOGW("[Demux] callback can't be null"); _hidl_cb(Result::INVALID_ARGUMENT, new Filter()); _hidl_cb(Result::INVALID_ARGUMENT, new Filter()); Loading @@ -82,8 +78,13 @@ Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize, mPcrFilterIds.insert(filterId); mPcrFilterIds.insert(filterId); } } bool result = true; bool result = true; if (mDvr != nullptr && mDvr->getType() == DvrType::PLAYBACK) { if (!filter->isRecordFilter()) { result = mDvr->addPlaybackFilter(filter); // Only save non-record filters for now. Record filters are saved when the // IDvr.attacheFilter is called. mPlaybackFilterIds.insert(filterId); if (mDvrPlayback != nullptr) { result = mDvrPlayback->addPlaybackFilter(filterId, filter); } } } _hidl_cb(result ? Result::SUCCESS : Result::INVALID_ARGUMENT, filter); _hidl_cb(result ? Result::SUCCESS : Result::INVALID_ARGUMENT, filter); Loading Loading @@ -154,7 +155,13 @@ Return<void> Demux::getAvSyncTime(AvSyncHwId avSyncHwId, getAvSyncTime_cb _hidl_ Return<Result> Demux::close() { Return<Result> Demux::close() { ALOGV("%s", __FUNCTION__); ALOGV("%s", __FUNCTION__); mUsedFilterIds.clear(); set<uint32_t>::iterator it; for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) { mDvrPlayback->removePlaybackFilter(*it); } mPlaybackFilterIds.clear(); mRecordFilterIds.clear(); mFilters.clear(); mLastUsedFilterId = -1; mLastUsedFilterId = -1; return Result::SUCCESS; return Result::SUCCESS; Loading @@ -170,15 +177,38 @@ Return<void> Demux::openDvr(DvrType type, uint32_t bufferSize, const sp<IDvrCall return Void(); return Void(); } } mDvr = new Dvr(type, bufferSize, cb, this); set<uint32_t>::iterator it; switch (type) { case DvrType::PLAYBACK: mDvrPlayback = new Dvr(type, bufferSize, cb, this); if (!mDvrPlayback->createDvrMQ()) { _hidl_cb(Result::UNKNOWN_ERROR, mDvrPlayback); return Void(); } for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) { if (!mDvrPlayback->addPlaybackFilter(*it, mFilters[*it])) { ALOGE("[Demux] Can't get filter info for DVR playback"); _hidl_cb(Result::UNKNOWN_ERROR, mDvrPlayback); return Void(); } } if (!mDvr->createDvrMQ()) { _hidl_cb(Result::SUCCESS, mDvrPlayback); _hidl_cb(Result::UNKNOWN_ERROR, mDvr); return Void(); case DvrType::RECORD: mDvrRecord = new Dvr(type, bufferSize, cb, this); if (!mDvrRecord->createDvrMQ()) { _hidl_cb(Result::UNKNOWN_ERROR, mDvrRecord); return Void(); return Void(); } } _hidl_cb(Result::SUCCESS, mDvr); _hidl_cb(Result::SUCCESS, mDvrRecord); return Void(); return Void(); default: _hidl_cb(Result::INVALID_ARGUMENT, nullptr); return Void(); } } } Return<Result> Demux::connectCiCam(uint32_t ciCamId) { Return<Result> Demux::connectCiCam(uint32_t ciCamId) { Loading @@ -198,8 +228,10 @@ Return<Result> Demux::disconnectCiCam() { Result Demux::removeFilter(uint32_t filterId) { Result Demux::removeFilter(uint32_t filterId) { ALOGV("%s", __FUNCTION__); ALOGV("%s", __FUNCTION__); // resetFilterRecords(filterId); if (mDvrPlayback != nullptr) { mUsedFilterIds.erase(filterId); mDvrPlayback->removePlaybackFilter(filterId); } mPlaybackFilterIds.erase(filterId); mRecordFilterIds.erase(filterId); mRecordFilterIds.erase(filterId); mFilters.erase(filterId); mFilters.erase(filterId); Loading @@ -212,7 +244,7 @@ void Demux::startBroadcastTsFilter(vector<uint8_t> data) { if (DEBUG_DEMUX) { if (DEBUG_DEMUX) { ALOGW("[Demux] start ts filter pid: %d", pid); ALOGW("[Demux] start ts filter pid: %d", pid); } } for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) { if (pid == mFilters[*it]->getTpid()) { if (pid == mFilters[*it]->getTpid()) { mFilters[*it]->updateFilterOutput(data); mFilters[*it]->updateFilterOutput(data); } } Loading @@ -233,7 +265,7 @@ bool Demux::startBroadcastFilterDispatcher() { set<uint32_t>::iterator it; set<uint32_t>::iterator it; // Handle the output data per filter type // Handle the output data per filter type for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) { if (mFilters[*it]->startFilterHandler() != Result::SUCCESS) { if (mFilters[*it]->startFilterHandler() != Result::SUCCESS) { return false; return false; } } Loading Loading @@ -280,58 +312,27 @@ void* Demux::__threadLoopFrontend(void* user) { void Demux::frontendInputThreadLoop() { void Demux::frontendInputThreadLoop() { std::lock_guard<std::mutex> lock(mFrontendInputThreadLock); std::lock_guard<std::mutex> lock(mFrontendInputThreadLock); mFrontendInputThreadRunning = true; mFrontendInputThreadRunning = true; mKeepFetchingDataFromFrontend = true; // open the stream and get its length std::ifstream inputData(mFrontendSourceFile, std::ifstream::binary); // TODO take the packet size from the frontend setting int packetSize = 188; int writePacketAmount = 6; char* buffer = new char[packetSize]; ALOGW("[Demux] Frontend input thread loop start %s", mFrontendSourceFile.c_str()); if (!inputData.is_open()) { mFrontendInputThreadRunning = false; ALOGW("[Demux] Error %s", strerror(errno)); } while (mFrontendInputThreadRunning) { while (mFrontendInputThreadRunning) { // move the stream pointer for packet size * 6 every read until the end uint32_t efState = 0; while (mKeepFetchingDataFromFrontend) { status_t status = mDvrPlayback->getDvrEventFlag()->wait( for (int i = 0; i < writePacketAmount; i++) { static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT, inputData.read(buffer, packetSize); true /* retry on spurious wake */); if (!inputData) { if (status != OK) { mKeepFetchingDataFromFrontend = false; ALOGD("[Demux] wait for data ready on the playback FMQ"); mFrontendInputThreadRunning = false; continue; } // 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) || !mDvrPlayback->startFilterDispatcher(true /*isVirtualFrontend*/, mIsRecording)) { ALOGE("[Demux] playback data failed to be filtered. Ending thread"); break; break; } } // filter and dispatch filter output vector<uint8_t> byteBuffer; byteBuffer.resize(packetSize); for (int index = 0; index < byteBuffer.size(); index++) { byteBuffer[index] = static_cast<uint8_t>(buffer[index]); } if (mIsRecording) { // Feed the data into the Dvr recording input sendFrontendInputToRecord(byteBuffer); } else { // Feed the data into the broadcast demux filter startBroadcastTsFilter(byteBuffer); } } if (mIsRecording) { // Dispatch the data into the broadcasting filters. startRecordFilterDispatcher(); } else { // Dispatch the data into the broadcasting filters. startBroadcastFilterDispatcher(); } usleep(100); } } } mFrontendInputThreadRunning = false; ALOGW("[Demux] Frontend Input thread end."); ALOGW("[Demux] Frontend Input thread end."); delete[] buffer; inputData.close(); } } void Demux::stopFrontendInput() { void Demux::stopFrontendInput() { Loading @@ -346,18 +347,19 @@ void Demux::setIsRecording(bool isRecording) { } } bool Demux::attachRecordFilter(int filterId) { bool Demux::attachRecordFilter(int filterId) { if (mFilters[filterId] == nullptr || mDvr == nullptr) { if (mFilters[filterId] == nullptr || mDvrRecord == nullptr || !mFilters[filterId]->isRecordFilter()) { return false; return false; } } mRecordFilterIds.insert(filterId); mRecordFilterIds.insert(filterId); mFilters[filterId]->attachFilterToRecord(mDvr); mFilters[filterId]->attachFilterToRecord(mDvrRecord); return true; return true; } } bool Demux::detachRecordFilter(int filterId) { bool Demux::detachRecordFilter(int filterId) { if (mFilters[filterId] == nullptr || mDvr == nullptr) { if (mFilters[filterId] == nullptr || mDvrRecord == nullptr) { return false; return false; } } Loading
tv/tuner/1.0/default/Demux.h +16 −15 Original line number Original line Diff line number Diff line Loading @@ -91,13 +91,23 @@ class Demux : public IDemux { void setIsRecording(bool isRecording); void setIsRecording(bool isRecording); void startFrontendInputLoop(); void startFrontendInputLoop(); /** * A dispatcher to read and dispatch input data to all the started filters. * Each filter handler handles the data filtering/output writing/filterEvent updating. * Note that recording filters are not included. */ bool startBroadcastFilterDispatcher(); void startBroadcastTsFilter(vector<uint8_t> data); void sendFrontendInputToRecord(vector<uint8_t> data); bool startRecordFilterDispatcher(); private: private: // Tuner service // Tuner service sp<Tuner> mTunerService; sp<Tuner> mTunerService; // Frontend source // Frontend source sp<Frontend> mFrontend; sp<Frontend> mFrontend; string mFrontendSourceFile; // A struct that passes the arguments to a newly created filter thread // A struct that passes the arguments to a newly created filter thread struct ThreadArgs { struct ThreadArgs { Loading @@ -117,16 +127,6 @@ class Demux : public IDemux { */ */ void deleteEventFlag(); void deleteEventFlag(); bool readDataFromMQ(); bool readDataFromMQ(); /** * A dispatcher to read and dispatch input data to all the started filters. * Each filter handler handles the data filtering/output writing/filterEvent updating. * Note that recording filters are not included. */ bool startBroadcastFilterDispatcher(); void startBroadcastTsFilter(vector<uint8_t> data); void sendFrontendInputToRecord(vector<uint8_t> data); bool startRecordFilterDispatcher(); uint32_t mDemuxId; uint32_t mDemuxId; uint32_t mCiCamId; uint32_t mCiCamId; Loading @@ -137,17 +137,17 @@ class Demux : public IDemux { */ */ uint32_t mLastUsedFilterId = -1; uint32_t mLastUsedFilterId = -1; /** /** * Record all the used filter Ids. * Record all the used playback filter Ids. * Any removed filter id should be removed from this set. * Any removed filter id should be removed from this set. */ */ set<uint32_t> mUsedFilterIds; set<uint32_t> mPlaybackFilterIds; /** /** * Record all the attached record filter Ids. * Record all the attached record filter Ids. * Any removed filter id should be removed from this set. * Any removed filter id should be removed from this set. */ */ set<uint32_t> mRecordFilterIds; set<uint32_t> mRecordFilterIds; /** /** * A list of created FilterMQ ptrs. * A list of created Filter sp. * The array number is the filter ID. * The array number is the filter ID. */ */ std::map<uint32_t, sp<Filter>> mFilters; std::map<uint32_t, sp<Filter>> mFilters; Loading @@ -160,7 +160,8 @@ class Demux : public IDemux { /** /** * Local reference to the opened DVR object. * Local reference to the opened DVR object. */ */ sp<Dvr> mDvr; sp<Dvr> mDvrPlayback; sp<Dvr> mDvrRecord; // Thread handlers // Thread handlers pthread_t mFrontendInputThread; pthread_t mFrontendInputThread; Loading
tv/tuner/1.0/default/Dvr.cpp +33 −36 Original line number Original line Diff line number Diff line Loading @@ -70,8 +70,7 @@ Return<Result> Dvr::attachFilter(const sp<IFilter>& filter) { return status; return status; } } // check if the attached filter is a record filter // TODO check if the attached filter is a record filter mFilters[filterId] = filter; if (!mDemux->attachRecordFilter(filterId)) { if (!mDemux->attachRecordFilter(filterId)) { return Result::INVALID_ARGUMENT; return Result::INVALID_ARGUMENT; } } Loading @@ -94,20 +93,9 @@ Return<Result> Dvr::detachFilter(const sp<IFilter>& filter) { return status; return status; } } std::map<uint32_t, sp<IFilter>>::iterator it; it = mFilters.find(filterId); if (it != mFilters.end()) { mFilters.erase(filterId); if (!mDemux->detachRecordFilter(filterId)) { if (!mDemux->detachRecordFilter(filterId)) { return Result::INVALID_ARGUMENT; return Result::INVALID_ARGUMENT; } } } // If all the filters are detached, record can't be started if (mFilters.empty()) { mIsRecordFilterAttached = false; } return Result::SUCCESS; return Result::SUCCESS; } } Loading Loading @@ -183,6 +171,10 @@ bool Dvr::createDvrMQ() { return true; return true; } } EventFlag* Dvr::getDvrEventFlag() { return mDvrEventFlag; } void* Dvr::__threadLoopPlayback(void* user) { void* Dvr::__threadLoopPlayback(void* user) { Dvr* const self = static_cast<Dvr*>(user); Dvr* const self = static_cast<Dvr*>(user); self->playbackThreadLoop(); self->playbackThreadLoop(); Loading @@ -205,8 +197,9 @@ void Dvr::playbackThreadLoop() { } } // Our current implementation filter the data and write it into the filter FMQ immediately // Our current implementation filter the data and write it into the filter FMQ immediately // after the DATA_READY from the VTS/framework // after the DATA_READY from the VTS/framework if (!readPlaybackFMQ() || !startFilterDispatcher()) { if (!readPlaybackFMQ(false /*isVirtualFrontend*/, false /*isRecording*/) || ALOGD("[Dvr] playback data failed to be filtered. Ending thread"); !startFilterDispatcher(false /*isVirtualFrontend*/, false /*isRecording*/)) { ALOGE("[Dvr] playback data failed to be filtered. Ending thread"); break; break; } } Loading Loading @@ -245,7 +238,7 @@ PlaybackStatus Dvr::checkPlaybackStatusChange(uint32_t availableToWrite, uint32_ return mPlaybackStatus; return mPlaybackStatus; } } bool Dvr::readPlaybackFMQ() { bool Dvr::readPlaybackFMQ(bool isVirtualFrontend, bool isRecording) { // Read playback data from the input FMQ // Read playback data from the input FMQ int size = mDvrMQ->availableToRead(); int size = mDvrMQ->availableToRead(); int playbackPacketSize = mDvrSettings.playback().packetSize; int playbackPacketSize = mDvrSettings.playback().packetSize; Loading @@ -256,8 +249,16 @@ bool Dvr::readPlaybackFMQ() { if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) { if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) { return false; return false; } } if (isVirtualFrontend) { if (isRecording) { mDemux->sendFrontendInputToRecord(dataOutputBuffer); } else { mDemux->startBroadcastTsFilter(dataOutputBuffer); } } else { startTpidFilter(dataOutputBuffer); startTpidFilter(dataOutputBuffer); } } } return true; return true; } } Loading @@ -275,7 +276,15 @@ void Dvr::startTpidFilter(vector<uint8_t> data) { } } } } bool Dvr::startFilterDispatcher() { bool Dvr::startFilterDispatcher(bool isVirtualFrontend, bool isRecording) { if (isVirtualFrontend) { if (isRecording) { return mDemux->startRecordFilterDispatcher(); } else { return mDemux->startBroadcastFilterDispatcher(); } } std::map<uint32_t, sp<IFilter>>::iterator it; std::map<uint32_t, sp<IFilter>>::iterator it; // Handle the output data per filter type // Handle the output data per filter type for (it = mFilters.begin(); it != mFilters.end(); it++) { for (it = mFilters.begin(); it != mFilters.end(); it++) { Loading Loading @@ -329,27 +338,15 @@ RecordStatus Dvr::checkRecordStatusChange(uint32_t availableToWrite, uint32_t av return mRecordStatus; return mRecordStatus; } } bool Dvr::addPlaybackFilter(sp<IFilter> filter) { bool Dvr::addPlaybackFilter(uint32_t filterId, sp<IFilter> filter) { uint32_t filterId; Result status; filter->getId([&](Result result, uint32_t id) { filterId = id; status = result; }); if (status != Result::SUCCESS) { return false; } mFilters[filterId] = filter; mFilters[filterId] = filter; return true; return true; } } DvrType Dvr::getType() { bool Dvr::removePlaybackFilter(uint32_t filterId) { return mType; mFilters.erase(filterId); return true; } } } // namespace implementation } // namespace implementation } // namespace V1_0 } // namespace V1_0 } // namespace tuner } // namespace tuner Loading
tv/tuner/1.0/default/Dvr.h +5 −8 Original line number Original line Diff line number Diff line Loading @@ -81,8 +81,11 @@ class Dvr : public IDvr { bool createDvrMQ(); bool createDvrMQ(); void sendBroadcastInputToDvrRecord(vector<uint8_t> byteBuffer); void sendBroadcastInputToDvrRecord(vector<uint8_t> byteBuffer); bool writeRecordFMQ(const std::vector<uint8_t>& data); bool writeRecordFMQ(const std::vector<uint8_t>& data); DvrType getType(); bool addPlaybackFilter(uint32_t filterId, sp<IFilter> filter); bool addPlaybackFilter(sp<IFilter> filter); bool removePlaybackFilter(uint32_t filterId); bool readPlaybackFMQ(bool isVirtualFrontend, bool isRecording); bool startFilterDispatcher(bool isVirtualFrontend, bool isRecording); EventFlag* getDvrEventFlag(); private: private: // Demux service // Demux service Loading @@ -105,9 +108,7 @@ class Dvr : public IDvr { * A dispatcher to read and dispatch input data to all the started filters. * A dispatcher to read and dispatch input data to all the started filters. * Each filter handler handles the data filtering/output writing/filterEvent updating. * Each filter handler handles the data filtering/output writing/filterEvent updating. */ */ bool readPlaybackFMQ(); void startTpidFilter(vector<uint8_t> data); void startTpidFilter(vector<uint8_t> data); bool startFilterDispatcher(); static void* __threadLoopPlayback(void* user); static void* __threadLoopPlayback(void* user); static void* __threadLoopRecord(void* user); static void* __threadLoopRecord(void* user); void playbackThreadLoop(); void playbackThreadLoop(); Loading @@ -123,7 +124,6 @@ class Dvr : public IDvr { // Thread handlers // Thread handlers pthread_t mDvrThread; pthread_t mDvrThread; pthread_t mBroadcastInputThread; // FMQ status local records // FMQ status local records PlaybackStatus mPlaybackStatus; PlaybackStatus mPlaybackStatus; Loading @@ -132,7 +132,6 @@ class Dvr : public IDvr { * If a specific filter's writing loop is still running * If a specific filter's writing loop is still running */ */ bool mDvrThreadRunning; bool mDvrThreadRunning; bool mBroadcastInputThreadRunning; bool mKeepFetchingDataFromFrontend; bool mKeepFetchingDataFromFrontend; /** /** * Lock to protect writes to the FMQs * Lock to protect writes to the FMQs Loading @@ -143,7 +142,6 @@ class Dvr : public IDvr { */ */ std::mutex mPlaybackStatusLock; std::mutex mPlaybackStatusLock; std::mutex mRecordStatusLock; std::mutex mRecordStatusLock; std::mutex mBroadcastInputThreadLock; std::mutex mDvrThreadLock; std::mutex mDvrThreadLock; const bool DEBUG_DVR = false; const bool DEBUG_DVR = false; Loading @@ -151,7 +149,6 @@ class Dvr : public IDvr { // Booleans to check if recording is running. // Booleans to check if recording is running. // Recording is ready when both of the following are set to true. // Recording is ready when both of the following are set to true. bool mIsRecordStarted = false; bool mIsRecordStarted = false; bool mIsRecordFilterAttached = false; }; }; } // namespace implementation } // namespace implementation Loading
tv/tuner/1.0/default/Filter.cpp +7 −7 Original line number Original line Diff line number Diff line Loading @@ -47,12 +47,18 @@ Filter::Filter(DemuxFilterType type, uint32_t filterId, uint32_t bufferSize, if (mType.subType.tsFilterType() == DemuxTsFilterType::PCR) { if (mType.subType.tsFilterType() == DemuxTsFilterType::PCR) { mIsPcrFilter = true; mIsPcrFilter = true; } } if (mType.subType.tsFilterType() == DemuxTsFilterType::RECORD) { mIsRecordFilter = true; } break; break; case DemuxFilterMainType::MMTP: case DemuxFilterMainType::MMTP: if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO || if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO || mType.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) { mType.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) { mIsMediaFilter = true; mIsMediaFilter = true; } } if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::RECORD) { mIsRecordFilter = true; } break; break; case DemuxFilterMainType::IP: case DemuxFilterMainType::IP: break; break; Loading Loading @@ -535,12 +541,6 @@ Result Filter::startMediaFilterHandler() { } } Result Filter::startRecordFilterHandler() { Result Filter::startRecordFilterHandler() { /*DemuxFilterTsRecordEvent tsRecordEvent; tsRecordEvent.pid.tPid(0); tsRecordEvent.indexMask.tsIndexMask(0x01); mFilterEvent.events.resize(1); mFilterEvent.events[0].tsRecord(tsRecordEvent); */ std::lock_guard<std::mutex> lock(mRecordFilterOutputLock); std::lock_guard<std::mutex> lock(mRecordFilterOutputLock); if (mRecordFilterOutput.empty()) { if (mRecordFilterOutput.empty()) { return Result::SUCCESS; return Result::SUCCESS; Loading @@ -567,7 +567,7 @@ Result Filter::startTemiFilterHandler() { bool Filter::writeSectionsAndCreateEvent(vector<uint8_t> data) { bool Filter::writeSectionsAndCreateEvent(vector<uint8_t> data) { // TODO check how many sections has been read // TODO check how many sections has been read ALOGD("[Filter] section hander"); ALOGD("[Filter] section handler"); std::lock_guard<std::mutex> lock(mFilterEventLock); std::lock_guard<std::mutex> lock(mFilterEventLock); if (!writeDataToFilterMQ(data)) { if (!writeDataToFilterMQ(data)) { return false; return false; Loading