#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#define WIDTH 640
#define HEIGHT 480
#define MAX_BUFFERS 64
#include "sdl.h"
struct pixel {
float r, g, b, a;
};
struct data {
const char *path;
SDL_Renderer *renderer;
SDL_Window *window;
SDL_Texture *texture;
SDL_Texture *cursor;
int32_t stride;
int counter;
SDL_Rect rect;
SDL_Rect cursor_rect;
bool is_yuv;
bool have_request_process;
};
static void handle_events(struct data *data)
{
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
break;
}
}
}
static void
on_process(void *_data)
{
struct data *data = _data;
void *sdata, *ddata;
int sstride, dstride, ostride;
uint32_t i, j;
uint8_t *src, *dst;
bool render_cursor = false;
b = NULL;
while (true) {
break;
if (b)
b = t;
}
if (b == NULL) {
return;
}
handle_events(data);
goto done;
}
void *cdata;
int cstride;
if (data->cursor == NULL) {
data->cursor = SDL_CreateTexture(data->renderer,
SDL_TEXTUREACCESS_STREAMING,
SDL_SetTextureBlendMode(data->cursor, SDL_BLENDMODE_BLEND);
}
if (SDL_LockTexture(data->cursor, NULL, &cdata, &cstride) < 0) {
fprintf(stderr, "Couldn't lock cursor texture: %s\n", SDL_GetError());
goto done;
}
dst = cdata;
memcpy(dst, src, ostride);
dst += cstride;
}
SDL_UnlockTexture(data->cursor);
render_cursor = true;
}
if (data->is_yuv) {
sstride = data->stride;
SDL_UpdateYUVTexture(data->texture,
NULL,
sdata,
sstride,
SPA_PTROFF(sdata, sstride * data->size.height,
void),
sstride / 2,
SPA_PTROFF(sdata, 5 * (sstride * data->size.height) / 4,
void),
sstride / 2);
}
else {
if (SDL_LockTexture(data->texture, NULL, &ddata, &dstride) < 0) {
fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError());
goto done;
}
ostride =
SPA_MIN(sstride, dstride);
src = sdata;
dst = ddata;
for (i = 0; i < data->size.height; i++) {
struct pixel *p = (struct pixel *) src;
for (j = 0; j < data->size.width; j++) {
dst[j * 4 + 0] =
SPA_CLAMP(p[j].r * 255.0f, 0, 255);
dst[j * 4 + 1] =
SPA_CLAMP(p[j].g * 255.0f, 0, 255);
dst[j * 4 + 2] =
SPA_CLAMP(p[j].b * 255.0f, 0, 255);
dst[j * 4 + 3] =
SPA_CLAMP(p[j].a * 255.0f, 0, 255);
}
src += sstride;
dst += dstride;
}
} else {
for (i = 0; i < data->size.height; i++) {
memcpy(dst, src, ostride);
src += sstride;
dst += dstride;
}
}
SDL_UnlockTexture(data->texture);
}
SDL_RenderClear(data->renderer);
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);
done:
}
static void enable_timeouts(struct data *data, bool enabled)
{
struct timespec timeout, interval, *to, *iv;
if (!enabled || data->have_request_process) {
to = iv = NULL;
} else {
timeout.tv_sec = 0;
timeout.tv_nsec = 1;
interval.tv_sec = 0;
to = &timeout;
iv = &interval;
}
data->timer, to, iv, false);
}
{
struct data *data = _data;
switch (state) {
break;
enable_timeouts(data, false);
break;
enable_timeouts(data, true);
break;
default:
break;
}
}
static void
on_stream_io_changed(void *_data, uint32_t id, void *area, uint32_t size)
{
struct data *data = _data;
switch (id) {
data->position = area;
break;
}
}
static void
on_trigger_done(void *_data)
{
struct data *data = _data;
}
static void on_timeout(void *userdata, uint64_t expirations)
{
struct data *data = userdata;
if (!data->have_request_process)
}
static void
on_command(
void *_data,
const struct spa_command *command)
{
struct data *data = _data;
data->have_request_process = true;
enable_timeouts(data, false);
break;
default:
break;
}
}
static void
on_stream_param_changed(
void *_data, uint32_t
id,
const struct spa_pod *param)
{
struct data *data = _data;
uint8_t params_buffer[1024];
Uint32 sdl_format;
void *d;
return;
fprintf(stderr, "got format:\n");
if (
spa_format_parse(param, &data->format.media_type, &data->format.media_subtype) < 0)
return;
return;
switch (data->format.media_subtype) {
sdl_format = id_to_sdl_format(data->format.info.raw.format);
data->format.info.raw.size.height);
mult = 1;
break;
return;
sdl_format = SDL_PIXELFORMAT_RGBA32;
data->position->video.size.height);
mult = 4;
break;
default:
sdl_format = SDL_PIXELFORMAT_UNKNOWN;
break;
}
if (sdl_format == SDL_PIXELFORMAT_UNKNOWN) {
return;
}
data->texture = SDL_CreateTexture(data->renderer,
sdl_format,
SDL_TEXTUREACCESS_STREAMING,
data->size.width,
data->size.height);
SDL_LockTexture(data->texture, NULL, &d, &data->stride);
SDL_UnlockTexture(data->texture);
switch(sdl_format) {
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
size = (data->stride * data->size.height) * 3 / 2;
data->is_yuv = true;
break;
default:
size = data->stride * data->size.height;
break;
}
data->rect.x = 0;
data->rect.y = 0;
data->rect.w = data->size.width;
data->rect.h = data->size.height;
#define CURSOR_META_SIZE(w,h) (sizeof(struct spa_meta_cursor) + \
sizeof(struct spa_meta_bitmap) + w * h * 4)
CURSOR_META_SIZE(64,64),
CURSOR_META_SIZE(1,1),
CURSOR_META_SIZE(256,256)));
}
.state_changed = on_stream_state_changed,
.io_changed = on_stream_io_changed,
.param_changed = on_stream_param_changed,
.process = on_process,
.trigger_done = on_trigger_done,
.command = on_command,
};
{
SDL_RendererInfo info;
SDL_GetRendererInfo(data->renderer, &info);
params[0] = sdl_build_formats(&info, b);
fprintf(stderr, "supported SDL formats:\n");
fprintf(stderr, "supported DSP formats:\n");
return 2;
}
static void do_quit(void *userdata, int signal_number)
{
struct data *data = userdata;
}
int main(int argc, char *argv[])
{
struct data data = { 0, };
uint8_t buffer[1024];
int res, n_params;
"video-play",
NULL),
&stream_events,
data.path = argc > 1 ? argv[1] : NULL;
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
fprintf(stderr, "can't initialize SDL: %s\n", SDL_GetError());
return -1;
}
if (SDL_CreateWindowAndRenderer
(WIDTH, HEIGHT, SDL_WINDOW_RESIZABLE, &
data.window, &
data.renderer)) {
fprintf(stderr, "can't create window: %s\n", SDL_GetError());
return -1;
}
n_params = build_format(&
data, &b, params);
params, n_params)) < 0) {
return -1;
}
SDL_DestroyTexture(
data.texture);
SDL_DestroyTexture(
data.cursor);
SDL_DestroyRenderer(
data.renderer);
SDL_DestroyWindow(
data.window);
return 0;
}