components: Implement Codec2.0 V4L2 decode component

This CL implements V4L2DecodeComponent, a decode C2Component via V4L2
API. It mainly contains these parts:

- VideoDecoder:
  An interface for video decoding, similar to media::VideoDecoder at
Chromium project.
- V4L2Decoder:
  An implementation of VideoDecoder via V4L2 stateful API. We wrap all
  V4L2-related logic in this class

- VideoFrame
  The data structure to represent the output buffer of VideoDecoder.
  It encapsulates a C2GraphicBlock and only exposes the essential
  information of physical buffers.
- VideoFramePool:
  The buffer pool used by VideoDecoder. It encapsulates C2BlockPool
  and provides asynchronous method to fetch buffers.

- V4L2DecodeComponent, V4L2DecodeInterface:
  The C2Component implementation that delegates the decode request to
  V4L2Decoder.
- V4L2ComponentFactory:
  The C2ComponentFactory that creates V4L2DecodeComponent.

Bug: 152714603
Test: mmm external/v4l2_codec2/
Test: Run e2e test and make sure the V4L2DecodeComponent is running

Change-Id: I23e9b3553b62dd6c83d943d7787297305372c37d
diff --git a/components/VideoFramePool.cpp b/components/VideoFramePool.cpp
new file mode 100644
index 0000000..c2f68fc
--- /dev/null
+++ b/components/VideoFramePool.cpp
@@ -0,0 +1,105 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "VideoFramePool"
+
+#include <v4l2_codec2/components/VideoFramePool.h>
+
+#include <stdint.h>
+#include <memory>
+
+#include <android/hardware/graphics/common/1.0/types.h>
+#include <base/bind.h>
+#include <base/time/time.h>
+#include <log/log.h>
+
+#include <v4l2_codec2/components/VideoTypes.h>
+
+using android::hardware::graphics::common::V1_0::BufferUsage;
+
+namespace android {
+namespace {
+constexpr size_t kAllocateBufferMaxRetries = 32;
+constexpr size_t kFetchRetryDelayUs = 500;
+}  // namespace
+
+VideoFramePool::VideoFramePool(std::shared_ptr<C2BlockPool> blockPool, const media::Size& size,
+                               HalPixelFormat pixelFormat, bool isSecure,
+                               scoped_refptr<::base::SequencedTaskRunner> taskRunner)
+      : mBlockPool(std::move(blockPool)),
+        mSize(size),
+        mPixelFormat(pixelFormat),
+        mMemoryUsage(isSecure ? C2MemoryUsage::READ_PROTECTED : C2MemoryUsage::CPU_READ,
+                     static_cast<uint64_t>(BufferUsage::VIDEO_DECODER)),
+        mTaskRunner(std::move(taskRunner)) {
+    ALOGV("%s()", __func__);
+    ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
+    DCHECK(mBlockPool);
+    DCHECK(mTaskRunner);
+
+    mWeakThis = mWeakThisFactory.GetWeakPtr();
+}
+
+VideoFramePool::~VideoFramePool() {
+    ALOGV("%s()", __func__);
+    ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
+
+    mWeakThisFactory.InvalidateWeakPtrs();
+}
+
+void VideoFramePool::getVideoFrame(GetVideoFrameCB cb) {
+    ALOGV("%s()", __func__);
+    ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
+
+    bool isRunning = !mCbQueue.empty();
+    mCbQueue.push(std::move(cb));
+    if (!isRunning) tryFetchGraphicBlock();
+}
+
+bool VideoFramePool::hasPendingRequests() const {
+    return !mCbQueue.empty();
+}
+
+void VideoFramePool::tryFetchGraphicBlock() {
+    ALOGV("%s()", __func__);
+    ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
+
+    if (mCbQueue.empty()) return;
+
+    std::shared_ptr<C2GraphicBlock> block;
+    auto err = mBlockPool->fetchGraphicBlock(mSize.width(), mSize.height(),
+                                             static_cast<uint32_t>(mPixelFormat), mMemoryUsage,
+                                             &block);
+
+    if ((err == C2_TIMED_OUT || err == C2_BLOCKING) && mNumRetries++ < kAllocateBufferMaxRetries) {
+        ALOGD("fetchGraphicBlock() timeout. retry %zu times", mNumRetries);
+        mTaskRunner->PostDelayedTask(
+                FROM_HERE, ::base::BindOnce(&VideoFramePool::tryFetchGraphicBlock, mWeakThis),
+                ::base::TimeDelta::FromMicroseconds(kFetchRetryDelayUs));
+    } else if (err != C2_OK) {
+        ALOGE("Failed to fetch block, err=%d, retry %zu times", err, mNumRetries);
+        sendVideoFrame(nullptr);
+    } else {
+        mNumRetries = 0;
+        sendVideoFrame(VideoFrame::Create(std::move(block)));
+
+        if (!mCbQueue.empty()) {
+            mTaskRunner->PostTask(
+                    FROM_HERE, ::base::BindOnce(&VideoFramePool::tryFetchGraphicBlock, mWeakThis));
+        }
+    }
+}
+
+void VideoFramePool::sendVideoFrame(std::unique_ptr<VideoFrame> frame) {
+    ALOGV("%s()", __func__);
+    ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
+    ALOG_ASSERT(!mCbQueue.empty());
+
+    auto cb = std::move(mCbQueue.front());
+    mCbQueue.pop();
+    std::move(cb).Run(std::move(frame));
+}
+
+}  // namespace android