diff --git a/spa/include/spa/buffer/buffer.h b/spa/include/spa/buffer/buffer.h index 39ca6fb81..29ef9f534 100644 --- a/spa/include/spa/buffer/buffer.h +++ b/spa/include/spa/buffer/buffer.h @@ -118,6 +118,17 @@ SPA_API_BUFFER void *spa_buffer_find_meta_data(const struct spa_buffer *b, uint3 return NULL; } +SPA_API_BUFFER bool spa_buffer_has_meta_features(const struct spa_buffer *b, uint32_t type, uint32_t features) +{ + uint32_t i; + for (i = 0; i < b->n_metas; i++) { + uint32_t t = b->metas[i].type; + if ((t >> 16) == type && (t & features) == features) + return true; + } + return false; +} + /** * \} */ diff --git a/spa/include/spa/buffer/meta.h b/spa/include/spa/buffer/meta.h index 19eee808a..287410f02 100644 --- a/spa/include/spa/buffer/meta.h +++ b/spa/include/spa/buffer/meta.h @@ -37,10 +37,17 @@ enum spa_meta_type { SPA_META_Busy, /**< don't write to buffer when count > 0 */ SPA_META_VideoTransform, /**< struct spa_meta_transform */ SPA_META_SyncTimeline, /**< struct spa_meta_sync_timeline */ - _SPA_META_LAST, /**< not part of ABI/API */ + + SPA_META_START_custom = 0x200, + + SPA_META_START_features = 0x10000, /* features start, these have 0 size, the + * type in the upper 16 bits and a bitmask in + * the lower 16 bits with type specific features. */ }; +#define SPA_META_TYPE_FEATURES(type,features) (((type)<<16)|(features)) + /** * A metadata element. * @@ -183,6 +190,8 @@ struct spa_meta_videotransform { * this metadata as SPA_PARAM_BUFFERS_metaType when negotiating a buffer * layout with 2 extra fds. */ +#define SPA_META_FEATURE_SYNC_TIMELINE_RELEASE (1<<0) /**< metadata supports RELEASE */ + struct spa_meta_sync_timeline { #define SPA_META_SYNC_TIMELINE_UNSCHEDULED_RELEASE (1<<0) /**< this flag is set by the producer and cleared * by the consumer when it promises to signal diff --git a/spa/include/spa/param/buffers.h b/spa/include/spa/param/buffers.h index cf0b4a698..bb07a3415 100644 --- a/spa/include/spa/param/buffers.h +++ b/spa/include/spa/param/buffers.h @@ -33,6 +33,7 @@ enum spa_param_meta { SPA_PARAM_META_START, SPA_PARAM_META_type, /**< the metadata, one of enum spa_meta_type (Id enum spa_meta_type) */ SPA_PARAM_META_size, /**< the expected maximum size the meta (Int) */ + SPA_PARAM_META_features, /**< meta data features (Features Int) */ }; /** properties for SPA_TYPE_OBJECT_ParamIO */ diff --git a/src/pipewire/buffers.c b/src/pipewire/buffers.c index 7a02a2d9f..71b4e11f0 100644 --- a/src/pipewire/buffers.c +++ b/src/pipewire/buffers.c @@ -221,12 +221,12 @@ int pw_buffers_negotiate(struct pw_context *context, uint32_t flags, if ((res = param_filter(result, &input, &output, SPA_PARAM_Meta, &b)) > 0) n_params += res; - metas = alloca(sizeof(struct spa_meta) * n_params); + metas = alloca(sizeof(struct spa_meta) * n_params * 2); n_metas = 0; params = alloca(n_params * sizeof(struct spa_pod *)); for (i = 0, offset = 0; i < n_params; i++) { - uint32_t type, size; + uint32_t type, size, features = 0; params[i] = SPA_PTROFF(buffer, offset, struct spa_pod); spa_pod_fixate(params[i]); @@ -239,7 +239,8 @@ int pw_buffers_negotiate(struct pw_context *context, uint32_t flags, if (spa_pod_parse_object(params[i], SPA_TYPE_OBJECT_ParamMeta, NULL, SPA_PARAM_META_type, SPA_POD_Id(&type), - SPA_PARAM_META_size, SPA_POD_Int(&size)) < 0) { + SPA_PARAM_META_size, SPA_POD_Int(&size), + SPA_PARAM_META_features, SPA_POD_OPT_Int(&features)) < 0) { pw_log_warn("%p: invalid Meta param", result); continue; } @@ -250,6 +251,11 @@ int pw_buffers_negotiate(struct pw_context *context, uint32_t flags, metas[n_metas].type = type; metas[n_metas].size = size; n_metas++; + if (features != 0) { + metas[n_metas].type = SPA_META_TYPE_FEATURES(type, features); + metas[n_metas].size = 0; + n_metas++; + } } max_buffers = context->settings.link_max_buffers;