mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-13 13:30:05 -05:00
examples: add video crop example
Add support for video crop metadata in video-play and draw only the cropped areas. Add support for video crop in video-src and make it generate cropping regions that grow and shrink dynamically.
This commit is contained in:
parent
1ea84b2869
commit
16b6a51b78
3 changed files with 55 additions and 8 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
executable('video-src',
|
executable('video-src',
|
||||||
'video-src.c',
|
'video-src.c',
|
||||||
install: false,
|
install: false,
|
||||||
dependencies : [pipewire_dep],
|
dependencies : [pipewire_dep, mathlib],
|
||||||
)
|
)
|
||||||
executable('export-source',
|
executable('export-source',
|
||||||
'export-source.c',
|
'export-source.c',
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ struct data {
|
||||||
int32_t stride;
|
int32_t stride;
|
||||||
|
|
||||||
int counter;
|
int counter;
|
||||||
|
SDL_Rect rect;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void handle_events(struct data *data)
|
static void handle_events(struct data *data)
|
||||||
|
|
@ -96,6 +97,7 @@ on_stream_process(void *_data)
|
||||||
struct spa_buffer *b;
|
struct spa_buffer *b;
|
||||||
void *sdata, *ddata;
|
void *sdata, *ddata;
|
||||||
int sstride, dstride, ostride;
|
int sstride, dstride, ostride;
|
||||||
|
struct spa_meta_video_crop *mc;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint8_t *src, *dst;
|
uint8_t *src, *dst;
|
||||||
|
|
||||||
|
|
@ -114,6 +116,17 @@ on_stream_process(void *_data)
|
||||||
fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError());
|
fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError());
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
if ((mc = spa_buffer_find_meta(b, data->t->meta.VideoCrop))) {
|
||||||
|
if (data->rect.x != mc->x ||
|
||||||
|
data->rect.y != mc->y ||
|
||||||
|
data->rect.w != mc->width ||
|
||||||
|
data->rect.h != mc->height) {
|
||||||
|
data->rect.x = mc->x;
|
||||||
|
data->rect.y = mc->y;
|
||||||
|
data->rect.w = mc->width;
|
||||||
|
data->rect.h = mc->height;
|
||||||
|
}
|
||||||
|
}
|
||||||
sstride = b->datas[0].chunk->stride;
|
sstride = b->datas[0].chunk->stride;
|
||||||
ostride = SPA_MIN(sstride, dstride);
|
ostride = SPA_MIN(sstride, dstride);
|
||||||
|
|
||||||
|
|
@ -127,7 +140,7 @@ on_stream_process(void *_data)
|
||||||
SDL_UnlockTexture(data->texture);
|
SDL_UnlockTexture(data->texture);
|
||||||
|
|
||||||
SDL_RenderClear(data->renderer);
|
SDL_RenderClear(data->renderer);
|
||||||
SDL_RenderCopy(data->renderer, data->texture, NULL, NULL);
|
SDL_RenderCopy(data->renderer, data->texture, &data->rect, NULL);
|
||||||
SDL_RenderPresent(data->renderer);
|
SDL_RenderPresent(data->renderer);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
@ -226,7 +239,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];
|
||||||
Uint32 sdl_format;
|
Uint32 sdl_format;
|
||||||
void *d;
|
void *d;
|
||||||
|
|
||||||
|
|
@ -254,6 +267,11 @@ 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->rect.x = 0;
|
||||||
|
data->rect.y = 0;
|
||||||
|
data->rect.w = data->format.size.width;
|
||||||
|
data->rect.h = data->format.size.height;
|
||||||
|
|
||||||
params[0] = spa_pod_builder_object(&b,
|
params[0] = spa_pod_builder_object(&b,
|
||||||
t->param.idBuffers, t->param_buffers.Buffers,
|
t->param.idBuffers, t->param_buffers.Buffers,
|
||||||
":", t->param_buffers.size, "i", data->stride * data->format.size.height,
|
":", t->param_buffers.size, "i", data->stride * data->format.size.height,
|
||||||
|
|
@ -266,8 +284,12 @@ 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.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));
|
||||||
|
params[2] = spa_pod_builder_object(&b,
|
||||||
|
t->param.idMeta, t->param_meta.Meta,
|
||||||
|
":", t->param_meta.type, "I", t->meta.VideoCrop,
|
||||||
|
":", t->param_meta.size, "i", sizeof(struct spa_meta_video_crop));
|
||||||
|
|
||||||
pw_stream_finish_format(stream, 0, params, 2);
|
pw_stream_finish_format(stream, 0, params, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct pw_stream_events stream_events = {
|
static const struct pw_stream_events stream_events = {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <math.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
#include <spa/support/type-map.h>
|
#include <spa/support/type-map.h>
|
||||||
|
|
@ -44,7 +45,12 @@ static inline void init_type(struct type *type, struct spa_type_map *map)
|
||||||
spa_type_video_format_map(map, &type->video_format);
|
spa_type_video_format_map(map, &type->video_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BPP 3
|
#define BPP 3
|
||||||
|
#define WIDTH 320
|
||||||
|
#define HEIGHT 200
|
||||||
|
#define CROP 8
|
||||||
|
|
||||||
|
#define M_PI_M2 ( M_PI + M_PI )
|
||||||
|
|
||||||
struct data {
|
struct data {
|
||||||
struct type type;
|
struct type type;
|
||||||
|
|
@ -65,6 +71,8 @@ struct data {
|
||||||
|
|
||||||
int counter;
|
int counter;
|
||||||
uint32_t seq;
|
uint32_t seq;
|
||||||
|
double crop;
|
||||||
|
double accumulator;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void on_timeout(void *userdata, uint64_t expirations)
|
static void on_timeout(void *userdata, uint64_t expirations)
|
||||||
|
|
@ -73,6 +81,7 @@ static void on_timeout(void *userdata, uint64_t expirations)
|
||||||
int i, j;
|
int i, j;
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
struct spa_meta_header *h;
|
struct spa_meta_header *h;
|
||||||
|
struct spa_meta_video_crop *mc;
|
||||||
struct pw_buffer *buf;
|
struct pw_buffer *buf;
|
||||||
struct spa_buffer *b;
|
struct spa_buffer *b;
|
||||||
|
|
||||||
|
|
@ -97,6 +106,18 @@ 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 ((mc = spa_buffer_find_meta(b, data->t->meta.VideoCrop))) {
|
||||||
|
mc->x = data->crop;
|
||||||
|
mc->y = data->crop;
|
||||||
|
mc->width = WIDTH - data->crop*2;
|
||||||
|
mc->height = HEIGHT - data->crop*2;
|
||||||
|
|
||||||
|
data->accumulator += M_PI_M2 / 50.0;
|
||||||
|
if (data->accumulator >= M_PI_M2)
|
||||||
|
data->accumulator -= M_PI_M2;
|
||||||
|
|
||||||
|
data->crop = (sin(data->accumulator) + 1.0) * 32.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++) {
|
||||||
|
|
@ -148,7 +169,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);
|
||||||
|
|
@ -170,8 +191,12 @@ 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.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));
|
||||||
|
params[2] = spa_pod_builder_object(&b,
|
||||||
|
t->param.idMeta, t->param_meta.Meta,
|
||||||
|
":", t->param_meta.type, "I", t->meta.VideoCrop,
|
||||||
|
":", t->param_meta.size, "i", sizeof(struct spa_meta_video_crop));
|
||||||
|
|
||||||
pw_stream_finish_format(stream, 0, params, 2);
|
pw_stream_finish_format(stream, 0, params, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct pw_stream_events stream_events = {
|
static const struct pw_stream_events stream_events = {
|
||||||
|
|
@ -214,7 +239,7 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo
|
||||||
"I", data->type.media_type.video,
|
"I", data->type.media_type.video,
|
||||||
"I", data->type.media_subtype.raw,
|
"I", data->type.media_subtype.raw,
|
||||||
":", data->type.format_video.format, "I", data->type.video_format.RGB,
|
":", data->type.format_video.format, "I", data->type.video_format.RGB,
|
||||||
":", data->type.format_video.size, "Rru", &SPA_RECTANGLE(320, 240),
|
":", data->type.format_video.size, "Rru", &SPA_RECTANGLE(WIDTH, HEIGHT),
|
||||||
SPA_POD_PROP_MIN_MAX(&SPA_RECTANGLE(1, 1),
|
SPA_POD_PROP_MIN_MAX(&SPA_RECTANGLE(1, 1),
|
||||||
&SPA_RECTANGLE(4096, 4096)),
|
&SPA_RECTANGLE(4096, 4096)),
|
||||||
":", data->type.format_video.framerate, "F", &SPA_FRACTION(25, 1));
|
":", data->type.format_video.framerate, "F", &SPA_FRACTION(25, 1));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue