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:

committed by
Chromium LUCI CQ

parent
53d1912a32
commit
72f14570e1
@ -20,6 +20,8 @@ source_set("v4l2") {
|
|||||||
"legacy/v4l2_video_decode_accelerator.h",
|
"legacy/v4l2_video_decode_accelerator.h",
|
||||||
"stateless/device.cc",
|
"stateless/device.cc",
|
||||||
"stateless/device.h",
|
"stateless/device.h",
|
||||||
|
"stateless/queue.cc",
|
||||||
|
"stateless/queue.h",
|
||||||
"stateless/stateless_decode_surface_handler.h",
|
"stateless/stateless_decode_surface_handler.h",
|
||||||
"stateless/stateless_device.cc",
|
"stateless/stateless_device.cc",
|
||||||
"stateless/stateless_device.h",
|
"stateless/stateless_device.h",
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
#include "build/build_config.h"
|
#include "build/build_config.h"
|
||||||
#if BUILDFLAG(IS_CHROMEOS)
|
#if BUILDFLAG(IS_CHROMEOS)
|
||||||
#include <linux/media/av1-ctrls.h>
|
#include <linux/media/av1-ctrls.h>
|
||||||
#include <linux/media/vp9-ctrls-upstream.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -111,6 +110,30 @@ std::set<VideoCodec> Device::EnumerateInputFormats() {
|
|||||||
return pix_fmts;
|
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
|
// VIDIOC_ENUM_FRAMESIZES
|
||||||
std::pair<gfx::Size, gfx::Size> Device::GetFrameResolutionRange(
|
std::pair<gfx::Size, gfx::Size> Device::GetFrameResolutionRange(
|
||||||
VideoCodec codec) {
|
VideoCodec codec) {
|
||||||
|
@ -18,6 +18,9 @@
|
|||||||
|
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
|
enum class BufferType { kCompressedData, kRawFrames, kInvalid };
|
||||||
|
enum class MemoryType { kMemoryMapped, kDmaBuf, kInvalid };
|
||||||
|
|
||||||
// Encapsulates the v4l2 subsystem and prevents <linux/videodev2.h> from
|
// Encapsulates the v4l2 subsystem and prevents <linux/videodev2.h> from
|
||||||
// being included elsewhere with the possible exception of the codec specific
|
// being included elsewhere with the possible exception of the codec specific
|
||||||
// delegates. This keeps all of the v4l2 driver specific structures in one
|
// 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.
|
// These are all of the compressed formats that the driver will accept.
|
||||||
std::set<VideoCodec> EnumerateInputFormats();
|
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);
|
std::pair<gfx::Size, gfx::Size> GetFrameResolutionRange(VideoCodec codec);
|
||||||
|
|
||||||
// Uses the VIDIOC_QUERYCTRL and VIDIOC_QUERYMENU ioctls to list the
|
// Uses the VIDIOC_QUERYCTRL and VIDIOC_QUERYMENU ioctls to list the
|
||||||
|
71
media/gpu/v4l2/stateless/queue.cc
Normal file
71
media/gpu/v4l2/stateless/queue.cc
Normal file
@ -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
|
50
media/gpu/v4l2/stateless/queue.h
Normal file
50
media/gpu/v4l2/stateless/queue.h
Normal file
@ -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;
|
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(
|
void V4L2StatelessVideoDecoder::ProcessCompressedBuffer(
|
||||||
scoped_refptr<DecoderBuffer> compressed_buffer,
|
scoped_refptr<DecoderBuffer> compressed_buffer,
|
||||||
VideoDecoder::DecodeCB decode_cb,
|
VideoDecoder::DecodeCB decode_cb,
|
||||||
@ -222,7 +234,14 @@ void V4L2StatelessVideoDecoder::ProcessCompressedBuffer(
|
|||||||
switch (decode_result) {
|
switch (decode_result) {
|
||||||
case AcceleratedVideoDecoder::kConfigChange:
|
case AcceleratedVideoDecoder::kConfigChange:
|
||||||
VLOGF(2) << "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;
|
break;
|
||||||
case AcceleratedVideoDecoder::kColorSpaceChange:
|
case AcceleratedVideoDecoder::kColorSpaceChange:
|
||||||
VLOGF(2) << "AcceleratedVideoDecoder::kColorSpaceChange";
|
VLOGF(2) << "AcceleratedVideoDecoder::kColorSpaceChange";
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "media/base/waiting.h"
|
#include "media/base/waiting.h"
|
||||||
#include "media/gpu/accelerated_video_decoder.h"
|
#include "media/gpu/accelerated_video_decoder.h"
|
||||||
#include "media/gpu/chromeos/video_decoder_pipeline.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_decode_surface_handler.h"
|
||||||
#include "media/gpu/v4l2/stateless/stateless_device.h"
|
#include "media/gpu/v4l2/stateless/stateless_device.h"
|
||||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||||
@ -76,6 +77,11 @@ class MEDIA_GPU_EXPORT V4L2StatelessVideoDecoder
|
|||||||
// the |decoder_| member variable.
|
// the |decoder_| member variable.
|
||||||
bool CreateDecoder(VideoCodecProfile profile, VideoColorSpace color_space);
|
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_|.
|
// Process the data in the |compressed_buffer| using the |decoder_|.
|
||||||
void ProcessCompressedBuffer(scoped_refptr<DecoderBuffer> compressed_buffer,
|
void ProcessCompressedBuffer(scoped_refptr<DecoderBuffer> compressed_buffer,
|
||||||
VideoDecoder::DecodeCB decode_cb,
|
VideoDecoder::DecodeCB decode_cb,
|
||||||
@ -92,6 +98,8 @@ class MEDIA_GPU_EXPORT V4L2StatelessVideoDecoder
|
|||||||
// Video decoder used to parse stream headers by software.
|
// Video decoder used to parse stream headers by software.
|
||||||
std::unique_ptr<AcceleratedVideoDecoder> decoder_;
|
std::unique_ptr<AcceleratedVideoDecoder> decoder_;
|
||||||
|
|
||||||
|
std::unique_ptr<InputQueue> input_queue_;
|
||||||
|
|
||||||
// Int32 safe ID generator, starting at 0. Generated IDs are used to uniquely
|
// Int32 safe ID generator, starting at 0. Generated IDs are used to uniquely
|
||||||
// identify a Decode() request for stateless backends. BitstreamID is just
|
// identify a Decode() request for stateless backends. BitstreamID is just
|
||||||
// a "phantom type" (see StrongAlias), essentially just a name.
|
// a "phantom type" (see StrongAlias), essentially just a name.
|
||||||
|
Reference in New Issue
Block a user