From f49ab32874c5c1a4bff2ed34f80c2f74b7ae9d70 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 9 Jul 2018 12:07:30 +0200 Subject: [PATCH] meta: add video damage region metadata Add damage region meta Implement damage region in video-src and export-sink --- spa/include/spa/buffer/meta.h | 33 ++++++++++++++++++------------- spa/include/spa/utils/defs.h | 13 +++++++++++- spa/lib/debug.c | 23 +++++++++++++++------- src/examples/export-sink.c | 37 +++++++++++++++++++++++++++++------ src/examples/video-src.c | 25 ++++++++++++++++++++--- 5 files changed, 100 insertions(+), 31 deletions(-) diff --git a/spa/include/spa/buffer/meta.h b/spa/include/spa/buffer/meta.h index fb137e90e..b0416912e 100644 --- a/spa/include/spa/buffer/meta.h +++ b/spa/include/spa/buffer/meta.h @@ -35,7 +35,14 @@ extern "C" { #define SPA_TYPE_META_BASE SPA_TYPE__Meta ":" #define SPA_TYPE_META__Header SPA_TYPE_META_BASE "Header" -#define SPA_TYPE_META__VideoCrop SPA_TYPE_META_BASE "VideoCrop" +#define SPA_TYPE_META__Region SPA_TYPE_META_BASE "Region" +#define SPA_TYPE_META_REGION_BASE SPA_TYPE_META__Region ":" + +#define SPA_TYPE_META__RegionArray SPA_TYPE_META_BASE "RegionArray" +#define SPA_TYPE_META_REGION_ARRAY_BASE SPA_TYPE_META__RegionArray ":" + +#define SPA_TYPE_META__VideoCrop SPA_TYPE_META_REGION_BASE "VideoCrop" +#define SPA_TYPE_META__VideoDamage SPA_TYPE_META_REGION_ARRAY_BASE "VideoDamage" /** * A metadata element. @@ -72,25 +79,22 @@ struct spa_meta_header { int64_t dts_offset; /**< decoding timestamp and a difference with pts */ }; -/** - * Video cropping metadata - * a */ -struct spa_meta_video_crop { - int32_t x, y; /**< x and y offsets */ - int32_t width, height; /**< width and height */ +/** metadata structure for Region or an array of these for RegionArray */ +struct spa_meta_region { + struct spa_region region; }; -/** - * Describes a control location in the buffer. - */ -struct spa_meta_control { - uint32_t id; /**< control id */ - uint32_t offset; /**< offset in buffer memory */ -}; +#define spa_meta_region_is_valid(m) ((m)->region.size.width != 0 && (m)->region.size.height != 0) + +#define spa_meta_region_for_each(pos,meta) \ + for (pos = spa_meta_first(meta); \ + spa_meta_check(pos, meta); \ + (pos)++) struct spa_type_meta { uint32_t Header; uint32_t VideoCrop; + uint32_t VideoDamage; }; static inline void spa_type_meta_map(struct spa_type_map *map, struct spa_type_meta *type) @@ -98,6 +102,7 @@ static inline void spa_type_meta_map(struct spa_type_map *map, struct spa_type_m if (type->Header == 0) { type->Header = spa_type_map_get_id(map, SPA_TYPE_META__Header); type->VideoCrop = spa_type_map_get_id(map, SPA_TYPE_META__VideoCrop); + type->VideoDamage = spa_type_map_get_id(map, SPA_TYPE_META__VideoDamage); } } diff --git a/spa/include/spa/utils/defs.h b/spa/include/spa/utils/defs.h index 0439f8dbd..36049c98f 100644 --- a/spa/include/spa/utils/defs.h +++ b/spa/include/spa/utils/defs.h @@ -55,12 +55,23 @@ enum spa_direction { #define SPA_DIRECTION_REVERSE(d) ((d) ^ 1) #define SPA_RECTANGLE(width,height) (struct spa_rectangle){ width, height } - struct spa_rectangle { uint32_t width; uint32_t height; }; +#define SPA_POINT(x,y) (struct spa_point){ x, y } +struct spa_point { + int32_t x; + int32_t y; +}; + +#define SPA_REGION(x,y,width,height) (struct spa_region){ SPA_POINT(x,y), SPA_RECTANGLE(width,height) } +struct spa_region { + struct spa_point position; + struct spa_rectangle size; +}; + #define SPA_FRACTION(num,denom) (struct spa_fraction){ num, denom } struct spa_fraction { uint32_t num; diff --git a/spa/lib/debug.c b/spa/lib/debug.c index c2665bac9..c20f77f31 100644 --- a/spa/lib/debug.c +++ b/spa/lib/debug.c @@ -72,13 +72,22 @@ int spa_debug_buffer(const struct spa_buffer *buffer) fprintf(stderr, " seq: %u\n", h->seq); fprintf(stderr, " pts: %" PRIi64 "\n", h->pts); fprintf(stderr, " dts_offset: %" PRIi64 "\n", h->dts_offset); - } else if (!strcmp(type_name, SPA_TYPE_META__VideoCrop)) { - struct spa_meta_video_crop *h = m->data; - fprintf(stderr, " struct spa_meta_video_crop:\n"); - fprintf(stderr, " x: %d\n", h->x); - fprintf(stderr, " y: %d\n", h->y); - fprintf(stderr, " width: %d\n", h->width); - fprintf(stderr, " height: %d\n", h->height); + } else if (strstr(type_name, SPA_TYPE_META_REGION_BASE) == type_name) { + struct spa_meta_region *h = m->data; + fprintf(stderr, " struct spa_meta_region:\n"); + fprintf(stderr, " x: %d\n", h->region.position.x); + fprintf(stderr, " y: %d\n", h->region.position.y); + fprintf(stderr, " width: %d\n", h->region.size.width); + fprintf(stderr, " height: %d\n", h->region.size.height); + } else if (strstr(type_name, SPA_TYPE_META_REGION_ARRAY_BASE) == type_name) { + struct spa_meta_region *p; + fprintf(stderr, " struct spa_meta_region_array:\n"); + spa_meta_region_for_each(p, m) { + fprintf(stderr, " x: %d\n", p->region.position.x); + fprintf(stderr, " y: %d\n", p->region.position.y); + fprintf(stderr, " width: %d\n", p->region.size.width); + fprintf(stderr, " height: %d\n", p->region.size.height); + } } else { fprintf(stderr, " Unknown:\n"); spa_debug_dump_mem(m->data, m->size); diff --git a/src/examples/export-sink.c b/src/examples/export-sink.c index d77a1340d..f3f199fe4 100644 --- a/src/examples/export-sink.c +++ b/src/examples/export-sink.c @@ -399,13 +399,24 @@ static int impl_port_enum_params(struct spa_node *node, ":", t->param_buffers.align, "i", 16); } else if (id == t->param.idMeta) { - if (*index != 0) + switch (*index) { + case 0: + param = spa_pod_builder_object(builder, + id, t->param_meta.Meta, + ":", t->param_meta.type, "I", t->meta.Header, + ":", t->param_meta.size, "i", sizeof(struct spa_meta_header)); + break; + case 1: + param = spa_pod_builder_object(builder, + id, t->param_meta.Meta, + ":", t->param_meta.type, "I", t->meta.VideoDamage, + ":", t->param_meta.size, "iru", sizeof(struct spa_meta_region), + SPA_POD_PROP_MIN_MAX(1 * sizeof(struct spa_meta_region), + 16 * sizeof(struct spa_meta_region))); + break; + default: return 0; - - param = spa_pod_builder_object(builder, - id, t->param_meta.Meta, - ":", t->param_meta.type, "I", t->meta.Header, - ":", t->param_meta.size, "i", sizeof(struct spa_meta_header)); + } } else if (id == t->param_io.idPropsOut) { struct props *p = &d->props; @@ -495,12 +506,15 @@ static int do_render(struct spa_loop *loop, bool async, uint32_t seq, const void *_data, size_t size, void *user_data) { struct data *d = user_data; + struct pw_type *t = d->t; const struct spa_buffer *buf = *(struct spa_buffer**)_data; uint8_t *map; void *sdata, *ddata; int sstride, dstride, ostride; uint32_t i; uint8_t *src, *dst; + struct spa_meta *m; + struct spa_meta_region *r; handle_events(d); @@ -519,6 +533,17 @@ static int do_render(struct spa_loop *loop, bool async, uint32_t seq, fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError()); return -EIO; } + + if ((m = spa_buffer_find_meta(buf, t->meta.VideoDamage))) { + spa_meta_region_for_each(r, m) { + if (!spa_meta_region_is_valid(r)) + break; + fprintf(stderr, "region %dx%d->%dx%d\n", + r->region.position.x, r->region.position.y, + r->region.size.width, r->region.size.height); + } + } + sstride = buf->datas[0].chunk->stride; ostride = SPA_MIN(sstride, dstride); diff --git a/src/examples/video-src.c b/src/examples/video-src.c index e801fb968..db3931ec5 100644 --- a/src/examples/video-src.c +++ b/src/examples/video-src.c @@ -76,6 +76,7 @@ static void on_timeout(void *userdata, uint64_t expirations) int i, j; uint8_t *p, *map; struct spa_meta_header *h; + struct spa_meta *m; pw_log_trace("timeout"); @@ -102,7 +103,7 @@ static void on_timeout(void *userdata, uint64_t expirations) } else return; - if ((h = spa_buffer_find_meta(buf, data->t->meta.Header))) { + if ((h = spa_buffer_find_meta_data(buf, data->t->meta.Header, sizeof(*h)))) { #if 0 struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -114,6 +115,17 @@ static void on_timeout(void *userdata, uint64_t expirations) h->seq = data->seq++; h->dts_offset = 0; } + if ((m = spa_buffer_find_meta(buf, data->t->meta.VideoDamage))) { + struct spa_meta_region *r = spa_meta_first(m); + + if (spa_meta_check(r, m)) { + r->region.position = SPA_POINT(0,0); + r->region.size = data->format.size; + r++; + } + if (spa_meta_check(r, m)) + r->region = SPA_REGION(0,0,0,0); + } for (i = 0; i < data->format.size.height; i++) { for (j = 0; j < data->format.size.width * BPP; j++) { @@ -167,7 +179,7 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) struct pw_type *t = data->t; uint8_t params_buffer[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer)); - const struct spa_pod *params[2]; + const struct spa_pod *params[3]; if (format == NULL) { pw_stream_finish_format(stream, 0, NULL, 0); @@ -190,7 +202,14 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) ":", t->param_meta.type, "I", t->meta.Header, ":", t->param_meta.size, "i", sizeof(struct spa_meta_header)); - pw_stream_finish_format(stream, 0, params, 2); + params[2] = spa_pod_builder_object(&b, + t->param.idMeta, t->param_meta.Meta, + ":", t->param_meta.type, "I", t->meta.VideoDamage, + ":", t->param_meta.size, "iru", sizeof(struct spa_meta_region) * 16, + SPA_POD_PROP_MIN_MAX(sizeof(struct spa_meta_region) * 1, + sizeof(struct spa_meta_region) * 16)); + + pw_stream_finish_format(stream, 0, params, 3); } static const struct pw_stream_events stream_events = {