#define PL_MPEG_IMPLEMENTATION #include "datastream.h" #include "cell.h" #include "jsffi.h" #include "limits.h" #include #include #include "font.h" #include "render.h" #include #include "cbuf.h" QJSCLASS(datastream,) void datastream_free(JSRuntime *rt,datastream *ds) { plm_destroy(ds->plm); free(ds); } 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); uncaught_exception(ds->js,ret); } JSC_CCALL(os_make_video, size_t len; void *data = js_get_blob_data(js,&len,argv[0]); 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), }; JSValue js_video_use(JSContext *js) { JSValue mod = JS_NewObject(js); JS_SetPropertyFunctionList(js,mod,js_video_funcs,countof(js_video_funcs)); return mod; }