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",
|
||||
"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
|
||||
|
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;
|
||||
}
|
||||
|
||||
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.
|
||||
|
Reference in New Issue
Block a user