From fa799aac8674457a475c30d0c604876143b8d331 Mon Sep 17 00:00:00 2001 From: Robert Mader Date: Sat, 3 Dec 2022 23:54:30 +0100 Subject: [PATCH] libcamera: Implement SPA_META_VideoTransform support libcamera can detect camera transforms/rotation, e.g. from the device tree, and makes that information usable for clients via `CameraConfiguration::transform`. Advertise this information via the VideoTransform meta so Pipewire clients can adjust their output accordingly. Rotated cameras are common in mobile devices such as the Pinephone Pro, which was used to test this feature. --- spa/plugins/libcamera/libcamera-source.cpp | 7 +++++ spa/plugins/libcamera/libcamera-utils.cpp | 34 ++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/spa/plugins/libcamera/libcamera-source.cpp b/spa/plugins/libcamera/libcamera-source.cpp index 565325369..50954e5e3 100644 --- a/spa/plugins/libcamera/libcamera-source.cpp +++ b/spa/plugins/libcamera/libcamera-source.cpp @@ -78,6 +78,7 @@ struct buffer { struct spa_list link; struct spa_buffer *outbuf; struct spa_meta_header *h; + struct spa_meta_videotransform *videotransform; void *ptr; }; @@ -589,6 +590,12 @@ next: SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header), SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_header))); break; + case 1: + param = (struct spa_pod*)spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_ParamMeta, id, + SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoTransform), + SPA_PARAM_META_size, SPA_POD_Int(sizeof(struct spa_meta_videotransform))); + break; default: return 0; } diff --git a/spa/plugins/libcamera/libcamera-utils.cpp b/spa/plugins/libcamera/libcamera-utils.cpp index 384847ff5..ec1c6720a 100644 --- a/spa/plugins/libcamera/libcamera-utils.cpp +++ b/spa/plugins/libcamera/libcamera-utils.cpp @@ -698,6 +698,31 @@ static int spa_libcamera_use_buffers(struct impl *impl, struct port *port, return -ENOTSUP; } +static const struct { + Transform libcamera_transform; + uint32_t spa_transform_value; +} transform_map[] = { + { Transform::Identity, SPA_META_TRANSFORMATION_None }, + { Transform::Rot0, SPA_META_TRANSFORMATION_None }, + { Transform::HFlip, SPA_META_TRANSFORMATION_Flipped }, + { Transform::VFlip, SPA_META_TRANSFORMATION_Flipped180 }, + { Transform::HVFlip, SPA_META_TRANSFORMATION_180 }, + { Transform::Rot180, SPA_META_TRANSFORMATION_180 }, + { Transform::Transpose, SPA_META_TRANSFORMATION_Flipped90 }, + { Transform::Rot90, SPA_META_TRANSFORMATION_270 }, + { Transform::Rot270, SPA_META_TRANSFORMATION_90 }, + { Transform::Rot180Transpose, SPA_META_TRANSFORMATION_Flipped270 }, +}; + +static uint32_t libcamera_transform_to_spa_transform_value(Transform transform) +{ + for (const auto& t : transform_map) { + if (t.libcamera_transform == transform) + return t.spa_transform_value; + } + return SPA_META_TRANSFORMATION_None; +} + static int mmap_init(struct impl *impl, struct port *port, struct spa_buffer **buffers, uint32_t n_buffers) @@ -742,6 +767,15 @@ mmap_init(struct impl *impl, struct port *port, b->flags = BUFFER_FLAG_OUTSTANDING; b->h = (struct spa_meta_header*)spa_buffer_find_meta_data(buffers[i], SPA_META_Header, sizeof(*b->h)); + b->videotransform = (struct spa_meta_videotransform*)spa_buffer_find_meta_data( + buffers[i], SPA_META_VideoTransform, sizeof(*b->videotransform)); + if (b->videotransform) { + b->videotransform->transform = + libcamera_transform_to_spa_transform_value(impl->config->transform); + spa_log_debug(impl->log, "Setting videotransform for buffer %d to %u", + i, b->videotransform->transform); + } + d = buffers[i]->datas; for(j = 0; j < buffers[i]->n_datas; ++j) { d[j].type = port->memtype;