mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
gst: Implement SPA_META_VideoTransform support
Many Gstreamer elements support transforming buffers via the `image-orientation` tag. Use it to implement support for the new VideoTransform meta. In order for Gstreamer pipelines to enable support for these tags usually the rotate method has to be set to `auto` or `automatic`, e.g. `videoflip method=automatic`, `glimagesink rotate-method=automatic` or `waylandsink rotate-method=auto`.
This commit is contained in:
parent
fa799aac86
commit
2ed7afb76c
4 changed files with 52 additions and 2 deletions
|
|
@ -115,6 +115,8 @@ void gst_pipewire_pool_wrap_buffer (GstPipeWirePool *pool, struct pw_buffer *b)
|
||||||
data->crop = spa_buffer_find_meta_data (b->buffer, SPA_META_VideoCrop, sizeof(*data->crop));
|
data->crop = spa_buffer_find_meta_data (b->buffer, SPA_META_VideoCrop, sizeof(*data->crop));
|
||||||
if (data->crop)
|
if (data->crop)
|
||||||
gst_buffer_add_video_crop_meta(buf);
|
gst_buffer_add_video_crop_meta(buf);
|
||||||
|
data->videotransform =
|
||||||
|
spa_buffer_find_meta_data (b->buffer, SPA_META_VideoTransform, sizeof(*data->videotransform));
|
||||||
|
|
||||||
gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf),
|
gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf),
|
||||||
pool_data_quark,
|
pool_data_quark,
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ struct _GstPipeWirePoolData {
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
gboolean queued;
|
gboolean queued;
|
||||||
struct spa_meta_region *crop;
|
struct spa_meta_region *crop;
|
||||||
|
struct spa_meta_videotransform *videotransform;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstPipeWirePool {
|
struct _GstPipeWirePool {
|
||||||
|
|
|
||||||
|
|
@ -514,6 +514,25 @@ on_remove_buffer (void *_data, struct pw_buffer *b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char * const transform_map[] = {
|
||||||
|
[SPA_META_TRANSFORMATION_None] = "rotate-0",
|
||||||
|
[SPA_META_TRANSFORMATION_90] = "rotate-90",
|
||||||
|
[SPA_META_TRANSFORMATION_180] = "rotate-180",
|
||||||
|
[SPA_META_TRANSFORMATION_270] = "rotate-270",
|
||||||
|
[SPA_META_TRANSFORMATION_Flipped] = "flip-rotate-0",
|
||||||
|
[SPA_META_TRANSFORMATION_Flipped90] = "flip-rotate-270",
|
||||||
|
[SPA_META_TRANSFORMATION_Flipped180] = "flip-rotate-180",
|
||||||
|
[SPA_META_TRANSFORMATION_Flipped270] = "flip-rotate-90",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *spa_transform_value_to_gst_image_orientation(uint32_t transform_value)
|
||||||
|
{
|
||||||
|
if (transform_value >= SPA_N_ELEMENTS(transform_map))
|
||||||
|
transform_value = SPA_META_TRANSFORMATION_None;
|
||||||
|
|
||||||
|
return transform_map[transform_value];
|
||||||
|
}
|
||||||
|
|
||||||
static GstBuffer *dequeue_buffer(GstPipeWireSrc *pwsrc)
|
static GstBuffer *dequeue_buffer(GstPipeWireSrc *pwsrc)
|
||||||
{
|
{
|
||||||
struct pw_buffer *b;
|
struct pw_buffer *b;
|
||||||
|
|
@ -521,6 +540,7 @@ static GstBuffer *dequeue_buffer(GstPipeWireSrc *pwsrc)
|
||||||
GstPipeWirePoolData *data;
|
GstPipeWirePoolData *data;
|
||||||
struct spa_meta_header *h;
|
struct spa_meta_header *h;
|
||||||
struct spa_meta_region *crop;
|
struct spa_meta_region *crop;
|
||||||
|
struct spa_meta_videotransform *videotransform;
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
b = pw_stream_dequeue_buffer (pwsrc->stream);
|
b = pw_stream_dequeue_buffer (pwsrc->stream);
|
||||||
|
|
@ -568,6 +588,27 @@ static GstBuffer *dequeue_buffer(GstPipeWireSrc *pwsrc)
|
||||||
meta->height = crop->region.size.height;
|
meta->height = crop->region.size.height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
videotransform = data->videotransform;
|
||||||
|
if (videotransform) {
|
||||||
|
if (pwsrc->transform_value != videotransform->transform) {
|
||||||
|
GstEvent *tag_event;
|
||||||
|
const char* tag_string;
|
||||||
|
|
||||||
|
tag_string =
|
||||||
|
spa_transform_value_to_gst_image_orientation(videotransform->transform);
|
||||||
|
|
||||||
|
GST_LOG_OBJECT (pwsrc, "got new videotransform: %u / %s",
|
||||||
|
videotransform->transform, tag_string);
|
||||||
|
|
||||||
|
tag_event = gst_event_new_tag(gst_tag_list_new(GST_TAG_IMAGE_ORIENTATION,
|
||||||
|
tag_string, NULL));
|
||||||
|
gst_pad_push_event (GST_BASE_SRC_PAD (pwsrc), tag_event);
|
||||||
|
|
||||||
|
pwsrc->transform_value = videotransform->transform;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < b->buffer->n_datas; i++) {
|
for (i = 0; i < b->buffer->n_datas; i++) {
|
||||||
struct spa_data *d = &b->buffer->datas[i];
|
struct spa_data *d = &b->buffer->datas[i];
|
||||||
GstMemory *pmem = gst_buffer_peek_memory (data->buf, i);
|
GstMemory *pmem = gst_buffer_peek_memory (data->buf, i);
|
||||||
|
|
@ -913,7 +954,7 @@ on_param_changed (void *data, uint32_t id,
|
||||||
pwsrc->negotiated = pwsrc->caps != NULL;
|
pwsrc->negotiated = pwsrc->caps != NULL;
|
||||||
|
|
||||||
if (pwsrc->negotiated) {
|
if (pwsrc->negotiated) {
|
||||||
const struct spa_pod *params[3];
|
const struct spa_pod *params[4];
|
||||||
struct spa_pod_builder b = { NULL };
|
struct spa_pod_builder b = { NULL };
|
||||||
uint8_t buffer[512];
|
uint8_t buffer[512];
|
||||||
uint32_t buffers = CLAMP (16, pwsrc->min_buffers, pwsrc->max_buffers);
|
uint32_t buffers = CLAMP (16, pwsrc->min_buffers, pwsrc->max_buffers);
|
||||||
|
|
@ -939,9 +980,13 @@ on_param_changed (void *data, uint32_t id,
|
||||||
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
|
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
|
||||||
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoCrop),
|
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoCrop),
|
||||||
SPA_PARAM_META_size, SPA_POD_Int(sizeof (struct spa_meta_region)));
|
SPA_PARAM_META_size, SPA_POD_Int(sizeof (struct spa_meta_region)));
|
||||||
|
params[3] = spa_pod_builder_add_object (&b,
|
||||||
|
SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
|
||||||
|
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoTransform),
|
||||||
|
SPA_PARAM_META_size, SPA_POD_Int(sizeof (struct spa_meta_videotransform)));
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (pwsrc, "doing finish format");
|
GST_DEBUG_OBJECT (pwsrc, "doing finish format");
|
||||||
pw_stream_update_params (pwsrc->stream, params, 3);
|
pw_stream_update_params (pwsrc->stream, params, SPA_N_ELEMENTS(params));
|
||||||
} else {
|
} else {
|
||||||
GST_WARNING_OBJECT (pwsrc, "finish format with error");
|
GST_WARNING_OBJECT (pwsrc, "finish format with error");
|
||||||
pw_stream_set_error (pwsrc->stream, -EINVAL, "unhandled format");
|
pw_stream_set_error (pwsrc->stream, -EINVAL, "unhandled format");
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,8 @@ struct _GstPipeWireSrc {
|
||||||
GstPipeWirePool *pool;
|
GstPipeWirePool *pool;
|
||||||
GstClock *clock;
|
GstClock *clock;
|
||||||
GstClockTime last_time;
|
GstClockTime last_time;
|
||||||
|
|
||||||
|
enum spa_meta_videotransform_value transform_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstPipeWireSrcClass {
|
struct _GstPipeWireSrcClass {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue