mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
meta: add video damage region metadata
Add damage region meta Implement damage region in video-src and export-sink
This commit is contained in:
parent
c98fbfe0a9
commit
f49ab32874
5 changed files with 100 additions and 31 deletions
|
|
@ -35,7 +35,14 @@ extern "C" {
|
||||||
#define SPA_TYPE_META_BASE SPA_TYPE__Meta ":"
|
#define SPA_TYPE_META_BASE SPA_TYPE__Meta ":"
|
||||||
|
|
||||||
#define SPA_TYPE_META__Header SPA_TYPE_META_BASE "Header"
|
#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.
|
* A metadata element.
|
||||||
|
|
@ -72,25 +79,22 @@ struct spa_meta_header {
|
||||||
int64_t dts_offset; /**< decoding timestamp and a difference with pts */
|
int64_t dts_offset; /**< decoding timestamp and a difference with pts */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/** metadata structure for Region or an array of these for RegionArray */
|
||||||
* Video cropping metadata
|
struct spa_meta_region {
|
||||||
* a */
|
struct spa_region region;
|
||||||
struct spa_meta_video_crop {
|
|
||||||
int32_t x, y; /**< x and y offsets */
|
|
||||||
int32_t width, height; /**< width and height */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
#define spa_meta_region_is_valid(m) ((m)->region.size.width != 0 && (m)->region.size.height != 0)
|
||||||
* Describes a control location in the buffer.
|
|
||||||
*/
|
#define spa_meta_region_for_each(pos,meta) \
|
||||||
struct spa_meta_control {
|
for (pos = spa_meta_first(meta); \
|
||||||
uint32_t id; /**< control id */
|
spa_meta_check(pos, meta); \
|
||||||
uint32_t offset; /**< offset in buffer memory */
|
(pos)++)
|
||||||
};
|
|
||||||
|
|
||||||
struct spa_type_meta {
|
struct spa_type_meta {
|
||||||
uint32_t Header;
|
uint32_t Header;
|
||||||
uint32_t VideoCrop;
|
uint32_t VideoCrop;
|
||||||
|
uint32_t VideoDamage;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void spa_type_meta_map(struct spa_type_map *map, struct spa_type_meta *type)
|
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) {
|
if (type->Header == 0) {
|
||||||
type->Header = spa_type_map_get_id(map, SPA_TYPE_META__Header);
|
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->VideoCrop = spa_type_map_get_id(map, SPA_TYPE_META__VideoCrop);
|
||||||
|
type->VideoDamage = spa_type_map_get_id(map, SPA_TYPE_META__VideoDamage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,12 +55,23 @@ enum spa_direction {
|
||||||
#define SPA_DIRECTION_REVERSE(d) ((d) ^ 1)
|
#define SPA_DIRECTION_REVERSE(d) ((d) ^ 1)
|
||||||
|
|
||||||
#define SPA_RECTANGLE(width,height) (struct spa_rectangle){ width, height }
|
#define SPA_RECTANGLE(width,height) (struct spa_rectangle){ width, height }
|
||||||
|
|
||||||
struct spa_rectangle {
|
struct spa_rectangle {
|
||||||
uint32_t width;
|
uint32_t width;
|
||||||
uint32_t height;
|
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 }
|
#define SPA_FRACTION(num,denom) (struct spa_fraction){ num, denom }
|
||||||
struct spa_fraction {
|
struct spa_fraction {
|
||||||
uint32_t num;
|
uint32_t num;
|
||||||
|
|
|
||||||
|
|
@ -72,13 +72,22 @@ int spa_debug_buffer(const struct spa_buffer *buffer)
|
||||||
fprintf(stderr, " seq: %u\n", h->seq);
|
fprintf(stderr, " seq: %u\n", h->seq);
|
||||||
fprintf(stderr, " pts: %" PRIi64 "\n", h->pts);
|
fprintf(stderr, " pts: %" PRIi64 "\n", h->pts);
|
||||||
fprintf(stderr, " dts_offset: %" PRIi64 "\n", h->dts_offset);
|
fprintf(stderr, " dts_offset: %" PRIi64 "\n", h->dts_offset);
|
||||||
} else if (!strcmp(type_name, SPA_TYPE_META__VideoCrop)) {
|
} else if (strstr(type_name, SPA_TYPE_META_REGION_BASE) == type_name) {
|
||||||
struct spa_meta_video_crop *h = m->data;
|
struct spa_meta_region *h = m->data;
|
||||||
fprintf(stderr, " struct spa_meta_video_crop:\n");
|
fprintf(stderr, " struct spa_meta_region:\n");
|
||||||
fprintf(stderr, " x: %d\n", h->x);
|
fprintf(stderr, " x: %d\n", h->region.position.x);
|
||||||
fprintf(stderr, " y: %d\n", h->y);
|
fprintf(stderr, " y: %d\n", h->region.position.y);
|
||||||
fprintf(stderr, " width: %d\n", h->width);
|
fprintf(stderr, " width: %d\n", h->region.size.width);
|
||||||
fprintf(stderr, " height: %d\n", h->height);
|
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 {
|
} else {
|
||||||
fprintf(stderr, " Unknown:\n");
|
fprintf(stderr, " Unknown:\n");
|
||||||
spa_debug_dump_mem(m->data, m->size);
|
spa_debug_dump_mem(m->data, m->size);
|
||||||
|
|
|
||||||
|
|
@ -399,13 +399,24 @@ static int impl_port_enum_params(struct spa_node *node,
|
||||||
":", t->param_buffers.align, "i", 16);
|
":", t->param_buffers.align, "i", 16);
|
||||||
}
|
}
|
||||||
else if (id == t->param.idMeta) {
|
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;
|
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) {
|
else if (id == t->param_io.idPropsOut) {
|
||||||
struct props *p = &d->props;
|
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)
|
const void *_data, size_t size, void *user_data)
|
||||||
{
|
{
|
||||||
struct data *d = user_data;
|
struct data *d = user_data;
|
||||||
|
struct pw_type *t = d->t;
|
||||||
const struct spa_buffer *buf = *(struct spa_buffer**)_data;
|
const struct spa_buffer *buf = *(struct spa_buffer**)_data;
|
||||||
uint8_t *map;
|
uint8_t *map;
|
||||||
void *sdata, *ddata;
|
void *sdata, *ddata;
|
||||||
int sstride, dstride, ostride;
|
int sstride, dstride, ostride;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint8_t *src, *dst;
|
uint8_t *src, *dst;
|
||||||
|
struct spa_meta *m;
|
||||||
|
struct spa_meta_region *r;
|
||||||
|
|
||||||
handle_events(d);
|
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());
|
fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError());
|
||||||
return -EIO;
|
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;
|
sstride = buf->datas[0].chunk->stride;
|
||||||
ostride = SPA_MIN(sstride, dstride);
|
ostride = SPA_MIN(sstride, dstride);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ static void on_timeout(void *userdata, uint64_t expirations)
|
||||||
int i, j;
|
int i, j;
|
||||||
uint8_t *p, *map;
|
uint8_t *p, *map;
|
||||||
struct spa_meta_header *h;
|
struct spa_meta_header *h;
|
||||||
|
struct spa_meta *m;
|
||||||
|
|
||||||
pw_log_trace("timeout");
|
pw_log_trace("timeout");
|
||||||
|
|
||||||
|
|
@ -102,7 +103,7 @@ static void on_timeout(void *userdata, uint64_t expirations)
|
||||||
} else
|
} else
|
||||||
return;
|
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
|
#if 0
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
|
@ -114,6 +115,17 @@ static void on_timeout(void *userdata, uint64_t expirations)
|
||||||
h->seq = data->seq++;
|
h->seq = data->seq++;
|
||||||
h->dts_offset = 0;
|
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 (i = 0; i < data->format.size.height; i++) {
|
||||||
for (j = 0; j < data->format.size.width * BPP; j++) {
|
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;
|
struct pw_type *t = data->t;
|
||||||
uint8_t params_buffer[1024];
|
uint8_t params_buffer[1024];
|
||||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
|
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) {
|
if (format == NULL) {
|
||||||
pw_stream_finish_format(stream, 0, NULL, 0);
|
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.type, "I", t->meta.Header,
|
||||||
":", t->param_meta.size, "i", sizeof(struct spa_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 = {
|
static const struct pw_stream_events stream_events = {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue