Skip to content

Commit 6ad5f97

Browse files
fix(linux/pipewire): restore dummy buffer for software encoders and fix buffer ownership (#5495)
Co-authored-by: luanweslley77 <luanweslley77@users.noreply.github.com>
1 parent c8763b6 commit 6ad5f97

4 files changed

Lines changed: 325 additions & 165 deletions

File tree

src/platform/linux/pipewire.cpp

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,17 @@ namespace pipewire {
128128
*/
129129
struct img_descriptor_t: public egl::img_descriptor_t {
130130
~img_descriptor_t() override {
131-
if (data) {
131+
// Only free buffers this image actually owns. The memory-buffer capture
132+
// path points img->data at the PipeWire staging vector (front_buffer),
133+
// which is owned by pipewire_t -- deleting it here corrupts the heap.
134+
if (data && data_owned) {
132135
delete[] data;
133-
data = nullptr;
134136
}
137+
data = nullptr;
138+
data_owned = false;
135139
}
140+
141+
bool data_owned = false; ///< Whether img->data is owned by this image and must be freed.
136142
};
137143

138144
/**
@@ -430,13 +436,17 @@ namespace pipewire {
430436

431437
struct spa_buffer *buf = stream_data.current_buffer->buffer;
432438
if (buf->datas[0].chunk->size != 0) {
433-
auto *img_descriptor = static_cast<egl::img_descriptor_t *>(img);
439+
auto *img_descriptor = static_cast<img_descriptor_t *>(img);
434440
fill_img_metadata(img_descriptor, buf);
435441
if (buf->datas[0].type == SPA_DATA_DmaBuf) {
436442
fill_img_dmabuf(img_descriptor, buf, stream_data);
437443
} else {
438444
img->data = stream_data.front_buffer->data();
445+
img_descriptor->data_owned = false;
439446
img->row_pitch = stream_data.local_stride;
447+
// NV12 is the only 1-byte-per-pixel format delivered on the memory
448+
// path; every other negotiated format is packed 4 bytes per pixel.
449+
img->pixel_pitch = (stream_data.format.info.raw.format == SPA_VIDEO_FORMAT_NV12) ? 1 : 4;
440450
}
441451
}
442452

@@ -937,6 +947,7 @@ namespace pipewire {
937947
img->sequence = 0;
938948
img->serial = std::numeric_limits<decltype(img->serial)>::max();
939949
img->data = nullptr;
950+
img->data_owned = false;
940951
std::fill_n(img->sd.fds, 4, -1);
941952

942953
return img;
@@ -1061,7 +1072,20 @@ namespace pipewire {
10611072
* @return Capture status reported to the streaming pipeline.
10621073
*/
10631074
int dummy_img(platf::img_t *img) override {
1064-
// Empty images are recognized as dummies by the zero sequence number
1075+
// Software encoders convert the dummy image immediately; provide a valid
1076+
// (black) buffer instead of leaving img->data null, which makes sws fail
1077+
// with EINVAL. The buffer is new[]-allocated and marked as owned so the
1078+
// destructor releases it.
1079+
if (img->data == nullptr) {
1080+
const auto w = img->width;
1081+
const auto h = img->height;
1082+
if (w > 0 && h > 0) {
1083+
img->data = new uint8_t[static_cast<size_t>(w) * h * 4](); // NOSONAR(cpp:S5025) - buffer is owned by the image and freed by img_descriptor_t's destructor
1084+
static_cast<img_descriptor_t *>(img)->data_owned = true;
1085+
img->row_pitch = w * 4;
1086+
img->pixel_pitch = 4;
1087+
}
1088+
}
10651089
return 0;
10661090
}
10671091

0 commit comments

Comments
 (0)