mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 14:52:16 +00:00
Bug 1876895 - WebRTC backport: Video capture PipeWire: add support for DMABuf buffer type r=pehrsons,webrtc-reviewers
This is a simple backport of an WebRTC upstream change. Upstream commit: 334e9133dcdecb5d00d991332e05c7b80ae26578 Differential Revision: https://phabricator.services.mozilla.com/D202929
This commit is contained in:
parent
3da8bca73f
commit
99133f08ff
@ -14,7 +14,6 @@
|
||||
#include <libdrm/drm_fourcc.h>
|
||||
#include <pipewire/pipewire.h>
|
||||
#include <spa/param/video/format-utils.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -49,33 +48,6 @@ constexpr int CursorMetaSize(int w, int h) {
|
||||
constexpr PipeWireVersion kDmaBufModifierMinVersion = {0, 3, 33};
|
||||
constexpr PipeWireVersion kDropSingleModifierMinVersion = {0, 3, 40};
|
||||
|
||||
class ScopedBuf {
|
||||
public:
|
||||
ScopedBuf() {}
|
||||
ScopedBuf(uint8_t* map, int map_size, int fd)
|
||||
: map_(map), map_size_(map_size), fd_(fd) {}
|
||||
~ScopedBuf() {
|
||||
if (map_ != MAP_FAILED) {
|
||||
munmap(map_, map_size_);
|
||||
}
|
||||
}
|
||||
|
||||
explicit operator bool() { return map_ != MAP_FAILED; }
|
||||
|
||||
void initialize(uint8_t* map, int map_size, int fd) {
|
||||
map_ = map;
|
||||
map_size_ = map_size;
|
||||
fd_ = fd;
|
||||
}
|
||||
|
||||
uint8_t* get() { return map_; }
|
||||
|
||||
protected:
|
||||
uint8_t* map_ = static_cast<uint8_t*>(MAP_FAILED);
|
||||
int map_size_;
|
||||
int fd_;
|
||||
};
|
||||
|
||||
class SharedScreenCastStreamPrivate {
|
||||
public:
|
||||
SharedScreenCastStreamPrivate();
|
||||
|
@ -11,6 +11,21 @@
|
||||
#ifndef MODULES_PORTAL_PIPEWIRE_UTILS_H_
|
||||
#define MODULES_PORTAL_PIPEWIRE_UTILS_H_
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
// static
|
||||
struct dma_buf_sync {
|
||||
uint64_t flags;
|
||||
};
|
||||
#define DMA_BUF_SYNC_READ (1 << 0)
|
||||
#define DMA_BUF_SYNC_START (0 << 2)
|
||||
#define DMA_BUF_SYNC_END (1 << 2)
|
||||
#define DMA_BUF_BASE 'b'
|
||||
#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
|
||||
|
||||
struct pw_thread_loop;
|
||||
|
||||
namespace webrtc {
|
||||
@ -32,6 +47,66 @@ class PipeWireThreadLoopLock {
|
||||
pw_thread_loop* const loop_;
|
||||
};
|
||||
|
||||
// We should synchronize DMA Buffer object access from CPU to avoid potential
|
||||
// cache incoherency and data loss.
|
||||
// See
|
||||
// https://01.org/linuxgraphics/gfx-docs/drm/driver-api/dma-buf.html#cpu-access-to-dma-buffer-objects
|
||||
static bool SyncDmaBuf(int fd, uint64_t start_or_end) {
|
||||
struct dma_buf_sync sync = {0};
|
||||
|
||||
sync.flags = start_or_end | DMA_BUF_SYNC_READ;
|
||||
|
||||
while (true) {
|
||||
int ret;
|
||||
ret = ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync);
|
||||
if (ret == -1 && errno == EINTR) {
|
||||
continue;
|
||||
} else if (ret == -1) {
|
||||
return false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class ScopedBuf {
|
||||
public:
|
||||
ScopedBuf() {}
|
||||
ScopedBuf(uint8_t* map, int map_size, int fd, bool is_dma_buf = false)
|
||||
: map_(map), map_size_(map_size), fd_(fd), is_dma_buf_(is_dma_buf) {}
|
||||
~ScopedBuf() {
|
||||
if (map_ != MAP_FAILED) {
|
||||
if (is_dma_buf_) {
|
||||
SyncDmaBuf(fd_, DMA_BUF_SYNC_END);
|
||||
}
|
||||
munmap(map_, map_size_);
|
||||
}
|
||||
}
|
||||
|
||||
explicit operator bool() { return map_ != MAP_FAILED; }
|
||||
|
||||
void initialize(uint8_t* map, int map_size, int fd, bool is_dma_buf = false) {
|
||||
map_ = map;
|
||||
map_size_ = map_size;
|
||||
is_dma_buf_ = is_dma_buf;
|
||||
fd_ = fd;
|
||||
|
||||
if (is_dma_buf_) {
|
||||
SyncDmaBuf(fd_, DMA_BUF_SYNC_START);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* get() { return map_; }
|
||||
|
||||
protected:
|
||||
uint8_t* map_ = static_cast<uint8_t*>(MAP_FAILED);
|
||||
int map_size_;
|
||||
int fd_;
|
||||
bool is_dma_buf_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_PORTAL_PIPEWIRE_UTILS_H_
|
||||
|
@ -178,8 +178,7 @@ int32_t VideoCaptureModulePipeWire::StartCapture(
|
||||
int res = pw_stream_connect(
|
||||
stream_, PW_DIRECTION_INPUT, node_id_,
|
||||
static_cast<enum pw_stream_flags>(PW_STREAM_FLAG_AUTOCONNECT |
|
||||
PW_STREAM_FLAG_DONT_RECONNECT |
|
||||
PW_STREAM_FLAG_MAP_BUFFERS),
|
||||
PW_STREAM_FLAG_DONT_RECONNECT),
|
||||
params.data(), params.size());
|
||||
if (res != 0) {
|
||||
RTC_LOG(LS_ERROR) << "Could not connect to camera stream: "
|
||||
@ -312,11 +311,11 @@ void VideoCaptureModulePipeWire::OnFormatChanged(const struct spa_pod* format) {
|
||||
0);
|
||||
}
|
||||
|
||||
const int buffer_types =
|
||||
(1 << SPA_DATA_DmaBuf) | (1 << SPA_DATA_MemFd) | (1 << SPA_DATA_MemPtr);
|
||||
spa_pod_builder_add(
|
||||
&builder, SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(8, 1, 32),
|
||||
SPA_PARAM_BUFFERS_dataType,
|
||||
SPA_POD_CHOICE_FLAGS_Int((1 << SPA_DATA_MemFd) | (1 << SPA_DATA_MemPtr)),
|
||||
0);
|
||||
SPA_PARAM_BUFFERS_dataType, SPA_POD_CHOICE_FLAGS_Int(buffer_types), 0);
|
||||
params.push_back(
|
||||
static_cast<spa_pod*>(spa_pod_builder_pop(&builder, &frame)));
|
||||
|
||||
@ -384,14 +383,15 @@ void VideoCaptureModulePipeWire::ProcessBuffers() {
|
||||
RTC_CHECK_RUNS_SERIALIZED(&capture_checker_);
|
||||
|
||||
while (pw_buffer* buffer = pw_stream_dequeue_buffer(stream_)) {
|
||||
spa_buffer* spaBuffer = buffer->buffer;
|
||||
struct spa_meta_header* h;
|
||||
h = static_cast<struct spa_meta_header*>(
|
||||
spa_buffer_find_meta_data(buffer->buffer, SPA_META_Header, sizeof(*h)));
|
||||
spa_buffer_find_meta_data(spaBuffer, SPA_META_Header, sizeof(*h)));
|
||||
|
||||
struct spa_meta_videotransform* videotransform;
|
||||
videotransform =
|
||||
static_cast<struct spa_meta_videotransform*>(spa_buffer_find_meta_data(
|
||||
buffer->buffer, SPA_META_VideoTransform, sizeof(*videotransform)));
|
||||
spaBuffer, SPA_META_VideoTransform, sizeof(*videotransform)));
|
||||
if (videotransform) {
|
||||
VideoRotation rotation =
|
||||
VideorotationFromPipeWireTransform(videotransform->transform);
|
||||
@ -401,11 +401,35 @@ void VideoCaptureModulePipeWire::ProcessBuffers() {
|
||||
|
||||
if (h->flags & SPA_META_HEADER_FLAG_CORRUPTED) {
|
||||
RTC_LOG(LS_INFO) << "Dropping corruped frame.";
|
||||
} else {
|
||||
IncomingFrame(static_cast<unsigned char*>(buffer->buffer->datas[0].data),
|
||||
buffer->buffer->datas[0].chunk->size,
|
||||
configured_capability_);
|
||||
pw_stream_queue_buffer(stream_, buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (spaBuffer->datas[0].type == SPA_DATA_DmaBuf ||
|
||||
spaBuffer->datas[0].type == SPA_DATA_MemFd) {
|
||||
ScopedBuf frame;
|
||||
frame.initialize(
|
||||
static_cast<uint8_t*>(
|
||||
mmap(nullptr,
|
||||
spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset,
|
||||
PROT_READ, MAP_PRIVATE, spaBuffer->datas[0].fd, 0)),
|
||||
spaBuffer->datas[0].maxsize + spaBuffer->datas[0].mapoffset,
|
||||
spaBuffer->datas[0].fd, spaBuffer->datas[0].type == SPA_DATA_DmaBuf);
|
||||
|
||||
if (!frame) {
|
||||
RTC_LOG(LS_ERROR) << "Failed to mmap the memory: "
|
||||
<< std::strerror(errno);
|
||||
return;
|
||||
}
|
||||
|
||||
IncomingFrame(
|
||||
SPA_MEMBER(frame.get(), spaBuffer->datas[0].mapoffset, uint8_t),
|
||||
spaBuffer->datas[0].chunk->size, configured_capability_);
|
||||
} else { // SPA_DATA_MemPtr
|
||||
IncomingFrame(static_cast<uint8_t*>(spaBuffer->datas[0].data),
|
||||
spaBuffer->datas[0].chunk->size, configured_capability_);
|
||||
}
|
||||
|
||||
pw_stream_queue_buffer(stream_, buffer);
|
||||
}
|
||||
}
|
||||
|
1
third_party/libwebrtc/moz-patch-stack/334e9133dc.no-op-cherry-pick-msg
vendored
Normal file
1
third_party/libwebrtc/moz-patch-stack/334e9133dc.no-op-cherry-pick-msg
vendored
Normal file
@ -0,0 +1 @@
|
||||
We cherry-picked this in bug 1876895.
|
Loading…
Reference in New Issue
Block a user