@@ -1,89 +1,56 @@
-From 262a19d57fccf1b27ede283398278b52820f4aae Mon Sep 17 00:00:00 2001
+From 7ccf158ac8742d3ffaaf9f39bc1b01108f4b88d4 Mon Sep 17 00:00:00 2001
From: Thorsten Lannynd <t-lannynd@ti.com>
-Date: Fri, 5 Dec 2025 12:40:27 -0600
-Subject: [PATCH] media/gpu/v4l2: Use ChromeOS-style dev paths for all
- platforms
+Date: Sun, 17 May 2026 02:40:44 -0500
+Subject: [PATCH] media/gpu/v4l2: Extend ChromeOS-style dev paths to Linux
Upstream-Status: Inappropriate [embedded-specific,
requires custom udev rules]
-Remove platform-specific conditionals and standardize on ChromeOS device
-naming (/dev/video-dec, /dev/video-enc, etc) instead of generic /dev/video*.
-Reduces device scanning from 256 to 10 devices for improved enumeration speed.
+Extend the IS_CHROMEOS guards for device enumeration to also cover
+IS_LINUX. This standardizes on named device paths (/dev/video-dec,
+/dev/video-enc, etc.) instead of scanning up to 256 /dev/video* nodes,
+reducing enumeration from 256 to 10 candidates.
Signed-off-by: Thorsten Lannynd <t-lannynd@ti.com>
---
- media/gpu/v4l2/v4l2_device.cc | 16 ----------------
- media/gpu/v4l2/v4l2_utils.cc | 10 ----------
- 2 files changed, 26 deletions(-)
+ media/gpu/v4l2/v4l2_device.cc | 4 ++--
+ media/gpu/v4l2/v4l2_utils.cc | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/media/gpu/v4l2/v4l2_device.cc b/media/gpu/v4l2/v4l2_device.cc
-index ea35d10be8..dee743ed48 100644
+index fecd6a9a70..5b56c87397 100644
--- a/media/gpu/v4l2/v4l2_device.cc
+++ b/media/gpu/v4l2/v4l2_device.cc
-@@ -874,20 +874,11 @@ void V4L2Device::CloseDevice() {
+@@ -861,7 +861,7 @@ void V4L2Device::CloseDevice() {
}
void V4L2Device::EnumerateDevicesForType(Type type) {
-#if BUILDFLAG(IS_CHROMEOS)
++#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
static const std::string kDecoderDevicePattern = "/dev/video-dec";
static const std::string kEncoderDevicePattern = "/dev/video-enc";
static const std::string kImageProcessorDevicePattern = "/dev/image-proc";
- static const std::string kJpegDecoderDevicePattern = "/dev/jpeg-dec";
- static const std::string kJpegEncoderDevicePattern = "/dev/jpeg-enc";
--#else
-- static const std::string kDecoderDevicePattern = "/dev/video";
-- static const std::string kEncoderDevicePattern = "/dev/video";
-- static const std::string kImageProcessorDevicePattern = "/dev/video";
-- static const std::string kJpegDecoderDevicePattern = "/dev/video";
-- static const std::string kJpegEncoderDevicePattern = "/dev/video";
--#endif
--
- std::string device_pattern;
- v4l2_buf_type input_buf_type;
- v4l2_buf_type output_buf_type;
-@@ -924,19 +915,12 @@ void V4L2Device::EnumerateDevicesForType(Type type) {
+@@ -911,7 +911,7 @@ void V4L2Device::EnumerateDevicesForType(Type type) {
// We are sandboxed, so we can't query directory contents to check which
// devices are actually available. Try to open the first 10; if not present,
// we will just fail to open immediately.
-#if BUILDFLAG(IS_CHROMEOS)
++#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
constexpr int kMaxDevices = 10;
candidate_paths.reserve(kMaxDevices + 1);
- // TODO(posciak): Remove this legacy unnumbered device once
- // all platforms are updated to use numbered devices.
- candidate_paths.push_back(device_pattern);
--#else
-- // On mainline Linux we need to check a much larger number of devices, mainly
-- // because the device pattern is shared with ISP devices.
-- constexpr int kMaxDevices = 256;
-- candidate_paths.reserve(kMaxDevices);
--#endif
- for (int i = 0; i < kMaxDevices; ++i) {
- candidate_paths.push_back(
- base::StringPrintf("%s%d", device_pattern.c_str(), i));
diff --git a/media/gpu/v4l2/v4l2_utils.cc b/media/gpu/v4l2/v4l2_utils.cc
-index d4cac5573c..50d720a365 100644
+index 94b2e3cfe8..039851c5a2 100644
--- a/media/gpu/v4l2/v4l2_utils.cc
+++ b/media/gpu/v4l2/v4l2_utils.cc
-@@ -583,18 +583,8 @@ std::optional<SupportedVideoDecoderConfigs> GetSupportedV4L2DecoderConfigs() {
+@@ -577,7 +577,7 @@ std::optional<SupportedVideoDecoderConfigs> GetSupportedV4L2DecoderConfigs() {
SupportedVideoDecoderConfigs supported_media_configs;
std::vector<std::string> candidate_paths;
-#if BUILDFLAG(IS_CHROMEOS)
++#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)
constexpr char kVideoDevicePattern[] = "/dev/video-dec0";
candidate_paths.push_back(kVideoDevicePattern);
--#else
-- constexpr char kVideoDevicePattern[] = "/dev/video";
-- constexpr int kMaxDevices = 256;
-- candidate_paths.reserve(kMaxDevices);
-- for (int i = 0; i < kMaxDevices; ++i) {
-- candidate_paths.push_back(
-- base::StringPrintf("%s%d", kVideoDevicePattern, i));
-- }
--#endif
-
- for (const auto& path : candidate_paths) {
- base::ScopedFD device_fd(
+ #else
--
2.34.1
@@ -1,4 +1,4 @@
-From d6a8f091cebd265c0f7f681173d2aa218a0b89cd Mon Sep 17 00:00:00 2001
+From c31cb261202bc96d9a0581c3efdba5279acc04ef Mon Sep 17 00:00:00 2001
From: Thorsten Lannynd <t-lannynd@ti.com>
Date: Thu, 5 Mar 2026 12:02:31 -0600
Subject: [PATCH] chromium: gpu: sandbox: Allow GPU sandbox access to V4L2
@@ -17,18 +17,17 @@ Signed-off-by: Thorsten Lannynd <t-lannynd@ti.com>
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/content/common/gpu_pre_sandbox_hook_linux.cc b/content/common/gpu_pre_sandbox_hook_linux.cc
-index 2e53794fa3..9dec7fa08b 100644
+index 2e53794fa3..e2facce9da 100644
--- a/content/common/gpu_pre_sandbox_hook_linux.cc
+++ b/content/common/gpu_pre_sandbox_hook_linux.cc
-@@ -627,13 +627,14 @@ std::vector<BrokerFilePermission> FilePermissionsForGpu(
- BrokerFilePermission::ReadOnly(kDriRcPath)};
+@@ -628,12 +628,13 @@ std::vector<BrokerFilePermission> FilePermissionsForGpu(
AddVulkanICDPermissions(&permissions);
-+
+
+ if (UseV4L2Codec(options)) {
+ AddV4L2GpuPermissions(&permissions, options);
+ }
-
++
if (IsChromeOS()) {
// Permissions are additive, there can be multiple GPUs in the system.
AddStandardChromeOsPermissions(&permissions);
@@ -1,12 +1,19 @@
-From d1d9bcefa8fd299049e6e51855f41b67b27823ed Mon Sep 17 00:00:00 2001
+From dd6b0301aa61a2d1440f1edc7f836f2612f9270f Mon Sep 17 00:00:00 2001
From: Thorsten Lannynd <t-lannynd@ti.com>
-Date: Sat, 9 Aug 2025 01:46:14 -0500
+Date: Sun, 17 May 2026 02:29:10 -0500
Subject: [PATCH] media/gpu/v4l2: Fix OUTPUT queue streaming in
V4L2StatefulVideoDecoder
Upstream-Status: Inappropriate [this change is needed to satisfy
Wave5 conditions, which isn't applicable upstream]
+PickDecoderOutputFormat: Fall back to NV12 when no renderable format
+matches decoder candidates.
+
+InitializeCAPTUREQueue: Call SetFormat() on the CAPTURE queue using
+the fourcc selected by PickDecoderOutputFormat. Pass buffer_size=0
+so the driver calculates the correct size.
+
This patch ensures that the OUTPUT queue in `V4L2StatefulVideoDecoder`
is properly checked and started before attempting to enqueue buffers.
Wave5 requires buffers to be enqueued before streaming.
@@ -15,23 +22,35 @@ It adds a check for `IsStreaming()` and attempts to start streaming
with `Streamon()` if necessary. This prevents potential failures
during video decoding initialization.
-`SetFormat()` needs to be called on the CAPTURE queue to ensure
-the raw output frames are in the correct pixel format and picture
-size.
-
These changes rely on appropriate udev rules when running on a generic
Linux distribution to set the correct device node names.
Signed-off-by: Thorsten Lannynd <t-lannynd@ti.com>
---
- media/gpu/v4l2/v4l2_stateful_video_decoder.cc | 32 +++++++++++++------
- 1 file changed, 23 insertions(+), 9 deletions(-)
+ media/gpu/chromeos/video_decoder_pipeline.cc | 4 ++++
+ media/gpu/v4l2/v4l2_stateful_video_decoder.cc | 22 ++++++++++++-------
+ 2 files changed, 18 insertions(+), 8 deletions(-)
+diff --git a/media/gpu/chromeos/video_decoder_pipeline.cc b/media/gpu/chromeos/video_decoder_pipeline.cc
+index 742c94d7a0..b133147bc3 100644
+--- a/media/gpu/chromeos/video_decoder_pipeline.cc
++++ b/media/gpu/chromeos/video_decoder_pipeline.cc
+@@ -1148,6 +1148,10 @@ VideoDecoderPipeline::PickDecoderOutputFormat(
+ // Only tested with video_decode_accelerator_tests
+ // TODO(wenst@) Test with full Chromium Browser
+ CHECK(!allocator.has_value());
++ if (!viable_candidate && !candidates.empty()) {
++ viable_candidate =
++ PixelLayoutCandidate{Fourcc(Fourcc::NV12), candidates.front().size};
++ }
+ if (viable_candidate) {
+ // Instead, let V4L2 allocate the buffers if it can decode directly
+ // to the preferred formats. There's no need to allocate frames.
diff --git a/media/gpu/v4l2/v4l2_stateful_video_decoder.cc b/media/gpu/v4l2/v4l2_stateful_video_decoder.cc
-index 359145244d..e3aeb060c2 100644
+index b5d28d9a86..79c880f365 100644
--- a/media/gpu/v4l2/v4l2_stateful_video_decoder.cc
+++ b/media/gpu/v4l2/v4l2_stateful_video_decoder.cc
-@@ -417,10 +417,6 @@ void V4L2StatefulVideoDecoder::Initialize(const VideoDecoderConfig& config,
+@@ -412,10 +412,6 @@ void V4L2StatefulVideoDecoder::Initialize(const VideoDecoderConfig& config,
std::move(init_cb).Run(DecoderStatus::Codes::kFailedToCreateDecoder);
return;
}
@@ -42,7 +61,7 @@ index 359145244d..e3aeb060c2 100644
client_->NotifyEstimatedMaxDecodeRequests(base::checked_cast<int>(
std::min(static_cast<size_t>(4), num_input_buffers)));
-@@ -525,10 +521,22 @@ void V4L2StatefulVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
+@@ -520,10 +516,15 @@ void V4L2StatefulVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
std::move(decode_cb));
}
@@ -54,33 +73,23 @@ index 359145244d..e3aeb060c2 100644
+ TryAndEnqueueOUTPUTQueueBuffers();
+ if(!OUTPUT_queue_->Streamon()) {
+ VLOG(1) << "Failed to start OUTPUT queue streaming";
-+ while (!decoder_buffer_and_callbacks_.empty()) {
-+ auto cb = std::move(decoder_buffer_and_callbacks_.front().second);
-+ decoder_buffer_and_callbacks_.pop();
-+ std::move(cb).Run(DecoderStatus::Codes::kFailed);
-+ }
+ return;
+ }
-+ client_->NotifyEstimatedMaxDecodeRequests(base::checked_cast<int>(
-+ std::min(static_cast<size_t>(4), OUTPUT_queue_->AllocatedBuffersCount())));
+ }
+ else {
+ TryAndEnqueueOUTPUTQueueBuffers();
}
if (!event_task_runner_) {
-@@ -743,7 +751,13 @@ bool V4L2StatefulVideoDecoder::InitializeCAPTUREQueue() {
- auto chosen_fourcc = output_format.fourcc;
+@@ -739,6 +740,11 @@ bool V4L2StatefulVideoDecoder::InitializeCAPTUREQueue() {
const auto chosen_size = output_format.size;
const auto chosen_modifier = output_format.modifier;
--
-+ VLOG(1) << "Chosen |CAPTURE_queue_| format: " << chosen_fourcc.ToString() << " " << chosen_size.ToString() << " (modifier: 0x" << std::hex << chosen_modifier;
-+ constexpr size_t kMiB = 1024 * 1024;
-+ constexpr int kFullHDNumPixels = 1920 * 1080;
-+ const size_t kInputBufferInMBs =
-+ (chosen_size.GetArea() <= kFullHDNumPixels) ? 2 : 4;
-+ const auto capture_format = CAPTURE_queue_->SetFormat(
-+ V4L2_PIX_FMT_NV12, chosen_size, kInputBufferInMBs * kMiB);
+
++ if (!CAPTURE_queue_->SetFormat(chosen_fourcc.ToV4L2PixFmt(), chosen_size, /*buffer_size=*/0)
++ .has_value()) {
++ return false;
++ }
++
// If our |client_| has a VideoFramePool to allocate buffers for us, we'll
// use it, otherwise we have to ask the driver.
const bool use_v4l2_allocated_buffers = !client_->GetVideoFramePool();
@@ -1,8 +1,8 @@
-From 942c5f57d34c2d1b077240147bb29be84c773e62 Mon Sep 17 00:00:00 2001
+From b6f490b43eebcc8aad7f9fecc01e4d59e827d547 Mon Sep 17 00:00:00 2001
From: Alexandros Frantzis <alexandros.frantzis@collabora.com>
Date: Wed, 11 Jun 2025 11:07:05 +0300
-Subject: [PATCH] media/gpu/v4l2: Avoid placing incomplete H264 access units in
- buffers
+Subject: [PATCH] media/gpu/v4l2: Avoid placing incomplete H264 access
+ units in buffers
Upstream-Status: Pending
@@ -10,39 +10,45 @@ Don't place SPS, PPS, etc NALUs in their own separate buffers
unconditionally, as they are not full access units by themselves,
and may confuse the decoder.
---
- media/gpu/v4l2/v4l2_stateful_video_decoder.cc | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
+ media/gpu/v4l2/v4l2_stateful_video_decoder.cc | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/media/gpu/v4l2/v4l2_stateful_video_decoder.cc b/media/gpu/v4l2/v4l2_stateful_video_decoder.cc
-index e3aeb060c2..3657bc1d36 100644
+index 79c880f365..d29cef84d7 100644
--- a/media/gpu/v4l2/v4l2_stateful_video_decoder.cc
+++ b/media/gpu/v4l2/v4l2_stateful_video_decoder.cc
-@@ -1342,7 +1342,7 @@ H264FrameReassembler::FindH264FrameBoundary(const uint8_t* const data,
+@@ -1332,8 +1332,8 @@ H264FrameReassembler::FindH264FrameBoundary(const uint8_t* const data,
return std::nullopt;
}
previous_slice_header_.reset();
- return FrameBoundaryInfo{.is_whole_frame = true,
+- .is_start_of_new_frame = true,
+ return FrameBoundaryInfo{.is_whole_frame = false,
- .is_start_of_new_frame = true,
++ .is_start_of_new_frame = false,
.nalu_size = nalu_size};
case H264NALU::kPPS:
-@@ -1352,7 +1352,7 @@ H264FrameReassembler::FindH264FrameBoundary(const uint8_t* const data,
+ result = h264_parser_.ParsePPS(&pps_id_);
+@@ -1342,8 +1342,8 @@ H264FrameReassembler::FindH264FrameBoundary(const uint8_t* const data,
return std::nullopt;
}
previous_slice_header_.reset();
- return FrameBoundaryInfo{.is_whole_frame = true,
+- .is_start_of_new_frame = true,
+ return FrameBoundaryInfo{.is_whole_frame = false,
- .is_start_of_new_frame = true,
++ .is_start_of_new_frame = false,
.nalu_size = nalu_size};
case H264NALU::kNonIDRSlice:
-@@ -1391,7 +1391,7 @@ H264FrameReassembler::FindH264FrameBoundary(const uint8_t* const data,
+ case H264NALU::kIDRSlice: {
+@@ -1381,8 +1381,8 @@ H264FrameReassembler::FindH264FrameBoundary(const uint8_t* const data,
case H264NALU::kReserved18:
// Anything else than SPS, PPS and Non/IDRs marks a new frame boundary.
previous_slice_header_.reset();
- return FrameBoundaryInfo{.is_whole_frame = true,
+- .is_start_of_new_frame = true,
+ return FrameBoundaryInfo{.is_whole_frame = false,
- .is_start_of_new_frame = true,
++ .is_start_of_new_frame = false,
.nalu_size = nalu_size};
default:
+ VLOGF(4) << "Unsupported NALU "
--
GitLab
0001: Replace unconditional removal of IS_CHROMEOS guards with targeted IS_LINUX extension. This keeps the guards intact and avoids diverging unnecessarily from upstream, while still enabling named device paths (/dev/video-dec, /dev/video-enc) on generic Linux. 0002: Minor formatting fix only. 0003: Replace the previous OUTPUT queue approach (hardcoded NV12 format with MiB-based size calculation) with two smaller,cleaner fixes: - Add an NV12 fallback in PickDecoderOutputFormat() for platforms where renderable_fourccs_ contains only display formats (e.g. AR24) and none match the decoder's CAPTURE candidates. - Call SetFormat() on the CAPTURE queue in InitializeCAPTUREQueue() using the fourcc selected above with buffer_size=0, letting the driver compute the correct buffer size. 0004: Set is_start_of_new_frame=false for SPS/PPS NALUs to combine them with the first frame for efficiency. Signed-off-by: Thorsten Lannynd <t-lannynd@ti.com> --- v2: - Add wrynose branch to subject prefix ...se-ChromeOS-style-dev-paths-for-all-.patch | 71 +++++-------------- ...dbox-Allow-GPU-sandbox-access-to-V4L.patch | 11 ++- ...2-Fix-OUTPUT-queue-streaming-in-V4L2.patch | 65 +++++++++-------- ...void-placing-incomplete-H264-access-.patch | 30 ++++---- 4 files changed, 79 insertions(+), 98 deletions(-)