Files
prosperon/datastream.c
2025-12-19 16:42:40 -06:00

119 lines
3.3 KiB
C

#include "cell.h"
#define PL_MPEG_IMPLEMENTATION
#include "pl_mpeg.h"
struct datastream {
plm_t *plm;
JSValue callback;
JSContext *js;
int width;
int height;
};
typedef struct datastream datastream;
#include "cell.h"
#include "limits.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "cbuf.h"
void datastream_free(JSRuntime *rt,datastream *ds)
{
plm_destroy(ds->plm);
free(ds);
}
QJSCLASS(datastream,)
struct datastream *ds_openvideo(void *raw, size_t rawlen)
{
struct datastream *ds = malloc(sizeof(*ds));
void *newraw = malloc(rawlen);
memcpy(newraw,raw,rawlen);
ds->plm = plm_create_with_memory(newraw, rawlen, 1);
if (!ds->plm) {
free(ds);
free(newraw);
return NULL;
}
return ds;
}
void ds_advance(struct datastream *ds, double s) {
plm_decode(ds->plm, s);
}
void ds_seek(struct datastream *ds, double time) {
plm_seek(ds->plm, time, false);
}
double ds_length(struct datastream *ds) {
return plm_get_duration(ds->plm);
}
JSC_CCALL(datastream_time, return number2js(js,plm_get_time(js2datastream(js,self)->plm)); )
JSC_CCALL(datastream_seek, ds_seek(js2datastream(js,self), js2number(js,argv[0])))
JSC_CCALL(datastream_advance, ds_advance(js2datastream(js,self), js2number(js,argv[0])))
JSC_CCALL(datastream_duration, return number2js(js,ds_length(js2datastream(js,self))))
JSC_CCALL(datastream_framerate, return number2js(js,plm_get_framerate(js2datastream(js,self)->plm)))
JSC_GETSET_CALLBACK(datastream, callback)
static const JSCFunctionListEntry js_datastream_funcs[] = {
MIST_FUNC_DEF(datastream, time, 0),
MIST_FUNC_DEF(datastream, seek, 1),
MIST_FUNC_DEF(datastream, advance, 1),
MIST_FUNC_DEF(datastream, duration, 0),
MIST_FUNC_DEF(datastream, framerate, 0),
CGETSET_ADD(datastream, callback),
};
static void render_frame(plm_t *mpeg, plm_frame_t *frame, void *d) {
datastream *ds = d;
if (JS_IsNull(ds->callback)) return;
uint8_t *rgb = malloc(frame->height*frame->width*4);
memset(rgb,255,frame->height*frame->width*4);
plm_frame_to_rgba(frame, rgb, frame->width*4);
// Create surface data object instead of SDL_Surface
JSValue surfData = JS_NewObject(ds->js);
JS_SetPropertyStr(ds->js, surfData, "width", JS_NewInt32(ds->js, frame->width));
JS_SetPropertyStr(ds->js, surfData, "height", JS_NewInt32(ds->js, frame->height));
JS_SetPropertyStr(ds->js, surfData, "format", JS_NewString(ds->js, "rgba32"));
JS_SetPropertyStr(ds->js, surfData, "pitch", JS_NewInt32(ds->js, frame->width*4));
JS_SetPropertyStr(ds->js, surfData, "pixels", js_new_blob_stoned_copy(ds->js, rgb, frame->height*frame->width*4));
JSValue s[1];
s[0] = surfData;
JSValue cb = JS_DupValue(ds->js,ds->callback);
JSValue ret = JS_Call(ds->js, cb, JS_NULL, 1, s);
JS_FreeValue(ds->js,cb);
free(rgb);
// TODO: raise exception
}
JSC_CCALL(os_make_video,
size_t len;
void *data = js_get_blob_data(js,&len,argv[0]);
if (data == -1 || !data) return JS_EXCEPTION;
datastream *ds = ds_openvideo(data, len);
if (!ds) return JS_ThrowReferenceError(js, "Video file was not valid.");
ds->js = js;
ds->callback = JS_NULL;
plm_set_video_decode_callback(ds->plm, render_frame, ds);
return datastream2js(js,ds);
)
static const JSCFunctionListEntry js_video_funcs[] = {
MIST_FUNC_DEF(os, make_video, 1),
};
CELL_USE_FUNCS(js_video_funcs)