|
|
|
@ -36,6 +36,7 @@
|
|
|
|
|
#include <media/stagefright/MediaErrors.h>
|
|
|
|
|
#include <ui/Fence.h>
|
|
|
|
|
#include <ui/GraphicBuffer.h>
|
|
|
|
|
#include <utils/Thread.h>
|
|
|
|
|
|
|
|
|
|
#include "C2OMXNode.h"
|
|
|
|
|
|
|
|
|
@ -50,16 +51,126 @@ public:
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
class C2OMXNode::QueueThread : public Thread {
|
|
|
|
|
public:
|
|
|
|
|
QueueThread() : Thread(false) {}
|
|
|
|
|
~QueueThread() override = default;
|
|
|
|
|
void queue(
|
|
|
|
|
const std::shared_ptr<Codec2Client::Component> &comp,
|
|
|
|
|
int fenceFd,
|
|
|
|
|
std::unique_ptr<C2Work> &&work,
|
|
|
|
|
android::base::unique_fd &&fd0,
|
|
|
|
|
android::base::unique_fd &&fd1) {
|
|
|
|
|
Mutexed<Jobs>::Locked jobs(mJobs);
|
|
|
|
|
auto it = jobs->queues.try_emplace(comp, comp, systemTime()).first;
|
|
|
|
|
it->second.workList.emplace_back(
|
|
|
|
|
std::move(work), fenceFd, std::move(fd0), std::move(fd1));
|
|
|
|
|
jobs->cond.broadcast();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
bool threadLoop() override {
|
|
|
|
|
constexpr nsecs_t kIntervalNs = nsecs_t(10) * 1000 * 1000; // 10ms
|
|
|
|
|
constexpr nsecs_t kWaitNs = kIntervalNs * 2;
|
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
|
|
|
Mutexed<Jobs>::Locked jobs(mJobs);
|
|
|
|
|
nsecs_t nowNs = systemTime();
|
|
|
|
|
bool queued = false;
|
|
|
|
|
for (auto it = jobs->queues.begin(); it != jobs->queues.end(); ++it) {
|
|
|
|
|
Queue &queue = it->second;
|
|
|
|
|
if (queue.workList.empty()
|
|
|
|
|
|| nowNs - queue.lastQueuedTimestampNs < kIntervalNs) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
std::shared_ptr<Codec2Client::Component> comp = queue.component.lock();
|
|
|
|
|
if (!comp) {
|
|
|
|
|
it = jobs->queues.erase(it);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
std::list<std::unique_ptr<C2Work>> items;
|
|
|
|
|
std::vector<int> fenceFds;
|
|
|
|
|
std::vector<android::base::unique_fd> uniqueFds;
|
|
|
|
|
while (!queue.workList.empty()) {
|
|
|
|
|
items.push_back(std::move(queue.workList.front().work));
|
|
|
|
|
fenceFds.push_back(queue.workList.front().fenceFd);
|
|
|
|
|
uniqueFds.push_back(std::move(queue.workList.front().fd0));
|
|
|
|
|
uniqueFds.push_back(std::move(queue.workList.front().fd1));
|
|
|
|
|
queue.workList.pop_front();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
jobs.unlock();
|
|
|
|
|
for (int fenceFd : fenceFds) {
|
|
|
|
|
sp<Fence> fence(new Fence(fenceFd));
|
|
|
|
|
fence->waitForever(LOG_TAG);
|
|
|
|
|
}
|
|
|
|
|
comp->queue(&items);
|
|
|
|
|
for (android::base::unique_fd &ufd : uniqueFds) {
|
|
|
|
|
(void)ufd.release();
|
|
|
|
|
}
|
|
|
|
|
jobs.lock();
|
|
|
|
|
|
|
|
|
|
queued = true;
|
|
|
|
|
}
|
|
|
|
|
if (queued) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (i == 0) {
|
|
|
|
|
jobs.waitForConditionRelative(jobs->cond, kWaitNs);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
struct WorkFence {
|
|
|
|
|
WorkFence(std::unique_ptr<C2Work> &&w, int fd) : work(std::move(w)), fenceFd(fd) {}
|
|
|
|
|
|
|
|
|
|
WorkFence(
|
|
|
|
|
std::unique_ptr<C2Work> &&w,
|
|
|
|
|
int fd,
|
|
|
|
|
android::base::unique_fd &&uniqueFd0,
|
|
|
|
|
android::base::unique_fd &&uniqueFd1)
|
|
|
|
|
: work(std::move(w)),
|
|
|
|
|
fenceFd(fd),
|
|
|
|
|
fd0(std::move(uniqueFd0)),
|
|
|
|
|
fd1(std::move(uniqueFd1)) {}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<C2Work> work;
|
|
|
|
|
int fenceFd;
|
|
|
|
|
android::base::unique_fd fd0;
|
|
|
|
|
android::base::unique_fd fd1;
|
|
|
|
|
};
|
|
|
|
|
struct Queue {
|
|
|
|
|
Queue(const std::shared_ptr<Codec2Client::Component> &comp, nsecs_t timestamp)
|
|
|
|
|
: component(comp), lastQueuedTimestampNs(timestamp) {}
|
|
|
|
|
Queue(const Queue &) = delete;
|
|
|
|
|
Queue &operator =(const Queue &) = delete;
|
|
|
|
|
|
|
|
|
|
std::weak_ptr<Codec2Client::Component> component;
|
|
|
|
|
std::list<WorkFence> workList;
|
|
|
|
|
nsecs_t lastQueuedTimestampNs;
|
|
|
|
|
};
|
|
|
|
|
struct Jobs {
|
|
|
|
|
std::map<std::weak_ptr<Codec2Client::Component>,
|
|
|
|
|
Queue,
|
|
|
|
|
std::owner_less<std::weak_ptr<Codec2Client::Component>>> queues;
|
|
|
|
|
Condition cond;
|
|
|
|
|
};
|
|
|
|
|
Mutexed<Jobs> mJobs;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
C2OMXNode::C2OMXNode(const std::shared_ptr<Codec2Client::Component> &comp)
|
|
|
|
|
: mComp(comp), mFrameIndex(0), mWidth(0), mHeight(0), mUsage(0),
|
|
|
|
|
mAdjustTimestampGapUs(0), mFirstInputFrame(true) {
|
|
|
|
|
mAdjustTimestampGapUs(0), mFirstInputFrame(true),
|
|
|
|
|
mQueueThread(new QueueThread) {
|
|
|
|
|
android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS);
|
|
|
|
|
mQueueThread->run("C2OMXNode", PRIORITY_AUDIO);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status_t C2OMXNode::freeNode() {
|
|
|
|
|
mComp.reset();
|
|
|
|
|
android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
|
|
|
|
|
return OK;
|
|
|
|
|
return mQueueThread->requestExitAndWait();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status_t C2OMXNode::sendCommand(OMX_COMMANDTYPE cmd, OMX_S32 param) {
|
|
|
|
@ -216,11 +327,6 @@ status_t C2OMXNode::fillBuffer(
|
|
|
|
|
status_t C2OMXNode::emptyBuffer(
|
|
|
|
|
buffer_id buffer, const OMXBuffer &omxBuf,
|
|
|
|
|
OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
|
|
|
|
|
// TODO: better fence handling
|
|
|
|
|
if (fenceFd >= 0) {
|
|
|
|
|
sp<Fence> fence = new Fence(fenceFd);
|
|
|
|
|
fence->waitForever(LOG_TAG);
|
|
|
|
|
}
|
|
|
|
|
std::shared_ptr<Codec2Client::Component> comp = mComp.lock();
|
|
|
|
|
if (!comp) {
|
|
|
|
|
return NO_INIT;
|
|
|
|
@ -299,22 +405,8 @@ status_t C2OMXNode::emptyBuffer(
|
|
|
|
|
}
|
|
|
|
|
work->worklets.clear();
|
|
|
|
|
work->worklets.emplace_back(new C2Worklet);
|
|
|
|
|
std::list<std::unique_ptr<C2Work>> items;
|
|
|
|
|
uint64_t index = work->input.ordinal.frameIndex.peeku();
|
|
|
|
|
items.push_back(std::move(work));
|
|
|
|
|
|
|
|
|
|
c2_status_t err = comp->queue(&items);
|
|
|
|
|
if (err != C2_OK) {
|
|
|
|
|
(void)fd0.release();
|
|
|
|
|
(void)fd1.release();
|
|
|
|
|
return UNKNOWN_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mBufferIdsInUse.lock()->emplace(index, buffer);
|
|
|
|
|
|
|
|
|
|
// release ownership of the fds
|
|
|
|
|
(void)fd0.release();
|
|
|
|
|
(void)fd1.release();
|
|
|
|
|
mBufferIdsInUse.lock()->emplace(work->input.ordinal.frameIndex.peeku(), buffer);
|
|
|
|
|
mQueueThread->queue(comp, fenceFd, std::move(work), std::move(fd0), std::move(fd1));
|
|
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
|
}
|
|
|
|
|