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:
Wim Taymans 2018-11-22 10:18:50 +01:00
parent 1ea84b2869
commit 16b6a51b78
3 changed files with 55 additions and 8 deletions

View file

@ -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',

View file

@ -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 = {

View file

@ -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));