From 0561794180fa7064a098d06761e1b99391521d93 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bart=C5=82omiej=20Grzesik?= <bgrzesik@google.com>
Date: Fri, 17 Feb 2023 12:13:45 +0000
Subject: [PATCH] V4L2Device: Refactor querying capabilities

This CL refactors querying capabilities. It eliminates usage of single
instance of V4L2Device for multiple devices by exporting querying
methods to static.

Bug: 251420501
Test: adb shell dumpsys media.player
Test: adb logcat
Change-Id: I0d4ea16d2818a9c3cbde3ae31a99419a457cb1c1
(cherry picked from commit e4b9917003de8c330c91a1cd0a1d55a7e9828e7d)
---
 common/V4L2Device.cpp                         | 265 +++++++++---------
 .../include/v4l2_codec2/common/V4L2Device.h   |  76 +++--
 components/V4L2DecodeInterface.cpp            |  37 +--
 components/V4L2Decoder.cpp                    |  20 +-
 components/V4L2EncodeInterface.cpp            |  10 +-
 components/V4L2Encoder.cpp                    |   6 +-
 .../v4l2_codec2/components/V4L2Decoder.h      |   2 -
 7 files changed, 184 insertions(+), 232 deletions(-)

diff --git a/common/V4L2Device.cpp b/common/V4L2Device.cpp
index a58ee56..09b809a 100644
--- a/common/V4L2Device.cpp
+++ b/common/V4L2Device.cpp
@@ -1256,7 +1256,7 @@ std::vector<uint32_t> V4L2Device::preferredInputFormat(Type type) {
 }
 
 // static
