V4L2Decoder: setup the output pixel format when resolution change

This CL setups the supported pixel format when resolution change.
Currently the supported pixel format is flexible 420 format.

Bug: 170199771
Test: android.media.cts.AdaptivePlaybackTest

Change-Id: Ic1b8f5c23fa5ff14c5dba026e0d927df092a6351
diff --git a/components/V4L2Decoder.cpp b/components/V4L2Decoder.cpp
index 9c6d42b..d694837 100644
--- a/components/V4L2Decoder.cpp
+++ b/components/V4L2Decoder.cpp
@@ -17,6 +17,7 @@
 #include <log/log.h>
 
 #include <v4l2_codec2/common/Common.h>
+#include <v4l2_codec2/common/Fourcc.h>
 
 namespace android {
 namespace {
@@ -25,6 +26,13 @@
 // Extra buffers for transmitting in the whole video pipeline.
 constexpr size_t kNumExtraOutputBuffers = 4;
 
+// Currently we only support flexible pixel 420 format YCBCR_420_888 in Android.
+// Here is the list of flexible 420 format.
+constexpr std::initializer_list<uint32_t> kSupportedOutputFourccs = {
+        Fourcc::YU12, Fourcc::YV12, Fourcc::YM12, Fourcc::YM21,
+        Fourcc::NV12, Fourcc::NV21, Fourcc::NM12, Fourcc::NM21,
+};
+
 uint32_t VideoCodecToV4L2PixFmt(VideoCodec codec) {
     switch (codec) {
     case VideoCodec::H264:
@@ -483,13 +491,22 @@
     ALOGV("%s()", __func__);
     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
 
-    std::optional<struct v4l2_format> format = getFormatInfo();
+    const std::optional<struct v4l2_format> format = getFormatInfo();
     std::optional<size_t> numOutputBuffers = getNumOutputBuffers();
     if (!format || !numOutputBuffers) {
         return false;
     }
 
-    mCodedSize.set(format->fmt.pix_mp.width, format->fmt.pix_mp.height);
+    const ui::Size codedSize(format->fmt.pix_mp.width, format->fmt.pix_mp.height);
+    if (!setupOutputFormat(codedSize)) {
+        return false;
+    }
+
+    const std::optional<struct v4l2_format> adjustedFormat = getFormatInfo();
+    if (!adjustedFormat) {
+        return false;
+    }
+    mCodedSize.set(adjustedFormat->fmt.pix_mp.width, adjustedFormat->fmt.pix_mp.height);
     mVisibleRect = getVisibleRect(mCodedSize);
 
     ALOGI("Need %zu output buffers. coded size: %s, visible rect: %s", *numOutputBuffers,
@@ -516,7 +533,7 @@
     // Release the previous VideoFramePool before getting a new one to guarantee only one pool
     // exists at the same time.
     mVideoFramePool.reset();
-    // Always use fexible pixel 420 format YCBCR_420_888 in Android.
+    // Always use flexible pixel 420 format YCBCR_420_888 in Android.
     mVideoFramePool = mGetPoolCb.Run(mCodedSize, HalPixelFormat::YCBCR_420_888, *numOutputBuffers);
     if (!mVideoFramePool) {
         ALOGE("Failed to get block pool with size: %s", toString(mCodedSize).c_str());
@@ -527,6 +544,24 @@
     return true;
 }
 
+bool V4L2Decoder::setupOutputFormat(const ui::Size& size) {
+    for (const uint32_t& pixfmt :
+         mDevice->enumerateSupportedPixelformats(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
+        if (std::find(kSupportedOutputFourccs.begin(), kSupportedOutputFourccs.end(), pixfmt) ==
+            kSupportedOutputFourccs.end()) {
+            ALOGD("Pixel format %s is not supported, skipping...", fourccToString(pixfmt).c_str());
+            continue;
+        }
+
+        if (mOutputQueue->setFormat(pixfmt, size, 0) != std::nullopt) {
+            return true;
+        }
+    }
+
+    ALOGE("Failed to find supported pixel format");
+    return false;
+}
+
 void V4L2Decoder::tryFetchVideoFrame() {
     ALOGV("%s()", __func__);
     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
diff --git a/components/include/v4l2_codec2/components/V4L2Decoder.h b/components/include/v4l2_codec2/components/V4L2Decoder.h
index de985a3..b65bd49 100644
--- a/components/include/v4l2_codec2/components/V4L2Decoder.h
+++ b/components/include/v4l2_codec2/components/V4L2Decoder.h
@@ -63,6 +63,7 @@
     void serviceDeviceTask(bool event);
     bool dequeueResolutionChangeEvent();
     bool changeResolution();
+    bool setupOutputFormat(const ui::Size& size);
 
     void tryFetchVideoFrame();
     void onVideoFrameReady(std::optional<VideoFramePool::FrameWithBlockId> frameWithBlockId);