0

v4l2/stateless: Input queue creation

Provide an abstraction for the V4L2 queues
and configure the input queue.

Bug: b:278935312
Change-Id: Idbeec708ef51bc7c0ed8b0c191d3529093900d49
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4852773
Reviewed-by: Nathan Hebert <nhebert@chromium.org>
Commit-Queue: Fritz Koenig <frkoenig@chromium.org>
Reviewed-by: Miguel Casas-Sanchez <mcasas@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1207318}
This commit is contained in:
Fritz Koenig
2023-10-09 22:03:10 +00:00
committed by Chromium LUCI CQ
parent 53d1912a32
commit 72f14570e1
7 changed files with 186 additions and 3 deletions

@ -20,6 +20,8 @@ source_set("v4l2") {
"legacy/v4l2_video_decode_accelerator.h",
"stateless/device.cc",
"stateless/device.h",
"stateless/queue.cc",
"stateless/queue.h",
"stateless/stateless_decode_surface_handler.h",
"stateless/stateless_device.cc",
"stateless/stateless_device.h",

@ -10,7 +10,6 @@
#include "build/build_config.h"
#if BUILDFLAG(IS_CHROMEOS)
#include <linux/media/av1-ctrls.h>
#include <linux/media/vp9-ctrls-upstream.h>
#endif
#include <fcntl.h>
@ -111,6 +110,30 @@ std::set<VideoCodec> Device::EnumerateInputFormats() {
return pix_fmts;
}
// VIDIOC_S_FMT
bool Device::SetInputFormat(VideoCodec codec,
gfx::Size resolution,
size_t encoded_buffer_size) {
const uint32_t pix_fmt = VideoCodecToV4L2PixFmt(codec);
struct v4l2_format format;
memset(&format, 0, sizeof(format));
format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
format.fmt.pix_mp.pixelformat = pix_fmt;
format.fmt.pix_mp.width = resolution.width();
format.fmt.pix_mp.height = resolution.height();
format.fmt.pix_mp.num_planes = 1;
format.fmt.pix_mp.plane_fmt[0].sizeimage = encoded_buffer_size;
if (IoctlDevice(VIDIOC_S_FMT, &format) != kIoctlOk ||
format.fmt.pix_mp.pixelformat != pix_fmt) {
DVLOGF(1) << "Failed to set format fourcc: " << FourccToString(pix_fmt);
return false;
}
return true;
}
// VIDIOC_ENUM_FRAMESIZES
std::pair<gfx::Size, gfx::Size> Device::GetFrameResolutionRange(
VideoCodec codec) {

@ -18,6 +18,9 @@
namespace media {
enum class BufferType { kCompressedData, kRawFrames, kInvalid };
enum class MemoryType { kMemoryMapped, kDmaBuf, kInvalid };
// Encapsulates the v4l2 subsystem and prevents <linux/videodev2.h> from
// being included elsewhere with the possible exception of the codec specific
// delegates. This keeps all of the v4l2 driver specific structures in one
@ -32,7 +35,14 @@ class MEDIA_GPU_EXPORT Device : public base::RefCountedThreadSafe<Device> {
// These are all of the compressed formats that the driver will accept.
std::set<VideoCodec> EnumerateInputFormats();
// VIDIOC_ENUM_FRAMESIZES
// Configures the driver to the requested |codec|, |resolution|, and
// |encoded_buffer_size| using the VIDIOC_S_FMT ioctl.
bool SetInputFormat(VideoCodec codec,
gfx::Size resolution,
size_t encoded_buffer_size);
// Query the driver for the smallest and largest uncompressed frame sizes that
// are supported using the VIDIOC_ENUM_FRAMESIZES ioctl.
std::pair<gfx::Size, gfx::Size> GetFrameResolutionRange(VideoCodec codec);
// Uses the VIDIOC_QUERYCTRL and VIDIOC_QUERYMENU ioctls to list the

@ -0,0 +1,71 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/gpu/v4l2/stateless/queue.h"
#include "base/containers/contains.h"
#include "media/gpu/macros.h"
namespace {
// See http://crbug.com/255116.
constexpr int k1080pArea = 1920 * 1088;
// Input bitstream buffer size for up to 1080p streams.
constexpr size_t kInputBufferMaxSizeFor1080p = 1024 * 1024;
// Input bitstream buffer size for up to 4k streams.
constexpr size_t kInputBufferMaxSizeFor4k = 4 * kInputBufferMaxSizeFor1080p;
// The number of planes for a compressed buffer is always 1.
constexpr uint32_t kNumberInputPlanes = 1;
} // namespace
namespace media {
BaseQueue::BaseQueue(scoped_refptr<StatelessDevice> device,
BufferType buffer_type,
MemoryType memory_type)
: device_(std::move(device)),
buffer_type_(buffer_type),
memory_type_(memory_type) {}
BaseQueue::~BaseQueue() {
DVLOGF(4);
}
// static
std::unique_ptr<InputQueue> InputQueue::Create(
scoped_refptr<StatelessDevice> device,
const VideoCodec codec,
const gfx::Size resolution) {
CHECK(device);
std::unique_ptr<InputQueue> queue =
std::make_unique<InputQueue>(device, codec);
if (!queue->SetupFormat(resolution)) {
return nullptr;
}
return queue;
}
InputQueue::InputQueue(scoped_refptr<StatelessDevice> device, VideoCodec codec)
: BaseQueue(device, BufferType::kCompressedData, MemoryType::kMemoryMapped),
codec_(codec) {}
bool InputQueue::SetupFormat(const gfx::Size resolution) {
DVLOGF(4);
CHECK(device_);
const auto range = device_->GetFrameResolutionRange(codec_);
size_t encoded_buffer_size = range.second.GetArea() > k1080pArea
? kInputBufferMaxSizeFor4k
: kInputBufferMaxSizeFor1080p;
if (!device_->SetInputFormat(codec_, resolution, encoded_buffer_size)) {
return false;
}
num_planes_ = kNumberInputPlanes;
return true;
}
} // namespace media

@ -0,0 +1,50 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_GPU_V4L2_STATELESS_QUEUE_H_
#define MEDIA_GPU_V4L2_STATELESS_QUEUE_H_
#include "media/base/video_codecs.h"
#include "media/gpu/chromeos/fourcc.h"
#include "media/gpu/media_gpu_export.h"
#include "media/gpu/v4l2/stateless/stateless_device.h"
namespace media {
// V4L2 has two similar queues. Capitalized OUTPUT (for compressed frames)
// and CAPTURE (for uncompressed frames) are the designation that the V4L2
// framework uses. As these are counterintuitive for video decoding this class
// encapsulates the compressed frames into |InputQueue| and uncompressed frames
// into |OutputQueue|.
class MEDIA_GPU_EXPORT BaseQueue {
public:
BaseQueue(scoped_refptr<StatelessDevice> device,
BufferType buffer_type,
MemoryType memory_type);
BaseQueue& operator=(const BaseQueue&);
~BaseQueue();
scoped_refptr<StatelessDevice> device_;
const BufferType buffer_type_;
const MemoryType memory_type_;
uint32_t num_planes_;
};
class MEDIA_GPU_EXPORT InputQueue : public BaseQueue {
public:
static std::unique_ptr<InputQueue> Create(
scoped_refptr<StatelessDevice> device,
const VideoCodec codec,
const gfx::Size resolution);
InputQueue(scoped_refptr<StatelessDevice> device, VideoCodec codec);
private:
bool SetupFormat(const gfx::Size resolution);
VideoCodec codec_;
};
} // namespace media
#endif // MEDIA_GPU_V4L2_STATELESS_QUEUE_H_

@ -193,6 +193,18 @@ bool V4L2StatelessVideoDecoder::CreateDecoder(VideoCodecProfile profile,
return true;
}
bool V4L2StatelessVideoDecoder::CreateInputQueue(VideoCodecProfile profile,
const gfx::Size resolution) {
DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
DVLOGF(4);
DCHECK(!input_queue_);
const VideoCodec codec = VideoCodecProfileToVideoCodec(profile);
input_queue_ = InputQueue::Create(device_, codec, resolution);
return !!input_queue_;
}
void V4L2StatelessVideoDecoder::ProcessCompressedBuffer(
scoped_refptr<DecoderBuffer> compressed_buffer,
VideoDecoder::DecodeCB decode_cb,
@ -222,7 +234,14 @@ void V4L2StatelessVideoDecoder::ProcessCompressedBuffer(
switch (decode_result) {
case AcceleratedVideoDecoder::kConfigChange:
VLOGF(2) << "AcceleratedVideoDecoder::kConfigChange";
NOTIMPLEMENTED();
if (!CreateInputQueue(decoder_->GetProfile(),
decoder_->GetPicSize())) {
std::move(decode_cb).Run(
DecoderStatus::Codes::kPlatformDecodeFailure);
VLOGF(1) << "Unable to create an input queue for "
<< GetProfileName(decoder_->GetProfile())
<< " of resolution " << decoder_->GetPicSize().ToString();
}
break;
case AcceleratedVideoDecoder::kColorSpaceChange:
VLOGF(2) << "AcceleratedVideoDecoder::kColorSpaceChange";

@ -18,6 +18,7 @@
#include "media/base/waiting.h"
#include "media/gpu/accelerated_video_decoder.h"
#include "media/gpu/chromeos/video_decoder_pipeline.h"
#include "media/gpu/v4l2/stateless/queue.h"
#include "media/gpu/v4l2/stateless/stateless_decode_surface_handler.h"
#include "media/gpu/v4l2/stateless/stateless_device.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@ -76,6 +77,11 @@ class MEDIA_GPU_EXPORT V4L2StatelessVideoDecoder
// the |decoder_| member variable.
bool CreateDecoder(VideoCodecProfile profile, VideoColorSpace color_space);
// Create a queue of buffers for compressed frames to go into. V4L2 needs
// to know |profile| and |resolution| in order to know if the queue
// can be created.
bool CreateInputQueue(VideoCodecProfile profile, const gfx::Size resolution);
// Process the data in the |compressed_buffer| using the |decoder_|.
void ProcessCompressedBuffer(scoped_refptr<DecoderBuffer> compressed_buffer,
VideoDecoder::DecodeCB decode_cb,
@ -92,6 +98,8 @@ class MEDIA_GPU_EXPORT V4L2StatelessVideoDecoder
// Video decoder used to parse stream headers by software.
std::unique_ptr<AcceleratedVideoDecoder> decoder_;
std::unique_ptr<InputQueue> input_queue_;
// Int32 safe ID generator, starting at 0. Generated IDs are used to uniquely
// identify a Decode() request for stateless backends. BitstreamID is just
// a "phantom type" (see StrongAlias), essentially just a name.