-uint32_t V4L2Device::C2ProfileToV4L2PixFmt(C2Config::profile_t profile, bool sliceBased) {
+uint32_t V4L2Device::c2ProfileToV4L2PixFmt(C2Config::profile_t profile, bool sliceBased) {
     if (profile >= C2Config::PROFILE_AVC_BASELINE &&
         profile <= C2Config::PROFILE_AVC_ENHANCED_MULTIVIEW_DEPTH_HIGH) {
         if (sliceBased) {
@@ -1491,7 +1491,21 @@ C2Config::profile_t V4L2Device::v4L2ProfileToC2Profile(VideoCodec codec, uint32_
     return C2Config::PROFILE_UNUSED;
 }
 
-std::vector<C2Config::level_t> V4L2Device::v4L2PixFmtToC2Levels(uint32_t pixFmt) {
+// static
+uint32_t V4L2Device::videoCodecToPixFmt(VideoCodec codec) {
+    switch (codec) {
+    case VideoCodec::H264:
+        return V4L2_PIX_FMT_H264;
+    case VideoCodec::VP8:
+        return V4L2_PIX_FMT_VP8;
+    case VideoCodec::VP9:
+        return V4L2_PIX_FMT_VP9;
+    case VideoCodec::HEVC:
+        return V4L2_PIX_FMT_HEVC;
+    }
+}
+
+std::vector<C2Config::level_t> V4L2Device::queryC2Levels(uint32_t pixFmt) {
     auto getSupportedLevels = [this](VideoCodec codec, std::vector<C2Config::level_t>* levels) {
         uint32_t queryId = 0;
         switch (codec) {
@@ -1582,8 +1596,7 @@ std::vector<C2Config::level_t> V4L2Device::v4L2PixFmtToC2Levels(uint32_t pixFmt)
     return levels;
 }
 
-std::vector<C2Config::profile_t> V4L2Device::v4L2PixFmtToC2Profiles(uint32_t pixFmt,
-                                                                    bool /*isEncoder*/) {
+std::vector<C2Config::profile_t> V4L2Device::queryC2Profiles(uint32_t pixFmt) {
     auto getSupportedProfiles = [this](VideoCodec codec,
                                        std::vector<C2Config::profile_t>* profiles) {
         uint32_t queryId = 0;
@@ -1744,7 +1757,7 @@ int32_t V4L2Device::h264LevelIdcToV4L2H264Level(uint8_t levelIdc) {
 }
 
 // static
-v4l2_mpeg_video_bitrate_mode V4L2Device::C2BitrateModeToV4L2BitrateMode(
+v4l2_mpeg_video_bitrate_mode V4L2Device::c2BitrateModeToV4L2BitrateMode(
         C2Config::bitrate_mode_t bitrateMode) {
     switch (bitrateMode) {
     case C2Config::bitrate_mode_t::BITRATE_CONST_SKIP_ALLOWED:
@@ -2102,44 +2115,48 @@ std::vector<uint32_t> V4L2Device::enumerateSupportedPixelformats(v4l2_buf_type b
     return pixelFormats;
 }
 
+// static
 std::vector<C2Config::level_t> V4L2Device::getSupportedDecodeLevels(VideoCodec videoCodecType) {
     std::vector<C2Config::level_t> supportedLevels;
     Type type = Type::kDecoder;
-    const auto& devices = getDevicesForType(type);
-    for (const auto& device : devices) {
-        if (!openDevicePath(device.first, type)) {
-            ALOGV("Failed opening %s", device.first.c_str());
+
+    for (const auto& info : getDeviceInfosForType(type)) {
+        scoped_refptr<V4L2Device> device = V4L2Device::create();
+        if (!device->openDevicePath(info.first, type)) {
+            ALOGV("Failed opening %s", info.first.c_str());
             continue;
         }
 
-        const auto& levels = enumerateSupportedDecodeLevels(videoCodecType);
+        const auto& levels = device->enumerateSupportedDecodeLevels(videoCodecType);
         supportedLevels.insert(supportedLevels.end(), levels.begin(), levels.end());
-        closeDevice();
+        device->closeDevice();
     }
 
     return supportedLevels;
 }
 
-V4L2Device::SupportedDecodeProfiles V4L2Device::getSupportedDecodeProfiles(
-        const std::vector<uint32_t>& pixelFormats) {
-    SupportedDecodeProfiles supportedProfiles;
-
-    Type type = Type::kDecoder;
-    const auto& devices = getDevicesForType(type);
-    for (const auto& device : devices) {
-        if (!openDevicePath(device.first, type)) {
-            ALOGV("Failed opening %s", device.first.c_str());
+// static
+V4L2Device::SupportedProfiles V4L2Device::getSupportedProfiles(
+        V4L2Device::Type type, const std::vector<uint32_t>& pixelFormats) {
+    SupportedProfiles supportedProfiles;
+
+    for (const auto& info : getDeviceInfosForType(type)) {
+        scoped_refptr<V4L2Device> device = V4L2Device::create();
+        if (!device->openDevicePath(info.first, type)) {
+            ALOGV("Failed opening %s", info.first.c_str());
             continue;
         }
 
-        const auto& profiles = enumerateSupportedDecodeProfiles(pixelFormats);
+        const auto& profiles = device->enumerateSupportedProfiles(type, pixelFormats);
         supportedProfiles.insert(supportedProfiles.end(), profiles.begin(), profiles.end());
-        closeDevice();
+
+        device->closeDevice();
     }
 
     return supportedProfiles;
 }
 
+// static
 C2Config::profile_t V4L2Device::getDefaultProfile(VideoCodec codec) {
     uint32_t queryId = 0;
 
@@ -2160,42 +2177,36 @@ C2Config::profile_t V4L2Device::getDefaultProfile(VideoCodec codec) {
         return C2Config::PROFILE_UNUSED;
     }
 
-    // Call to query control which will return structure including
-    // index of default profile
-    v4l2_queryctrl queryCtrl = {};
-    queryCtrl.id = queryId;
-    if (ioctl(VIDIOC_QUERYCTRL, &queryCtrl) != 0) {
-        return C2Config::PROFILE_UNUSED;
-    }
-
-    v4l2_querymenu queryMenu = {};
-    queryMenu.id = queryCtrl.id;
-    queryMenu.index = queryCtrl.default_value;
-    if (ioctl(VIDIOC_QUERYMENU, &queryMenu) == 0) {
-        return v4L2ProfileToC2Profile(codec, queryMenu.index);
-    }
-    return C2Config::PROFILE_UNUSED;
-}
-
-V4L2Device::SupportedEncodeProfiles V4L2Device::getSupportedEncodeProfiles() {
-    SupportedEncodeProfiles supportedProfiles;
+    for (const auto& info : getDeviceInfosForType(Type::kDecoder)) {
+        scoped_refptr<V4L2Device> device = V4L2Device::create();
+        if (!device->openDevicePath(info.first, Type::kDecoder)) {
+            ALOGV("Failed opening %s", info.first.c_str());
+            continue;
+        }
 
-    Type type = Type::kEncoder;
-    const auto& devices = getDevicesForType(type);
-    for (const auto& device : devices) {
-        if (!openDevicePath(device.first, type)) {
-            ALOGV("Failed opening %s", device.first.c_str());
+        // Call to query control which will return structure including
+        // index of default profile
+        v4l2_queryctrl queryCtrl = {};
+        queryCtrl.id = queryId;
+        if (device->ioctl(VIDIOC_QUERYCTRL, &queryCtrl) != 0) {
+            device->closeDevice();
             continue;
         }
 
-        const auto& profiles = enumerateSupportedEncodeProfiles();
-        supportedProfiles.insert(supportedProfiles.end(), profiles.begin(), profiles.end());
-        closeDevice();
-    }
+        v4l2_querymenu queryMenu = {};
+        queryMenu.id = queryCtrl.id;
+        queryMenu.index = queryCtrl.default_value;
+        if (device->ioctl(VIDIOC_QUERYMENU, &queryMenu) == 0) {
+            device->closeDevice();
+            return v4L2ProfileToC2Profile(codec, queryMenu.index);
+        }
 
-    return supportedProfiles;
+        device->closeDevice();
+    }
+    return C2Config::PROFILE_UNUSED;
 }
 
+// static
 C2Config::level_t V4L2Device::getDefaultLevel(VideoCodec codec) {
     uint32_t queryId = 0;
 
@@ -2215,17 +2226,29 @@ C2Config::level_t V4L2Device::getDefaultLevel(VideoCodec codec) {
         return C2Config::LEVEL_UNUSED;
     }
 
-    v4l2_queryctrl queryCtrl = {};
-    queryCtrl.id = queryId;
-    if (ioctl(VIDIOC_QUERYCTRL, &queryCtrl) != 0) {  // gets index of default profile
-        return C2Config::LEVEL_UNUSED;
-    }
+    for (const auto& info : getDeviceInfosForType(Type::kDecoder)) {
+        scoped_refptr<V4L2Device> device = V4L2Device::create();
+        if (!device->openDevicePath(info.first, Type::kDecoder)) {
+            ALOGV("Failed opening %s", info.first.c_str());
+            continue;
+        }
+
+        v4l2_queryctrl queryCtrl = {};
+        queryCtrl.id = queryId;
+        if (device->ioctl(VIDIOC_QUERYCTRL, &queryCtrl) != 0) {  // gets index of default profile
+            device->closeDevice();
+            continue;
+        }
 
-    v4l2_querymenu queryMenu = {};
-    queryMenu.id = queryCtrl.id;
-    queryMenu.index = queryCtrl.default_value;
-    if (ioctl(VIDIOC_QUERYMENU, &queryMenu) == 0) {
-        return v4L2LevelToC2Level(codec, queryMenu.index);
+        v4l2_querymenu queryMenu = {};
+        queryMenu.id = queryCtrl.id;
+        queryMenu.index = queryCtrl.default_value;
+        if (device->ioctl(VIDIOC_QUERYMENU, &queryMenu) == 0) {
+            device->closeDevice();
+            return v4L2LevelToC2Level(codec, queryMenu.index);
+        }
+
+        device->closeDevice();
     }
 
     return C2Config::LEVEL_UNUSED;
@@ -2240,7 +2263,7 @@ std::vector<C2Config::level_t> V4L2Device::enumerateSupportedDecodeLevels(
 
     for (uint32_t pixelFormat : supportedPixelformats) {
         if (isValidPixFmtForCodec(videoCodecType, pixelFormat)) {
-            std::vector<C2Config::level_t> levels = v4L2PixFmtToC2Levels(pixelFormat);
+            std::vector<C2Config::level_t> levels = queryC2Levels(pixelFormat);
             supportedLevels.insert(supportedLevels.end(), levels.begin(), levels.end());
         }
     }
@@ -2248,55 +2271,42 @@ std::vector<C2Config::level_t> V4L2Device::enumerateSupportedDecodeLevels(
     return supportedLevels;
 }
 
-V4L2Device::SupportedDecodeProfiles V4L2Device::enumerateSupportedDecodeProfiles(
-        const std::vector<uint32_t>& pixelFormats) {
-    SupportedDecodeProfiles profiles;
+V4L2Device::SupportedProfiles V4L2Device::enumerateSupportedProfiles(
+        V4L2Device::Type type, const std::vector<uint32_t>& pixelFormats) {
+    SupportedProfiles profiles;
 
-    const auto& supportedPixelformats =
-            enumerateSupportedPixelformats(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+    v4l2_buf_type bufType;
+    switch (type) {
+    case Type::kDecoder:
+        bufType = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+        break;
+    case Type::kEncoder:
+        bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+        break;
+    }
+
+    const auto& supportedPixelformats = enumerateSupportedPixelformats(bufType);
 
     for (uint32_t pixelFormat : supportedPixelformats) {
         if (std::find(pixelFormats.begin(), pixelFormats.end(), pixelFormat) == pixelFormats.end())
             continue;
 
-        SupportedDecodeProfile profile;
-        getSupportedResolution(pixelFormat, &profile.min_resolution, &profile.max_resolution);
-
-        const auto videoCodecProfiles = v4L2PixFmtToC2Profiles(pixelFormat, false);
-
-        for (const auto& videoCodecProfile : videoCodecProfiles) {
-            profile.profile = videoCodecProfile;
-            profiles.push_back(profile);
-
-            ALOGV("Found decoder profile %s, resolutions: %s %s", profileToString(profile.profile),
-                  toString(profile.min_resolution).c_str(),
-                  toString(profile.max_resolution).c_str());
+        SupportedProfile profile;
+        if (type == Type::kEncoder) {
+            profile.max_framerate_numerator = 30;
+            profile.max_framerate_denominator = 1;
         }
-    }
 
-    return profiles;
-}
-
-V4L2Device::SupportedEncodeProfiles V4L2Device::enumerateSupportedEncodeProfiles() {
-    SupportedEncodeProfiles profiles;
-
-    const auto& supportedPixelformats =
-            enumerateSupportedPixelformats(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
-
-    for (const auto& pixelformat : supportedPixelformats) {
-        SupportedEncodeProfile profile;
-        profile.max_framerate_numerator = 30;
-        profile.max_framerate_denominator = 1;
-        ui::Size minResolution;
-        getSupportedResolution(pixelformat, &minResolution, &profile.max_resolution);
+        getSupportedResolution(pixelFormat, &profile.min_resolution, &profile.max_resolution);
 
-        const auto videoCodecProfiles = v4L2PixFmtToC2Profiles(pixelformat, true);
+        const auto videoCodecProfiles = queryC2Profiles(pixelFormat);
 
         for (const auto& videoCodecProfile : videoCodecProfiles) {
             profile.profile = videoCodecProfile;
             profiles.push_back(profile);
 
-            ALOGV("Found encoder profile %s, max resolution: %s", profileToString(profile.profile),
+            ALOGV("Found profile %s, resolutions: %s %s", profileToString(profile.profile),
+                  toString(profile.min_resolution).c_str(),
                   toString(profile.max_resolution).c_str());
         }
     }
@@ -2396,70 +2406,59 @@ void V4L2Device::closeDevice() {
     mDeviceFd.reset();
 }
 
-void V4L2Device::enumerateDevicesForType(Type type) {
+// static
+const V4L2Device::DeviceInfos& V4L2Device::getDeviceInfosForType(V4L2Device::Type type) {
     // video input/output devices are registered as /dev/videoX in V4L2.
-    static const std::string kVideoDevicePattern = "/dev/video";
+    static constexpr const char* kVideoDevicePattern = "/dev/video";
+    static const DeviceInfos sNoDevices = {};
+    static std::mutex sDeviceInfosCacheLock;
+    static std::map<Type, DeviceInfos> sDeviceInfosCache;
+
+    std::lock_guard lock(sDeviceInfosCacheLock);
+    if (sDeviceInfosCache.find(type) != sDeviceInfosCache.end()) {
+        return sDeviceInfosCache[type];
+    }
 
-    std::string devicePattern;
     v4l2_buf_type bufType;
     switch (type) {
     case Type::kDecoder:
-        devicePattern = kVideoDevicePattern;
         bufType = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
         break;
     case Type::kEncoder:
-        devicePattern = kVideoDevicePattern;
         bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
         break;
     default:
         ALOGE("Only decoder and encoder types are supported!!");
-        return;
+        return sNoDevices;
     }
 
-    std::vector<std::string> candidatePaths;
-
-    // TODO(posciak): Remove this legacy unnumbered device once all platforms are updated to use
-    // numbered devices.
-    candidatePaths.push_back(devicePattern);
+    DeviceInfos deviceInfos;
+    for (int i = 0; i < 10; ++i) {
+        std::string path = base::StringPrintf("%s%d", kVideoDevicePattern, i);
 
-    // We are sandboxed, so we can't query directory contents to check which devices are actually
-    // available. Try to open the first 16; if not present, we will just fail to open immediately.
-    for (int i = 0; i < 16; ++i) {
-        candidatePaths.push_back(base::StringPrintf("%s%d", devicePattern.c_str(), i));
-    }
-
-    Devices devices;
-    for (const auto& path : candidatePaths) {
-        if (!openDevicePath(path, type)) {
+        scoped_refptr<V4L2Device> device = V4L2Device::create();
+        if (!device->openDevicePath(path, type)) {
             continue;
         }
 
-        const auto& supportedPixelformats = enumerateSupportedPixelformats(bufType);
+        const auto& supportedPixelformats = device->enumerateSupportedPixelformats(bufType);
         if (!supportedPixelformats.empty()) {
             ALOGV("Found device: %s", path.c_str());
-            devices.push_back(std::make_pair(path, supportedPixelformats));
+            deviceInfos.push_back(std::make_pair(path, supportedPixelformats));
         }
 
-        closeDevice();
+        device->closeDevice();
     }
 
-    ALOG_ASSERT(mDevicesByType.count(type) == 0u);
-    mDevicesByType[type] = devices;
-}
+    sDeviceInfosCache[type] = deviceInfos;
 
-const V4L2Device::Devices& V4L2Device::getDevicesForType(Type type) {
-    if (mDevicesByType.count(type) == 0) enumerateDevicesForType(type);
-
-    ALOG_ASSERT(mDevicesByType.count(type) != 0u);
-    return mDevicesByType[type];
+    return sDeviceInfosCache[type];
 }
 
 std::string V4L2Device::getDevicePathFor(Type type, uint32_t pixFmt) {
-    const Devices& devices = getDevicesForType(type);
-
-    for (const auto& device : devices) {
-        if (std::find(device.second.begin(), device.second.end(), pixFmt) != device.second.end())
-            return device.first;
+    for (const auto& info : getDeviceInfosForType(type)) {
+        if (std::find(info.second.begin(), info.second.end(), pixFmt) != info.second.end())
+            return info.first;
     }
 
     return std::string();
diff --git a/common/include/v4l2_codec2/common/V4L2Device.h b/common/include/v4l2_codec2/common/V4L2Device.h
index 534b063..7e7b941 100644
--- a/common/include/v4l2_codec2/common/V4L2Device.h
+++ b/common/include/v4l2_codec2/common/V4L2Device.h
@@ -342,39 +342,29 @@ private:
 class V4L2Device : public base::RefCountedThreadSafe<V4L2Device> {
 public:
     // Specification of an encoding profile supported by an encoder.
-    struct SupportedEncodeProfile {
+    struct SupportedProfile {
         C2Config::profile_t profile = C2Config::PROFILE_UNUSED;
         ui::Size min_resolution;
         ui::Size max_resolution;
         uint32_t max_framerate_numerator = 0;
         uint32_t max_framerate_denominator = 0;
-    };
-    using SupportedEncodeProfiles = std::vector<SupportedEncodeProfile>;
-
-    // Specification of a decoding profile supported by an decoder.
-    // |max_resolution| and |min_resolution| are inclusive.
-    struct SupportedDecodeProfile {
-        C2Config::profile_t profile = C2Config::PROFILE_UNUSED;
-        ui::Size max_resolution;
-        ui::Size min_resolution;
         bool encrypted_only = false;
     };
-    using SupportedDecodeProfiles = std::vector<SupportedDecodeProfile>;
+    using SupportedProfiles = std::vector<SupportedProfile>;
 
     // Utility format conversion functions
     // If there is no corresponding single- or multi-planar format, returns 0.
-    static uint32_t C2ProfileToV4L2PixFmt(C2Config::profile_t profile, bool sliceBased);
+    static uint32_t c2ProfileToV4L2PixFmt(C2Config::profile_t profile, bool sliceBased);
     static C2Config::level_t v4L2LevelToC2Level(VideoCodec codec, uint32_t level);
     static C2Config::profile_t v4L2ProfileToC2Profile(VideoCodec codec, uint32_t profile);
-    std::vector<C2Config::level_t> v4L2PixFmtToC2Levels(uint32_t pixFmt);
-    std::vector<C2Config::profile_t> v4L2PixFmtToC2Profiles(uint32_t pixFmt, bool isEncoder);
+    static uint32_t videoCodecToPixFmt(VideoCodec codec);
     // Calculates the largest plane's allocation size requested by a V4L2 device.
     static ui::Size allocatedSizeFromV4L2Format(const struct v4l2_format& format);
 
     // Convert required H264 profile and level to V4L2 enums.
     static int32_t c2ProfileToV4L2H264Profile(C2Config::profile_t profile);
     static int32_t h264LevelIdcToV4L2H264Level(uint8_t levelIdc);
-    static v4l2_mpeg_video_bitrate_mode C2BitrateModeToV4L2BitrateMode(
+    static v4l2_mpeg_video_bitrate_mode c2BitrateModeToV4L2BitrateMode(
             C2Config::bitrate_mode_t bitrateMode);
 
     // Converts v4l2_memory to a string.
@@ -403,6 +393,19 @@ public:
 
     enum class Type { kDecoder, kEncoder };
 
+    // Gets supported coding formats for |type| device and |pixelFormats|
+    static SupportedProfiles getSupportedProfiles(Type type,
+                                                  const std::vector<uint32_t>& pixelFormats);
+
+    // Gets supported levels for all decoder devices
+    static std::vector<C2Config::level_t> getSupportedDecodeLevels(VideoCodec videoCodecType);
+
+    // Get first current profile for any device
+    static C2Config::profile_t getDefaultProfile(VideoCodec codec);
+
+    // Gets first current profile for any device
+    static C2Config::level_t getDefaultLevel(VideoCodec codec);
+
     // Create and initialize an appropriate V4L2Device instance for the current platform, or return
     // nullptr if not available.
     static scoped_refptr<V4L2Device> create(uint32_t debugStreamId = -1);
@@ -456,22 +459,17 @@ public:
     void getSupportedResolution(uint32_t pixelFormat, ui::Size* minResolution,
                                 ui::Size* maxResolution);
 
-    std::vector<uint32_t> enumerateSupportedPixelformats(v4l2_buf_type bufType);
+    // Queries supported levels for |pixFmt| pixel format
+    std::vector<C2Config::level_t> queryC2Levels(uint32_t pixFmt);
 
-    std::vector<C2Config::level_t> getSupportedDecodeLevels(VideoCodec videoCodecType);
+    // Queries supported profiles for |pixFmt| pixel format
+    std::vector<C2Config::profile_t> queryC2Profiles(uint32_t pixFmt);
 
-    std::vector<C2Config::level_t> enumerateSupportedDecodeLevels(VideoCodec videoCodecType);
-
-    // Return supported profiles for decoder, including only profiles for given fourcc
-    // |pixelFormats|.
-    SupportedDecodeProfiles getSupportedDecodeProfiles(const std::vector<uint32_t>& pixelFormats);
-
-    // Return supported profiles for encoder.
-    SupportedEncodeProfiles getSupportedEncodeProfiles();
-
-    C2Config::profile_t getDefaultProfile(VideoCodec codec);
+    // Queries supported pixel format for a |bufType| queue type
+    std::vector<uint32_t> enumerateSupportedPixelformats(v4l2_buf_type bufType);
 
-    C2Config::level_t getDefaultLevel(VideoCodec codec);
+    // Queries supported levels for |videoCodecType|
+    std::vector<C2Config::level_t> enumerateSupportedDecodeLevels(VideoCodec videoCodecType);
 
     // Start polling on this V4L2Device. |eventCallback| will be posted to the caller's sequence if
     // a buffer is ready to be dequeued and/or a V4L2 event has been posted. |errorCallback| will
@@ -503,7 +501,10 @@ public:
 
 private:
     // Vector of video device node paths and corresponding pixelformats supported by each device node.
-    using Devices = std::vector<std::pair<std::string, std::vector<uint32_t>>>;
+    using DeviceInfos = std::vector<std::pair<std::string, std::vector<uint32_t>>>;
+
+    // Enumerate all V4L2 devices on the system for |type| and return them
+    static const DeviceInfos& getDeviceInfosForType(V4L2Device::Type type);
 
     friend class base::RefCountedThreadSafe<V4L2Device>;
     V4L2Device(uint32_t debugStreamId);
@@ -512,10 +513,8 @@ private:
     V4L2Device(const V4L2Device&) = delete;
     V4L2Device& operator=(const V4L2Device&) = delete;
 
-    SupportedDecodeProfiles enumerateSupportedDecodeProfiles(
-            const std::vector<uint32_t>& pixelFormats);
-
-    SupportedEncodeProfiles enumerateSupportedEncodeProfiles();
+    SupportedProfiles enumerateSupportedProfiles(V4L2Device::Type type,
+                                                 const std::vector<uint32_t>& pixelFormats);
 
     // Open device node for |path| as a device of |type|.
     bool openDevicePath(const std::string& path, Type type);
@@ -523,14 +522,6 @@ private:
     // Close the currently open device.
     void closeDevice();
 
-    // Enumerate all V4L2 devices on the system for |type| and store the results under
-    // mDevicesByType[type].
-    void enumerateDevicesForType(V4L2Device::Type type);
-
-    // Return device information for all devices of |type| available in the system. Enumerates and
-    // queries devices on first run and caches the results for subsequent calls.
-    const Devices& getDevicesForType(V4L2Device::Type type);
-
     // Return device node path for device of |type| supporting |pixFmt|, or an empty string if the
     // given combination is not supported by the system.
     std::string getDevicePathFor(V4L2Device::Type type, uint32_t pixFmt);
@@ -541,9 +532,6 @@ private:
     // Identifier used for debugging purposes.
     uint32_t mDebugStreamId;
 
-    // Stores information for all devices available on the system for each device Type.
-    std::map<V4L2Device::Type, Devices> mDevicesByType;
-
     // The actual device fd.
     base::ScopedFD mDeviceFd;
 
diff --git a/components/V4L2DecodeInterface.cpp b/components/V4L2DecodeInterface.cpp
index fa7f6ba..a218f13 100644
--- a/components/V4L2DecodeInterface.cpp
+++ b/components/V4L2DecodeInterface.cpp
@@ -132,23 +132,16 @@ V4L2DecodeInterface::V4L2DecodeInterface(const std::string& name,
 
     std::string inputMime;
 
-    scoped_refptr<V4L2Device> device = V4L2Device::create();
-    if (!device) {
-        ALOGE("Failed to create V4L2 device");
-    }
-
     ui::Size maxSize(1, 1);
 
     std::vector<uint32_t> profiles;
-    if (device) {
-        V4L2Device::SupportedDecodeProfiles supportedProfiles =
-                device->getSupportedDecodeProfiles({VideoCodecToV4L2PixFmt(*mVideoCodec)});
-        for (const auto& supportedProfile : supportedProfiles) {
-            if (isValidProfileForCodec(mVideoCodec.value(), supportedProfile.profile)) {
-                profiles.push_back(static_cast<uint32_t>(supportedProfile.profile));
-                maxSize.setWidth(std::max(maxSize.width, supportedProfile.max_resolution.width));
-                maxSize.setHeight(std::max(maxSize.height, supportedProfile.max_resolution.height));
-            }
+    V4L2Device::SupportedProfiles supportedProfiles = V4L2Device::getSupportedProfiles(
+            V4L2Device::Type::kDecoder, {V4L2Device::videoCodecToPixFmt(*mVideoCodec)});
+    for (const auto& supportedProfile : supportedProfiles) {
+        if (isValidProfileForCodec(mVideoCodec.value(), supportedProfile.profile)) {
+            profiles.push_back(static_cast<uint32_t>(supportedProfile.profile));
+            maxSize.setWidth(std::max(maxSize.width, supportedProfile.max_resolution.width));
+            maxSize.setHeight(std::max(maxSize.height, supportedProfile.max_resolution.height));
         }
     }
 
@@ -177,18 +170,15 @@ V4L2DecodeInterface::V4L2DecodeInterface(const std::string& name,
         }
     }
 
-    uint32_t defaultProfile = C2Config::PROFILE_UNUSED;
-    if (device) defaultProfile = device->getDefaultProfile(*mVideoCodec);
+    uint32_t defaultProfile = V4L2Device::getDefaultProfile(*mVideoCodec);
     if (defaultProfile == C2Config::PROFILE_UNUSED)
         defaultProfile = *std::min_element(profiles.begin(), profiles.end());
 
     std::vector<unsigned int> levels;
-    if (device) {
-        std::vector<C2Config::level_t> supportedLevels =
-                device->getSupportedDecodeLevels(*mVideoCodec);
-        for (const auto& supportedLevel : supportedLevels) {
-            levels.push_back(static_cast<unsigned int>(supportedLevel));
-        }
+    std::vector<C2Config::level_t> supportedLevels =
+            V4L2Device::getSupportedDecodeLevels(*mVideoCodec);
+    for (const auto& supportedLevel : supportedLevels) {
+        levels.push_back(static_cast<unsigned int>(supportedLevel));
     }
 
     if (levels.empty()) {
@@ -222,8 +212,7 @@ V4L2DecodeInterface::V4L2DecodeInterface(const std::string& name,
         }
     }
 
-    uint32_t defaultLevel = C2Config::LEVEL_UNUSED;
-    if (device) defaultLevel = device->getDefaultLevel(*mVideoCodec);
+    uint32_t defaultLevel = V4L2Device::getDefaultLevel(*mVideoCodec);
     if (defaultLevel == C2Config::LEVEL_UNUSED)
         defaultLevel = *std::min_element(levels.begin(), levels.end());
 
diff --git a/components/V4L2Decoder.cpp b/components/V4L2Decoder.cpp
index 089e221..dfbcec1 100644
--- a/components/V4L2Decoder.cpp
+++ b/components/V4L2Decoder.cpp
@@ -31,19 +31,6 @@ constexpr size_t kNumExtraOutputBuffers = 4;
 
 }  // namespace
 
-uint32_t VideoCodecToV4L2PixFmt(VideoCodec codec) {
-    switch (codec) {
-    case VideoCodec::H264:
-        return V4L2_PIX_FMT_H264;
-    case VideoCodec::VP8:
-        return V4L2_PIX_FMT_VP8;
-    case VideoCodec::VP9:
-        return V4L2_PIX_FMT_VP9;
-    case VideoCodec::HEVC:
-        return V4L2_PIX_FMT_HEVC;
-    }
-}
-
 // static
 std::unique_ptr<VideoDecoder> V4L2Decoder::Create(
         uint32_t debugStreamId, const VideoCodec& codec, const size_t inputBufferSize,
@@ -112,7 +99,7 @@ bool V4L2Decoder::start(const VideoCodec& codec, const size_t inputBufferSize,
 
     mDevice = V4L2Device::create(mDebugStreamId);
 
-    const uint32_t inputPixelFormat = VideoCodecToV4L2PixFmt(codec);
+    const uint32_t inputPixelFormat = V4L2Device::videoCodecToPixFmt(codec);
     if (!mDevice->open(V4L2Device::Type::kDecoder, inputPixelFormat)) {
         ALOGE("Failed to open device for %s", VideoCodecToString(codec));
         return false;
@@ -123,10 +110,7 @@ bool V4L2Decoder::start(const VideoCodec& codec, const size_t inputBufferSize,
         return false;
     }
 
-    struct v4l2_decoder_cmd cmd;
-    memset(&cmd, 0, sizeof(cmd));
-    cmd.cmd = V4L2_DEC_CMD_STOP;
-    if (mDevice->ioctl(VIDIOC_TRY_DECODER_CMD, &cmd) != 0) {
+    if (!sendV4L2DecoderCmd(false)) {
         ALOGE("Device does not support flushing (V4L2_DEC_CMD_STOP)");
         return false;
     }
diff --git a/components/V4L2EncodeInterface.cpp b/components/V4L2EncodeInterface.cpp
index 1c5b950..23a559d 100644
--- a/components/V4L2EncodeInterface.cpp
+++ b/components/V4L2EncodeInterface.cpp
@@ -229,13 +229,6 @@ V4L2EncodeInterface::V4L2EncodeInterface(const C2String& name,
 }
 
 void V4L2EncodeInterface::Initialize(const C2String& name) {
-    scoped_refptr<V4L2Device> device = V4L2Device::create();
-    if (!device) {
-        ALOGE("Failed to create V4L2 device");
-        mInitStatus = C2_CORRUPTED;
-        return;
-    }
-
     auto codec = getCodecFromComponentName(name);
     if (!codec) {
         ALOGE("Invalid component name");
@@ -243,7 +236,8 @@ void V4L2EncodeInterface::Initialize(const C2String& name) {
         return;
     }
 
-    V4L2Device::SupportedEncodeProfiles supported_profiles = device->getSupportedEncodeProfiles();
+    auto supported_profiles = V4L2Device::getSupportedProfiles(
+            V4L2Device::Type::kEncoder, {V4L2Device::videoCodecToPixFmt(codec.value())});
 
     // Compile the list of supported profiles.
     // Note: unsigned int is used here, since std::vector<C2Config::profile_t> cannot convert to
diff --git a/components/V4L2Encoder.cpp b/components/V4L2Encoder.cpp
index 9c98324..fa09191 100644
--- a/components/V4L2Encoder.cpp
+++ b/components/V4L2Encoder.cpp
@@ -223,7 +223,7 @@ bool V4L2Encoder::initialize(C2Config::profile_t outputProfile, std::optional<ui
 
     // Open the V4L2 device for encoding to the requested output format.
     // TODO(dstaessens): Avoid conversion to VideoCodecProfile and use C2Config::profile_t directly.
-    uint32_t outputPixelFormat = V4L2Device::C2ProfileToV4L2PixFmt(outputProfile, false);
+    uint32_t outputPixelFormat = V4L2Device::c2ProfileToV4L2PixFmt(outputProfile, false);
     if (!outputPixelFormat) {
         ALOGE("Invalid output profile %s", profileToString(outputProfile));
         return false;
@@ -575,7 +575,7 @@ bool V4L2Encoder::configureOutputFormat(C2Config::profile_t outputProfile) {
     ALOG_ASSERT(!mOutputQueue->isStreaming());
     ALOG_ASSERT(!isEmpty(mVisibleSize));
 
-    auto format = mOutputQueue->setFormat(V4L2Device::C2ProfileToV4L2PixFmt(outputProfile, false),
+    auto format = mOutputQueue->setFormat(V4L2Device::c2ProfileToV4L2PixFmt(outputProfile, false),
                                           mVisibleSize, GetMaxOutputBufferSize(mVisibleSize));
     if (!format) {
         ALOGE("Failed to set output format to %s", profileToString(outputProfile));
@@ -675,7 +675,7 @@ bool V4L2Encoder::configureBitrateMode(C2Config::bitrate_mode_t bitrateMode) {
     ALOG_ASSERT(mTaskRunner->RunsTasksInCurrentSequence());
 
     v4l2_mpeg_video_bitrate_mode v4l2BitrateMode =
-            V4L2Device::C2BitrateModeToV4L2BitrateMode(bitrateMode);
+            V4L2Device::c2BitrateModeToV4L2BitrateMode(bitrateMode);
     if (!mDevice->setExtCtrls(V4L2_CTRL_CLASS_MPEG,
                               {V4L2ExtCtrl(V4L2_CID_MPEG_VIDEO_BITRATE_MODE, v4l2BitrateMode)})) {
         // TODO(b/190336806): Our stack doesn't support bitrate mode changes yet. We default to CBR
diff --git a/components/include/v4l2_codec2/components/V4L2Decoder.h b/components/include/v4l2_codec2/components/V4L2Decoder.h
index 0277995..1848b1e 100644
--- a/components/include/v4l2_codec2/components/V4L2Decoder.h
+++ b/components/include/v4l2_codec2/components/V4L2Decoder.h
@@ -34,8 +34,6 @@ constexpr std::initializer_list<uint32_t> kSupportedOutputFourccs = {
         Fourcc::NV12, Fourcc::NV21, Fourcc::NM12, Fourcc::NM21,
 };
 
-uint32_t VideoCodecToV4L2PixFmt(VideoCodec codec);
-
 class V4L2Decoder : public VideoDecoder {
 public:
     static std::unique_ptr<VideoDecoder> Create(
-- 
GitLab