mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-07 13:30:09 -05:00
meta: add cursor metadata and examples
Add a moving and flashing circle cursor to video-src Render the cursor in video-play
This commit is contained in:
parent
67a0b33dc8
commit
cd53eca92b
3 changed files with 122 additions and 8 deletions
|
|
@ -36,6 +36,7 @@ extern "C" {
|
||||||
|
|
||||||
#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__VideoCrop SPA_TYPE_META_BASE "VideoCrop"
|
||||||
|
#define SPA_TYPE_META__Cursor SPA_TYPE_META_BASE "Cursor"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A metadata element.
|
* A metadata element.
|
||||||
|
|
@ -84,6 +85,28 @@ struct spa_meta_control {
|
||||||
uint32_t offset; /**< offset in buffer memory */
|
uint32_t offset; /**< offset in buffer memory */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bitmap information
|
||||||
|
*/
|
||||||
|
struct spa_meta_bitmap {
|
||||||
|
uint32_t format; /**< bitmap video format */
|
||||||
|
uint32_t width, height; /**< width and height of bitmap */
|
||||||
|
uint32_t stride; /**< stride of bitmap data */
|
||||||
|
uint32_t size; /**< size of bitmap data */
|
||||||
|
uint32_t offset; /**< offset of bitmap data in this structure */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cursor information
|
||||||
|
*/
|
||||||
|
struct spa_meta_cursor {
|
||||||
|
uint32_t id; /**< cursor id */
|
||||||
|
int32_t x, y; /**< offsets on screen */
|
||||||
|
int32_t hotspot_x, hotspot_y; /**< offsets for hotspot in bitmap */
|
||||||
|
uint32_t bitmap_offset; /**< offset of bitmap meta in this structure */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct spa_type_meta {
|
struct spa_type_meta {
|
||||||
uint32_t Header;
|
uint32_t Header;
|
||||||
uint32_t VideoCrop;
|
uint32_t VideoCrop;
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ struct type {
|
||||||
struct spa_type_media_subtype media_subtype;
|
struct spa_type_media_subtype media_subtype;
|
||||||
struct spa_type_format_video format_video;
|
struct spa_type_format_video format_video;
|
||||||
struct spa_type_video_format video_format;
|
struct spa_type_video_format video_format;
|
||||||
|
uint32_t meta_cursor;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void init_type(struct type *type, struct spa_type_map *map)
|
static inline void init_type(struct type *type, struct spa_type_map *map)
|
||||||
|
|
@ -44,6 +45,7 @@ static inline void init_type(struct type *type, struct spa_type_map *map)
|
||||||
spa_type_media_subtype_map(map, &type->media_subtype);
|
spa_type_media_subtype_map(map, &type->media_subtype);
|
||||||
spa_type_format_video_map(map, &type->format_video);
|
spa_type_format_video_map(map, &type->format_video);
|
||||||
spa_type_video_format_map(map, &type->video_format);
|
spa_type_video_format_map(map, &type->video_format);
|
||||||
|
type->meta_cursor = spa_type_map_get_id(map, SPA_TYPE_META__Cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define WIDTH 640
|
#define WIDTH 640
|
||||||
|
|
@ -58,6 +60,7 @@ struct data {
|
||||||
SDL_Renderer *renderer;
|
SDL_Renderer *renderer;
|
||||||
SDL_Window *window;
|
SDL_Window *window;
|
||||||
SDL_Texture *texture;
|
SDL_Texture *texture;
|
||||||
|
SDL_Texture *cursor;
|
||||||
|
|
||||||
struct pw_main_loop *loop;
|
struct pw_main_loop *loop;
|
||||||
|
|
||||||
|
|
@ -74,6 +77,7 @@ struct data {
|
||||||
|
|
||||||
int counter;
|
int counter;
|
||||||
SDL_Rect rect;
|
SDL_Rect rect;
|
||||||
|
SDL_Rect cursor_rect;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void handle_events(struct data *data)
|
static void handle_events(struct data *data)
|
||||||
|
|
@ -98,8 +102,10 @@ on_stream_process(void *_data)
|
||||||
void *sdata, *ddata;
|
void *sdata, *ddata;
|
||||||
int sstride, dstride, ostride;
|
int sstride, dstride, ostride;
|
||||||
struct spa_meta_video_crop *mc;
|
struct spa_meta_video_crop *mc;
|
||||||
|
struct spa_meta_cursor *mcs;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint8_t *src, *dst;
|
uint8_t *src, *dst;
|
||||||
|
bool render_cursor = false;
|
||||||
|
|
||||||
handle_events(data);
|
handle_events(data);
|
||||||
|
|
||||||
|
|
@ -127,6 +133,37 @@ on_stream_process(void *_data)
|
||||||
data->rect.h = mc->height;
|
data->rect.h = mc->height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ((mcs = spa_buffer_find_meta(b, data->type.meta_cursor))) {
|
||||||
|
struct spa_meta_bitmap *mb;
|
||||||
|
void *cdata;
|
||||||
|
int cstride;
|
||||||
|
|
||||||
|
data->cursor_rect.x = mcs->x;
|
||||||
|
data->cursor_rect.y = mcs->y;
|
||||||
|
|
||||||
|
mb = SPA_MEMBER(mcs, mcs->bitmap_offset, struct spa_meta_bitmap);
|
||||||
|
data->cursor_rect.w = mb->width;
|
||||||
|
data->cursor_rect.h = mb->height;
|
||||||
|
|
||||||
|
if (SDL_LockTexture(data->cursor, NULL, &cdata, &cstride) < 0) {
|
||||||
|
fprintf(stderr, "Couldn't lock cursor texture: %s\n", SDL_GetError());
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
src = SPA_MEMBER(mb, mb->offset, uint8_t);
|
||||||
|
dst = cdata;
|
||||||
|
ostride = SPA_MIN(cstride, mb->stride);
|
||||||
|
|
||||||
|
for (i = 0; i < mb->height; i++) {
|
||||||
|
memcpy(dst, src, ostride);
|
||||||
|
dst += cstride;
|
||||||
|
src += mb->stride;
|
||||||
|
}
|
||||||
|
SDL_UnlockTexture(data->cursor);
|
||||||
|
|
||||||
|
render_cursor = true;
|
||||||
|
}
|
||||||
|
|
||||||
sstride = b->datas[0].chunk->stride;
|
sstride = b->datas[0].chunk->stride;
|
||||||
ostride = SPA_MIN(sstride, dstride);
|
ostride = SPA_MIN(sstride, dstride);
|
||||||
|
|
||||||
|
|
@ -141,6 +178,9 @@ on_stream_process(void *_data)
|
||||||
|
|
||||||
SDL_RenderClear(data->renderer);
|
SDL_RenderClear(data->renderer);
|
||||||
SDL_RenderCopy(data->renderer, data->texture, &data->rect, NULL);
|
SDL_RenderCopy(data->renderer, data->texture, &data->rect, NULL);
|
||||||
|
if (render_cursor) {
|
||||||
|
SDL_RenderCopy(data->renderer, data->cursor, NULL, &data->cursor_rect);
|
||||||
|
}
|
||||||
SDL_RenderPresent(data->renderer);
|
SDL_RenderPresent(data->renderer);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
@ -239,7 +279,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[3];
|
const struct spa_pod *params[4];
|
||||||
Uint32 sdl_format;
|
Uint32 sdl_format;
|
||||||
void *d;
|
void *d;
|
||||||
|
|
||||||
|
|
@ -267,6 +307,12 @@ on_stream_format_changed(void *_data, const struct spa_pod *format)
|
||||||
SDL_LockTexture(data->texture, NULL, &d, &data->stride);
|
SDL_LockTexture(data->texture, NULL, &d, &data->stride);
|
||||||
SDL_UnlockTexture(data->texture);
|
SDL_UnlockTexture(data->texture);
|
||||||
|
|
||||||
|
data->cursor = SDL_CreateTexture(data->renderer,
|
||||||
|
SDL_PIXELFORMAT_ARGB8888,
|
||||||
|
SDL_TEXTUREACCESS_STREAMING,
|
||||||
|
64, 64);
|
||||||
|
SDL_SetTextureBlendMode(data->cursor, SDL_BLENDMODE_BLEND);
|
||||||
|
|
||||||
data->rect.x = 0;
|
data->rect.x = 0;
|
||||||
data->rect.y = 0;
|
data->rect.y = 0;
|
||||||
data->rect.w = data->format.size.width;
|
data->rect.w = data->format.size.width;
|
||||||
|
|
@ -288,8 +334,14 @@ on_stream_format_changed(void *_data, const struct spa_pod *format)
|
||||||
t->param.idMeta, t->param_meta.Meta,
|
t->param.idMeta, t->param_meta.Meta,
|
||||||
":", t->param_meta.type, "I", t->meta.VideoCrop,
|
":", t->param_meta.type, "I", t->meta.VideoCrop,
|
||||||
":", t->param_meta.size, "i", sizeof(struct spa_meta_video_crop));
|
":", t->param_meta.size, "i", sizeof(struct spa_meta_video_crop));
|
||||||
|
params[3] = spa_pod_builder_object(&b,
|
||||||
|
t->param.idMeta, t->param_meta.Meta,
|
||||||
|
":", t->param_meta.type, "I", data->type.meta_cursor,
|
||||||
|
":", t->param_meta.size, "i", sizeof(struct spa_meta_cursor) +
|
||||||
|
sizeof(struct spa_meta_bitmap) +
|
||||||
|
64 * 64 * 4);
|
||||||
|
|
||||||
pw_stream_finish_format(stream, 0, params, 3);
|
pw_stream_finish_format(stream, 0, params, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct pw_stream_events stream_events = {
|
static const struct pw_stream_events stream_events = {
|
||||||
|
|
@ -472,6 +524,7 @@ int main(int argc, char *argv[])
|
||||||
pw_main_loop_destroy(data.loop);
|
pw_main_loop_destroy(data.loop);
|
||||||
|
|
||||||
SDL_DestroyTexture(data.texture);
|
SDL_DestroyTexture(data.texture);
|
||||||
|
SDL_DestroyTexture(data.cursor);
|
||||||
SDL_DestroyRenderer(data.renderer);
|
SDL_DestroyRenderer(data.renderer);
|
||||||
SDL_DestroyWindow(data.window);
|
SDL_DestroyWindow(data.window);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ struct type {
|
||||||
struct spa_type_media_subtype media_subtype;
|
struct spa_type_media_subtype media_subtype;
|
||||||
struct spa_type_format_video format_video;
|
struct spa_type_format_video format_video;
|
||||||
struct spa_type_video_format video_format;
|
struct spa_type_video_format video_format;
|
||||||
|
uint32_t meta_cursor;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void init_type(struct type *type, struct spa_type_map *map)
|
static inline void init_type(struct type *type, struct spa_type_map *map)
|
||||||
|
|
@ -43,6 +44,7 @@ static inline void init_type(struct type *type, struct spa_type_map *map)
|
||||||
spa_type_media_subtype_map(map, &type->media_subtype);
|
spa_type_media_subtype_map(map, &type->media_subtype);
|
||||||
spa_type_format_video_map(map, &type->format_video);
|
spa_type_format_video_map(map, &type->format_video);
|
||||||
spa_type_video_format_map(map, &type->video_format);
|
spa_type_video_format_map(map, &type->video_format);
|
||||||
|
type->meta_cursor = spa_type_map_get_id(map, SPA_TYPE_META__Cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BPP 3
|
#define BPP 3
|
||||||
|
|
@ -82,6 +84,7 @@ static void on_timeout(void *userdata, uint64_t expirations)
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
struct spa_meta_header *h;
|
struct spa_meta_header *h;
|
||||||
struct spa_meta_video_crop *mc;
|
struct spa_meta_video_crop *mc;
|
||||||
|
struct spa_meta_cursor *mcs;
|
||||||
struct pw_buffer *buf;
|
struct pw_buffer *buf;
|
||||||
struct spa_buffer *b;
|
struct spa_buffer *b;
|
||||||
|
|
||||||
|
|
@ -107,16 +110,41 @@ static void on_timeout(void *userdata, uint64_t expirations)
|
||||||
h->dts_offset = 0;
|
h->dts_offset = 0;
|
||||||
}
|
}
|
||||||
if ((mc = spa_buffer_find_meta(b, data->t->meta.VideoCrop))) {
|
if ((mc = spa_buffer_find_meta(b, data->t->meta.VideoCrop))) {
|
||||||
|
data->crop = (sin(data->accumulator) + 1.0) * 32.0;
|
||||||
mc->x = data->crop;
|
mc->x = data->crop;
|
||||||
mc->y = data->crop;
|
mc->y = data->crop;
|
||||||
mc->width = WIDTH - data->crop*2;
|
mc->width = WIDTH - data->crop*2;
|
||||||
mc->height = HEIGHT - data->crop*2;
|
mc->height = HEIGHT - data->crop*2;
|
||||||
|
}
|
||||||
|
if ((mcs = spa_buffer_find_meta(b, data->type.meta_cursor))) {
|
||||||
|
struct spa_meta_bitmap *mb;
|
||||||
|
uint32_t *bitmap, color;
|
||||||
|
|
||||||
data->accumulator += M_PI_M2 / 50.0;
|
mcs->id = 0;
|
||||||
if (data->accumulator >= M_PI_M2)
|
mcs->x = (sin(data->accumulator) + 1.0) * 160.0 + 80;
|
||||||
data->accumulator -= M_PI_M2;
|
mcs->y = (cos(data->accumulator) + 1.0) * 100.0 + 50;
|
||||||
|
mcs->hotspot_x = 0;
|
||||||
|
mcs->hotspot_y = 0;
|
||||||
|
mcs->bitmap_offset = sizeof(struct spa_meta_cursor);
|
||||||
|
|
||||||
data->crop = (sin(data->accumulator) + 1.0) * 32.0;
|
mb = SPA_MEMBER(mcs, mcs->bitmap_offset, struct spa_meta_bitmap);
|
||||||
|
mb->format = data->type.video_format.ARGB;
|
||||||
|
mb->width = 64;
|
||||||
|
mb->height = 64;
|
||||||
|
mb->stride = 64 * 4;
|
||||||
|
mb->size = mb->stride * mb->height;
|
||||||
|
mb->offset = sizeof(struct spa_meta_bitmap);
|
||||||
|
|
||||||
|
bitmap = SPA_MEMBER(mb, mb->offset, uint32_t);
|
||||||
|
color = (cos(data->accumulator) + 1.0) * (1 << 23);
|
||||||
|
color |= 0xff000000;
|
||||||
|
|
||||||
|
for (i = 0; i < mb->height; i++) {
|
||||||
|
for (j = 0; j < mb->width; j++) {
|
||||||
|
int v = (i - 32) * (i - 32) + (j - 32) * (j - 32);
|
||||||
|
bitmap[i*64+j] = (v <= 32*32) ? color : 0x00000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < data->format.size.height; i++) {
|
for (i = 0; i < data->format.size.height; i++) {
|
||||||
|
|
@ -127,6 +155,10 @@ static void on_timeout(void *userdata, uint64_t expirations)
|
||||||
data->counter += 13;
|
data->counter += 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data->accumulator += M_PI_M2 / 50.0;
|
||||||
|
if (data->accumulator >= M_PI_M2)
|
||||||
|
data->accumulator -= M_PI_M2;
|
||||||
|
|
||||||
b->datas[0].chunk->size = b->datas[0].maxsize;
|
b->datas[0].chunk->size = b->datas[0].maxsize;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
@ -169,7 +201,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[3];
|
const struct spa_pod *params[4];
|
||||||
|
|
||||||
if (format == NULL) {
|
if (format == NULL) {
|
||||||
pw_stream_finish_format(stream, 0, NULL, 0);
|
pw_stream_finish_format(stream, 0, NULL, 0);
|
||||||
|
|
@ -195,8 +227,14 @@ on_stream_format_changed(void *_data, const struct spa_pod *format)
|
||||||
t->param.idMeta, t->param_meta.Meta,
|
t->param.idMeta, t->param_meta.Meta,
|
||||||
":", t->param_meta.type, "I", t->meta.VideoCrop,
|
":", t->param_meta.type, "I", t->meta.VideoCrop,
|
||||||
":", t->param_meta.size, "i", sizeof(struct spa_meta_video_crop));
|
":", t->param_meta.size, "i", sizeof(struct spa_meta_video_crop));
|
||||||
|
params[3] = spa_pod_builder_object(&b,
|
||||||
|
t->param.idMeta, t->param_meta.Meta,
|
||||||
|
":", t->param_meta.type, "I", data->type.meta_cursor,
|
||||||
|
":", t->param_meta.size, "i", sizeof(struct spa_meta_cursor) +
|
||||||
|
sizeof(struct spa_meta_bitmap) +
|
||||||
|
64 * 64 * 4);
|
||||||
|
|
||||||
pw_stream_finish_format(stream, 0, params, 3);
|
pw_stream_finish_format(stream, 0, params, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
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