From 87df6921e83bba3d1166979d1bd93fa1373bc07e Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Sun, 6 Feb 2022 16:14:57 +0000 Subject: [PATCH] Turned on warnings and fixed --- Makefile | 17 +- source/editor/debug.c | 2 +- source/editor/editor.cpp | 371 +- source/editor/editor.h | 19 +- source/engine/2dphysics.c | 6 - source/engine/3dphysics.h | 1 + source/engine/camera.c | 14 +- source/engine/config.h | 2 +- source/engine/datastream.c | 41 +- source/engine/datastream.h | 8 +- source/engine/engine.c | 45 +- source/engine/engine.h | 10 +- source/engine/font.c | 12 +- source/engine/gameobject.c | 7 +- source/engine/gizmo.h | 6 + source/engine/input.c | 52 +- source/engine/input.h | 16 +- source/engine/level.c | 1 + source/engine/light.c | 2 +- source/engine/light.h | 9 +- source/engine/log.c | 21 +- source/engine/log.h | 14 +- source/engine/mathc.c | 5 +- source/engine/mesh.c | 22 +- source/engine/model.c | 1 + source/engine/openglrender.c | 45 +- source/engine/openglrender.h | 3 +- source/engine/registry.c | 2 +- source/engine/render.h | 8 +- source/engine/resources.c | 11 +- source/engine/resources.h | 4 +- source/engine/script.c | 2 +- source/engine/script.h | 2 +- source/engine/shader.c | 10 +- source/engine/skybox.c | 10 +- source/engine/sound.c | 35 +- source/engine/sound.h | 13 +- source/engine/sprite.c | 11 +- source/engine/sprite.h | 10 +- source/engine/texture.c | 22 +- source/engine/texture.h | 14 +- source/engine/thirdparty/enet/src/win32.c | 25 +- .../thirdparty/pl_mpeg/include/pl_mpeg.h | 3710 +---------------- source/engine/thirdpersonfollow.c | 6 - source/engine/thirdpersonfollow.h | 1 - source/engine/vec.c | 11 +- source/engine/vec.h | 8 +- source/engine/window.c | 90 +- source/engine/window.h | 18 +- source/engine/yugine.c | 41 +- 50 files changed, 570 insertions(+), 4246 deletions(-) diff --git a/Makefile b/Makefile index bafff9f..599684b 100755 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ endif UNAME_P != uname -m #CC specifies which compiler we're using -CC = clang +CC = clang -std=c99 CXX = clang++ ifeq ($(DEBUG), 1) @@ -58,7 +58,7 @@ ehead != $(call findindir,./source/engine,*.h) eobjects != $(call make_objs, ./source/engine) eobjects != $(call rm,$(eobjects),sqlite pl_mpeg_extract_frames pl_mpeg_player yugine.c yugine.c) -imguisrcs = imgui imgui_draw imgui_widgets imgui_tables backends/imgui_impl_sdl backends/imgui_impl_opengl3 +imguisrcs = imgui imgui_draw imgui_widgets imgui_tables backends/imgui_impl_glfw backends/imgui_impl_opengl3 imguiobjs != $(call prefix,$(imguisrcs),$(objprefix)/source/editor/imgui/,.o) eddirs != find ./source/editor -type d @@ -79,8 +79,8 @@ includeflag != $(call prefix,$(edirs) $(eddirs) $(pindirs) $(bsdirs),-I) COMPINCLUDE = $(edirs) $(eddirs) $(pindirs) $(bsdirs) #COMPILER_FLAGS specifies the additional compilation options we're using -WARNING_FLAGS = -w #-pedantic -Wall -Wextra -Wwrite-strings -COMPILER_FLAGS = $(includeflag) -g -O0 $(WARNING_FLAGS) -DGLEW_STATIC -c -MMD -MP $< -o $@ +WARNING_FLAGS = -Wall -Wextra -Wwrite-strings -Wno-unused-parameter -Wno-unused-function -Wno-missing-braces -Wno-incompatible-function-pointer-types -Wno-gnu-statement-expression -Wno-complex-component-init -pedantic +COMPILER_FLAGS = $(includeflag) -g -O0 $(WARNING_FLAGS) -DGLEW_STATIC -D_GLFW_X11 -D_POSIX_C_SOURCE=1993809L -c -MMD -MP $< -o $@ LIBPATH = -L./bin @@ -93,7 +93,7 @@ ifeq ($(UNAME), Windows_NT) else LINKER_FLAGS = ELIBS = editor engine - CLIBS = SDL2 SDL2_mixer GLEW GL dl pthread + CLIBS = glfw SDL2 SDL2_mixer dl pthread EXT = endif @@ -119,10 +119,13 @@ LINK = $(LIBPATH) $(LINKER_FLAGS) $(LELIBS) -o $@ engine: $(yuginec:.%.c=$(objprefix)%.o) $(ENGINE) @echo Linking engine @$(CXX) $< $(linkinclude:%=-I%) $(LINK) + @echo Finished build editor: $(yuginec:.%.c=$(objprefix)%.o) $(EDITOR) $(ENGINE) @echo Linking editor $(CXX) $< $(linkinclude:%=-I%) $(LINK) + @mv editor yugine/editor + @echo Finished build $(ENGINE): $(eobjects) @echo Making library engine.a @@ -147,12 +150,12 @@ pinball: $(ENGINE) $(pinobjects) $(objprefix)/%.o:%.cpp @mkdir -p $(@D) @echo Making C++ object $@ - @$(CXX) $(COMPILER_FLAGS) + -@$(CXX) $(COMPILER_FLAGS) $(objprefix)/%.o:%.c @mkdir -p $(@D) @echo Making C object $@ - @$(CC) $(COMPILER_FLAGS) + -@$(CC) $(COMPILER_FLAGS) clean: @echo Cleaning project diff --git a/source/editor/debug.c b/source/editor/debug.c index efccac7..cdcfd76 100755 --- a/source/editor/debug.c +++ b/source/editor/debug.c @@ -5,4 +5,4 @@ unsigned long long triCount = 0; void resetTriangles() { triCount = 0; -} \ No newline at end of file +} diff --git a/source/editor/editor.cpp b/source/editor/editor.cpp index 8b9a31e..9a7690c 100755 --- a/source/editor/editor.cpp +++ b/source/editor/editor.cpp @@ -1,4 +1,5 @@ extern "C" { +#include "openglrender.h" #include "editor.h" #include "window.h" #include "resources.h" @@ -12,7 +13,6 @@ extern "C" { #include "editorstate.h" #include #include "input.h" -#include "openglrender.h" #include "2dphysics.h" #include "debugdraw.h" #include "level.h" @@ -20,7 +20,6 @@ extern "C" { #include "sprite.h" #include #include "math.h" -#include #include #include #include "pinball.h" @@ -32,20 +31,13 @@ extern "C" { #include #define ASSET_TEXT_BUF 1024*1024 /* 1 MB buffer for editing text files */ #include -#include +#include #include struct gameproject *cur_project; struct vec *projects; static char setpath[MAXPATH]; - - - - - - - // Menus // TODO: Pack this into a bitfield static struct editorVars editor = { 0 }; @@ -55,14 +47,11 @@ bool flashlightOn = false; // Lighting effect flags static bool renderAO = true; static bool renderDynamicShadows = true; -static bool renderRefraction = true; -static bool renderReflection = true; // Debug render modes static bool renderGizmos = false; static bool showGrid = true; static bool debugDrawPhysics = false; -static bool renderNav = false; const char *allowed_extensions[] = { "jpg", "png", "gltf", "glsl" }; @@ -79,10 +68,6 @@ struct fileasset *selected_asset; static int selected_index = -1; -static struct mCamera camera = { 0 }; - -static int tex_view = 0; - static int grid1_width = 1; static int grid1_span = 100; static int grid2_width = 3; @@ -260,6 +245,155 @@ void editor_save() fclose(feditor); } +static void edit_input_cb(GLFWwindow *w, int key, int scancode, int action, int mods) +{ + if (editor_wantkeyboard()) return; + + switch (key) { + case GLFW_KEY_ESCAPE: + quit = true; + editor_save_projects(); + editor_save(); + break; + + case GLFW_KEY_1: + renderMode = LIT; + break; + + case GLFW_KEY_2: + renderMode = UNLIT; + break; + + case GLFW_KEY_3: + renderMode = WIREFRAME; + break; + + case GLFW_KEY_4: + renderMode = DIRSHADOWMAP; + break; + + case GLFW_KEY_5: + renderGizmos = !renderGizmos; + break; + + case GLFW_KEY_6: + debugDrawPhysics = !debugDrawPhysics; + break; + + case GLFW_KEY_7: + break; + + case GLFW_KEY_8: + break; + + case GLFW_KEY_9: + break; + + case GLFW_KEY_0: + break; + + case GLFW_KEY_T: + break; + + case GLFW_KEY_F2: + editor.showAssetMenu = !editor.showAssetMenu; + break; + + case GLFW_KEY_F3: + editor.showStats = !editor.showStats; + break; + + case GLFW_KEY_F4: + editor.showHierarchy = !editor.showHierarchy; + break; + + case GLFW_KEY_F5: + editor.showLighting = !editor.showLighting; + break; + + case GLFW_KEY_F6: + editor.showGameSettings = !editor.showGameSettings; + break; + + case GLFW_KEY_F7: + editor.showViewmode = !editor.showViewmode; + break; + + case GLFW_KEY_F8: + editor.showDebugMenu = !editor.showDebugMenu; + break; + + case GLFW_KEY_F9: + editor.showExport = !editor.showExport; + break; + + case GLFW_KEY_F10: + editor.showLevel = !editor.showLevel; + break; + + case GLFW_KEY_F11: + window_togglefullscreen(mainwin); + break; + + case GLFW_KEY_GRAVE_ACCENT: + editor.showREPL = !editor.showREPL; + break; + + case GLFW_KEY_K: + showGrid = !showGrid; + break; + + case GLFW_KEY_DELETE: + break; + + case GLFW_KEY_F: + /* + if (selectedobject != NULL) { + cam_goto_object(&camera, &selectedobject->transform); + } + */ + break; + + } +} + +static void edit_mouse_cb(GLFWwindow *w, int button, int action, int mods) +{ + if (editor_wantkeyboard()) return; + + if (action == GLFW_PRESS) { + switch (button) { + case GLFW_MOUSE_BUTTON_RIGHT: + cursor_hide(); + break; + + case GLFW_MOUSE_BUTTON_MIDDLE: + /* + glBindFramebuffer(GL_FRAMEBUFFER, debugColorPickBO); + int mx = 0; + int my = 0; + SDL_GetMouseState(&mx, &my); + unsigned char data[4]; + glReadPixels(mx, SCREEN_HEIGHT - my, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data); + int pickID = data[0] + data[1]*256 + data[2]*256*256; + snprintf(objectName, 200, "Object %d", pickID); + pickGameObject(pickID); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + */ + + pickGameObject(-1); + + break; + } + } else if (action == GLFW_RELEASE) { + switch (button) { + case GLFW_MOUSE_BUTTON_RIGHT: + cursor_show(); + break; + } + } +} + void editor_init(struct mSDLWindow *window) { projects = vec_make(sizeof(struct gameproject), 5); @@ -276,197 +410,24 @@ void editor_init(struct mSDLWindow *window) - IMGUI_CHECKVERSION(); ImGui::CreateContext(); - ImGuiIO & io = ImGui::GetIO(); - (void) io; ImGui::StyleColorsClassic(); - ImGui_ImplSDL2_InitForOpenGL(window->window, window->glContext); + ImGui_ImplGlfw_InitForOpenGL(window->window, true); ImGui_ImplOpenGL3_Init(); + + glfwSetKeyCallback(window->window, edit_input_cb); + glfwSetMouseButtonCallback(window->window, edit_mouse_cb); } -void editor_input(struct mSDLWindow *window, SDL_Event * e) +void editor_input() { - ImGui_ImplSDL2_ProcessEvent(e); io = &ImGui::GetIO(); - - - //User requests quit - if (e->type == SDL_QUIT) { - quit = true; - } - //Handle keypress with current mouse position - else if (!editor_wantkeyboard() && e->type == SDL_KEYDOWN) { - switch (e->key.keysym.sym) { - case SDLK_ESCAPE: - quit = true; - editor_save_projects(); - editor_save(); - break; - - case SDLK_1: - renderMode = LIT; - break; - - case SDLK_2: - renderMode = UNLIT; - break; - - case SDLK_3: - renderMode = WIREFRAME; - break; - - case SDLK_4: - renderMode = DIRSHADOWMAP; - break; - - case SDLK_5: - renderGizmos = !renderGizmos; - break; - - case SDLK_6: - debugDrawPhysics = !debugDrawPhysics; - break; - - case SDLK_7: - break; - - case SDLK_8: - break; - - case SDLK_9: - break; - - case SDLK_0: - break; - - case SDLK_t: - break; - - case SDLK_F2: - editor.showAssetMenu = !editor.showAssetMenu; - break; - - case SDLK_F3: - editor.showStats = !editor.showStats; - break; - - case SDLK_F4: - editor.showHierarchy = !editor.showHierarchy; - break; - - case SDLK_F5: - editor.showLighting = !editor.showLighting; - break; - - case SDLK_F6: - editor.showGameSettings = !editor.showGameSettings; - break; - - case SDLK_F7: - editor.showViewmode = !editor.showViewmode; - break; - - case SDLK_F8: - editor.showDebugMenu = !editor.showDebugMenu; - break; - - case SDLK_F9: - editor.showExport = !editor.showExport; - break; - - case SDLK_F10: - editor.showLevel = !editor.showLevel; - break; - - case SDLK_F11: - window_togglefullscreen(window); - break; - - case SDLK_BACKQUOTE: - editor.showREPL = !editor.showREPL; - break; - - case SDLK_k: - showGrid = !showGrid; - break; - - case SDLK_DELETE: - break; - - case SDLK_f: - /* - if (selectedobject != NULL) { - cam_goto_object(&camera, &selectedobject->transform); - } - */ - break; - - }; - } else if (!editor_wantkeyboard() && e->type == SDL_MOUSEBUTTONDOWN) { - if (selectedobject != NULL) { - switch (e->key.keysym.sym) { - case SDLK_g: - // handle translate - break; - - case SDLK_r: - break; - - case SDLK_t: - break; - } - } - switch (e->button.button) { - case SDL_BUTTON_RIGHT: - SDL_SetRelativeMouseMode(SDL_TRUE); - break; - - case SDL_BUTTON_MIDDLE: -/* - glBindFramebuffer(GL_FRAMEBUFFER, debugColorPickBO); - int mx = 0; - int my = 0; - SDL_GetMouseState(&mx, &my); - unsigned char data[4]; - glReadPixels(mx, SCREEN_HEIGHT - my, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data); - int pickID = data[0] + data[1]*256 + data[2]*256*256; - snprintf(objectName, 200, "Object %d", pickID); - pickGameObject(pickID); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - */ - - pickGameObject(-1); - - break; - } - - } else if (!editor_wantkeyboard() && e->type == SDL_MOUSEBUTTONUP) { - switch (e->button.button) { - case SDL_BUTTON_RIGHT: - - SDL_SetRelativeMouseMode(SDL_FALSE); - SDL_WarpMouseInWindow(window->window, SCREEN_WIDTH / 2.f, - SCREEN_HEIGHT / 2.f); - break; - } - } else if (e->type == SDL_MOUSEWHEEL) { - mouseWheelY = e->wheel.y; - } - - - - - SDL_GetRelativeMouseState(&xchange, &ychange); - - if (SDL_GetRelativeMouseMode()) { - // camera_update(&camera, xchange, ychange, currentKeyStates, mouseWheelY, deltaT); - } } int editor_wantkeyboard() { + if (io == NULL) return 0; return io->WantCaptureKeyboard; } @@ -589,7 +550,7 @@ void editor_project_gui() if (editor.showStats) { ImGui::Begin("Stats", &editor.showStats); ImGui::Text("FPS: %2.4f", 1.f / deltaT); - ImGui::Text("Triangles rendered: %d", triCount); + ImGui::Text("Triangles rendered: %llu", triCount); ImGui::End(); } @@ -789,7 +750,7 @@ void editor_project_gui() void editor_render() { ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplSDL2_NewFrame(); + ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); @@ -817,7 +778,7 @@ void pickGameObject(int pickID) int is_allowed_extension(const char *ext) { - for (int i = 0; + for (size_t i = 0; i < sizeof(allowed_extensions) / sizeof(allowed_extensions[0]); i++) { if (!strcmp(ext + 1, allowed_extensions[i])) @@ -1019,7 +980,7 @@ void editor_project_btn_gui(struct gameproject *gp) ImGui::SameLine(); - ImGui::Text(gp->path); + ImGui::Text("%s", gp->path); } void editor_proj_select_gui() @@ -1053,7 +1014,7 @@ void editor_init_project(struct gameproject *gp) void editor_make_project(char *path) { - FILE *f = path_open("%s%s", "w", path, "/project.yugh"); + FILE *f = path_open("w", "%s%s", path, "/project.yugh"); cur_project = (struct gameproject *) malloc(sizeof(struct gameproject)); strncpy(cur_project->name, "New Game", 127); @@ -1069,7 +1030,7 @@ void editor_make_project(char *path) void editor_import_project(char *path) { - FILE *f = path_open("%s%s", "r", path, "/project.yugh"); + FILE *f = path_open("r", "%s%s", path, "/project.yugh"); if (!f) return; @@ -1133,7 +1094,7 @@ void staticactor_gui(struct mStaticActor *sa) object_gui(&sa->obj); if (ImGui::CollapsingHeader("Model")) { ImGui::Checkbox("Cast Shadows", &sa->castShadows); - ImGui::Text("Model path", &sa->currentModelPath); + ImGui::Text("Model path: %s", sa->currentModelPath); ImGui::SameLine(); if (ImGui::Button("Load model")) { @@ -1237,10 +1198,6 @@ void object_gui(struct mGameObject *go) } - end: - - - ImGui::PopID(); } diff --git a/source/editor/editor.h b/source/editor/editor.h index 15b68f1..a623a6f 100755 --- a/source/editor/editor.h +++ b/source/editor/editor.h @@ -2,7 +2,6 @@ #define EDITOR_H #include -#include #include #include "resources.h" @@ -41,12 +40,13 @@ struct gameproject { }; struct Texture; +struct mSDLWindow; void pickGameObject(int pickID); int is_allowed_extension(const char *ext); void editor_init(struct mSDLWindow *window); -void editor_input(struct mSDLWindow *window, SDL_Event * e); +void editor_input(); void editor_render(); int editor_wantkeyboard(); void editor_save(); @@ -77,6 +77,21 @@ void game_pause(); void get_levels(); +struct mLight; +struct mPointLight; +struct mSpotLight; +struct mStaticActor; +struct mTransform; +struct mGameObject; +struct mSprite; +struct phys2d_circle; +struct phys2d_segment; +struct phys2d_box; +struct phys2d_edge; +struct phys2d_shape; +struct phys2d_poly; +struct flipper; + ///////// Object GUIs void light_gui(struct mLight *light); void pointlight_gui(struct mPointLight *light); diff --git a/source/engine/2dphysics.c b/source/engine/2dphysics.c index 0ce7077..364967f 100755 --- a/source/engine/2dphysics.c +++ b/source/engine/2dphysics.c @@ -98,9 +98,6 @@ struct phys2d_box *Make2DBox(struct mGameObject *go) void phys2d_boxinit(struct phys2d_box *box, struct mGameObject *go) { - cpVect verts[4] = - { { -5.f, -5.f }, { 5.f, -5.f }, { 5.f, 5.f }, { -5.f, 5.f } }; - cpTransform T = { 0 }; box->shape.shape = cpSpaceAddShape(space, cpBoxShapeNew(go->body, box->w, box->h, box->r)); @@ -291,7 +288,6 @@ void phys2d_dbgdrawcircle(struct phys2d_circle *circle) void phys2d_dbgdrawseg(struct phys2d_segment *seg) { cpVect p = cpBodyGetPosition(seg->shape.go->body); - float s = seg->shape.go->scale; cpVect a = cpSegmentShapeGetA(seg->shape.shape); cpVect b = cpSegmentShapeGetB(seg->shape.shape); @@ -329,7 +325,6 @@ void phys2d_dbgdrawpoly(struct phys2d_poly *poly) float s = poly->shape.go->scale; for (int i = 0; i < poly->n; i++) { - float point[2]; float d = sqrt(pow(poly->points[i * 2] * s, 2.f) + pow(poly->points[i * 2 + 1] * s, 2.f)); @@ -362,7 +357,6 @@ void phys2d_dbgdrawedge(struct phys2d_edge *edge) float angle = cpBodyGetAngle(edge->shape.go->body); for (int i = 0; i < edge->n; i++) { - float point[2]; float d = sqrt(pow(edge->points[i * 2] * s, 2.f) + pow(edge->points[i * 2 + 1] * s, 2.f)); diff --git a/source/engine/3dphysics.h b/source/engine/3dphysics.h index 3d6a394..3097c22 100755 --- a/source/engine/3dphysics.h +++ b/source/engine/3dphysics.h @@ -1,4 +1,5 @@ #ifndef THREEDPHYSICS_H #define THREEDPHYSICS_H + #endif diff --git a/source/engine/camera.c b/source/engine/camera.c index 6f9c00b..e63e5fa 100755 --- a/source/engine/camera.c +++ b/source/engine/camera.c @@ -2,7 +2,7 @@ #include "gameobject.h" #include "input.h" -#include + const float CAMERA_MINSPEED = 1.f; const float CAMERA_MAXSPEED = 300.f; @@ -41,20 +41,18 @@ mfloat_t *getviewmatrix(mfloat_t view[16], void camera_2d_update(struct mCamera *camera, float deltaT) { - static mfloat_t holdvec[3]; static mfloat_t frame[3]; vec3_zero(frame); - - if (currentKeystates[SDL_SCANCODE_W]) + if (action_down(GLFW_KEY_W)) vec3_add(frame, frame, UP); - if (currentKeystates[SDL_SCANCODE_S]) + if (action_down(GLFW_KEY_S)) vec3_add(frame, frame, DOWN); - if (currentKeystates[SDL_SCANCODE_A]) + if (action_down(GLFW_KEY_A)) vec3_add(frame, frame, LEFT); - if (currentKeystates[SDL_SCANCODE_D]) + if (action_down(GLFW_KEY_D)) vec3_add(frame, frame, RIGHT); - float speedMult = currentKeystates[SDL_SCANCODE_LSHIFT] ? 2.f : 1.f; + float speedMult = action_down(GLFW_KEY_LEFT_SHIFT) ? 2.f : 1.f; if (!vec3_is_zero(frame)) { vec3_normalize(frame, frame); diff --git a/source/engine/config.h b/source/engine/config.h index 0a84fdd..fc1af51 100755 --- a/source/engine/config.h +++ b/source/engine/config.h @@ -18,4 +18,4 @@ -#endif \ No newline at end of file +#endif diff --git a/source/engine/datastream.c b/source/engine/datastream.c index bb06286..ed29cfb 100755 --- a/source/engine/datastream.c +++ b/source/engine/datastream.c @@ -1,12 +1,12 @@ #include "datastream.h" -#include - +#include "render.h" #include "config.h" #include "shader.h" #include "resources.h" -#include +#include "sound.h" #include +#include "log.h" static void ds_update_texture(uint32_t unit, uint32_t texture, plm_plane_t * plane) @@ -30,11 +30,10 @@ static void render_audio(plm_t * mpeg, plm_samples_t * samples, void *user) { struct datastream *ds = (struct datastream *) user; int size = sizeof(float) * samples->count * 2; - SDL_QueueAudio(ds->audio_device, samples->interleaved, size); + play_raw(ds->audio_device, samples->interleaved, size); } -void ds_openvideo(struct datastream *ds, const char *video, - const char *adriver) +void ds_openvideo(struct datastream *ds, const char *video, const char *adriver) { ds_stop(ds); char buf[MAXPATH] = {'\0'}; @@ -42,12 +41,10 @@ void ds_openvideo(struct datastream *ds, const char *video, ds->plm = plm_create_with_filename(buf); if (!ds->plm) { - SDL_Log("Couldn't open %s", video); + YughLog(0, 0, "Couldn't open %s", video); } - int samplerate = plm_get_samplerate(ds->plm); - - SDL_Log("Opened %s - framerate: %f, samplerate: %d, duration: %f", + YughLog(0, 0, "Opened %s - framerate: %f, samplerate: %d, duration: %f", video, plm_get_framerate(ds->plm), plm_get_samplerate(ds->plm), plm_get_duration(ds->plm) @@ -59,24 +56,6 @@ void ds_openvideo(struct datastream *ds, const char *video, plm_set_audio_enabled(ds->plm, true); plm_set_audio_stream(ds->plm, 0); - SDL_AudioSpec audio_spec; - SDL_memset(&audio_spec, 0, sizeof(audio_spec)); - audio_spec.freq = samplerate; - audio_spec.format = AUDIO_F32; - audio_spec.channels = 2; - audio_spec.samples = 4096; - - ds->audio_device = - SDL_OpenAudioDevice(adriver, 0, &audio_spec, NULL, 0); - printf("Opened audio device %d on driver %s\n", ds->audio_device, - adriver); - // if (audio_device == 0) { - // SDL_Log("Failed to open audio device: %s", SDL_GetError()); - // } - SDL_PauseAudioDevice(ds->audio_device, 0); - - - // Adjust the audio lead time according to the audio_spec buffer size //plm_set_audio_lead_time(plm, (double)audio_spec.samples / (double)samplerate); @@ -127,7 +106,7 @@ void ds_advance(struct datastream *ds, uint32_t ms) void ds_seek(struct datastream *ds, uint32_t time) { - SDL_ClearQueuedAudio(0); + clear_raw(ds->audio_device); plm_seek(ds->plm, time, false); } @@ -151,7 +130,7 @@ void ds_stop(struct datastream *ds) ds->plm = NULL; } if (ds->audio_device) - SDL_CloseAudioDevice(ds->audio_device); + close_audio_device(ds->audio_device); ds->playing = false; } @@ -173,4 +152,4 @@ double ds_remainingtime(struct datastream *ds) double ds_length(struct datastream *ds) { return plm_get_duration(ds->plm); -} \ No newline at end of file +} diff --git a/source/engine/datastream.h b/source/engine/datastream.h index 6b5ab35..ec84d28 100755 --- a/source/engine/datastream.h +++ b/source/engine/datastream.h @@ -1,17 +1,15 @@ #ifndef DATASTREAM_H #define DATASTREAM_H -#include - -typedef struct plm_t plm_t; - +#include +#include struct datastream { plm_t *plm; struct mShader *shader; double last_time; int playing; - SDL_AudioDeviceID audio_device; + int audio_device; uint32_t texture_y; uint32_t texture_cb; uint32_t texture_cr; diff --git a/source/engine/engine.c b/source/engine/engine.c index 4876d8b..bfe8a02 100755 --- a/source/engine/engine.c +++ b/source/engine/engine.c @@ -1,6 +1,5 @@ #include "engine.h" -#define PL_MPEG_IMPLEMENTATION #define CGLTF_IMPLEMENTATION #define GL_GLEXT_PROTOTYPES #define STB_DS_IMPLEMENTATION @@ -14,8 +13,8 @@ #include #include -#include -#include +#include "render.h" + #include "openglrender.h" #include "window.h" #include "camera.h" @@ -26,51 +25,47 @@ #include "registry.h" #include "log.h" #include "resources.h" +#include "timer.h" +#include "script.h" +#include "vec.h" +#include "sound.h" // TODO: Init on the heap #include "engine.h" +void error_callback(int error, const char *description) +{ + fprintf(stderr, "Error: %s\n", description); +} + void engine_init() { - - - //Initialize SDL - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { - YughLog(0, SDL_LOG_PRIORITY_ERROR, - "SDL could not initialize! SDL Error: %s", SDL_GetError()); + /* Initialize GLFW */ + if (!glfwInit()) { + printf("Could not init GLFW\n"); } + glfwSetErrorCallback(error_callback); - //Use OpenGL 3.3 - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, - SDL_GL_CONTEXT_PROFILE_CORE); - - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2); /* How many x MSAA */ - - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1); - + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); resources_init(); script_init(); registry_init(); init_gameobjects(); + timer_init(); prefabs = vec_make(MAXNAME, 25); stbi_set_flip_vertically_on_load(1); phys2d_init(); gui_init(); sound_init(); - - Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048); } void engine_stop() { - SDL_StopTextInput(); - SDL_Quit(); -} \ No newline at end of file + glfwTerminate(); +} diff --git a/source/engine/engine.h b/source/engine/engine.h index 2e6f5ab..c4edcc8 100755 --- a/source/engine/engine.h +++ b/source/engine/engine.h @@ -3,11 +3,17 @@ #define FPS30 33 #define FPS60 17 -#define FPS120 8; +#define FPS120 8 #define FPS144 7 #define FPS300 3 +#define sFPS30 0.033 +#define sFPS60 0.017 +#define sFPS120 0.008 +#define sFPS144 0.007 +#define sFPS300 0.003 + void engine_init(); void engine_stop(); -#endif \ No newline at end of file +#endif diff --git a/source/engine/font.c b/source/engine/font.c index 53ce6db..5a92c49 100755 --- a/source/engine/font.c +++ b/source/engine/font.c @@ -1,11 +1,11 @@ #include "font.h" +#include "render.h" #include #include #include #include #include -#include #define STB_TRUETYPE_IMPLEMENTATION @@ -33,7 +33,7 @@ struct sFont *MakeFont(const char *fontfile, int height) snprintf(fontpath, 256, "fonts/%s", fontfile); stbtt_fontinfo fontinfo = { 0 }; - int i, j, ascent, baseline, ch = 0; + int ascent = 0; stbtt_InitFont(&fontinfo, ttf_buffer, 0); stbtt_GetFontVMetrics(&fontinfo, &ascent, 0, 0); @@ -164,10 +164,6 @@ void text_settype(struct sFont *mfont) font = mfont; } -void strwidth(const char *str) { - -} - void renderText(const char *text, mfloat_t pos[2], float scale, mfloat_t color[3], float lw) { shader_use(shader); @@ -181,8 +177,8 @@ void renderText(const char *text, mfloat_t pos[2], float scale, mfloat_t color[3 glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); - char *line, *wordstart; - line = text; + const unsigned char *line, *wordstart; + line = (unsigned char*)text; while (*line != '\0') { diff --git a/source/engine/gameobject.c b/source/engine/gameobject.c index aa513b7..bacaea9 100755 --- a/source/engine/gameobject.c +++ b/source/engine/gameobject.c @@ -9,6 +9,7 @@ #include "input.h" #include #include +#include "resources.h" struct vec *gameobjects = NULL; struct mGameObject *updateGO = NULL; @@ -186,7 +187,7 @@ void gameobject_update(struct mGameObject *go) script_run(updateGO->update); } - vec_walk(go->components, component_update); + vec_walk(go->components, &component_update); } void gameobject_move(struct mGameObject *go, float xs, float ys) @@ -205,5 +206,5 @@ void gameobject_rotate(struct mGameObject *go, float as) } void update_gameobjects() { - vec_walk(gameobjects, gameobject_update); -} \ No newline at end of file + vec_walk(gameobjects, &gameobject_update); +} diff --git a/source/engine/gizmo.h b/source/engine/gizmo.h index 5d23c32..cee2607 100755 --- a/source/engine/gizmo.h +++ b/source/engine/gizmo.h @@ -1,4 +1,10 @@ #ifndef GIZMO_H #define GIZMO_H +#include + +struct gizmo { + uint8_t color[3]; +}; + #endif diff --git a/source/engine/input.c b/source/engine/input.c index 637bc40..db0b003 100755 --- a/source/engine/input.c +++ b/source/engine/input.c @@ -1,17 +1,35 @@ #include "input.h" -#include "window.h" -#include - int32_t mouseWheelX = 0; int32_t mouseWheelY = 0; int ychange = 0; int xchange = 0; float deltaT = 0; int quit = 0; -SDL_Event e = { 0 }; -uint8_t *currentKeystates = NULL; +static double c_xpos; +static double c_ypos; + +static void cursor_pos_cb(GLFWwindow *w, double xpos, double ypos) +{ + xchange = (int)xpos - c_xpos; + ychange = (int)ypos - c_ypos; + + c_xpos = xpos; + c_ypos = ypos; +} + +static void scroll_cb(GLFWwindow *w, double xoffset, double yoffset) +{ + mouseWheelY = yoffset; + mouseWheelX = xoffset; +} + +void input_init() +{ + glfwSetCursorPosCallback(mainwin->window, cursor_pos_cb); + glfwSetScrollCallback(mainwin->window, scroll_cb); +} void input_poll() { @@ -19,15 +37,25 @@ void input_poll() xchange = 0; mouseWheelX = 0; mouseWheelY = 0; - currentKeystates = SDL_GetKeyboardState(NULL); - while (SDL_PollEvent(&e)) { - window_all_handle_events(&e); + glfwPollEvents(); -#ifdef EDITOR - //editor_input(&e); -#endif - } + //editor_input(&e); } + +void cursor_hide() +{ + glfwSetInputMode(mainwin->window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); +} + +void cursor_show() +{ + glfwSetInputMode(mainwin->window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); +} + +int action_down(int scancode) +{ + return glfwGetKey(mainwin->window, scancode); +} diff --git a/source/engine/input.h b/source/engine/input.h index 771d299..57e4fb4 100755 --- a/source/engine/input.h +++ b/source/engine/input.h @@ -1,8 +1,8 @@ #ifndef INPUT_H #define INPUT_H -#include #include +#include "window.h" extern int32_t mouseWheelX; extern int32_t mouseWheelY; @@ -10,9 +10,19 @@ extern int ychange; extern int xchange; extern float deltaT; extern int quit; -extern SDL_Event e; -extern uint8_t *currentKeystates; +void input_init(); void input_poll(); +void cursor_hide(); +void cursor_show(); + +int action_down(int scancode); + +struct inputaction +{ + int scancode; + +}; + #endif diff --git a/source/engine/level.c b/source/engine/level.c index d1b486d..0ef058d 100755 --- a/source/engine/level.c +++ b/source/engine/level.c @@ -3,6 +3,7 @@ #include #include "vec.h" #include "gameobject.h" +#include "resources.h" void save_level(char name[MAXNAME]) { diff --git a/source/engine/light.c b/source/engine/light.c index 4fde7db..270e34f 100755 --- a/source/engine/light.c +++ b/source/engine/light.c @@ -157,4 +157,4 @@ void spotlight_prepshader(struct mSpotLight *light, struct mShader *shader, shader_setfloat(shader, "spotLight.constant", light->constant); } -*/ \ No newline at end of file +*/ diff --git a/source/engine/light.h b/source/engine/light.h index c51986f..5d1c08b 100755 --- a/source/engine/light.h +++ b/source/engine/light.h @@ -1,16 +1,17 @@ #ifndef LIGHT_H #define LIGHT_H -/* +#include + struct mLight { - struct mGameObject obj; - mfloat_t color[3]; + struct mGameObject *go; + uint8_t color[3]; float strength; int dynamic; int on; }; - +/* struct mPointLight { struct mLight light; float constant; diff --git a/source/engine/log.c b/source/engine/log.c index 55cc963..8346adf 100755 --- a/source/engine/log.c +++ b/source/engine/log.c @@ -1,16 +1,15 @@ #include "log.h" +#include "render.h" #include #include #include #include #include -#include #define logLevel 4 -void mYughLog(int category, int priority, const char *message, - int line, const char *file, ...) +void mYughLog(int category, int priority, int line, const char *file, const char *message, ...) { if (priority >= logLevel) { time_t now = time(0); @@ -27,8 +26,7 @@ void mYughLog(int category, int priority, const char *message, snprintf(buffer, ERROR_BUFFER, "LEVEL %d :: %s [ %s:%d ] %s\n", priority, msgbuffer, file, line, dt); - //SDL_LogMessage(category, priority, buffer); - printf(buffer); + printf("%s", buffer); fflush(stdout); } } @@ -38,19 +36,8 @@ void FlushGLErrors() GLenum glErr = GL_NO_ERROR; glErr = glGetError(); while (glErr != GL_NO_ERROR) { - YughLog(SDL_LOG_CATEGORY_RENDER, SDL_LOG_PRIORITY_ERROR, + YughLog(0, 3, "GL Error: %d", glErr); glErr = glGetError(); } } - -int TestSDLError(int sdlErr) -{ - if (sdlErr != 0) { - YughLog(0, SDL_LOG_PRIORITY_ERROR, "SDL Error :: %s", - SDL_GetError()); - return 0; - } - - return 1; -} \ No newline at end of file diff --git a/source/engine/log.h b/source/engine/log.h index 4dbb814..fcc707d 100755 --- a/source/engine/log.h +++ b/source/engine/log.h @@ -1,17 +1,19 @@ #ifndef LOG_H #define LOG_H -#include - #define ERROR_BUFFER 2048 -#define YughLog(cat, pri, msg, ...) mYughLog(cat, pri, msg, __LINE__, __FILE__, __VA_ARGS__) +#define LOG_INFO 0 +#define LOG_WARN 1 +#define LOG_ERROR 2 +#define LOG_CRITICAL 3 -void mYughLog(int category, int priority, const char *message, - int line, const char *file, ...); +#define YughLog(cat, pri, msg, ...) mYughLog(cat, pri, __LINE__, __FILE__, msg, __VA_ARGS__) + +void mYughLog(int category, int priority, int line, const char *file, const char *message, ...); void FlushGLErrors(); int TestSDLError(int sdlErr); -#endif \ No newline at end of file +#endif diff --git a/source/engine/mathc.c b/source/engine/mathc.c index dbcc5e9..90c09a4 100755 --- a/source/engine/mathc.c +++ b/source/engine/mathc.c @@ -44,8 +44,6 @@ const mint_t VEC3I_ONE[3] = { 1, 1, 1 }; #include -typedef float mfloat_t; - #if defined(MATHC_USE_INT) mint_t clampi(mint_t value, mint_t min, mint_t max) { @@ -4971,9 +4969,10 @@ bool squat_is_equal(struct quat q0, struct quat q1) return quat_is_equal((mfloat_t *) & q0, (mfloat_t *) & q1); } +// TODO: Implement struct quat squat_from_euler(mfloat_t x, mfloat_t y, mfloat_t z) { - struct quat result; + struct quat result = {0}; return result; } diff --git a/source/engine/mesh.c b/source/engine/mesh.c index f455e43..3dd3a20 100755 --- a/source/engine/mesh.c +++ b/source/engine/mesh.c @@ -1,11 +1,11 @@ #include "mesh.h" +#include "render.h" #include "shader.h" #include "texture.h" #include #include #include -#include void DrawMesh(struct mMesh *mesh, struct mShader *shader) { @@ -18,26 +18,26 @@ void DrawMesh(struct mMesh *mesh, struct mShader *shader) for (uint32_t i = 0; i < (mesh->te - mesh->textures); i++) { glActiveTexture(GL_TEXTURE0 + i); // active proper texture unit before binding // retrieve texture number (the N in diffuse_textureN) - char number; + char number = 0; // TODO: malloc every single frame ... nope! Change to stack - char *name = + /*char *name = (char *) malloc(sizeof(char) * - (strlen(mesh->textures[i].type) + 2)); - if (mesh->textures[i].type == "texture_diffuse") + (strlen(mesh->textures[i].type) + 2));*/ + if (mesh->textures[i].type == TEX_DIFF) number = diffuseNr++; - else if (mesh->textures[i].type == "texture_specular") + else if (mesh->textures[i].type == TEX_SPEC) number = specularNr++; - else if (mesh->textures[i].type == "texture_normal") + else if (mesh->textures[i].type == TEX_NORM) number = normalNr++; - else if (mesh->textures[i].type == "texture_height") + else if (mesh->textures[i].type == TEX_HEIGHT) number = heightNr++; - sprintf(name, "%s%d", mesh->textures[i].type, number); - // now set the sampler to the correct texture unit + +/* glUniform1i(glGetUniformLocation(shader->id, name), i); - // and finally bind the texture glBindTexture(GL_TEXTURE_2D, mesh->textures[i].id); free(name); + */ } // draw mesh diff --git a/source/engine/model.c b/source/engine/model.c index 1b9d2d8..082468a 100755 --- a/source/engine/model.c +++ b/source/engine/model.c @@ -5,6 +5,7 @@ #include "shader.h" #include #include +#include static struct mModel *lastRendered; static struct mModel *loadedModels[100]; diff --git a/source/engine/openglrender.c b/source/engine/openglrender.c index 2981015..47d22ce 100755 --- a/source/engine/openglrender.c +++ b/source/engine/openglrender.c @@ -1,6 +1,5 @@ #include "openglrender.h" -#include #include "sprite.h" #include "shader.h" #include "font.h" @@ -15,7 +14,7 @@ int renderMode = 0; static GLuint UBO; -static GLuint UBOBind = 0; + static GLuint gridVBO = 0; static GLuint gridVAO = 0; @@ -84,22 +83,17 @@ bool renderReflection = true; struct mGameObject *selectedobject = NULL; char objectName[200] = { '\0' }; // object name buffer -uint16_t debugColorPickBO = 0; -uint16_t debugColorPickTEX = 0; +GLuint debugColorPickBO = 0; +GLuint debugColorPickTEX = 0; struct mSprite *tsprite = NULL; -static struct mSprite *tanim = NULL; + static unsigned int projUBO; void openglInit() { - if (SDL_GL_SetSwapInterval(1)) { - YughLog(0, SDL_LOG_PRIORITY_WARN, - "Unable to set VSync! SDL Error: %s", SDL_GetError()); - } - sprite_initialize(); ////// MAKE SHADERS @@ -222,34 +216,7 @@ void openglRender(struct mSDLWindow *window, struct mCamera *mcamera) void openglInit3d(struct mSDLWindow *window) { - //Initialize SDL - if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { - YughLog(0, SDL_LOG_PRIORITY_ERROR, - "SDL could not initialize! SDL Error: %s", SDL_GetError()); - } - //Use OpenGL 3.3 - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, - SDL_GL_CONTEXT_PROFILE_CORE); - - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2); /* How many x MSAA */ - - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1); - - // TODO: Add non starter initializtion return here for some reason? - MakeSDLWindow("Untitled Game", 1280, 720, - SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | - SDL_WINDOW_RESIZABLE); - - - //Use Vsync - if (!SDL_GL_SetSwapInterval(1)) { - YughLog(0, SDL_LOG_PRIORITY_WARN, - "Unable to set VSync! SDL Error: %s", SDL_GetError()); - } -/* TODO: IMG init doesn't work in C+ +/* TODO: IMG init doesn't work in C++ int init =(0x00000001 | 0x00000002); int initted =IMG_Init(init); YughLog(0, SDL_LOG_PRIORITY_ERROR, "Init flags: %d\nInitted values: %d ", init, initted); @@ -438,7 +405,7 @@ void openglRender3d(struct mSDLWindow *window, struct mCamera *mcamera) glClear(GL_DEPTH_BUFFER_BIT); // Configure matrices with an orthogonal - mfloat_t lightView[16] = { 0.f }; + mfloat_t lightSpaceMatrix[16] = { 0.f }; /* diff --git a/source/engine/openglrender.h b/source/engine/openglrender.h index d126a0b..42c9832 100755 --- a/source/engine/openglrender.h +++ b/source/engine/openglrender.h @@ -2,7 +2,6 @@ #define OPENGL_RENDER_H #include "render.h" -#include "window.h" struct mCamera; struct mSDLWindow; @@ -31,7 +30,7 @@ extern float plane_size; extern float near_plane; extern float far_plane; extern char objectName[]; -extern uint16_t debugColorPickBO; +extern GLuint debugColorPickBO; extern struct mGameObject *selectedobject; diff --git a/source/engine/registry.c b/source/engine/registry.c index c521fb1..5627ef0 100755 --- a/source/engine/registry.c +++ b/source/engine/registry.c @@ -12,7 +12,7 @@ int ncomponent = 0; void registry_init() { register_component("Sprite", sizeof(struct mSprite), &MakeSprite, NULL, - sprite_gui, &sprite_init, NULL); + &sprite_gui, &sprite_init, NULL); register_component("2D Circle Collider", sizeof(struct phys2d_circle), &Make2DCircle, &phys2d_dbgdrawcircle, &circle_gui, &phys2d_circleinit, NULL); diff --git a/source/engine/render.h b/source/engine/render.h index 17081a3..89763e1 100755 --- a/source/engine/render.h +++ b/source/engine/render.h @@ -1,9 +1,7 @@ #ifndef RENDER_H #define RENDER_H -#define GL_GLEXT_PROTOTYPES -#include -#include +#include +#include - -#endif \ No newline at end of file +#endif diff --git a/source/engine/resources.c b/source/engine/resources.c index 3718e7f..e6f4c1f 100755 --- a/source/engine/resources.c +++ b/source/engine/resources.c @@ -11,6 +11,7 @@ #include #include #include +#include char *DATA_PATH = NULL; char *PREF_PATH = NULL; @@ -22,7 +23,6 @@ const char *EXT_LEVEL = ".level"; int stemlen = 0; static const char *cur_ext = NULL; -static DIR *cur_dir = NULL; struct dirent *c_dirent = NULL; struct vec *c_vec = NULL; @@ -35,9 +35,6 @@ void resources_init() getcwd(DATA_PATH, 256); strncat(DATA_PATH, "/", 256); - - - PREF_PATH = SDL_GetPrefPath("Odplot", "Test Game"); if (!PREF_PATH) PREF_PATH = strdup("./tmp/"); } @@ -104,7 +101,7 @@ void findPrefabs() fill_extensions(prefabs, DATA_PATH, EXT_PREFAB); } -FILE *path_open(const char *fmt, const char *tag, ...) +FILE *path_open(const char *tag, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -115,9 +112,9 @@ FILE *path_open(const char *fmt, const char *tag, ...) return f; } -char *make_path(char *file) +char *make_path(const char *file) { strncpy(pathbuf, DATA_PATH, MAXPATH); strncat(pathbuf, file, MAXPATH); return pathbuf; -} \ No newline at end of file +} diff --git a/source/engine/resources.h b/source/engine/resources.h index b40a634..2d35718 100755 --- a/source/engine/resources.h +++ b/source/engine/resources.h @@ -22,7 +22,7 @@ void fill_extensions(struct vec *vec, const char *path, const char *ext); char *get_filename_from_path(char *path, int extension); char *get_directory_from_path(char *path); FILE *res_open(char *path, const char *tag); -FILE *path_open(const char *fmt, const char *tag, ...); -char *make_path(char *file); +FILE *path_open(const char *tag, const char *fmt, ...); +char *make_path(const char *file); #endif diff --git a/source/engine/script.c b/source/engine/script.c index d8d740c..864b6d7 100755 --- a/source/engine/script.c +++ b/source/engine/script.c @@ -51,4 +51,4 @@ void script_init() void script_run(const char *script) { s7_eval_c_string(s7, script); -} \ No newline at end of file +} diff --git a/source/engine/script.h b/source/engine/script.h index 38f39fb..eeb2fed 100755 --- a/source/engine/script.h +++ b/source/engine/script.h @@ -7,4 +7,4 @@ extern struct s7_scheme *s7; void script_init(); void script_run(const char *script); -#endif \ No newline at end of file +#endif diff --git a/source/engine/shader.c b/source/engine/shader.c index 206b9ea..e7b75d9 100755 --- a/source/engine/shader.c +++ b/source/engine/shader.c @@ -1,12 +1,12 @@ #include "shader.h" +#include "render.h" #include "config.h" #include #include #include #include "log.h" #include "resources.h" -#include #define SHADER_BUF 10000 @@ -33,7 +33,7 @@ int shader_compile_error(GLuint shader) if (success) return 0; glGetShaderInfoLog(shader, ERROR_BUFFER, NULL, infoLog); - YughLog(0, SDL_LOG_PRIORITY_ERROR, "Shader compilation error.\nLog: %s", infoLog); + YughLog(0, LOG_ERROR, "Shader compilation error.\nLog: %s", infoLog); return 1; } @@ -47,12 +47,12 @@ int shader_link_error(GLuint shader) if (success) return 0; glGetProgramInfoLog(shader, ERROR_BUFFER, NULL, infoLog); - YughLog(0, SDL_LOG_PRIORITY_ERROR, "Shader link error.\nLog: %s", infoLog); + YughLog(0, LOG_ERROR, "Shader link error.\nLog: %s", infoLog); return 1; } -GLuint load_shader_from_file(char *path, int type) +GLuint load_shader_from_file(const char *path, int type) { char spath[MAXPATH] = {'\0'}; @@ -169,7 +169,7 @@ void shader_compile_all() { struct mShader **curshader = mshaders; do { - YughLog(0, SDL_LOG_PRIORITY_INFO, "Compiled Shader %d", 1); + YughLog(0, LOG_INFO, "Compiled Shader %d", 1); shader_compile(*curshader); } while (++curshader != lastShader); diff --git a/source/engine/skybox.c b/source/engine/skybox.c index 4cee2f3..27aa32d 100755 --- a/source/engine/skybox.c +++ b/source/engine/skybox.c @@ -3,6 +3,7 @@ #include "shader.h" #include "camera.h" #include +#include #include "openglrender.h" @@ -71,24 +72,27 @@ struct mSkybox *MakeSkybox(const char *cubemap) shader_use(newskybox->shader); shader_setint(newskybox->shader, "skybox", 0); +/* const char *faces[6] = { "right.jpg", "left.jpg", "top.jpg", "bottom.jpg", "front.jpg", "back.jpg" }; +*/ glGenTextures(1, &newskybox->id); glBindTexture(GL_TEXTURE_CUBE_MAP, newskybox->id); - char buf[100] = { '\0' }; + /*char buf[100] = { '\0' };*/ for (unsigned int i = 0; i < 6; i++) { + /* buf[0] = '\0'; strcat(buf, cubemap); strcat(buf, "/"); strcat(buf, faces[i]); - SDL_Surface *data = NULL; //IMG_Load(buf); + IMG_Load(buf); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, 2048, 2048, 0, GL_RGB, GL_UNSIGNED_BYTE, data->pixels); - SDL_FreeSurface(data); + */ } glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); diff --git a/source/engine/sound.c b/source/engine/sound.c index 61db1e3..0a4e5dc 100755 --- a/source/engine/sound.c +++ b/source/engine/sound.c @@ -1,4 +1,5 @@ #include "sound.h" +#include "resources.h" const char *audioDriver; @@ -8,11 +9,13 @@ void sound_init() { int flags = MIX_INIT_MP3 | MIX_INIT_OGG; int err = Mix_Init(flags); - if (err&flags != flags) { + if ((err&flags) != flags) { printf("MIX did not init!!"); } mus_ch = Mix_AllocateChannels(1); + + Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048); } void audio_open(const char *device) @@ -91,4 +94,32 @@ void music_stop() void audio_init() { audioDriver = SDL_GetAudioDeviceName(0,0); -} \ No newline at end of file +} + +void play_raw(int device, void *data, int size) +{ + SDL_QueueAudio(device, data, size); +} + +void close_audio_device(int device) +{ + SDL_CloseAudioDevice(device); +} + +void clear_raw(int device) +{ + SDL_ClearQueuedAudio(device); +} + +int open_device(const char *adriver) +{ + SDL_AudioSpec audio_spec; + SDL_memset(&audio_spec, 0, sizeof(audio_spec)); + audio_spec.freq = 48000; + audio_spec.format = AUDIO_F32; + audio_spec.channels = 2; + audio_spec.samples = 4096; + int dev = (int) SDL_OpenAudioDevice(adriver, 0, &audio_spec, NULL, 0); + SDL_PauseAudioDevice(dev, 0); + return dev; +} diff --git a/source/engine/sound.h b/source/engine/sound.h index 864ea87..4f548e6 100755 --- a/source/engine/sound.h +++ b/source/engine/sound.h @@ -3,8 +3,6 @@ #include - - struct sound { Mix_Chunk *sound; unsigned char volume; @@ -15,10 +13,6 @@ struct music { unsigned char volume; }; -struct player { - -}; - extern const char *audioDriver; void sound_init(); @@ -41,6 +35,11 @@ void music_resume(); void music_pause(); void music_stop(); +void close_audio_device(int device); +void clear_raw(int device); +void play_raw(int device, void *data, int size); +int open_device(const char *adriver); + void audio_init(); -#endif \ No newline at end of file +#endif diff --git a/source/engine/sprite.c b/source/engine/sprite.c index 09e31ec..88aa12c 100755 --- a/source/engine/sprite.c +++ b/source/engine/sprite.c @@ -1,6 +1,7 @@ #include "sprite.h" +#include "timer.h" #include "render.h" #include "openglrender.h" #include "texture.h" @@ -18,14 +19,13 @@ static struct mShader *spriteShader = NULL; static struct mShader *animSpriteShader = NULL; */ -struct TextureOptions TEX_SPRITE = { 1, 0 }; +struct TextureOptions TEX_SPRITE = { 1, 0, 0 }; struct mSprite *sprites[100] = { NULL }; int numSprites = 0; static uint32_t quadVAO; -static uint32_t VBO; struct mSprite *MakeSprite(struct mGameObject *go) { @@ -58,8 +58,7 @@ void sprite_loadanim(struct mSprite *sprite, const char *path, { sprite->tex = texture_loadfromfile(path); sprite->anim = anim; - sprite->anim.timer = - SDL_AddTimer(sprite->anim.ms, incrementAnimFrame, sprite); + sprite->anim.timer = timer_make(sprite->anim.ms, &incrementAnimFrame, sprite); /* sprite->tex = texture_loadanimfromfile(sprite->tex, path, sprite->anim.frames, sprite->anim.dimensions); @@ -71,7 +70,7 @@ void sprite_settex(struct mSprite *sprite, struct Texture *tex) sprite->tex = tex; } -Uint32 incrementAnimFrame(Uint32 interval, struct mSprite *sprite) +unsigned int incrementAnimFrame(unsigned int interval, struct mSprite *sprite) { sprite->anim.frame = (sprite->anim.frame + 1) % sprite->anim.frames; return interval; @@ -220,4 +219,4 @@ struct mSprite *gui_makesprite() { struct mSprite *new = MakeSprite(gui_go); return new; -} \ No newline at end of file +} diff --git a/source/engine/sprite.h b/source/engine/sprite.h index ad56396..c9610b3 100755 --- a/source/engine/sprite.h +++ b/source/engine/sprite.h @@ -1,18 +1,20 @@ #ifndef SPRITE_H #define SPRITE_H -#include +#include "timer.h" #include "mathc.h" struct datastream; struct mGameObject; struct Texture; +struct timer; + struct Anim2D { int frames; int frame; int dimensions[2]; - SDL_TimerID timer; + struct timer *timer; int ms; }; @@ -36,12 +38,12 @@ void sprite_loadtex(struct mSprite *sprite, const char *path); void sprite_loadanim(struct mSprite *sprite, const char *path, struct Anim2D anim); void sprite_settex(struct mSprite *sprite, struct Texture *tex); -void sprite_initalize(); +void sprite_initialize(); void sprite_draw(struct mSprite *sprite); void spriteanim_draw(struct mSprite *sprite); void video_draw(struct datastream *ds, mfloat_t pos[2], mfloat_t size[2], float rotate, mfloat_t color[3]); -Uint32 incrementAnimFrame(Uint32 interval, struct mSprite *sprite); +unsigned int incrementAnimFrame(unsigned int interval, struct mSprite *sprite); struct mSprite *gui_makesprite(); void gui_init(); diff --git a/source/engine/texture.c b/source/engine/texture.c index 9843128..b55e2c3 100755 --- a/source/engine/texture.c +++ b/source/engine/texture.c @@ -1,11 +1,11 @@ #include "texture.h" -#include +#include "render.h" #include #include #include -#include #include "log.h" +#include static struct { char *key; @@ -59,7 +59,7 @@ struct Texture *texture_loadfromfile(const char *path) void tex_pull(struct Texture *tex) { - uint8_t n; + int n; stbi_set_flip_vertically_on_load(0); tex->data = stbi_load(tex->path, &tex->width, &tex->height, &n, 4); @@ -112,6 +112,7 @@ void tex_gpu_load(struct Texture *tex) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } else { + /* glBindTexture(GL_TEXTURE_2D_ARRAY, tex->id); glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, @@ -163,10 +164,11 @@ void tex_gpu_load(struct Texture *tex) SDL_FreeSurface(loadedSurface); SDL_FreeSurface(tempSurface); + */ } } -Uint32 tex_incr_anim(Uint32 interval, struct TexAnimation *tex_anim) +unsigned int tex_incr_anim(unsigned int interval, struct TexAnimation *tex_anim) { anim_incr(tex_anim); @@ -195,9 +197,9 @@ void anim_decr(struct TexAnimation *anim) void tex_anim_set(struct TexAnimation *anim) { if (anim->playing) { - SDL_RemoveTimer(anim->timer); + timer_remove(anim->timer); anim->timer = - SDL_AddTimer(floor(1000.f / anim->tex->anim.ms), tex_incr_anim, + timer_make(floor(1000.f / anim->tex->anim.ms), &tex_incr_anim, anim); } @@ -262,9 +264,9 @@ void anim_play(struct TexAnimation *anim) anim->frame = 0; anim->playing = 1; - SDL_RemoveTimer(anim->timer); + timer_remove(anim->timer); anim->timer = - SDL_AddTimer(floor(1000.f / anim->tex->anim.ms), tex_incr_anim, + timer_make(floor(1000.f / anim->tex->anim.ms), &tex_incr_anim, anim); } @@ -276,7 +278,7 @@ void anim_stop(struct TexAnimation *anim) anim->playing = 0; anim->frame = 0; anim->pausetime = 0; - SDL_RemoveTimer(anim->timer); + timer_remove(anim->timer); tex_anim_calc_uv(anim); } @@ -286,7 +288,7 @@ void anim_pause(struct TexAnimation *anim) return; anim->playing = 0; - SDL_RemoveTimer(anim->timer); + timer_remove(anim->timer); } void anim_fwd(struct TexAnimation *anim) diff --git a/source/engine/texture.h b/source/engine/texture.h index 80e5454..3ea22cd 100755 --- a/source/engine/texture.h +++ b/source/engine/texture.h @@ -1,7 +1,13 @@ #ifndef TEXTURE_H #define TEXTURE_H -#include +#include "timer.h" + +#define TEX_SPEC 0 +#define TEX_NORM 1 +#define TEX_HEIGHT 2 +#define TEX_DIFF 3 + struct Rect { float x; @@ -14,7 +20,7 @@ struct TexAnimation { int frame; int playing; int pausetime; - SDL_TimerID timer; + struct timer *timer; struct Rect uv; struct Texture *tex; }; @@ -33,7 +39,7 @@ struct TextureOptions { }; struct Texture { - char *type; + int type; unsigned int id; char *path; int width; @@ -65,7 +71,7 @@ void anim_bkwd(struct TexAnimation *anim); void anim_incr(struct TexAnimation *anim); void anim_decr(struct TexAnimation *anim); -Uint32 tex_incr_anim(Uint32 interval, struct TexAnimation *tex_anim); +unsigned int tex_incr_anim(unsigned int interval, struct TexAnimation *tex_anim); void tex_anim_calc_uv(struct TexAnimation *anim); void tex_anim_set(struct TexAnimation *anim); diff --git a/source/engine/thirdparty/enet/src/win32.c b/source/engine/thirdparty/enet/src/win32.c index eebdb03..83005a0 100755 --- a/source/engine/thirdparty/enet/src/win32.c +++ b/source/engine/thirdparty/enet/src/win32.c @@ -1,4 +1,4 @@ -/** +/** @file win32.c @brief ENet Win32 system specific functions */ @@ -16,7 +16,7 @@ enet_initialize (void) { WORD versionRequested = MAKEWORD (1, 1); WSADATA wsaData; - + if (WSAStartup (versionRequested, & wsaData)) return -1; @@ -24,7 +24,7 @@ enet_initialize (void) HIBYTE (wsaData.wVersion) != 1) { WSACleanup (); - + return -1; } @@ -121,9 +121,9 @@ enet_address_get_host (const ENetAddress * address, char * name, size_t nameLeng { struct in_addr in; struct hostent * hostEntry; - + in.s_addr = address -> host; - + hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET); if (hostEntry == NULL) return enet_address_get_host_ip (address, name, nameLength); @@ -280,8 +280,8 @@ enet_socket_accept (ENetSocket socket, ENetAddress * address) struct sockaddr_in sin; int sinLength = sizeof (struct sockaddr_in); - result = accept (socket, - address != NULL ? (struct sockaddr *) & sin : NULL, + result = accept (socket, + address != NULL ? (struct sockaddr *) & sin : NULL, address != NULL ? & sinLength : NULL); if (result == INVALID_SOCKET) @@ -327,7 +327,7 @@ enet_socket_send (ENetSocket socket, sin.sin_addr.s_addr = address -> host; } - if (WSASendTo (socket, + if (WSASendTo (socket, (LPWSABUF) buffers, (DWORD) bufferCount, & sentLength, @@ -406,10 +406,10 @@ enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeou fd_set readSet, writeSet; struct timeval timeVal; int selectCount; - + timeVal.tv_sec = timeout / 1000; timeVal.tv_usec = (timeout % 1000) * 1000; - + FD_ZERO (& readSet); FD_ZERO (& writeSet); @@ -431,12 +431,11 @@ enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeou if (FD_ISSET (socket, & writeSet)) * condition |= ENET_SOCKET_WAIT_SEND; - + if (FD_ISSET (socket, & readSet)) * condition |= ENET_SOCKET_WAIT_RECEIVE; return 0; -} +} #endif - diff --git a/source/engine/thirdparty/pl_mpeg/include/pl_mpeg.h b/source/engine/thirdparty/pl_mpeg/include/pl_mpeg.h index 7539fd3..e847309 100755 --- a/source/engine/thirdparty/pl_mpeg/include/pl_mpeg.h +++ b/source/engine/thirdparty/pl_mpeg/include/pl_mpeg.h @@ -1,164 +1,3 @@ -/* -PL_MPEG - MPEG1 Video decoder, MP2 Audio decoder, MPEG-PS demuxer - -Dominic Szablewski - https://phoboslab.org - - --- LICENSE: The MIT License(MIT) - -Copyright(c) 2019 Dominic Szablewski - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files(the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions : -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - - - --- Synopsis - -// Define `PL_MPEG_IMPLEMENTATION` in *one* C/C++ file before including this -// library to create the implementation. - -#define PL_MPEG_IMPLEMENTATION -#include "plmpeg.h" - -// This function gets called for each decoded video frame -void my_video_callback(plm_t *plm, plm_frame_t *frame, void *user) { - // Do something with frame->y.data, frame->cr.data, frame->cb.data -} - -// This function gets called for each decoded audio frame -void my_audio_callback(plm_t *plm, plm_samples_t *frame, void *user) { - // Do something with samples->interleaved -} - -// Load a .mpg (MPEG Program Stream) file -plm_t *plm = plm_create_with_filename("some-file.mpg"); - -// Install the video & audio decode callbacks -plm_set_video_decode_callback(plm, my_video_callback, my_data); -plm_set_audio_decode_callback(plm, my_audio_callback, my_data); - - -// Decode -do { - plm_decode(plm, time_since_last_call); -} while (!plm_has_ended(plm)); - -// All done -plm_destroy(plm); - - - --- Documentation - -This library provides several interfaces to load, demux and decode MPEG video -and audio data. A high-level API combines the demuxer, video & audio decoders -in an easy to use wrapper. - -Lower-level APIs for accessing the demuxer, video decoder and audio decoder, -as well as providing different data sources are also available. - -Interfaces are written in an object orientet style, meaning you create object -instances via various different constructor functions (plm_*create()), -do some work on them and later dispose them via plm_*destroy(). - -plm_* ......... the high-level interface, combining demuxer and decoders -plm_buffer_* .. the data source used by all interfaces -plm_demux_* ... the MPEG-PS demuxer -plm_video_* ... the MPEG1 Video ("mpeg1") decoder -plm_audio_* ... the MPEG1 Audio Layer II ("mp2") decoder - - -With the high-level interface you have two options to decode video & audio: - - 1. Use plm_decode() and just hand over the delta time since the last call. - It will decode everything needed and call your callbacks (specified through - plm_set_{video|audio}_decode_callback()) any number of times. - - 2. Use plm_decode_video() and plm_decode_audio() to decode exactly one - frame of video or audio data at a time. How you handle the synchronization - of both streams is up to you. - -If you only want to decode video *or* audio through these functions, you should -disable the other stream (plm_set_{video|audio}_enabled(FALSE)) - -Video data is decoded into a struct with all 3 planes (Y, Cr, Cb) stored in -separate buffers. You can either convert this to RGB on the CPU (slow) via the -plm_frame_to_rgb() function or do it on the GPU with the following matrix: - -mat4 bt601 = mat4( - 1.16438, 0.00000, 1.59603, -0.87079, - 1.16438, -0.39176, -0.81297, 0.52959, - 1.16438, 2.01723, 0.00000, -1.08139, - 0, 0, 0, 1 -); -gl_FragColor = vec4(y, cb, cr, 1.0) * bt601; - -Audio data is decoded into a struct with either one single float array with the -samples for the left and right channel interleaved, or if the -PLM_AUDIO_SEPARATE_CHANNELS is defined *before* including this library, into -two separate float arrays - one for each channel. - - -Data can be supplied to the high level interface, the demuxer and the decoders -in three different ways: - - 1. Using plm_create_from_filename() or with a file handle with - plm_create_from_file(). - - 2. Using plm_create_with_memory() and supplying a pointer to memory that - contains the whole file. - - 3. Using plm_create_with_buffer(), supplying your own plm_buffer_t instance and - periodically writing to this buffer. - -When using your own plm_buffer_t instance, you can fill this buffer using -plm_buffer_write(). You can either monitor plm_buffer_get_remaining() and push -data when appropriate, or install a callback on the buffer with -plm_buffer_set_load_callback() that gets called whenever the buffer needs more -data. - -A buffer created with plm_buffer_create_with_capacity() is treated as a ring -buffer, meaning that data that has already been read, will be discarded. In -contrast, a buffer created with plm_buffer_create_for_appending() will keep all -data written to it in memory. This enables seeking in the already loaded data. - - -There should be no need to use the lower level plm_demux_*, plm_video_* and -plm_audio_* functions, if all you want to do is read/decode an MPEG-PS file. -However, if you get raw mpeg1video data or raw mp2 audio data from a different -source, these functions can be used to decode the raw data directly. Similarly, -if you only want to analyze an MPEG-PS file or extract raw video or audio -packets from it, you can use the plm_demux_* functions. - - -This library uses malloc(), realloc() and free() to manage memory. Typically -all allocation happens up-front when creating the interface. However, the -default buffer size may be too small for certain inputs. In these cases plmpeg -will realloc() the buffer with a larger size whenever needed. You can configure -the default buffer size by defining PLM_BUFFER_DEFAULT_SIZE *before* -including this library. - - -See below for detailed the API documentation. - -*/ - - #ifndef PL_MPEG_H #define PL_MPEG_H @@ -198,11 +37,11 @@ typedef struct { } plm_packet_t; -// Decoded Video Plane +// Decoded Video Plane // The byte length of the data is width * height. Note that different planes -// have different sizes: the Luma plane (Y) is double the size of each of +// have different sizes: the Luma plane (Y) is double the size of each of // the two Chroma planes (Cr, Cb) - i.e. 4 times the byte length. -// Also note that the size of the plane does *not* denote the size of the +// Also note that the size of the plane does *not* denote the size of the // displayed frame. The sizes of planes are always rounded up to the nearest // macroblock (16px). @@ -285,8 +124,8 @@ plm_t *plm_create_with_file(FILE *fh, int close_when_done); // Create a plmpeg instance with a pointer to memory as source. This assumes the -// whole file is in memory. The memory is not copied. Pass TRUE to -// free_when_done to let plmpeg call free() on the pointer when plm_destroy() +// whole file is in memory. The memory is not copied. Pass TRUE to +// free_when_done to let plmpeg call free() on the pointer when plm_destroy() // is called. plm_t *plm_create_with_memory(uint8_t *bytes, size_t length, int free_when_done); @@ -392,14 +231,14 @@ void plm_set_loop(plm_t *self, int loop); int plm_has_ended(plm_t *self); -// Set the callback for decoded video frames used with plm_decode(). If no +// Set the callback for decoded video frames used with plm_decode(). If no // callback is set, video data will be ignored and not be decoded. The *user // Parameter will be passed to your callback. void plm_set_video_decode_callback(plm_t *self, plm_video_decode_callback fp, void *user); -// Set the callback for decoded audio samples used with plm_decode(). If no +// Set the callback for decoded audio samples used with plm_decode(). If no // callback is set, audio data will be ignored and not be decoded. The *user // Parameter will be passed to your callback. @@ -415,16 +254,16 @@ void plm_decode(plm_t *self, double seconds); // Decode and return one video frame. Returns NULL if no frame could be decoded -// (either because the source ended or data is corrupt). If you only want to +// (either because the source ended or data is corrupt). If you only want to // decode video, you should disable audio via plm_set_audio_enabled(). -// The returned plm_frame_t is valid until the next call to plm_decode_video() +// The returned plm_frame_t is valid until the next call to plm_decode_video() // or until plm_destroy() is called. plm_frame_t *plm_decode_video(plm_t *self); // Decode and return one audio frame. Returns NULL if no frame could be decoded -// (either because the source ended or data is corrupt). If you only want to +// (either because the source ended or data is corrupt). If you only want to // decode audio, you should disable video via plm_set_video_enabled(). // The returned plm_samples_t is valid until the next call to plm_decode_audio() // or until plm_destroy() is called. @@ -432,14 +271,14 @@ plm_frame_t *plm_decode_video(plm_t *self); plm_samples_t *plm_decode_audio(plm_t *self); -// Seek to the specified time, clamped between 0 -- duration. This can only be -// used when the underlying plm_buffer is seekable, i.e. for files, fixed -// memory buffers or _for_appending buffers. -// If seek_exact is TRUE this will seek to the exact time, otherwise it will -// seek to the last intra frame just before the desired time. Exact seeking can +// Seek to the specified time, clamped between 0 -- duration. This can only be +// used when the underlying plm_buffer is seekable, i.e. for files, fixed +// memory buffers or _for_appending buffers. +// If seek_exact is TRUE this will seek to the exact time, otherwise it will +// seek to the last intra frame just before the desired time. Exact seeking can // be slow, because all frames up to the seeked one have to be decoded on top of // the previous intra frame. -// If seeking succeeds, this function will call the video_decode_callback +// If seeking succeeds, this function will call the video_decode_callback // exactly once with the target frame. If audio is enabled, it will also call // the audio_decode_callback any number of times, until the audio_lead_time is // satisfied. @@ -481,8 +320,8 @@ plm_buffer_t *plm_buffer_create_with_file(FILE *fh, int close_when_done); // Create a buffer instance with a pointer to memory as source. This assumes -// the whole file is in memory. The bytes are not copied. Pass 1 to -// free_when_done to let plmpeg call free() on the pointer when plm_destroy() +// the whole file is in memory. The bytes are not copied. Pass 1 to +// free_when_done to let plmpeg call free() on the pointer when plm_destroy() // is called. plm_buffer_t *plm_buffer_create_with_memory(uint8_t *bytes, size_t length, int free_when_done); @@ -496,7 +335,7 @@ plm_buffer_t *plm_buffer_create_with_capacity(size_t capacity); // Create an empty buffer with an initial capacity. The buffer will grow // as needed. Decoded data will *not* be discarded. This can be used when -// loading a file over the network, without needing to throttle the download. +// loading a file over the network, without needing to throttle the download. // It also allows for seeking in the already loaded data. plm_buffer_t *plm_buffer_create_for_appending(size_t initial_capacity); @@ -507,8 +346,8 @@ plm_buffer_t *plm_buffer_create_for_appending(size_t initial_capacity); void plm_buffer_destroy(plm_buffer_t *self); -// Copy data into the buffer. If the data to be written is larger than the -// available space, the buffer will realloc() with a larger capacity. +// Copy data into the buffer. If the data to be written is larger than the +// available space, the buffer will realloc() with a larger capacity. // Returns the number of bytes written. This will always be the same as the // passed in length, except when the buffer was created _with_memory() for // which _write() is forbidden. @@ -516,7 +355,7 @@ void plm_buffer_destroy(plm_buffer_t *self); size_t plm_buffer_write(plm_buffer_t *self, uint8_t *bytes, size_t length); -// Mark the current byte length as the end of this buffer and signal that no +// Mark the current byte length as the end of this buffer and signal that no // more data is expected to be written to it. This function should be called // just after the last plm_buffer_write(). // For _with_capacity buffers, this is cleared on a plm_buffer_rewind(). @@ -535,7 +374,7 @@ void plm_buffer_set_load_callback(plm_buffer_t *self, plm_buffer_load_callback f void plm_buffer_rewind(plm_buffer_t *self); -// Get the total size. For files, this returns the file size. For all other +// Get the total size. For files, this returns the file size. For all other // types it returns the number of bytes currently in the buffer. size_t plm_buffer_get_size(plm_buffer_t *self); @@ -547,7 +386,7 @@ size_t plm_buffer_get_size(plm_buffer_t *self); size_t plm_buffer_get_remaining(plm_buffer_t *self); -// Get whether the read position of the buffer is at the end and no more data +// Get whether the read position of the buffer is at the end and no more data // is expected. int plm_buffer_has_ended(plm_buffer_t *self); @@ -609,9 +448,9 @@ int plm_demux_has_ended(plm_demux_t *self); // Seek to a packet of the specified type with a PTS just before specified time. -// If force_intra is TRUE, only packets containing an intra frame will be +// If force_intra is TRUE, only packets containing an intra frame will be // considered - this only makes sense when the type is PLM_DEMUX_PACKET_VIDEO_1. -// Note that the specified time is considered 0-based, regardless of the first +// Note that the specified time is considered 0-based, regardless of the first // PTS in the data source. plm_packet_t *plm_demux_seek(plm_demux_t *self, double time, int type, int force_intra); @@ -698,7 +537,7 @@ void plm_video_rewind(plm_video_t *self); int plm_video_has_ended(plm_video_t *self); -// Decode and return one frame of video and advance the internal time by +// Decode and return one frame of video and advance the internal time by // 1/framerate seconds. The returned frame_t is valid until the next call of // plm_video_decode() or until the video decoder is destroyed. @@ -707,7 +546,7 @@ plm_frame_t *plm_video_decode(plm_video_t *self); // Convert the YCrCb data of a frame into interleaved R G B data. The stride // specifies the width in bytes of the destination buffer. I.e. the number of -// bytes from one line to the next. The stride must be at least +// bytes from one line to the next. The stride must be at least // (frame->width * bytes_per_pixel). The buffer pointed to by *dest must have a // size of at least (stride * frame->height). // Note that the alpha component of the dest buffer is always left untouched. @@ -768,8 +607,8 @@ void plm_audio_rewind(plm_audio_t *self); int plm_audio_has_ended(plm_audio_t *self); -// Decode and return one "frame" of audio and advance the internal time by -// (PLM_AUDIO_SAMPLES_PER_FRAME/samplerate) seconds. The returned samples_t +// Decode and return one "frame" of audio and advance the internal time by +// (PLM_AUDIO_SAMPLES_PER_FRAME/samplerate) seconds. The returned samples_t // is valid until the next call of plm_audio_decode() or until the audio // decoder is destroyed. @@ -781,3493 +620,4 @@ plm_samples_t *plm_audio_decode(plm_audio_t *self); } #endif -#endif // PL_MPEG_H - - - - - -// ----------------------------------------------------------------------------- -// ----------------------------------------------------------------------------- -// IMPLEMENTATION - -#ifdef PL_MPEG_IMPLEMENTATION - -#include -#include - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 #endif - -#define PLM_UNUSED(expr) (void)(expr) - - -// ----------------------------------------------------------------------------- -// plm (high-level interface) implementation - -typedef struct plm_t { - plm_demux_t *demux; - double time; - int has_ended; - int loop; - int has_decoders; - - int video_enabled; - int video_packet_type; - plm_buffer_t *video_buffer; - plm_video_t *video_decoder; - - int audio_enabled; - int audio_stream_index; - int audio_packet_type; - double audio_lead_time; - plm_buffer_t *audio_buffer; - plm_audio_t *audio_decoder; - - plm_video_decode_callback video_decode_callback; - void *video_decode_callback_user_data; - - plm_audio_decode_callback audio_decode_callback; - void *audio_decode_callback_user_data; -} plm_t; - -int plm_init_decoders(plm_t *self); -void plm_handle_end(plm_t *self); -void plm_read_video_packet(plm_buffer_t *buffer, void *user); -void plm_read_audio_packet(plm_buffer_t *buffer, void *user); -void plm_read_packets(plm_t *self, int requested_type); - -plm_t *plm_create_with_filename(const char *filename) { - plm_buffer_t *buffer = plm_buffer_create_with_filename(filename); - if (!buffer) { - return NULL; - } - return plm_create_with_buffer(buffer, TRUE); -} - -plm_t *plm_create_with_file(FILE *fh, int close_when_done) { - plm_buffer_t *buffer = plm_buffer_create_with_file(fh, close_when_done); - return plm_create_with_buffer(buffer, TRUE); -} - -plm_t *plm_create_with_memory(uint8_t *bytes, size_t length, int free_when_done) { - plm_buffer_t *buffer = plm_buffer_create_with_memory(bytes, length, free_when_done); - return plm_create_with_buffer(buffer, TRUE); -} - -plm_t *plm_create_with_buffer(plm_buffer_t *buffer, int destroy_when_done) { - plm_t *self = (plm_t *)malloc(sizeof(plm_t)); - memset(self, 0, sizeof(plm_t)); - - self->demux = plm_demux_create(buffer, destroy_when_done); - self->video_enabled = TRUE; - self->audio_enabled = TRUE; - plm_init_decoders(self); - - return self; -} - -int plm_init_decoders(plm_t *self) { - if (self->has_decoders) { - return TRUE; - } - - if (!plm_demux_has_headers(self->demux)) { - return FALSE; - } - - if (plm_demux_get_num_video_streams(self->demux) > 0) { - if (self->video_enabled) { - self->video_packet_type = PLM_DEMUX_PACKET_VIDEO_1; - } - self->video_buffer = plm_buffer_create_with_capacity(PLM_BUFFER_DEFAULT_SIZE); - plm_buffer_set_load_callback(self->video_buffer, plm_read_video_packet, self); - } - - if (plm_demux_get_num_audio_streams(self->demux) > 0) { - if (self->audio_enabled) { - self->audio_packet_type = PLM_DEMUX_PACKET_AUDIO_1 + self->audio_stream_index; - } - self->audio_buffer = plm_buffer_create_with_capacity(PLM_BUFFER_DEFAULT_SIZE); - plm_buffer_set_load_callback(self->audio_buffer, plm_read_audio_packet, self); - } - - if (self->video_buffer) { - self->video_decoder = plm_video_create_with_buffer(self->video_buffer, TRUE); - } - - if (self->audio_buffer) { - self->audio_decoder = plm_audio_create_with_buffer(self->audio_buffer, TRUE); - } - - self->has_decoders = TRUE; - return TRUE; -} - -void plm_destroy(plm_t *self) { - if (self->video_decoder) { - plm_video_destroy(self->video_decoder); - } - if (self->audio_decoder) { - plm_audio_destroy(self->audio_decoder); - } - - plm_demux_destroy(self->demux); - free(self); -} - -int plm_get_audio_enabled(plm_t *self) { - return self->audio_enabled; -} - -int plm_has_headers(plm_t *self) { - if (!plm_demux_has_headers(self->demux)) { - return FALSE; - } - - if (!plm_init_decoders(self)) { - return FALSE; - } - - if ( - (self->video_decoder && !plm_video_has_header(self->video_decoder)) || - (self->audio_decoder && !plm_audio_has_header(self->audio_decoder)) - ) { - return FALSE; - } - - return TRUE; -} - -void plm_set_audio_enabled(plm_t *self, int enabled) { - self->audio_enabled = enabled; - - if (!enabled) { - self->audio_packet_type = 0; - return; - } - - self->audio_packet_type = (plm_init_decoders(self) && self->audio_decoder) - ? PLM_DEMUX_PACKET_AUDIO_1 + self->audio_stream_index - : 0; -} - -void plm_set_audio_stream(plm_t *self, int stream_index) { - if (stream_index < 0 || stream_index > 3) { - return; - } - self->audio_stream_index = stream_index; - - // Set the correct audio_packet_type - plm_set_audio_enabled(self, self->audio_enabled); -} - -int plm_get_video_enabled(plm_t *self) { - return self->video_enabled; -} - -void plm_set_video_enabled(plm_t *self, int enabled) { - self->video_enabled = enabled; - - if (!enabled) { - self->video_packet_type = 0; - return; - } - - self->video_packet_type = (plm_init_decoders(self) && self->video_decoder) - ? PLM_DEMUX_PACKET_VIDEO_1 - : 0; -} - -int plm_get_num_video_streams(plm_t *self) { - return plm_demux_get_num_video_streams(self->demux); -} - -int plm_get_width(plm_t *self) { - return (plm_init_decoders(self) && self->video_decoder) - ? plm_video_get_width(self->video_decoder) - : 0; -} - -int plm_get_height(plm_t *self) { - return (plm_init_decoders(self) && self->video_decoder) - ? plm_video_get_height(self->video_decoder) - : 0; -} - -double plm_get_framerate(plm_t *self) { - return (plm_init_decoders(self) && self->video_decoder) - ? plm_video_get_framerate(self->video_decoder) - : 0; -} - -int plm_get_num_audio_streams(plm_t *self) { - return plm_demux_get_num_audio_streams(self->demux); -} - -int plm_get_samplerate(plm_t *self) { - return (plm_init_decoders(self) && self->audio_decoder) - ? plm_audio_get_samplerate(self->audio_decoder) - : 0; -} - -double plm_get_audio_lead_time(plm_t *self) { - return self->audio_lead_time; -} - -void plm_set_audio_lead_time(plm_t *self, double lead_time) { - self->audio_lead_time = lead_time; -} - -double plm_get_time(plm_t *self) { - return self->time; -} - -double plm_get_duration(plm_t *self) { - return plm_demux_get_duration(self->demux, PLM_DEMUX_PACKET_VIDEO_1); -} - -void plm_rewind(plm_t *self) { - if (self->video_decoder) { - plm_video_rewind(self->video_decoder); - } - - if (self->audio_decoder) { - plm_audio_rewind(self->audio_decoder); - } - - plm_demux_rewind(self->demux); - self->time = 0; -} - -int plm_get_loop(plm_t *self) { - return self->loop; -} - -void plm_set_loop(plm_t *self, int loop) { - self->loop = loop; -} - -int plm_has_ended(plm_t *self) { - return self->has_ended; -} - -void plm_set_video_decode_callback(plm_t *self, plm_video_decode_callback fp, void *user) { - self->video_decode_callback = fp; - self->video_decode_callback_user_data = user; -} - -void plm_set_audio_decode_callback(plm_t *self, plm_audio_decode_callback fp, void *user) { - self->audio_decode_callback = fp; - self->audio_decode_callback_user_data = user; -} - -void plm_decode(plm_t *self, double tick) { - if (!plm_init_decoders(self)) { - return; - } - - int decode_video = (self->video_decode_callback && self->video_packet_type); - int decode_audio = (self->audio_decode_callback && self->audio_packet_type); - - if (!decode_video && !decode_audio) { - // Nothing to do here - return; - } - - int did_decode = FALSE; - int decode_video_failed = FALSE; - int decode_audio_failed = FALSE; - - double video_target_time = self->time + tick; - double audio_target_time = self->time + tick + self->audio_lead_time; - - do { - did_decode = FALSE; - - if (decode_video && plm_video_get_time(self->video_decoder) < video_target_time) { - plm_frame_t *frame = plm_video_decode(self->video_decoder); - if (frame) { - self->video_decode_callback(self, frame, self->video_decode_callback_user_data); - did_decode = TRUE; - } - else { - decode_video_failed = TRUE; - } - } - - if (decode_audio && plm_audio_get_time(self->audio_decoder) < audio_target_time) { - plm_samples_t *samples = plm_audio_decode(self->audio_decoder); - if (samples) { - self->audio_decode_callback(self, samples, self->audio_decode_callback_user_data); - did_decode = TRUE; - } - else { - decode_audio_failed = TRUE; - } - } - } while (did_decode); - - // Did all sources we wanted to decode fail and the demuxer is at the end? - if ( - (!decode_video || decode_video_failed) && - (!decode_audio || decode_audio_failed) && - plm_demux_has_ended(self->demux) - ) { - plm_handle_end(self); - return; - } - - self->time += tick; -} - -plm_frame_t *plm_decode_video(plm_t *self) { - if (!plm_init_decoders(self)) { - return NULL; - } - - if (!self->video_packet_type) { - return NULL; - } - - plm_frame_t *frame = plm_video_decode(self->video_decoder); - if (frame) { - self->time = frame->time; - } - else if (plm_demux_has_ended(self->demux)) { - plm_handle_end(self); - } - return frame; -} - -plm_samples_t *plm_decode_audio(plm_t *self) { - if (!plm_init_decoders(self)) { - return NULL; - } - - if (!self->audio_packet_type) { - return NULL; - } - - plm_samples_t *samples = plm_audio_decode(self->audio_decoder); - if (samples) { - self->time = samples->time; - } - else if (plm_demux_has_ended(self->demux)) { - plm_handle_end(self); - } - return samples; -} - -void plm_handle_end(plm_t *self) { - if (self->loop) { - plm_rewind(self); - } - else { - self->has_ended = TRUE; - } -} - -void plm_read_video_packet(plm_buffer_t *buffer, void *user) { - PLM_UNUSED(buffer); - plm_t *self = (plm_t *)user; - plm_read_packets(self, self->video_packet_type); -} - -void plm_read_audio_packet(plm_buffer_t *buffer, void *user) { - PLM_UNUSED(buffer); - plm_t *self = (plm_t *)user; - plm_read_packets(self, self->audio_packet_type); -} - -void plm_read_packets(plm_t *self, int requested_type) { - plm_packet_t *packet; - while ((packet = plm_demux_decode(self->demux))) { - if (packet->type == self->video_packet_type) { - plm_buffer_write(self->video_buffer, packet->data, packet->length); - } - else if (packet->type == self->audio_packet_type) { - plm_buffer_write(self->audio_buffer, packet->data, packet->length); - } - - if (packet->type == requested_type) { - return; - } - } - - if (plm_demux_has_ended(self->demux)) { - if (self->video_buffer) { - plm_buffer_signal_end(self->video_buffer); - } - if (self->audio_buffer) { - plm_buffer_signal_end(self->audio_buffer); - } - } -} - -plm_frame_t *plm_seek_frame(plm_t *self, double time, int seek_exact) { - if (!plm_init_decoders(self)) { - return NULL; - } - - if (!self->video_packet_type) { - return NULL; - } - - int type = self->video_packet_type; - - double start_time = plm_demux_get_start_time(self->demux, type); - double duration = plm_demux_get_duration(self->demux, type); - - if (time < 0) { - time = 0; - } - else if (time > duration) { - time = duration; - } - - plm_packet_t *packet = plm_demux_seek(self->demux, time, type, TRUE); - if (!packet) { - return NULL; - } - - // Disable writing to the audio buffer while decoding video - int previous_audio_packet_type = self->audio_packet_type; - self->audio_packet_type = 0; - - // Clear video buffer and decode the found packet - plm_video_rewind(self->video_decoder); - plm_video_set_time(self->video_decoder, packet->pts - start_time); - plm_buffer_write(self->video_buffer, packet->data, packet->length); - plm_frame_t *frame = plm_video_decode(self->video_decoder); - - // If we want to seek to an exact frame, we have to decode all frames - // on top of the intra frame we just jumped to. - if (seek_exact) { - while (frame && frame->time < time) { - frame = plm_video_decode(self->video_decoder); - } - } - - // Enable writing to the audio buffer again? - self->audio_packet_type = previous_audio_packet_type; - - if (frame) { - self->time = frame->time; - } - - self->has_ended = FALSE; - return frame; -} - -int plm_seek(plm_t *self, double time, int seek_exact) { - plm_frame_t *frame = plm_seek_frame(self, time, seek_exact); - - if (!frame) { - return FALSE; - } - - if (self->video_decode_callback) { - self->video_decode_callback(self, frame, self->video_decode_callback_user_data); - } - - // If audio is not enabled we are done here. - if (!self->audio_packet_type) { - return TRUE; - } - - // Sync up Audio. This demuxes more packets until the first audio packet - // with a PTS greater than the current time is found. plm_decode() is then - // called to decode enough audio data to satisfy the audio_lead_time. - - double start_time = plm_demux_get_start_time(self->demux, self->video_packet_type); - plm_audio_rewind(self->audio_decoder); - - plm_packet_t *packet = NULL; - while ((packet = plm_demux_decode(self->demux))) { - if (packet->type == self->video_packet_type) { - plm_buffer_write(self->video_buffer, packet->data, packet->length); - } - else if ( - packet->type == self->audio_packet_type && - packet->pts - start_time > self->time - ) { - plm_audio_set_time(self->audio_decoder, packet->pts - start_time); - plm_buffer_write(self->audio_buffer, packet->data, packet->length); - plm_decode(self, 0); - break; - } - } - - return TRUE; -} - - - -// ----------------------------------------------------------------------------- -// plm_buffer implementation - -enum plm_buffer_mode { - PLM_BUFFER_MODE_FILE, - PLM_BUFFER_MODE_FIXED_MEM, - PLM_BUFFER_MODE_RING, - PLM_BUFFER_MODE_APPEND -}; - -typedef struct plm_buffer_t { - size_t bit_index; - size_t capacity; - size_t length; - size_t total_size; - int discard_read_bytes; - int has_ended; - int free_when_done; - int close_when_done; - FILE *fh; - plm_buffer_load_callback load_callback; - void *load_callback_user_data; - uint8_t *bytes; - enum plm_buffer_mode mode; -} plm_buffer_t; - -typedef struct { - int16_t index; - int16_t value; -} plm_vlc_t; - -typedef struct { - int16_t index; - uint16_t value; -} plm_vlc_uint_t; - - -void plm_buffer_seek(plm_buffer_t *self, size_t pos); -size_t plm_buffer_tell(plm_buffer_t *self); -void plm_buffer_discard_read_bytes(plm_buffer_t *self); -void plm_buffer_load_file_callback(plm_buffer_t *self, void *user); - -int plm_buffer_has(plm_buffer_t *self, size_t count); -int plm_buffer_read(plm_buffer_t *self, int count); -void plm_buffer_align(plm_buffer_t *self); -void plm_buffer_skip(plm_buffer_t *self, size_t count); -int plm_buffer_skip_bytes(plm_buffer_t *self, uint8_t v); -int plm_buffer_next_start_code(plm_buffer_t *self); -int plm_buffer_find_start_code(plm_buffer_t *self, int code); -int plm_buffer_no_start_code(plm_buffer_t *self); -int16_t plm_buffer_read_vlc(plm_buffer_t *self, const plm_vlc_t *table); -uint16_t plm_buffer_read_vlc_uint(plm_buffer_t *self, const plm_vlc_uint_t *table); - -plm_buffer_t *plm_buffer_create_with_filename(const char *filename) { - FILE *fh = fopen(filename, "rb"); - if (!fh) { - return NULL; - } - return plm_buffer_create_with_file(fh, TRUE); -} - -plm_buffer_t *plm_buffer_create_with_file(FILE *fh, int close_when_done) { - plm_buffer_t *self = plm_buffer_create_with_capacity(PLM_BUFFER_DEFAULT_SIZE); - self->fh = fh; - self->close_when_done = close_when_done; - self->mode = PLM_BUFFER_MODE_FILE; - self->discard_read_bytes = TRUE; - - fseek(self->fh, 0, SEEK_END); - self->total_size = ftell(self->fh); - fseek(self->fh, 0, SEEK_SET); - - plm_buffer_set_load_callback(self, plm_buffer_load_file_callback, NULL); - return self; -} - -plm_buffer_t *plm_buffer_create_with_memory(uint8_t *bytes, size_t length, int free_when_done) { - plm_buffer_t *self = (plm_buffer_t *)malloc(sizeof(plm_buffer_t)); - memset(self, 0, sizeof(plm_buffer_t)); - self->capacity = length; - self->length = length; - self->total_size = length; - self->free_when_done = free_when_done; - self->bytes = bytes; - self->mode = PLM_BUFFER_MODE_FIXED_MEM; - self->discard_read_bytes = FALSE; - return self; -} - -plm_buffer_t *plm_buffer_create_with_capacity(size_t capacity) { - plm_buffer_t *self = (plm_buffer_t *)malloc(sizeof(plm_buffer_t)); - memset(self, 0, sizeof(plm_buffer_t)); - self->capacity = capacity; - self->free_when_done = TRUE; - self->bytes = (uint8_t *)malloc(capacity); - self->mode = PLM_BUFFER_MODE_RING; - self->discard_read_bytes = TRUE; - return self; -} - -plm_buffer_t *plm_buffer_create_for_appending(size_t initial_capacity) { - plm_buffer_t *self = plm_buffer_create_with_capacity(initial_capacity); - self->mode = PLM_BUFFER_MODE_APPEND; - self->discard_read_bytes = FALSE; - return self; -} - -void plm_buffer_destroy(plm_buffer_t *self) { - if (self->fh && self->close_when_done) { - fclose(self->fh); - } - if (self->free_when_done) { - free(self->bytes); - } - free(self); -} - -size_t plm_buffer_get_size(plm_buffer_t *self) { - return (self->mode == PLM_BUFFER_MODE_FILE) - ? self->total_size - : self->length; -} - -size_t plm_buffer_get_remaining(plm_buffer_t *self) { - return self->length - (self->bit_index >> 3); -} - -size_t plm_buffer_write(plm_buffer_t *self, uint8_t *bytes, size_t length) { - if (self->mode == PLM_BUFFER_MODE_FIXED_MEM) { - return 0; - } - - if (self->discard_read_bytes) { - // This should be a ring buffer, but instead it just shifts all unread - // data to the beginning of the buffer and appends new data at the end. - // Seems to be good enough. - - plm_buffer_discard_read_bytes(self); - if (self->mode == PLM_BUFFER_MODE_RING) { - self->total_size = 0; - } - } - - // Do we have to resize to fit the new data? - size_t bytes_available = self->capacity - self->length; - if (bytes_available < length) { - size_t new_size = self->capacity; - do { - new_size *= 2; - } while (new_size - self->length < length); - self->bytes = (uint8_t *)realloc(self->bytes, new_size); - self->capacity = new_size; - } - - memcpy(self->bytes + self->length, bytes, length); - self->length += length; - self->has_ended = FALSE; - return length; -} - -void plm_buffer_signal_end(plm_buffer_t *self) { - self->total_size = self->length; -} - -void plm_buffer_set_load_callback(plm_buffer_t *self, plm_buffer_load_callback fp, void *user) { - self->load_callback = fp; - self->load_callback_user_data = user; -} - -void plm_buffer_rewind(plm_buffer_t *self) { - plm_buffer_seek(self, 0); -} - -void plm_buffer_seek(plm_buffer_t *self, size_t pos) { - self->has_ended = FALSE; - - if (self->mode == PLM_BUFFER_MODE_FILE) { - fseek(self->fh, pos, SEEK_SET); - self->bit_index = 0; - self->length = 0; - } - else if (self->mode == PLM_BUFFER_MODE_RING) { - if (pos != 0) { - // Seeking to non-0 is forbidden for dynamic-mem buffers - return; - } - self->bit_index = 0; - self->length = 0; - self->total_size = 0; - } - else if (pos < self->length) { - self->bit_index = pos << 3; - } -} - -size_t plm_buffer_tell(plm_buffer_t *self) { - return self->mode == PLM_BUFFER_MODE_FILE - ? ftell(self->fh) + (self->bit_index >> 3) - self->length - : self->bit_index >> 3; -} - -void plm_buffer_discard_read_bytes(plm_buffer_t *self) { - size_t byte_pos = self->bit_index >> 3; - if (byte_pos == self->length) { - self->bit_index = 0; - self->length = 0; - } - else if (byte_pos > 0) { - memmove(self->bytes, self->bytes + byte_pos, self->length - byte_pos); - self->bit_index -= byte_pos << 3; - self->length -= byte_pos; - } -} - -void plm_buffer_load_file_callback(plm_buffer_t *self, void *user) { - PLM_UNUSED(user); - - if (self->discard_read_bytes) { - plm_buffer_discard_read_bytes(self); - } - - size_t bytes_available = self->capacity - self->length; - size_t bytes_read = fread(self->bytes + self->length, 1, bytes_available, self->fh); - self->length += bytes_read; - - if (bytes_read == 0) { - self->has_ended = TRUE; - } -} - -int plm_buffer_has_ended(plm_buffer_t *self) { - return self->has_ended; -} - -int plm_buffer_has(plm_buffer_t *self, size_t count) { - if (((self->length << 3) - self->bit_index) >= count) { - return TRUE; - } - - if (self->load_callback) { - self->load_callback(self, self->load_callback_user_data); - } - - if (((self->length << 3) - self->bit_index) >= count) { - return TRUE; - } - - if (self->total_size != 0 && self->length == self->total_size) { - self->has_ended = TRUE; - } - return FALSE; -} - -int plm_buffer_read(plm_buffer_t *self, int count) { - if (!plm_buffer_has(self, count)) { - return 0; - } - - int value = 0; - while (count) { - int current_byte = self->bytes[self->bit_index >> 3]; - - int remaining = 8 - (self->bit_index & 7); // Remaining bits in byte - int read = remaining < count ? remaining : count; // Bits in self run - int shift = remaining - read; - int mask = (0xff >> (8 - read)); - - value = (value << read) | ((current_byte & (mask << shift)) >> shift); - - self->bit_index += read; - count -= read; - } - - return value; -} - -void plm_buffer_align(plm_buffer_t *self) { - self->bit_index = ((self->bit_index + 7) >> 3) << 3; // Align to next byte -} - -void plm_buffer_skip(plm_buffer_t *self, size_t count) { - if (plm_buffer_has(self, count)) { - self->bit_index += count; - } -} - -int plm_buffer_skip_bytes(plm_buffer_t *self, uint8_t v) { - plm_buffer_align(self); - int skipped = 0; - while (plm_buffer_has(self, 8) && self->bytes[self->bit_index >> 3] == v) { - self->bit_index += 8; - skipped++; - } - return skipped; -} - -int plm_buffer_next_start_code(plm_buffer_t *self) { - plm_buffer_align(self); - - while (plm_buffer_has(self, (5 << 3))) { - size_t byte_index = (self->bit_index) >> 3; - if ( - self->bytes[byte_index] == 0x00 && - self->bytes[byte_index + 1] == 0x00 && - self->bytes[byte_index + 2] == 0x01 - ) { - self->bit_index = (byte_index + 4) << 3; - return self->bytes[byte_index + 3]; - } - self->bit_index += 8; - } - return -1; -} - -int plm_buffer_find_start_code(plm_buffer_t *self, int code) { - int current = 0; - while (TRUE) { - current = plm_buffer_next_start_code(self); - if (current == code || current == -1) { - return current; - } - } - return -1; -} - -int plm_buffer_has_start_code(plm_buffer_t *self, int code) { - size_t previous_bit_index = self->bit_index; - int previous_discard_read_bytes = self->discard_read_bytes; - - self->discard_read_bytes = FALSE; - int current = plm_buffer_find_start_code(self, code); - - self->bit_index = previous_bit_index; - self->discard_read_bytes = previous_discard_read_bytes; - return current; -} - -int plm_buffer_no_start_code(plm_buffer_t *self) { - if (!plm_buffer_has(self, (5 << 3))) { - return FALSE; - } - - size_t byte_index = ((self->bit_index + 7) >> 3); - return !( - self->bytes[byte_index] == 0x00 && - self->bytes[byte_index + 1] == 0x00 && - self->bytes[byte_index + 2] == 0x01 - ); -} - -int16_t plm_buffer_read_vlc(plm_buffer_t *self, const plm_vlc_t *table) { - plm_vlc_t state = {0, 0}; - do { - state = table[state.index + plm_buffer_read(self, 1)]; - } while (state.index > 0); - return state.value; -} - -uint16_t plm_buffer_read_vlc_uint(plm_buffer_t *self, const plm_vlc_uint_t *table) { - return (uint16_t)plm_buffer_read_vlc(self, (const plm_vlc_t *)table); -} - - - -// ---------------------------------------------------------------------------- -// plm_demux implementation - -static const int PLM_START_PACK = 0xBA; -static const int PLM_START_END = 0xB9; -static const int PLM_START_SYSTEM = 0xBB; - -typedef struct plm_demux_t { - plm_buffer_t *buffer; - int destroy_buffer_when_done; - double system_clock_ref; - - size_t last_file_size; - double last_decoded_pts; - double start_time; - double duration; - - int start_code; - int has_pack_header; - int has_system_header; - int has_headers; - - int num_audio_streams; - int num_video_streams; - plm_packet_t current_packet; - plm_packet_t next_packet; -} plm_demux_t; - - -void plm_demux_buffer_seek(plm_demux_t *self, size_t pos); -double plm_demux_decode_time(plm_demux_t *self); -plm_packet_t *plm_demux_decode_packet(plm_demux_t *self, int type); -plm_packet_t *plm_demux_get_packet(plm_demux_t *self); - -plm_demux_t *plm_demux_create(plm_buffer_t *buffer, int destroy_when_done) { - plm_demux_t *self = (plm_demux_t *)malloc(sizeof(plm_demux_t)); - memset(self, 0, sizeof(plm_demux_t)); - - self->buffer = buffer; - self->destroy_buffer_when_done = destroy_when_done; - - self->start_time = PLM_PACKET_INVALID_TS; - self->duration = PLM_PACKET_INVALID_TS; - self->start_code = -1; - - plm_demux_has_headers(self); - return self; -} - -void plm_demux_destroy(plm_demux_t *self) { - if (self->destroy_buffer_when_done) { - plm_buffer_destroy(self->buffer); - } - free(self); -} - -int plm_demux_has_headers(plm_demux_t *self) { - if (self->has_headers) { - return TRUE; - } - - // Decode pack header - if (!self->has_pack_header) { - if ( - self->start_code != PLM_START_PACK && - plm_buffer_find_start_code(self->buffer, PLM_START_PACK) == -1 - ) { - return FALSE; - } - - self->start_code = PLM_START_PACK; - if (!plm_buffer_has(self->buffer, 64)) { - return FALSE; - } - self->start_code = -1; - - if (plm_buffer_read(self->buffer, 4) != 0x02) { - return FALSE; - } - - self->system_clock_ref = plm_demux_decode_time(self); - plm_buffer_skip(self->buffer, 1); - plm_buffer_skip(self->buffer, 22); // mux_rate * 50 - plm_buffer_skip(self->buffer, 1); - - self->has_pack_header = TRUE; - } - - // Decode system header - if (!self->has_system_header) { - if ( - self->start_code != PLM_START_SYSTEM && - plm_buffer_find_start_code(self->buffer, PLM_START_SYSTEM) == -1 - ) { - return FALSE; - } - - self->start_code = PLM_START_SYSTEM; - if (!plm_buffer_has(self->buffer, 56)) { - return FALSE; - } - self->start_code = -1; - - plm_buffer_skip(self->buffer, 16); // header_length - plm_buffer_skip(self->buffer, 24); // rate bound - self->num_audio_streams = plm_buffer_read(self->buffer, 6); - plm_buffer_skip(self->buffer, 5); // misc flags - self->num_video_streams = plm_buffer_read(self->buffer, 5); - - self->has_system_header = TRUE; - } - - self->has_headers = TRUE; - return TRUE; -} - -int plm_demux_get_num_video_streams(plm_demux_t *self) { - return plm_demux_has_headers(self) - ? self->num_video_streams - : 0; -} - -int plm_demux_get_num_audio_streams(plm_demux_t *self) { - return plm_demux_has_headers(self) - ? self->num_audio_streams - : 0; -} - -void plm_demux_rewind(plm_demux_t *self) { - plm_buffer_rewind(self->buffer); - self->current_packet.length = 0; - self->next_packet.length = 0; - self->start_code = -1; -} - -int plm_demux_has_ended(plm_demux_t *self) { - return plm_buffer_has_ended(self->buffer); -} - -void plm_demux_buffer_seek(plm_demux_t *self, size_t pos) { - plm_buffer_seek(self->buffer, pos); - self->current_packet.length = 0; - self->next_packet.length = 0; - self->start_code = -1; -} - -double plm_demux_get_start_time(plm_demux_t *self, int type) { - if (self->start_time != PLM_PACKET_INVALID_TS) { - return self->start_time; - } - - int previous_pos = plm_buffer_tell(self->buffer); - int previous_start_code = self->start_code; - - // Find first video PTS - plm_demux_rewind(self); - do { - plm_packet_t *packet = plm_demux_decode(self); - if (!packet) { - break; - } - if (packet->type == type) { - self->start_time = packet->pts; - } - } while (self->start_time == PLM_PACKET_INVALID_TS); - - plm_demux_buffer_seek(self, previous_pos); - self->start_code = previous_start_code; - return self->start_time; -} - -double plm_demux_get_duration(plm_demux_t *self, int type) { - size_t file_size = plm_buffer_get_size(self->buffer); - - if ( - self->duration != PLM_PACKET_INVALID_TS && - self->last_file_size == file_size - ) { - return self->duration; - } - - size_t previous_pos = plm_buffer_tell(self->buffer); - int previous_start_code = self->start_code; - - // Find last video PTS. Start searching 64kb from the end and go further - // back if needed. - long start_range = 64 * 1024; - long max_range = 4096 * 1024; - for (long range = start_range; range <= max_range; range *= 2) { - long seek_pos = file_size - range; - if (seek_pos < 0) { - seek_pos = 0; - range = max_range; // Make sure to bail after this round - } - plm_demux_buffer_seek(self, seek_pos); - self->current_packet.length = 0; - - double last_pts = PLM_PACKET_INVALID_TS; - plm_packet_t *packet = NULL; - while ((packet = plm_demux_decode(self))) { - if (packet->pts != PLM_PACKET_INVALID_TS && packet->type == type) { - last_pts = packet->pts; - } - } - if (last_pts != PLM_PACKET_INVALID_TS) { - self->duration = last_pts - plm_demux_get_start_time(self, type); - break; - } - } - - plm_demux_buffer_seek(self, previous_pos); - self->start_code = previous_start_code; - self->last_file_size = file_size; - return self->duration; -} - -plm_packet_t *plm_demux_seek(plm_demux_t *self, double seek_time, int type, int force_intra) { - if (!plm_demux_has_headers(self)) { - return NULL; - } - - // Using the current time, current byte position and the average bytes per - // second for this file, try to jump to a byte position that hopefully has - // packets containing timestamps within one second before to the desired - // seek_time. - - // If we hit close to the seek_time scan through all packets to find the - // last one (just before the seek_time) containing an intra frame. - // Otherwise we should at least be closer than before. Calculate the bytes - // per second for the jumped range and jump again. - - // The number of retries here is hard-limited to a generous amount. Usually - // the correct range is found after 1--5 jumps, even for files with very - // variable bitrates. If significantly more jumps are needed, there's - // probably something wrong with the file and we just avoid getting into an - // infinite loop. 32 retries should be enough for anybody. - - double duration = plm_demux_get_duration(self, type); - long file_size = plm_buffer_get_size(self->buffer); - long byterate = file_size / duration; - - double cur_time = self->last_decoded_pts; - double scan_span = 1; - - if (seek_time > duration) { - seek_time = duration; - } - else if (seek_time < 0) { - seek_time = 0; - } - seek_time += self->start_time; - - for (int retry = 0; retry < 32; retry++) { - int found_packet_with_pts = FALSE; - int found_packet_in_range = FALSE; - long last_valid_packet_start = -1; - double first_packet_time = PLM_PACKET_INVALID_TS; - - long cur_pos = plm_buffer_tell(self->buffer); - - // Estimate byte offset and jump to it. - long offset = (seek_time - cur_time - scan_span) * byterate; - long seek_pos = cur_pos + offset; - if (seek_pos < 0) { - seek_pos = 0; - } - else if (seek_pos > file_size - 256) { - seek_pos = file_size - 256; - } - - plm_demux_buffer_seek(self, seek_pos); - - // Scan through all packets up to the seek_time to find the last packet - // containing an intra frame. - while (plm_buffer_find_start_code(self->buffer, type) != -1) { - long packet_start = plm_buffer_tell(self->buffer); - plm_packet_t *packet = plm_demux_decode_packet(self, type); - - // Skip packet if it has no PTS - if (!packet || packet->pts == PLM_PACKET_INVALID_TS) { - continue; - } - - // Bail scanning through packets if we hit one that is outside - // seek_time - scan_span. - // We also adjust the cur_time and byterate values here so the next - // iteration can be a bit more precise. - if (packet->pts > seek_time || packet->pts < seek_time - scan_span) { - found_packet_with_pts = TRUE; - byterate = (seek_pos - cur_pos) / (packet->pts - cur_time); - cur_time = packet->pts; - break; - } - - // If we are still here, it means this packet is in close range to - // the seek_time. If this is the first packet for this jump position - // record the PTS. If we later have to back off, when there was no - // intra frame in this range, we can lower the seek_time to not scan - // this range again. - if (!found_packet_in_range) { - found_packet_in_range = TRUE; - first_packet_time = packet->pts; - } - - // Check if this is an intra frame packet. If so, record the buffer - // position of the start of this packet. We want to jump back to it - // later, when we know it's the last intra frame before desired - // seek time. - if (force_intra) { - for (size_t i = 0; i < packet->length - 6; i++) { - // Find the START_PICTURE code - if ( - packet->data[i] == 0x00 && - packet->data[i + 1] == 0x00 && - packet->data[i + 2] == 0x01 && - packet->data[i + 3] == 0x00 - ) { - // Bits 11--13 in the picture header contain the frame - // type, where 1=Intra - if ((packet->data[i + 5] & 0x38) == 8) { - last_valid_packet_start = packet_start; - } - break; - } - } - } - - // If we don't want intra frames, just use the last PTS found. - else { - last_valid_packet_start = packet_start; - } - } - - // If there was at least one intra frame in the range scanned above, - // our search is over. Jump back to the packet and decode it again. - if (last_valid_packet_start != -1) { - plm_demux_buffer_seek(self, last_valid_packet_start); - return plm_demux_decode_packet(self, type); - } - - // If we hit the right range, but still found no intra frame, we have - // to increases the scan_span. This is done exponentially to also handle - // video files with very few intra frames. - else if (found_packet_in_range) { - scan_span *= 2; - seek_time = first_packet_time; - } - - // If we didn't find any packet with a PTS, it probably means we reached - // the end of the file. Estimate byterate and cur_time accordingly. - else if (!found_packet_with_pts) { - byterate = (seek_pos - cur_pos) / (duration - cur_time); - cur_time = duration; - } - } - - return NULL; -} - -plm_packet_t *plm_demux_decode(plm_demux_t *self) { - if (!plm_demux_has_headers(self)) { - return NULL; - } - - if (self->current_packet.length) { - size_t bits_till_next_packet = self->current_packet.length << 3; - if (!plm_buffer_has(self->buffer, bits_till_next_packet)) { - return NULL; - } - plm_buffer_skip(self->buffer, bits_till_next_packet); - self->current_packet.length = 0; - } - - // Pending packet waiting for data? - if (self->next_packet.length) { - return plm_demux_get_packet(self); - } - - // Pending packet waiting for header? - if (self->start_code != -1) { - return plm_demux_decode_packet(self, self->start_code); - } - - do { - self->start_code = plm_buffer_next_start_code(self->buffer); - if ( - self->start_code == PLM_DEMUX_PACKET_VIDEO_1 || - self->start_code == PLM_DEMUX_PACKET_PRIVATE || ( - self->start_code >= PLM_DEMUX_PACKET_AUDIO_1 && - self->start_code <= PLM_DEMUX_PACKET_AUDIO_4 - ) - ) { - return plm_demux_decode_packet(self, self->start_code); - } - } while (self->start_code != -1); - - return NULL; -} - -double plm_demux_decode_time(plm_demux_t *self) { - int64_t clock = plm_buffer_read(self->buffer, 3) << 30; - plm_buffer_skip(self->buffer, 1); - clock |= plm_buffer_read(self->buffer, 15) << 15; - plm_buffer_skip(self->buffer, 1); - clock |= plm_buffer_read(self->buffer, 15); - plm_buffer_skip(self->buffer, 1); - return (double)clock / 90000.0; -} - -plm_packet_t *plm_demux_decode_packet(plm_demux_t *self, int type) { - if (!plm_buffer_has(self->buffer, 16 << 3)) { - return NULL; - } - - self->start_code = -1; - - self->next_packet.type = type; - self->next_packet.length = plm_buffer_read(self->buffer, 16); - self->next_packet.length -= plm_buffer_skip_bytes(self->buffer, 0xff); // stuffing - - // skip P-STD - if (plm_buffer_read(self->buffer, 2) == 0x01) { - plm_buffer_skip(self->buffer, 16); - self->next_packet.length -= 2; - } - - int pts_dts_marker = plm_buffer_read(self->buffer, 2); - if (pts_dts_marker == 0x03) { - self->next_packet.pts = plm_demux_decode_time(self); - self->last_decoded_pts = self->next_packet.pts; - plm_buffer_skip(self->buffer, 40); // skip dts - self->next_packet.length -= 10; - } - else if (pts_dts_marker == 0x02) { - self->next_packet.pts = plm_demux_decode_time(self); - self->last_decoded_pts = self->next_packet.pts; - self->next_packet.length -= 5; - } - else if (pts_dts_marker == 0x00) { - self->next_packet.pts = PLM_PACKET_INVALID_TS; - plm_buffer_skip(self->buffer, 4); - self->next_packet.length -= 1; - } - else { - return NULL; // invalid - } - - return plm_demux_get_packet(self); -} - -plm_packet_t *plm_demux_get_packet(plm_demux_t *self) { - if (!plm_buffer_has(self->buffer, self->next_packet.length << 3)) { - return NULL; - } - - self->current_packet.data = self->buffer->bytes + (self->buffer->bit_index >> 3); - self->current_packet.length = self->next_packet.length; - self->current_packet.type = self->next_packet.type; - self->current_packet.pts = self->next_packet.pts; - - self->next_packet.length = 0; - return &self->current_packet; -} - - - -// ----------------------------------------------------------------------------- -// plm_video implementation - -// Inspired by Java MPEG-1 Video Decoder and Player by Zoltan Korandi -// https://sourceforge.net/projects/javampeg1video/ - -static const int PLM_VIDEO_PICTURE_TYPE_INTRA = 1; -static const int PLM_VIDEO_PICTURE_TYPE_PREDICTIVE = 2; -static const int PLM_VIDEO_PICTURE_TYPE_B = 3; - -static const int PLM_START_SEQUENCE = 0xB3; -static const int PLM_START_SLICE_FIRST = 0x01; -static const int PLM_START_SLICE_LAST = 0xAF; -static const int PLM_START_PICTURE = 0x00; -static const int PLM_START_EXTENSION = 0xB5; -static const int PLM_START_USER_DATA = 0xB2; - -#define PLM_START_IS_SLICE(c) \ - (c >= PLM_START_SLICE_FIRST && c <= PLM_START_SLICE_LAST) - -static const double PLM_VIDEO_PICTURE_RATE[] = { - 0.000, 23.976, 24.000, 25.000, 29.970, 30.000, 50.000, 59.940, - 60.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000, 0.000 -}; - -static const uint8_t PLM_VIDEO_ZIG_ZAG[] = { - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63 -}; - -static const uint8_t PLM_VIDEO_INTRA_QUANT_MATRIX[] = { - 8, 16, 19, 22, 26, 27, 29, 34, - 16, 16, 22, 24, 27, 29, 34, 37, - 19, 22, 26, 27, 29, 34, 34, 38, - 22, 22, 26, 27, 29, 34, 37, 40, - 22, 26, 27, 29, 32, 35, 40, 48, - 26, 27, 29, 32, 35, 40, 48, 58, - 26, 27, 29, 34, 38, 46, 56, 69, - 27, 29, 35, 38, 46, 56, 69, 83 -}; - -static const uint8_t PLM_VIDEO_NON_INTRA_QUANT_MATRIX[] = { - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16 -}; - -static const uint8_t PLM_VIDEO_PREMULTIPLIER_MATRIX[] = { - 32, 44, 42, 38, 32, 25, 17, 9, - 44, 62, 58, 52, 44, 35, 24, 12, - 42, 58, 55, 49, 42, 33, 23, 12, - 38, 52, 49, 44, 38, 30, 20, 10, - 32, 44, 42, 38, 32, 25, 17, 9, - 25, 35, 33, 30, 25, 20, 14, 7, - 17, 24, 23, 20, 17, 14, 9, 5, - 9, 12, 12, 10, 9, 7, 5, 2 -}; - -static const plm_vlc_t PLM_VIDEO_MACROBLOCK_ADDRESS_INCREMENT[] = { - { 1 << 1, 0}, { 0, 1}, // 0: x - { 2 << 1, 0}, { 3 << 1, 0}, // 1: 0x - { 4 << 1, 0}, { 5 << 1, 0}, // 2: 00x - { 0, 3}, { 0, 2}, // 3: 01x - { 6 << 1, 0}, { 7 << 1, 0}, // 4: 000x - { 0, 5}, { 0, 4}, // 5: 001x - { 8 << 1, 0}, { 9 << 1, 0}, // 6: 0000x - { 0, 7}, { 0, 6}, // 7: 0001x - { 10 << 1, 0}, { 11 << 1, 0}, // 8: 0000 0x - { 12 << 1, 0}, { 13 << 1, 0}, // 9: 0000 1x - { 14 << 1, 0}, { 15 << 1, 0}, // 10: 0000 00x - { 16 << 1, 0}, { 17 << 1, 0}, // 11: 0000 01x - { 18 << 1, 0}, { 19 << 1, 0}, // 12: 0000 10x - { 0, 9}, { 0, 8}, // 13: 0000 11x - { -1, 0}, { 20 << 1, 0}, // 14: 0000 000x - { -1, 0}, { 21 << 1, 0}, // 15: 0000 001x - { 22 << 1, 0}, { 23 << 1, 0}, // 16: 0000 010x - { 0, 15}, { 0, 14}, // 17: 0000 011x - { 0, 13}, { 0, 12}, // 18: 0000 100x - { 0, 11}, { 0, 10}, // 19: 0000 101x - { 24 << 1, 0}, { 25 << 1, 0}, // 20: 0000 0001x - { 26 << 1, 0}, { 27 << 1, 0}, // 21: 0000 0011x - { 28 << 1, 0}, { 29 << 1, 0}, // 22: 0000 0100x - { 30 << 1, 0}, { 31 << 1, 0}, // 23: 0000 0101x - { 32 << 1, 0}, { -1, 0}, // 24: 0000 0001 0x - { -1, 0}, { 33 << 1, 0}, // 25: 0000 0001 1x - { 34 << 1, 0}, { 35 << 1, 0}, // 26: 0000 0011 0x - { 36 << 1, 0}, { 37 << 1, 0}, // 27: 0000 0011 1x - { 38 << 1, 0}, { 39 << 1, 0}, // 28: 0000 0100 0x - { 0, 21}, { 0, 20}, // 29: 0000 0100 1x - { 0, 19}, { 0, 18}, // 30: 0000 0101 0x - { 0, 17}, { 0, 16}, // 31: 0000 0101 1x - { 0, 35}, { -1, 0}, // 32: 0000 0001 00x - { -1, 0}, { 0, 34}, // 33: 0000 0001 11x - { 0, 33}, { 0, 32}, // 34: 0000 0011 00x - { 0, 31}, { 0, 30}, // 35: 0000 0011 01x - { 0, 29}, { 0, 28}, // 36: 0000 0011 10x - { 0, 27}, { 0, 26}, // 37: 0000 0011 11x - { 0, 25}, { 0, 24}, // 38: 0000 0100 00x - { 0, 23}, { 0, 22}, // 39: 0000 0100 01x -}; - -static const plm_vlc_t PLM_VIDEO_MACROBLOCK_TYPE_INTRA[] = { - { 1 << 1, 0}, { 0, 0x01}, // 0: x - { -1, 0}, { 0, 0x11}, // 1: 0x -}; - -static const plm_vlc_t PLM_VIDEO_MACROBLOCK_TYPE_PREDICTIVE[] = { - { 1 << 1, 0}, { 0, 0x0a}, // 0: x - { 2 << 1, 0}, { 0, 0x02}, // 1: 0x - { 3 << 1, 0}, { 0, 0x08}, // 2: 00x - { 4 << 1, 0}, { 5 << 1, 0}, // 3: 000x - { 6 << 1, 0}, { 0, 0x12}, // 4: 0000x - { 0, 0x1a}, { 0, 0x01}, // 5: 0001x - { -1, 0}, { 0, 0x11}, // 6: 0000 0x -}; - -static const plm_vlc_t PLM_VIDEO_MACROBLOCK_TYPE_B[] = { - { 1 << 1, 0}, { 2 << 1, 0}, // 0: x - { 3 << 1, 0}, { 4 << 1, 0}, // 1: 0x - { 0, 0x0c}, { 0, 0x0e}, // 2: 1x - { 5 << 1, 0}, { 6 << 1, 0}, // 3: 00x - { 0, 0x04}, { 0, 0x06}, // 4: 01x - { 7 << 1, 0}, { 8 << 1, 0}, // 5: 000x - { 0, 0x08}, { 0, 0x0a}, // 6: 001x - { 9 << 1, 0}, { 10 << 1, 0}, // 7: 0000x - { 0, 0x1e}, { 0, 0x01}, // 8: 0001x - { -1, 0}, { 0, 0x11}, // 9: 0000 0x - { 0, 0x16}, { 0, 0x1a}, // 10: 0000 1x -}; - -static const plm_vlc_t *PLM_VIDEO_MACROBLOCK_TYPE[] = { - NULL, - PLM_VIDEO_MACROBLOCK_TYPE_INTRA, - PLM_VIDEO_MACROBLOCK_TYPE_PREDICTIVE, - PLM_VIDEO_MACROBLOCK_TYPE_B -}; - -static const plm_vlc_t PLM_VIDEO_CODE_BLOCK_PATTERN[] = { - { 1 << 1, 0}, { 2 << 1, 0}, // 0: x - { 3 << 1, 0}, { 4 << 1, 0}, // 1: 0x - { 5 << 1, 0}, { 6 << 1, 0}, // 2: 1x - { 7 << 1, 0}, { 8 << 1, 0}, // 3: 00x - { 9 << 1, 0}, { 10 << 1, 0}, // 4: 01x - { 11 << 1, 0}, { 12 << 1, 0}, // 5: 10x - { 13 << 1, 0}, { 0, 60}, // 6: 11x - { 14 << 1, 0}, { 15 << 1, 0}, // 7: 000x - { 16 << 1, 0}, { 17 << 1, 0}, // 8: 001x - { 18 << 1, 0}, { 19 << 1, 0}, // 9: 010x - { 20 << 1, 0}, { 21 << 1, 0}, // 10: 011x - { 22 << 1, 0}, { 23 << 1, 0}, // 11: 100x - { 0, 32}, { 0, 16}, // 12: 101x - { 0, 8}, { 0, 4}, // 13: 110x - { 24 << 1, 0}, { 25 << 1, 0}, // 14: 0000x - { 26 << 1, 0}, { 27 << 1, 0}, // 15: 0001x - { 28 << 1, 0}, { 29 << 1, 0}, // 16: 0010x - { 30 << 1, 0}, { 31 << 1, 0}, // 17: 0011x - { 0, 62}, { 0, 2}, // 18: 0100x - { 0, 61}, { 0, 1}, // 19: 0101x - { 0, 56}, { 0, 52}, // 20: 0110x - { 0, 44}, { 0, 28}, // 21: 0111x - { 0, 40}, { 0, 20}, // 22: 1000x - { 0, 48}, { 0, 12}, // 23: 1001x - { 32 << 1, 0}, { 33 << 1, 0}, // 24: 0000 0x - { 34 << 1, 0}, { 35 << 1, 0}, // 25: 0000 1x - { 36 << 1, 0}, { 37 << 1, 0}, // 26: 0001 0x - { 38 << 1, 0}, { 39 << 1, 0}, // 27: 0001 1x - { 40 << 1, 0}, { 41 << 1, 0}, // 28: 0010 0x - { 42 << 1, 0}, { 43 << 1, 0}, // 29: 0010 1x - { 0, 63}, { 0, 3}, // 30: 0011 0x - { 0, 36}, { 0, 24}, // 31: 0011 1x - { 44 << 1, 0}, { 45 << 1, 0}, // 32: 0000 00x - { 46 << 1, 0}, { 47 << 1, 0}, // 33: 0000 01x - { 48 << 1, 0}, { 49 << 1, 0}, // 34: 0000 10x - { 50 << 1, 0}, { 51 << 1, 0}, // 35: 0000 11x - { 52 << 1, 0}, { 53 << 1, 0}, // 36: 0001 00x - { 54 << 1, 0}, { 55 << 1, 0}, // 37: 0001 01x - { 56 << 1, 0}, { 57 << 1, 0}, // 38: 0001 10x - { 58 << 1, 0}, { 59 << 1, 0}, // 39: 0001 11x - { 0, 34}, { 0, 18}, // 40: 0010 00x - { 0, 10}, { 0, 6}, // 41: 0010 01x - { 0, 33}, { 0, 17}, // 42: 0010 10x - { 0, 9}, { 0, 5}, // 43: 0010 11x - { -1, 0}, { 60 << 1, 0}, // 44: 0000 000x - { 61 << 1, 0}, { 62 << 1, 0}, // 45: 0000 001x - { 0, 58}, { 0, 54}, // 46: 0000 010x - { 0, 46}, { 0, 30}, // 47: 0000 011x - { 0, 57}, { 0, 53}, // 48: 0000 100x - { 0, 45}, { 0, 29}, // 49: 0000 101x - { 0, 38}, { 0, 26}, // 50: 0000 110x - { 0, 37}, { 0, 25}, // 51: 0000 111x - { 0, 43}, { 0, 23}, // 52: 0001 000x - { 0, 51}, { 0, 15}, // 53: 0001 001x - { 0, 42}, { 0, 22}, // 54: 0001 010x - { 0, 50}, { 0, 14}, // 55: 0001 011x - { 0, 41}, { 0, 21}, // 56: 0001 100x - { 0, 49}, { 0, 13}, // 57: 0001 101x - { 0, 35}, { 0, 19}, // 58: 0001 110x - { 0, 11}, { 0, 7}, // 59: 0001 111x - { 0, 39}, { 0, 27}, // 60: 0000 0001x - { 0, 59}, { 0, 55}, // 61: 0000 0010x - { 0, 47}, { 0, 31}, // 62: 0000 0011x -}; - -static const plm_vlc_t PLM_VIDEO_MOTION[] = { - { 1 << 1, 0}, { 0, 0}, // 0: x - { 2 << 1, 0}, { 3 << 1, 0}, // 1: 0x - { 4 << 1, 0}, { 5 << 1, 0}, // 2: 00x - { 0, 1}, { 0, -1}, // 3: 01x - { 6 << 1, 0}, { 7 << 1, 0}, // 4: 000x - { 0, 2}, { 0, -2}, // 5: 001x - { 8 << 1, 0}, { 9 << 1, 0}, // 6: 0000x - { 0, 3}, { 0, -3}, // 7: 0001x - { 10 << 1, 0}, { 11 << 1, 0}, // 8: 0000 0x - { 12 << 1, 0}, { 13 << 1, 0}, // 9: 0000 1x - { -1, 0}, { 14 << 1, 0}, // 10: 0000 00x - { 15 << 1, 0}, { 16 << 1, 0}, // 11: 0000 01x - { 17 << 1, 0}, { 18 << 1, 0}, // 12: 0000 10x - { 0, 4}, { 0, -4}, // 13: 0000 11x - { -1, 0}, { 19 << 1, 0}, // 14: 0000 001x - { 20 << 1, 0}, { 21 << 1, 0}, // 15: 0000 010x - { 0, 7}, { 0, -7}, // 16: 0000 011x - { 0, 6}, { 0, -6}, // 17: 0000 100x - { 0, 5}, { 0, -5}, // 18: 0000 101x - { 22 << 1, 0}, { 23 << 1, 0}, // 19: 0000 0011x - { 24 << 1, 0}, { 25 << 1, 0}, // 20: 0000 0100x - { 26 << 1, 0}, { 27 << 1, 0}, // 21: 0000 0101x - { 28 << 1, 0}, { 29 << 1, 0}, // 22: 0000 0011 0x - { 30 << 1, 0}, { 31 << 1, 0}, // 23: 0000 0011 1x - { 32 << 1, 0}, { 33 << 1, 0}, // 24: 0000 0100 0x - { 0, 10}, { 0, -10}, // 25: 0000 0100 1x - { 0, 9}, { 0, -9}, // 26: 0000 0101 0x - { 0, 8}, { 0, -8}, // 27: 0000 0101 1x - { 0, 16}, { 0, -16}, // 28: 0000 0011 00x - { 0, 15}, { 0, -15}, // 29: 0000 0011 01x - { 0, 14}, { 0, -14}, // 30: 0000 0011 10x - { 0, 13}, { 0, -13}, // 31: 0000 0011 11x - { 0, 12}, { 0, -12}, // 32: 0000 0100 00x - { 0, 11}, { 0, -11}, // 33: 0000 0100 01x -}; - -static const plm_vlc_t PLM_VIDEO_DCT_SIZE_LUMINANCE[] = { - { 1 << 1, 0}, { 2 << 1, 0}, // 0: x - { 0, 1}, { 0, 2}, // 1: 0x - { 3 << 1, 0}, { 4 << 1, 0}, // 2: 1x - { 0, 0}, { 0, 3}, // 3: 10x - { 0, 4}, { 5 << 1, 0}, // 4: 11x - { 0, 5}, { 6 << 1, 0}, // 5: 111x - { 0, 6}, { 7 << 1, 0}, // 6: 1111x - { 0, 7}, { 8 << 1, 0}, // 7: 1111 1x - { 0, 8}, { -1, 0}, // 8: 1111 11x -}; - -static const plm_vlc_t PLM_VIDEO_DCT_SIZE_CHROMINANCE[] = { - { 1 << 1, 0}, { 2 << 1, 0}, // 0: x - { 0, 0}, { 0, 1}, // 1: 0x - { 0, 2}, { 3 << 1, 0}, // 2: 1x - { 0, 3}, { 4 << 1, 0}, // 3: 11x - { 0, 4}, { 5 << 1, 0}, // 4: 111x - { 0, 5}, { 6 << 1, 0}, // 5: 1111x - { 0, 6}, { 7 << 1, 0}, // 6: 1111 1x - { 0, 7}, { 8 << 1, 0}, // 7: 1111 11x - { 0, 8}, { -1, 0}, // 8: 1111 111x -}; - -static const plm_vlc_t *PLM_VIDEO_DCT_SIZE[] = { - PLM_VIDEO_DCT_SIZE_LUMINANCE, - PLM_VIDEO_DCT_SIZE_CHROMINANCE, - PLM_VIDEO_DCT_SIZE_CHROMINANCE -}; - - -// dct_coeff bitmap: -// 0xff00 run -// 0x00ff level - -// Decoded values are unsigned. Sign bit follows in the stream. - -static const plm_vlc_uint_t PLM_VIDEO_DCT_COEFF[] = { - { 1 << 1, 0}, { 0, 0x0001}, // 0: x - { 2 << 1, 0}, { 3 << 1, 0}, // 1: 0x - { 4 << 1, 0}, { 5 << 1, 0}, // 2: 00x - { 6 << 1, 0}, { 0, 0x0101}, // 3: 01x - { 7 << 1, 0}, { 8 << 1, 0}, // 4: 000x - { 9 << 1, 0}, { 10 << 1, 0}, // 5: 001x - { 0, 0x0002}, { 0, 0x0201}, // 6: 010x - { 11 << 1, 0}, { 12 << 1, 0}, // 7: 0000x - { 13 << 1, 0}, { 14 << 1, 0}, // 8: 0001x - { 15 << 1, 0}, { 0, 0x0003}, // 9: 0010x - { 0, 0x0401}, { 0, 0x0301}, // 10: 0011x - { 16 << 1, 0}, { 0, 0xffff}, // 11: 0000 0x - { 17 << 1, 0}, { 18 << 1, 0}, // 12: 0000 1x - { 0, 0x0701}, { 0, 0x0601}, // 13: 0001 0x - { 0, 0x0102}, { 0, 0x0501}, // 14: 0001 1x - { 19 << 1, 0}, { 20 << 1, 0}, // 15: 0010 0x - { 21 << 1, 0}, { 22 << 1, 0}, // 16: 0000 00x - { 0, 0x0202}, { 0, 0x0901}, // 17: 0000 10x - { 0, 0x0004}, { 0, 0x0801}, // 18: 0000 11x - { 23 << 1, 0}, { 24 << 1, 0}, // 19: 0010 00x - { 25 << 1, 0}, { 26 << 1, 0}, // 20: 0010 01x - { 27 << 1, 0}, { 28 << 1, 0}, // 21: 0000 000x - { 29 << 1, 0}, { 30 << 1, 0}, // 22: 0000 001x - { 0, 0x0d01}, { 0, 0x0006}, // 23: 0010 000x - { 0, 0x0c01}, { 0, 0x0b01}, // 24: 0010 001x - { 0, 0x0302}, { 0, 0x0103}, // 25: 0010 010x - { 0, 0x0005}, { 0, 0x0a01}, // 26: 0010 011x - { 31 << 1, 0}, { 32 << 1, 0}, // 27: 0000 0000x - { 33 << 1, 0}, { 34 << 1, 0}, // 28: 0000 0001x - { 35 << 1, 0}, { 36 << 1, 0}, // 29: 0000 0010x - { 37 << 1, 0}, { 38 << 1, 0}, // 30: 0000 0011x - { 39 << 1, 0}, { 40 << 1, 0}, // 31: 0000 0000 0x - { 41 << 1, 0}, { 42 << 1, 0}, // 32: 0000 0000 1x - { 43 << 1, 0}, { 44 << 1, 0}, // 33: 0000 0001 0x - { 45 << 1, 0}, { 46 << 1, 0}, // 34: 0000 0001 1x - { 0, 0x1001}, { 0, 0x0502}, // 35: 0000 0010 0x - { 0, 0x0007}, { 0, 0x0203}, // 36: 0000 0010 1x - { 0, 0x0104}, { 0, 0x0f01}, // 37: 0000 0011 0x - { 0, 0x0e01}, { 0, 0x0402}, // 38: 0000 0011 1x - { 47 << 1, 0}, { 48 << 1, 0}, // 39: 0000 0000 00x - { 49 << 1, 0}, { 50 << 1, 0}, // 40: 0000 0000 01x - { 51 << 1, 0}, { 52 << 1, 0}, // 41: 0000 0000 10x - { 53 << 1, 0}, { 54 << 1, 0}, // 42: 0000 0000 11x - { 55 << 1, 0}, { 56 << 1, 0}, // 43: 0000 0001 00x - { 57 << 1, 0}, { 58 << 1, 0}, // 44: 0000 0001 01x - { 59 << 1, 0}, { 60 << 1, 0}, // 45: 0000 0001 10x - { 61 << 1, 0}, { 62 << 1, 0}, // 46: 0000 0001 11x - { -1, 0}, { 63 << 1, 0}, // 47: 0000 0000 000x - { 64 << 1, 0}, { 65 << 1, 0}, // 48: 0000 0000 001x - { 66 << 1, 0}, { 67 << 1, 0}, // 49: 0000 0000 010x - { 68 << 1, 0}, { 69 << 1, 0}, // 50: 0000 0000 011x - { 70 << 1, 0}, { 71 << 1, 0}, // 51: 0000 0000 100x - { 72 << 1, 0}, { 73 << 1, 0}, // 52: 0000 0000 101x - { 74 << 1, 0}, { 75 << 1, 0}, // 53: 0000 0000 110x - { 76 << 1, 0}, { 77 << 1, 0}, // 54: 0000 0000 111x - { 0, 0x000b}, { 0, 0x0802}, // 55: 0000 0001 000x - { 0, 0x0403}, { 0, 0x000a}, // 56: 0000 0001 001x - { 0, 0x0204}, { 0, 0x0702}, // 57: 0000 0001 010x - { 0, 0x1501}, { 0, 0x1401}, // 58: 0000 0001 011x - { 0, 0x0009}, { 0, 0x1301}, // 59: 0000 0001 100x - { 0, 0x1201}, { 0, 0x0105}, // 60: 0000 0001 101x - { 0, 0x0303}, { 0, 0x0008}, // 61: 0000 0001 110x - { 0, 0x0602}, { 0, 0x1101}, // 62: 0000 0001 111x - { 78 << 1, 0}, { 79 << 1, 0}, // 63: 0000 0000 0001x - { 80 << 1, 0}, { 81 << 1, 0}, // 64: 0000 0000 0010x - { 82 << 1, 0}, { 83 << 1, 0}, // 65: 0000 0000 0011x - { 84 << 1, 0}, { 85 << 1, 0}, // 66: 0000 0000 0100x - { 86 << 1, 0}, { 87 << 1, 0}, // 67: 0000 0000 0101x - { 88 << 1, 0}, { 89 << 1, 0}, // 68: 0000 0000 0110x - { 90 << 1, 0}, { 91 << 1, 0}, // 69: 0000 0000 0111x - { 0, 0x0a02}, { 0, 0x0902}, // 70: 0000 0000 1000x - { 0, 0x0503}, { 0, 0x0304}, // 71: 0000 0000 1001x - { 0, 0x0205}, { 0, 0x0107}, // 72: 0000 0000 1010x - { 0, 0x0106}, { 0, 0x000f}, // 73: 0000 0000 1011x - { 0, 0x000e}, { 0, 0x000d}, // 74: 0000 0000 1100x - { 0, 0x000c}, { 0, 0x1a01}, // 75: 0000 0000 1101x - { 0, 0x1901}, { 0, 0x1801}, // 76: 0000 0000 1110x - { 0, 0x1701}, { 0, 0x1601}, // 77: 0000 0000 1111x - { 92 << 1, 0}, { 93 << 1, 0}, // 78: 0000 0000 0001 0x - { 94 << 1, 0}, { 95 << 1, 0}, // 79: 0000 0000 0001 1x - { 96 << 1, 0}, { 97 << 1, 0}, // 80: 0000 0000 0010 0x - { 98 << 1, 0}, { 99 << 1, 0}, // 81: 0000 0000 0010 1x - {100 << 1, 0}, {101 << 1, 0}, // 82: 0000 0000 0011 0x - {102 << 1, 0}, {103 << 1, 0}, // 83: 0000 0000 0011 1x - { 0, 0x001f}, { 0, 0x001e}, // 84: 0000 0000 0100 0x - { 0, 0x001d}, { 0, 0x001c}, // 85: 0000 0000 0100 1x - { 0, 0x001b}, { 0, 0x001a}, // 86: 0000 0000 0101 0x - { 0, 0x0019}, { 0, 0x0018}, // 87: 0000 0000 0101 1x - { 0, 0x0017}, { 0, 0x0016}, // 88: 0000 0000 0110 0x - { 0, 0x0015}, { 0, 0x0014}, // 89: 0000 0000 0110 1x - { 0, 0x0013}, { 0, 0x0012}, // 90: 0000 0000 0111 0x - { 0, 0x0011}, { 0, 0x0010}, // 91: 0000 0000 0111 1x - {104 << 1, 0}, {105 << 1, 0}, // 92: 0000 0000 0001 00x - {106 << 1, 0}, {107 << 1, 0}, // 93: 0000 0000 0001 01x - {108 << 1, 0}, {109 << 1, 0}, // 94: 0000 0000 0001 10x - {110 << 1, 0}, {111 << 1, 0}, // 95: 0000 0000 0001 11x - { 0, 0x0028}, { 0, 0x0027}, // 96: 0000 0000 0010 00x - { 0, 0x0026}, { 0, 0x0025}, // 97: 0000 0000 0010 01x - { 0, 0x0024}, { 0, 0x0023}, // 98: 0000 0000 0010 10x - { 0, 0x0022}, { 0, 0x0021}, // 99: 0000 0000 0010 11x - { 0, 0x0020}, { 0, 0x010e}, // 100: 0000 0000 0011 00x - { 0, 0x010d}, { 0, 0x010c}, // 101: 0000 0000 0011 01x - { 0, 0x010b}, { 0, 0x010a}, // 102: 0000 0000 0011 10x - { 0, 0x0109}, { 0, 0x0108}, // 103: 0000 0000 0011 11x - { 0, 0x0112}, { 0, 0x0111}, // 104: 0000 0000 0001 000x - { 0, 0x0110}, { 0, 0x010f}, // 105: 0000 0000 0001 001x - { 0, 0x0603}, { 0, 0x1002}, // 106: 0000 0000 0001 010x - { 0, 0x0f02}, { 0, 0x0e02}, // 107: 0000 0000 0001 011x - { 0, 0x0d02}, { 0, 0x0c02}, // 108: 0000 0000 0001 100x - { 0, 0x0b02}, { 0, 0x1f01}, // 109: 0000 0000 0001 101x - { 0, 0x1e01}, { 0, 0x1d01}, // 110: 0000 0000 0001 110x - { 0, 0x1c01}, { 0, 0x1b01}, // 111: 0000 0000 0001 111x -}; - -typedef struct { - int full_px; - int is_set; - int r_size; - int h; - int v; -} plm_video_motion_t; - -typedef struct plm_video_t { - double framerate; - double time; - int frames_decoded; - int width; - int height; - int mb_width; - int mb_height; - int mb_size; - - int luma_width; - int luma_height; - - int chroma_width; - int chroma_height; - - int start_code; - int picture_type; - - plm_video_motion_t motion_forward; - plm_video_motion_t motion_backward; - - int has_sequence_header; - - int quantizer_scale; - int slice_begin; - int macroblock_address; - - int mb_row; - int mb_col; - - int macroblock_type; - int macroblock_intra; - - int dc_predictor[3]; - - plm_buffer_t *buffer; - int destroy_buffer_when_done; - - plm_frame_t frame_current; - plm_frame_t frame_forward; - plm_frame_t frame_backward; - - uint8_t *frames_data; - - int block_data[64]; - uint8_t intra_quant_matrix[64]; - uint8_t non_intra_quant_matrix[64]; - - int has_reference_frame; - int assume_no_b_frames; -} plm_video_t; - -static inline uint8_t plm_clamp(int n) { - if (n > 255) { - n = 255; - } - else if (n < 0) { - n = 0; - } - return n; -} - -int plm_video_decode_sequence_header(plm_video_t *self); -void plm_video_init_frame(plm_video_t *self, plm_frame_t *frame, uint8_t *base); -void plm_video_decode_picture(plm_video_t *self); -void plm_video_decode_slice(plm_video_t *self, int slice); -void plm_video_decode_macroblock(plm_video_t *self); -void plm_video_decode_motion_vectors(plm_video_t *self); -int plm_video_decode_motion_vector(plm_video_t *self, int r_size, int motion); -void plm_video_predict_macroblock(plm_video_t *self); -void plm_video_copy_macroblock(plm_video_t *self, int motion_h, int motion_v, plm_frame_t *d); -void plm_video_interpolate_macroblock(plm_video_t *self, int motion_h, int motion_v, plm_frame_t *d); -void plm_video_process_macroblock(plm_video_t *self, uint8_t *d, uint8_t *s, int mh, int mb, int bs, int interp); -void plm_video_decode_block(plm_video_t *self, int block); -void plm_video_idct(int *block); - -plm_video_t * plm_video_create_with_buffer(plm_buffer_t *buffer, int destroy_when_done) { - plm_video_t *self = (plm_video_t *)malloc(sizeof(plm_video_t)); - memset(self, 0, sizeof(plm_video_t)); - - self->buffer = buffer; - self->destroy_buffer_when_done = destroy_when_done; - - // Attempt to decode the sequence header - self->start_code = plm_buffer_find_start_code(self->buffer, PLM_START_SEQUENCE); - if (self->start_code != -1) { - plm_video_decode_sequence_header(self); - } - return self; -} - -void plm_video_destroy(plm_video_t *self) { - if (self->destroy_buffer_when_done) { - plm_buffer_destroy(self->buffer); - } - - if (self->has_sequence_header) { - free(self->frames_data); - } - - free(self); -} - -double plm_video_get_framerate(plm_video_t *self) { - return plm_video_has_header(self) - ? self->framerate - : 0; -} - -int plm_video_get_width(plm_video_t *self) { - return plm_video_has_header(self) - ? self->width - : 0; -} - -int plm_video_get_height(plm_video_t *self) { - return plm_video_has_header(self) - ? self->height - : 0; -} - -void plm_video_set_no_delay(plm_video_t *self, int no_delay) { - self->assume_no_b_frames = no_delay; -} - -double plm_video_get_time(plm_video_t *self) { - return self->time; -} - -void plm_video_set_time(plm_video_t *self, double time) { - self->frames_decoded = self->framerate * time; - self->time = time; -} - -void plm_video_rewind(plm_video_t *self) { - plm_buffer_rewind(self->buffer); - self->time = 0; - self->frames_decoded = 0; - self->has_reference_frame = FALSE; - self->start_code = -1; -} - -int plm_video_has_ended(plm_video_t *self) { - return plm_buffer_has_ended(self->buffer); -} - -plm_frame_t *plm_video_decode(plm_video_t *self) { - if (!plm_video_has_header(self)) { - return NULL; - } - - plm_frame_t *frame = NULL; - do { - if (self->start_code != PLM_START_PICTURE) { - self->start_code = plm_buffer_find_start_code(self->buffer, PLM_START_PICTURE); - - if (self->start_code == -1) { - // If we reached the end of the file and the previously decoded - // frame was a reference frame, we still have to return it. - if ( - self->has_reference_frame && - !self->assume_no_b_frames && - plm_buffer_has_ended(self->buffer) && ( - self->picture_type == PLM_VIDEO_PICTURE_TYPE_INTRA || - self->picture_type == PLM_VIDEO_PICTURE_TYPE_PREDICTIVE - ) - ) { - self->has_reference_frame = FALSE; - frame = &self->frame_backward; - break; - } - - return NULL; - } - } - - // Make sure we have a full picture in the buffer before attempting to - // decode it. Sadly, this can only be done by seeking for the start code - // of the next picture. Also, if we didn't find the start code for the - // next picture, but the source has ended, we assume that this last - // picture is in the buffer. - if ( - plm_buffer_has_start_code(self->buffer, PLM_START_PICTURE) == -1 && - !plm_buffer_has_ended(self->buffer) - ) { - return NULL; - } - - plm_video_decode_picture(self); - - if (self->assume_no_b_frames) { - frame = &self->frame_backward; - } - else if (self->picture_type == PLM_VIDEO_PICTURE_TYPE_B) { - frame = &self->frame_current; - } - else if (self->has_reference_frame) { - frame = &self->frame_forward; - } - else { - self->has_reference_frame = TRUE; - } - } while (!frame); - - frame->time = self->time; - self->frames_decoded++; - self->time = (double)self->frames_decoded / self->framerate; - - return frame; -} - -int plm_video_has_header(plm_video_t *self) { - if (self->has_sequence_header) { - return TRUE; - } - - if (self->start_code != PLM_START_SEQUENCE) { - self->start_code = plm_buffer_find_start_code(self->buffer, PLM_START_SEQUENCE); - } - if (self->start_code == -1) { - return FALSE; - } - - if (!plm_video_decode_sequence_header(self)) { - return FALSE; - } - - return TRUE; -} - -int plm_video_decode_sequence_header(plm_video_t *self) { - int max_header_size = 64 + 2 * 64 * 8; // 64 bit header + 2x 64 byte matrix - if (!plm_buffer_has(self->buffer, max_header_size)) { - return FALSE; - } - - self->width = plm_buffer_read(self->buffer, 12); - self->height = plm_buffer_read(self->buffer, 12); - - if (self->width <= 0 || self->height <= 0) { - return FALSE; - } - - // Skip pixel aspect ratio - plm_buffer_skip(self->buffer, 4); - - self->framerate = PLM_VIDEO_PICTURE_RATE[plm_buffer_read(self->buffer, 4)]; - - // Skip bit_rate, marker, buffer_size and constrained bit - plm_buffer_skip(self->buffer, 18 + 1 + 10 + 1); - - // Load custom intra quant matrix? - if (plm_buffer_read(self->buffer, 1)) { - for (int i = 0; i < 64; i++) { - int idx = PLM_VIDEO_ZIG_ZAG[i]; - self->intra_quant_matrix[idx] = plm_buffer_read(self->buffer, 8); - } - } - else { - memcpy(self->intra_quant_matrix, PLM_VIDEO_INTRA_QUANT_MATRIX, 64); - } - - // Load custom non intra quant matrix? - if (plm_buffer_read(self->buffer, 1)) { - for (int i = 0; i < 64; i++) { - int idx = PLM_VIDEO_ZIG_ZAG[i]; - self->non_intra_quant_matrix[idx] = plm_buffer_read(self->buffer, 8); - } - } - else { - memcpy(self->non_intra_quant_matrix, PLM_VIDEO_NON_INTRA_QUANT_MATRIX, 64); - } - - self->mb_width = (self->width + 15) >> 4; - self->mb_height = (self->height + 15) >> 4; - self->mb_size = self->mb_width * self->mb_height; - - self->luma_width = self->mb_width << 4; - self->luma_height = self->mb_height << 4; - - self->chroma_width = self->mb_width << 3; - self->chroma_height = self->mb_height << 3; - - - // Allocate one big chunk of data for all 3 frames = 9 planes - size_t luma_plane_size = self->luma_width * self->luma_height; - size_t chroma_plane_size = self->chroma_width * self->chroma_height; - size_t frame_data_size = (luma_plane_size + 2 * chroma_plane_size); - - self->frames_data = (uint8_t*)malloc(frame_data_size * 3); - plm_video_init_frame(self, &self->frame_current, self->frames_data + frame_data_size * 0); - plm_video_init_frame(self, &self->frame_forward, self->frames_data + frame_data_size * 1); - plm_video_init_frame(self, &self->frame_backward, self->frames_data + frame_data_size * 2); - - self->has_sequence_header = TRUE; - return TRUE; -} - -void plm_video_init_frame(plm_video_t *self, plm_frame_t *frame, uint8_t *base) { - size_t luma_plane_size = self->luma_width * self->luma_height; - size_t chroma_plane_size = self->chroma_width * self->chroma_height; - - frame->width = self->width; - frame->height = self->height; - frame->y.width = self->luma_width; - frame->y.height = self->luma_height; - frame->y.data = base; - - frame->cr.width = self->chroma_width; - frame->cr.height = self->chroma_height; - frame->cr.data = base + luma_plane_size; - - frame->cb.width = self->chroma_width; - frame->cb.height = self->chroma_height; - frame->cb.data = base + luma_plane_size + chroma_plane_size; -} - -void plm_video_decode_picture(plm_video_t *self) { - plm_buffer_skip(self->buffer, 10); // skip temporalReference - self->picture_type = plm_buffer_read(self->buffer, 3); - plm_buffer_skip(self->buffer, 16); // skip vbv_delay - - // D frames or unknown coding type - if (self->picture_type <= 0 || self->picture_type > PLM_VIDEO_PICTURE_TYPE_B) { - return; - } - - // Forward full_px, f_code - if ( - self->picture_type == PLM_VIDEO_PICTURE_TYPE_PREDICTIVE || - self->picture_type == PLM_VIDEO_PICTURE_TYPE_B - ) { - self->motion_forward.full_px = plm_buffer_read(self->buffer, 1); - int f_code = plm_buffer_read(self->buffer, 3); - if (f_code == 0) { - // Ignore picture with zero f_code - return; - } - self->motion_forward.r_size = f_code - 1; - } - - // Backward full_px, f_code - if (self->picture_type == PLM_VIDEO_PICTURE_TYPE_B) { - self->motion_backward.full_px = plm_buffer_read(self->buffer, 1); - int f_code = plm_buffer_read(self->buffer, 3); - if (f_code == 0) { - // Ignore picture with zero f_code - return; - } - self->motion_backward.r_size = f_code - 1; - } - - plm_frame_t frame_temp = self->frame_forward; - if ( - self->picture_type == PLM_VIDEO_PICTURE_TYPE_INTRA || - self->picture_type == PLM_VIDEO_PICTURE_TYPE_PREDICTIVE - ) { - self->frame_forward = self->frame_backward; - } - - - // Find the first slice; this skips extension and user data - do { - self->start_code = plm_buffer_next_start_code(self->buffer); - } while (!PLM_START_IS_SLICE(self->start_code)); - - // Decode all slices - do { - plm_video_decode_slice(self, self->start_code & 0x000000FF); - if (self->macroblock_address == self->mb_size - 1) { - break; - } - self->start_code = plm_buffer_next_start_code(self->buffer); - } while (PLM_START_IS_SLICE(self->start_code)); - - // If this is a reference picture rotate the prediction pointers - if ( - self->picture_type == PLM_VIDEO_PICTURE_TYPE_INTRA || - self->picture_type == PLM_VIDEO_PICTURE_TYPE_PREDICTIVE - ) { - self->frame_backward = self->frame_current; - self->frame_current = frame_temp; - } -} - -void plm_video_decode_slice(plm_video_t *self, int slice) { - self->slice_begin = TRUE; - self->macroblock_address = (slice - 1) * self->mb_width - 1; - - // Reset motion vectors and DC predictors - self->motion_backward.h = self->motion_forward.h = 0; - self->motion_backward.v = self->motion_forward.v = 0; - self->dc_predictor[0] = 128; - self->dc_predictor[1] = 128; - self->dc_predictor[2] = 128; - - self->quantizer_scale = plm_buffer_read(self->buffer, 5); - - // Skip extra - while (plm_buffer_read(self->buffer, 1)) { - plm_buffer_skip(self->buffer, 8); - } - - do { - plm_video_decode_macroblock(self); - } while ( - self->macroblock_address < self->mb_size - 1 && - plm_buffer_no_start_code(self->buffer) - ); -} - -void plm_video_decode_macroblock(plm_video_t *self) { - // Decode self->macroblock_address_increment - int increment = 0; - int t = plm_buffer_read_vlc(self->buffer, PLM_VIDEO_MACROBLOCK_ADDRESS_INCREMENT); - - while (t == 34) { - // macroblock_stuffing - t = plm_buffer_read_vlc(self->buffer, PLM_VIDEO_MACROBLOCK_ADDRESS_INCREMENT); - } - while (t == 35) { - // macroblock_escape - increment += 33; - t = plm_buffer_read_vlc(self->buffer, PLM_VIDEO_MACROBLOCK_ADDRESS_INCREMENT); - } - increment += t; - - // Process any skipped macroblocks - if (self->slice_begin) { - // The first self->macroblock_address_increment of each slice is relative - // to beginning of the preverious row, not the preverious macroblock - self->slice_begin = FALSE; - self->macroblock_address += increment; - } - else { - if (self->macroblock_address + increment >= self->mb_size) { - return; // invalid - } - if (increment > 1) { - // Skipped macroblocks reset DC predictors - self->dc_predictor[0] = 128; - self->dc_predictor[1] = 128; - self->dc_predictor[2] = 128; - - // Skipped macroblocks in P-pictures reset motion vectors - if (self->picture_type == PLM_VIDEO_PICTURE_TYPE_PREDICTIVE) { - self->motion_forward.h = 0; - self->motion_forward.v = 0; - } - } - - // Predict skipped macroblocks - while (increment > 1) { - self->macroblock_address++; - self->mb_row = self->macroblock_address / self->mb_width; - self->mb_col = self->macroblock_address % self->mb_width; - - plm_video_predict_macroblock(self); - increment--; - } - self->macroblock_address++; - } - - self->mb_row = self->macroblock_address / self->mb_width; - self->mb_col = self->macroblock_address % self->mb_width; - - if (self->mb_col >= self->mb_width || self->mb_row >= self->mb_height) { - return; // corrupt stream; - } - - // Process the current macroblock - const plm_vlc_t *table = PLM_VIDEO_MACROBLOCK_TYPE[self->picture_type]; - self->macroblock_type = plm_buffer_read_vlc(self->buffer, table); - - self->macroblock_intra = (self->macroblock_type & 0x01); - self->motion_forward.is_set = (self->macroblock_type & 0x08); - self->motion_backward.is_set = (self->macroblock_type & 0x04); - - // Quantizer scale - if ((self->macroblock_type & 0x10) != 0) { - self->quantizer_scale = plm_buffer_read(self->buffer, 5); - } - - if (self->macroblock_intra) { - // Intra-coded macroblocks reset motion vectors - self->motion_backward.h = self->motion_forward.h = 0; - self->motion_backward.v = self->motion_forward.v = 0; - } - else { - // Non-intra macroblocks reset DC predictors - self->dc_predictor[0] = 128; - self->dc_predictor[1] = 128; - self->dc_predictor[2] = 128; - - plm_video_decode_motion_vectors(self); - plm_video_predict_macroblock(self); - } - - // Decode blocks - int cbp = ((self->macroblock_type & 0x02) != 0) - ? plm_buffer_read_vlc(self->buffer, PLM_VIDEO_CODE_BLOCK_PATTERN) - : (self->macroblock_intra ? 0x3f : 0); - - for (int block = 0, mask = 0x20; block < 6; block++) { - if ((cbp & mask) != 0) { - plm_video_decode_block(self, block); - } - mask >>= 1; - } -} - -void plm_video_decode_motion_vectors(plm_video_t *self) { - - // Forward - if (self->motion_forward.is_set) { - int r_size = self->motion_forward.r_size; - self->motion_forward.h = plm_video_decode_motion_vector(self, r_size, self->motion_forward.h); - self->motion_forward.v = plm_video_decode_motion_vector(self, r_size, self->motion_forward.v); - } - else if (self->picture_type == PLM_VIDEO_PICTURE_TYPE_PREDICTIVE) { - // No motion information in P-picture, reset vectors - self->motion_forward.h = 0; - self->motion_forward.v = 0; - } - - if (self->motion_backward.is_set) { - int r_size = self->motion_backward.r_size; - self->motion_backward.h = plm_video_decode_motion_vector(self, r_size, self->motion_backward.h); - self->motion_backward.v = plm_video_decode_motion_vector(self, r_size, self->motion_backward.v); - } -} - -int plm_video_decode_motion_vector(plm_video_t *self, int r_size, int motion) { - int fscale = 1 << r_size; - int m_code = plm_buffer_read_vlc(self->buffer, PLM_VIDEO_MOTION); - int r = 0; - int d; - - if ((m_code != 0) && (fscale != 1)) { - r = plm_buffer_read(self->buffer, r_size); - d = ((abs(m_code) - 1) << r_size) + r + 1; - if (m_code < 0) { - d = -d; - } - } - else { - d = m_code; - } - - motion += d; - if (motion >(fscale << 4) - 1) { - motion -= fscale << 5; - } - else if (motion < ((-fscale) << 4)) { - motion += fscale << 5; - } - - return motion; -} - -void plm_video_predict_macroblock(plm_video_t *self) { - int fw_h = self->motion_forward.h; - int fw_v = self->motion_forward.v; - - if (self->motion_forward.full_px) { - fw_h <<= 1; - fw_v <<= 1; - } - - if (self->picture_type == PLM_VIDEO_PICTURE_TYPE_B) { - int bw_h = self->motion_backward.h; - int bw_v = self->motion_backward.v; - - if (self->motion_backward.full_px) { - bw_h <<= 1; - bw_v <<= 1; - } - - if (self->motion_forward.is_set) { - plm_video_copy_macroblock(self, fw_h, fw_v, &self->frame_forward); - if (self->motion_backward.is_set) { - plm_video_interpolate_macroblock(self, bw_h, bw_v, &self->frame_backward); - } - } - else { - plm_video_copy_macroblock(self, bw_h, bw_v, &self->frame_backward); - } - } - else { - plm_video_copy_macroblock(self, fw_h, fw_v, &self->frame_forward); - } -} - -void plm_video_copy_macroblock(plm_video_t *self, int motion_h, int motion_v, plm_frame_t *d) { - plm_frame_t *s = &self->frame_current; - plm_video_process_macroblock(self, s->y.data, d->y.data, motion_h, motion_v, 16, FALSE); - plm_video_process_macroblock(self, s->cr.data, d->cr.data, motion_h / 2, motion_v / 2, 8, FALSE); - plm_video_process_macroblock(self, s->cb.data, d->cb.data, motion_h / 2, motion_v / 2, 8, FALSE); -} - -void plm_video_interpolate_macroblock(plm_video_t *self, int motion_h, int motion_v, plm_frame_t *d) { - plm_frame_t *s = &self->frame_current; - plm_video_process_macroblock(self, s->y.data, d->y.data, motion_h, motion_v, 16, TRUE); - plm_video_process_macroblock(self, s->cr.data, d->cr.data, motion_h / 2, motion_v / 2, 8, TRUE); - plm_video_process_macroblock(self, s->cb.data, d->cb.data, motion_h / 2, motion_v / 2, 8, TRUE); -} - -#define PLM_BLOCK_SET(DEST, DEST_INDEX, DEST_WIDTH, SOURCE_INDEX, SOURCE_WIDTH, BLOCK_SIZE, OP) do { \ - int dest_scan = DEST_WIDTH - BLOCK_SIZE; \ - int source_scan = SOURCE_WIDTH - BLOCK_SIZE; \ - for (int y = 0; y < BLOCK_SIZE; y++) { \ - for (int x = 0; x < BLOCK_SIZE; x++) { \ - DEST[DEST_INDEX] = OP; \ - SOURCE_INDEX++; DEST_INDEX++; \ - } \ - SOURCE_INDEX += source_scan; \ - DEST_INDEX += dest_scan; \ - }} while(FALSE) - -void plm_video_process_macroblock( - plm_video_t *self, uint8_t *d, uint8_t *s, - int motion_h, int motion_v, int block_size, int interpolate -) { - int dw = self->mb_width * block_size; - - int hp = motion_h >> 1; - int vp = motion_v >> 1; - int odd_h = (motion_h & 1) == 1; - int odd_v = (motion_v & 1) == 1; - - unsigned int si = ((self->mb_row * block_size) + vp) * dw + (self->mb_col * block_size) + hp; - unsigned int di = (self->mb_row * dw + self->mb_col) * block_size; - - unsigned int max_address = (dw * (self->mb_height * block_size - block_size + 1) - block_size); - if (si > max_address || di > max_address) { - return; // corrupt video - } - - #define PLM_MB_CASE(INTERPOLATE, ODD_H, ODD_V, OP) \ - case ((INTERPOLATE << 2) | (ODD_H << 1) | (ODD_V)): \ - PLM_BLOCK_SET(d, di, dw, si, dw, block_size, OP); \ - break - - switch ((interpolate << 2) | (odd_h << 1) | (odd_v)) { - PLM_MB_CASE(0, 0, 0, (s[si])); - PLM_MB_CASE(0, 0, 1, (s[si] + s[si + dw] + 1) >> 1); - PLM_MB_CASE(0, 1, 0, (s[si] + s[si + 1] + 1) >> 1); - PLM_MB_CASE(0, 1, 1, (s[si] + s[si + 1] + s[si + dw] + s[si + dw + 1] + 2) >> 2); - - PLM_MB_CASE(1, 0, 0, (d[di] + (s[si]) + 1) >> 1); - PLM_MB_CASE(1, 0, 1, (d[di] + ((s[si] + s[si + dw] + 1) >> 1) + 1) >> 1); - PLM_MB_CASE(1, 1, 0, (d[di] + ((s[si] + s[si + 1] + 1) >> 1) + 1) >> 1); - PLM_MB_CASE(1, 1, 1, (d[di] + ((s[si] + s[si + 1] + s[si + dw] + s[si + dw + 1] + 2) >> 2) + 1) >> 1); - } - - #undef PLM_MB_CASE -} - -void plm_video_decode_block(plm_video_t *self, int block) { - - int n = 0; - uint8_t *quant_matrix; - - // Decode DC coefficient of intra-coded blocks - if (self->macroblock_intra) { - int predictor; - int dct_size; - - // DC prediction - int plane_index = block > 3 ? block - 3 : 0; - predictor = self->dc_predictor[plane_index]; - dct_size = plm_buffer_read_vlc(self->buffer, PLM_VIDEO_DCT_SIZE[plane_index]); - - // Read DC coeff - if (dct_size > 0) { - int differential = plm_buffer_read(self->buffer, dct_size); - if ((differential & (1 << (dct_size - 1))) != 0) { - self->block_data[0] = predictor + differential; - } - else { - self->block_data[0] = predictor + (-(1 << dct_size) | (differential + 1)); - } - } - else { - self->block_data[0] = predictor; - } - - // Save predictor value - self->dc_predictor[plane_index] = self->block_data[0]; - - // Dequantize + premultiply - self->block_data[0] <<= (3 + 5); - - quant_matrix = self->intra_quant_matrix; - n = 1; - } - else { - quant_matrix = self->non_intra_quant_matrix; - } - - // Decode AC coefficients (+DC for non-intra) - int level = 0; - while (TRUE) { - int run = 0; - uint16_t coeff = plm_buffer_read_vlc_uint(self->buffer, PLM_VIDEO_DCT_COEFF); - - if ((coeff == 0x0001) && (n > 0) && (plm_buffer_read(self->buffer, 1) == 0)) { - // end_of_block - break; - } - if (coeff == 0xffff) { - // escape - run = plm_buffer_read(self->buffer, 6); - level = plm_buffer_read(self->buffer, 8); - if (level == 0) { - level = plm_buffer_read(self->buffer, 8); - } - else if (level == 128) { - level = plm_buffer_read(self->buffer, 8) - 256; - } - else if (level > 128) { - level = level - 256; - } - } - else { - run = coeff >> 8; - level = coeff & 0xff; - if (plm_buffer_read(self->buffer, 1)) { - level = -level; - } - } - - n += run; - if (n < 0 || n >= 64) { - return; // invalid - } - - int de_zig_zagged = PLM_VIDEO_ZIG_ZAG[n]; - n++; - - // Dequantize, oddify, clip - level <<= 1; - if (!self->macroblock_intra) { - level += (level < 0 ? -1 : 1); - } - level = (level * self->quantizer_scale * quant_matrix[de_zig_zagged]) >> 4; - if ((level & 1) == 0) { - level -= level > 0 ? 1 : -1; - } - if (level > 2047) { - level = 2047; - } - else if (level < -2048) { - level = -2048; - } - - // Save premultiplied coefficient - self->block_data[de_zig_zagged] = level * PLM_VIDEO_PREMULTIPLIER_MATRIX[de_zig_zagged]; - } - - // Move block to its place - uint8_t *d; - int dw; - int di; - - if (block < 4) { - d = self->frame_current.y.data; - dw = self->luma_width; - di = (self->mb_row * self->luma_width + self->mb_col) << 4; - if ((block & 1) != 0) { - di += 8; - } - if ((block & 2) != 0) { - di += self->luma_width << 3; - } - } - else { - d = (block == 4) ? self->frame_current.cb.data : self->frame_current.cr.data; - dw = self->chroma_width; - di = ((self->mb_row * self->luma_width) << 2) + (self->mb_col << 3); - } - - int *s = self->block_data; - int si = 0; - if (self->macroblock_intra) { - // Overwrite (no prediction) - if (n == 1) { - int clamped = plm_clamp((s[0] + 128) >> 8); - PLM_BLOCK_SET(d, di, dw, si, 8, 8, clamped); - s[0] = 0; - } - else { - plm_video_idct(s); - PLM_BLOCK_SET(d, di, dw, si, 8, 8, plm_clamp(s[si])); - memset(self->block_data, 0, sizeof(self->block_data)); - } - } - else { - // Add data to the predicted macroblock - if (n == 1) { - int value = (s[0] + 128) >> 8; - PLM_BLOCK_SET(d, di, dw, si, 8, 8, plm_clamp(d[di] + value)); - s[0] = 0; - } - else { - plm_video_idct(s); - PLM_BLOCK_SET(d, di, dw, si, 8, 8, plm_clamp(d[di] + s[si])); - memset(self->block_data, 0, sizeof(self->block_data)); - } - } -} - -void plm_video_idct(int *block) { - int - b1, b3, b4, b6, b7, tmp1, tmp2, m0, - x0, x1, x2, x3, x4, y3, y4, y5, y6, y7; - - // Transform columns - for (int i = 0; i < 8; ++i) { - b1 = block[4 * 8 + i]; - b3 = block[2 * 8 + i] + block[6 * 8 + i]; - b4 = block[5 * 8 + i] - block[3 * 8 + i]; - tmp1 = block[1 * 8 + i] + block[7 * 8 + i]; - tmp2 = block[3 * 8 + i] + block[5 * 8 + i]; - b6 = block[1 * 8 + i] - block[7 * 8 + i]; - b7 = tmp1 + tmp2; - m0 = block[0 * 8 + i]; - x4 = ((b6 * 473 - b4 * 196 + 128) >> 8) - b7; - x0 = x4 - (((tmp1 - tmp2) * 362 + 128) >> 8); - x1 = m0 - b1; - x2 = (((block[2 * 8 + i] - block[6 * 8 + i]) * 362 + 128) >> 8) - b3; - x3 = m0 + b1; - y3 = x1 + x2; - y4 = x3 + b3; - y5 = x1 - x2; - y6 = x3 - b3; - y7 = -x0 - ((b4 * 473 + b6 * 196 + 128) >> 8); - block[0 * 8 + i] = b7 + y4; - block[1 * 8 + i] = x4 + y3; - block[2 * 8 + i] = y5 - x0; - block[3 * 8 + i] = y6 - y7; - block[4 * 8 + i] = y6 + y7; - block[5 * 8 + i] = x0 + y5; - block[6 * 8 + i] = y3 - x4; - block[7 * 8 + i] = y4 - b7; - } - - // Transform rows - for (int i = 0; i < 64; i += 8) { - b1 = block[4 + i]; - b3 = block[2 + i] + block[6 + i]; - b4 = block[5 + i] - block[3 + i]; - tmp1 = block[1 + i] + block[7 + i]; - tmp2 = block[3 + i] + block[5 + i]; - b6 = block[1 + i] - block[7 + i]; - b7 = tmp1 + tmp2; - m0 = block[0 + i]; - x4 = ((b6 * 473 - b4 * 196 + 128) >> 8) - b7; - x0 = x4 - (((tmp1 - tmp2) * 362 + 128) >> 8); - x1 = m0 - b1; - x2 = (((block[2 + i] - block[6 + i]) * 362 + 128) >> 8) - b3; - x3 = m0 + b1; - y3 = x1 + x2; - y4 = x3 + b3; - y5 = x1 - x2; - y6 = x3 - b3; - y7 = -x0 - ((b4 * 473 + b6 * 196 + 128) >> 8); - block[0 + i] = (b7 + y4 + 128) >> 8; - block[1 + i] = (x4 + y3 + 128) >> 8; - block[2 + i] = (y5 - x0 + 128) >> 8; - block[3 + i] = (y6 - y7 + 128) >> 8; - block[4 + i] = (y6 + y7 + 128) >> 8; - block[5 + i] = (x0 + y5 + 128) >> 8; - block[6 + i] = (y3 - x4 + 128) >> 8; - block[7 + i] = (y4 - b7 + 128) >> 8; - } -} - -// YCbCr conversion following the BT.601 standard: -// https://infogalactic.com/info/YCbCr#ITU-R_BT.601_conversion - -#define PLM_PUT_PIXEL(RI, GI, BI, Y_OFFSET, DEST_OFFSET) \ - y = ((frame->y.data[y_index + Y_OFFSET]-16) * 76309) >> 16; \ - dest[d_index + DEST_OFFSET + RI] = plm_clamp(y + r); \ - dest[d_index + DEST_OFFSET + GI] = plm_clamp(y - g); \ - dest[d_index + DEST_OFFSET + BI] = plm_clamp(y + b); - -#define PLM_DEFINE_FRAME_CONVERT_FUNCTION(NAME, BYTES_PER_PIXEL, RI, GI, BI) \ - void NAME(plm_frame_t *frame, uint8_t *dest, int stride) { \ - int cols = frame->width >> 1; \ - int rows = frame->height >> 1; \ - int yw = frame->y.width; \ - int cw = frame->cb.width; \ - for (int row = 0; row < rows; row++) { \ - int c_index = row * cw; \ - int y_index = row * 2 * yw; \ - int d_index = row * 2 * stride; \ - for (int col = 0; col < cols; col++) { \ - int y; \ - int cr = frame->cr.data[c_index] - 128; \ - int cb = frame->cb.data[c_index] - 128; \ - int r = (cr * 104597) >> 16; \ - int g = (cb * 25674 + cr * 53278) >> 16; \ - int b = (cb * 132201) >> 16; \ - PLM_PUT_PIXEL(RI, GI, BI, 0, 0); \ - PLM_PUT_PIXEL(RI, GI, BI, 1, BYTES_PER_PIXEL); \ - PLM_PUT_PIXEL(RI, GI, BI, yw, stride); \ - PLM_PUT_PIXEL(RI, GI, BI, yw + 1, stride + BYTES_PER_PIXEL); \ - c_index += 1; \ - y_index += 2; \ - d_index += 2 * BYTES_PER_PIXEL; \ - } \ - } \ - } - -PLM_DEFINE_FRAME_CONVERT_FUNCTION(plm_frame_to_rgb, 3, 0, 1, 2) -PLM_DEFINE_FRAME_CONVERT_FUNCTION(plm_frame_to_bgr, 3, 2, 1, 0) -PLM_DEFINE_FRAME_CONVERT_FUNCTION(plm_frame_to_rgba, 4, 0, 1, 2) -PLM_DEFINE_FRAME_CONVERT_FUNCTION(plm_frame_to_bgra, 4, 2, 1, 0) -PLM_DEFINE_FRAME_CONVERT_FUNCTION(plm_frame_to_argb, 4, 1, 2, 3) -PLM_DEFINE_FRAME_CONVERT_FUNCTION(plm_frame_to_abgr, 4, 3, 2, 1) - - -#undef PLM_PUT_PIXEL -#undef PLM_DEFINE_FRAME_CONVERT_FUNCTION - - - -// ----------------------------------------------------------------------------- -// plm_audio implementation - -// Based on kjmp2 by Martin J. Fiedler -// http://keyj.emphy.de/kjmp2/ - -static const int PLM_AUDIO_FRAME_SYNC = 0x7ff; - -static const int PLM_AUDIO_MPEG_2_5 = 0x0; -static const int PLM_AUDIO_MPEG_2 = 0x2; -static const int PLM_AUDIO_MPEG_1 = 0x3; - -static const int PLM_AUDIO_LAYER_III = 0x1; -static const int PLM_AUDIO_LAYER_II = 0x2; -static const int PLM_AUDIO_LAYER_I = 0x3; - -static const int PLM_AUDIO_MODE_STEREO = 0x0; -static const int PLM_AUDIO_MODE_JOINT_STEREO = 0x1; -static const int PLM_AUDIO_MODE_DUAL_CHANNEL = 0x2; -static const int PLM_AUDIO_MODE_MONO = 0x3; - -static const unsigned short PLM_AUDIO_SAMPLE_RATE[] = { - 44100, 48000, 32000, 0, // MPEG-1 - 22050, 24000, 16000, 0 // MPEG-2 -}; - -static const short PLM_AUDIO_BIT_RATE[] = { - 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, // MPEG-1 - 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 // MPEG-2 -}; - -static const int PLM_AUDIO_SCALEFACTOR_BASE[] = { - 0x02000000, 0x01965FEA, 0x01428A30 -}; - -static const float PLM_AUDIO_SYNTHESIS_WINDOW[] = { - 0.0, -0.5, -0.5, -0.5, -0.5, -0.5, - -0.5, -1.0, -1.0, -1.0, -1.0, -1.5, - -1.5, -2.0, -2.0, -2.5, -2.5, -3.0, - -3.5, -3.5, -4.0, -4.5, -5.0, -5.5, - -6.5, -7.0, -8.0, -8.5, -9.5, -10.5, - -12.0, -13.0, -14.5, -15.5, -17.5, -19.0, - -20.5, -22.5, -24.5, -26.5, -29.0, -31.5, - -34.0, -36.5, -39.5, -42.5, -45.5, -48.5, - -52.0, -55.5, -58.5, -62.5, -66.0, -69.5, - -73.5, -77.0, -80.5, -84.5, -88.0, -91.5, - -95.0, -98.0, -101.0, -104.0, 106.5, 109.0, - 111.0, 112.5, 113.5, 114.0, 114.0, 113.5, - 112.0, 110.5, 107.5, 104.0, 100.0, 94.5, - 88.5, 81.5, 73.0, 63.5, 53.0, 41.5, - 28.5, 14.5, -1.0, -18.0, -36.0, -55.5, - -76.5, -98.5, -122.0, -147.0, -173.5, -200.5, - -229.5, -259.5, -290.5, -322.5, -355.5, -389.5, - -424.0, -459.5, -495.5, -532.0, -568.5, -605.0, - -641.5, -678.0, -714.0, -749.0, -783.5, -817.0, - -849.0, -879.5, -908.5, -935.0, -959.5, -981.0, - -1000.5, -1016.0, -1028.5, -1037.5, -1042.5, -1043.5, - -1040.0, -1031.5, 1018.5, 1000.0, 976.0, 946.5, - 911.0, 869.5, 822.0, 767.5, 707.0, 640.0, - 565.5, 485.0, 397.0, 302.5, 201.0, 92.5, - -22.5, -144.0, -272.5, -407.0, -547.5, -694.0, - -846.0, -1003.0, -1165.0, -1331.5, -1502.0, -1675.5, - -1852.5, -2031.5, -2212.5, -2394.0, -2576.5, -2758.5, - -2939.5, -3118.5, -3294.5, -3467.5, -3635.5, -3798.5, - -3955.0, -4104.5, -4245.5, -4377.5, -4499.0, -4609.5, - -4708.0, -4792.5, -4863.5, -4919.0, -4958.0, -4979.5, - -4983.0, -4967.5, -4931.5, -4875.0, -4796.0, -4694.5, - -4569.5, -4420.0, -4246.0, -4046.0, -3820.0, -3567.0, - 3287.0, 2979.5, 2644.0, 2280.5, 1888.0, 1467.5, - 1018.5, 541.0, 35.0, -499.0, -1061.0, -1650.0, - -2266.5, -2909.0, -3577.0, -4270.0, -4987.5, -5727.5, - -6490.0, -7274.0, -8077.5, -8899.5, -9739.0, -10594.5, - -11464.5, -12347.0, -13241.0, -14144.5, -15056.0, -15973.5, - -16895.5, -17820.0, -18744.5, -19668.0, -20588.0, -21503.0, - -22410.5, -23308.5, -24195.0, -25068.5, -25926.5, -26767.0, - -27589.0, -28389.0, -29166.5, -29919.0, -30644.5, -31342.0, - -32009.5, -32645.0, -33247.0, -33814.5, -34346.0, -34839.5, - -35295.0, -35710.0, -36084.5, -36417.5, -36707.5, -36954.0, - -37156.5, -37315.0, -37428.0, -37496.0, 37519.0, 37496.0, - 37428.0, 37315.0, 37156.5, 36954.0, 36707.5, 36417.5, - 36084.5, 35710.0, 35295.0, 34839.5, 34346.0, 33814.5, - 33247.0, 32645.0, 32009.5, 31342.0, 30644.5, 29919.0, - 29166.5, 28389.0, 27589.0, 26767.0, 25926.5, 25068.5, - 24195.0, 23308.5, 22410.5, 21503.0, 20588.0, 19668.0, - 18744.5, 17820.0, 16895.5, 15973.5, 15056.0, 14144.5, - 13241.0, 12347.0, 11464.5, 10594.5, 9739.0, 8899.5, - 8077.5, 7274.0, 6490.0, 5727.5, 4987.5, 4270.0, - 3577.0, 2909.0, 2266.5, 1650.0, 1061.0, 499.0, - -35.0, -541.0, -1018.5, -1467.5, -1888.0, -2280.5, - -2644.0, -2979.5, 3287.0, 3567.0, 3820.0, 4046.0, - 4246.0, 4420.0, 4569.5, 4694.5, 4796.0, 4875.0, - 4931.5, 4967.5, 4983.0, 4979.5, 4958.0, 4919.0, - 4863.5, 4792.5, 4708.0, 4609.5, 4499.0, 4377.5, - 4245.5, 4104.5, 3955.0, 3798.5, 3635.5, 3467.5, - 3294.5, 3118.5, 2939.5, 2758.5, 2576.5, 2394.0, - 2212.5, 2031.5, 1852.5, 1675.5, 1502.0, 1331.5, - 1165.0, 1003.0, 846.0, 694.0, 547.5, 407.0, - 272.5, 144.0, 22.5, -92.5, -201.0, -302.5, - -397.0, -485.0, -565.5, -640.0, -707.0, -767.5, - -822.0, -869.5, -911.0, -946.5, -976.0, -1000.0, - 1018.5, 1031.5, 1040.0, 1043.5, 1042.5, 1037.5, - 1028.5, 1016.0, 1000.5, 981.0, 959.5, 935.0, - 908.5, 879.5, 849.0, 817.0, 783.5, 749.0, - 714.0, 678.0, 641.5, 605.0, 568.5, 532.0, - 495.5, 459.5, 424.0, 389.5, 355.5, 322.5, - 290.5, 259.5, 229.5, 200.5, 173.5, 147.0, - 122.0, 98.5, 76.5, 55.5, 36.0, 18.0, - 1.0, -14.5, -28.5, -41.5, -53.0, -63.5, - -73.0, -81.5, -88.5, -94.5, -100.0, -104.0, - -107.5, -110.5, -112.0, -113.5, -114.0, -114.0, - -113.5, -112.5, -111.0, -109.0, 106.5, 104.0, - 101.0, 98.0, 95.0, 91.5, 88.0, 84.5, - 80.5, 77.0, 73.5, 69.5, 66.0, 62.5, - 58.5, 55.5, 52.0, 48.5, 45.5, 42.5, - 39.5, 36.5, 34.0, 31.5, 29.0, 26.5, - 24.5, 22.5, 20.5, 19.0, 17.5, 15.5, - 14.5, 13.0, 12.0, 10.5, 9.5, 8.5, - 8.0, 7.0, 6.5, 5.5, 5.0, 4.5, - 4.0, 3.5, 3.5, 3.0, 2.5, 2.5, - 2.0, 2.0, 1.5, 1.5, 1.0, 1.0, - 1.0, 1.0, 0.5, 0.5, 0.5, 0.5, - 0.5, 0.5 -}; - -// Quantizer lookup, step 1: bitrate classes -static const uint8_t PLM_AUDIO_QUANT_LUT_STEP_1[2][16] = { - // 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384 <- bitrate - { 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, // mono - // 16, 24, 28, 32, 40, 48, 56, 64, 80, 96,112,128,160,192 <- bitrate / chan - { 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2 } // stereo -}; - -// Quantizer lookup, step 2: bitrate class, sample rate -> B2 table idx, sblimit -static const uint8_t PLM_AUDIO_QUANT_TAB_A = (27 | 64); // Table 3-B.2a: high-rate, sblimit = 27 -static const uint8_t PLM_AUDIO_QUANT_TAB_B = (30 | 64); // Table 3-B.2b: high-rate, sblimit = 30 -static const uint8_t PLM_AUDIO_QUANT_TAB_C = 8; // Table 3-B.2c: low-rate, sblimit = 8 -static const uint8_t PLM_AUDIO_QUANT_TAB_D = 12; // Table 3-B.2d: low-rate, sblimit = 12 - -/* TODO: This doesn't compile w/ TCC for some reason? -static const uint8_t QUANT_LUT_STEP_2[3][3] = { - //44.1 kHz, 48 kHz, 32 kHz - { PLM_AUDIO_QUANT_TAB_C, PLM_AUDIO_QUANT_TAB_C, PLM_AUDIO_QUANT_TAB_D }, // 32 - 48 kbit/sec/ch - { PLM_AUDIO_QUANT_TAB_A, PLM_AUDIO_QUANT_TAB_A, PLM_AUDIO_QUANT_TAB_A }, // 56 - 80 kbit/sec/ch - { PLM_AUDIO_QUANT_TAB_B, PLM_AUDIO_QUANT_TAB_A, PLM_AUDIO_QUANT_TAB_B } // 96+ kbit/sec/ch -}; -*/ - -static const uint8_t QUANT_LUT_STEP_2[3][3] = { - //44.1 kHz, 48 kHz, 32 kHz - { 8, 8, 12 }, // 32 - 48 kbit/sec/ch - { (27 | 64), (27 | 64), (27 | 64) }, // 56 - 80 kbit/sec/ch - { (30 | 64), (27 | 64), (30 | 64) } // 96+ kbit/sec/ch -}; - -// Quantizer lookup, step 3: B2 table, subband -> nbal, row index -// (upper 4 bits: nbal, lower 4 bits: row index) -static const uint8_t PLM_AUDIO_QUANT_LUT_STEP_3[3][32] = { - // Low-rate table (3-B.2c and 3-B.2d) - { - 0x44,0x44, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34,0x34 - }, - // High-rate table (3-B.2a and 3-B.2b) - { - 0x43,0x43,0x43, - 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42, - 0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31, - 0x20,0x20,0x20,0x20,0x20,0x20,0x20 - }, - // MPEG-2 LSR table (B.2 in ISO 13818-3) - { - 0x45,0x45,0x45,0x45, - 0x34,0x34,0x34,0x34,0x34,0x34,0x34, - 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, - 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24 - } -}; - -// Quantizer lookup, step 4: table row, allocation[] value -> quant table index -static const uint8_t PLM_AUDIO_QUANT_LUT_STEP4[6][16] = { - { 0, 1, 2, 17 }, - { 0, 1, 2, 3, 4, 5, 6, 17 }, - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17 }, - { 0, 1, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }, - { 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17 }, - { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } -}; - -typedef struct plm_quantizer_spec_t { - unsigned short levels; - unsigned char group; - unsigned char bits; -} plm_quantizer_spec_t; - -static const plm_quantizer_spec_t PLM_AUDIO_QUANT_TAB[] = { - { 3, 1, 5 }, // 1 - { 5, 1, 7 }, // 2 - { 7, 0, 3 }, // 3 - { 9, 1, 10 }, // 4 - { 15, 0, 4 }, // 5 - { 31, 0, 5 }, // 6 - { 63, 0, 6 }, // 7 - { 127, 0, 7 }, // 8 - { 255, 0, 8 }, // 9 - { 511, 0, 9 }, // 10 - { 1023, 0, 10 }, // 11 - { 2047, 0, 11 }, // 12 - { 4095, 0, 12 }, // 13 - { 8191, 0, 13 }, // 14 - { 16383, 0, 14 }, // 15 - { 32767, 0, 15 }, // 16 - { 65535, 0, 16 } // 17 -}; - -typedef struct plm_audio_t { - double time; - int samples_decoded; - int samplerate_index; - int bitrate_index; - int version; - int layer; - int mode; - int bound; - int v_pos; - int next_frame_data_size; - int has_header; - - plm_buffer_t *buffer; - int destroy_buffer_when_done; - - const plm_quantizer_spec_t *allocation[2][32]; - uint8_t scale_factor_info[2][32]; - int scale_factor[2][32][3]; - int sample[2][32][3]; - - plm_samples_t samples; - float D[1024]; - float V[2][1024]; - float U[32]; -} plm_audio_t; - -int plm_audio_find_frame_sync(plm_audio_t *self); -int plm_audio_decode_header(plm_audio_t *self); -void plm_audio_decode_frame(plm_audio_t *self); -const plm_quantizer_spec_t *plm_audio_read_allocation(plm_audio_t *self, int sb, int tab3); -void plm_audio_read_samples(plm_audio_t *self, int ch, int sb, int part); -void plm_audio_matrix_transform(int s[32][3], int ss, float *d, int dp); - -plm_audio_t *plm_audio_create_with_buffer(plm_buffer_t *buffer, int destroy_when_done) { - plm_audio_t *self = (plm_audio_t *)malloc(sizeof(plm_audio_t)); - memset(self, 0, sizeof(plm_audio_t)); - - self->samples.count = PLM_AUDIO_SAMPLES_PER_FRAME; - self->buffer = buffer; - self->destroy_buffer_when_done = destroy_when_done; - self->samplerate_index = 3; // Indicates 0 - - memcpy(self->D, PLM_AUDIO_SYNTHESIS_WINDOW, 512 * sizeof(float)); - memcpy(self->D + 512, PLM_AUDIO_SYNTHESIS_WINDOW, 512 * sizeof(float)); - - // Attempt to decode first header - self->next_frame_data_size = plm_audio_decode_header(self); - - return self; -} - -void plm_audio_destroy(plm_audio_t *self) { - if (self->destroy_buffer_when_done) { - plm_buffer_destroy(self->buffer); - } - free(self); -} - -int plm_audio_has_header(plm_audio_t *self) { - if (self->has_header) { - return TRUE; - } - - self->next_frame_data_size = plm_audio_decode_header(self); - return self->has_header; -} - -int plm_audio_get_samplerate(plm_audio_t *self) { - return plm_audio_has_header(self) - ? PLM_AUDIO_SAMPLE_RATE[self->samplerate_index] - : 0; -} - -double plm_audio_get_time(plm_audio_t *self) { - return self->time; -} - -void plm_audio_set_time(plm_audio_t *self, double time) { - self->samples_decoded = time * - (double)PLM_AUDIO_SAMPLE_RATE[self->samplerate_index]; - self->time = time; -} - -void plm_audio_rewind(plm_audio_t *self) { - plm_buffer_rewind(self->buffer); - self->time = 0; - self->samples_decoded = 0; - self->next_frame_data_size = 0; -} - -int plm_audio_has_ended(plm_audio_t *self) { - return plm_buffer_has_ended(self->buffer); -} - -plm_samples_t *plm_audio_decode(plm_audio_t *self) { - // Do we have at least enough information to decode the frame header? - if (!self->next_frame_data_size) { - if (!plm_buffer_has(self->buffer, 48)) { - return NULL; - } - self->next_frame_data_size = plm_audio_decode_header(self); - } - - if ( - self->next_frame_data_size == 0 || - !plm_buffer_has(self->buffer, self->next_frame_data_size << 3) - ) { - return NULL; - } - - plm_audio_decode_frame(self); - self->next_frame_data_size = 0; - - self->samples.time = self->time; - - self->samples_decoded += PLM_AUDIO_SAMPLES_PER_FRAME; - self->time = (double)self->samples_decoded / - (double)PLM_AUDIO_SAMPLE_RATE[self->samplerate_index]; - - return &self->samples; -} - -int plm_audio_find_frame_sync(plm_audio_t *self) { - size_t i; - for (i = self->buffer->bit_index >> 3; i < self->buffer->length-1; i++) { - if ( - self->buffer->bytes[i] == 0xFF && - (self->buffer->bytes[i+1] & 0xFE) == 0xFC - ) { - self->buffer->bit_index = ((i+1) << 3) + 3; - return TRUE; - } - } - self->buffer->bit_index = (i + 1) << 3; - return FALSE; -} - -int plm_audio_decode_header(plm_audio_t *self) { - if (!plm_buffer_has(self->buffer, 48)) { - return 0; - } - - plm_buffer_skip_bytes(self->buffer, 0x00); - int sync = plm_buffer_read(self->buffer, 11); - - - // Attempt to resync if no syncword was found. This sucks balls. The MP2 - // stream contains a syncword just before every frame (11 bits set to 1). - // However, this syncword is not guaranteed to not occur elswhere in the - // stream. So, if we have to resync, we also have to check if the header - // (samplerate, bitrate) differs from the one we had before. This all - // may still lead to garbage data being decoded :/ - - if (sync != PLM_AUDIO_FRAME_SYNC && !plm_audio_find_frame_sync(self)) { - return 0; - } - - self->version = plm_buffer_read(self->buffer, 2); - self->layer = plm_buffer_read(self->buffer, 2); - int hasCRC = !plm_buffer_read(self->buffer, 1); - - if ( - self->version != PLM_AUDIO_MPEG_1 || - self->layer != PLM_AUDIO_LAYER_II - ) { - return 0; - } - - int bitrate_index = plm_buffer_read(self->buffer, 4) - 1; - if (bitrate_index > 13) { - return 0; - } - - int samplerate_index = plm_buffer_read(self->buffer, 2); - if (samplerate_index == 3) { - return 0; - } - - int padding = plm_buffer_read(self->buffer, 1); - plm_buffer_skip(self->buffer, 1); // f_private - int mode = plm_buffer_read(self->buffer, 2); - - // If we already have a header, make sure the samplerate, bitrate and mode - // are still the same, otherwise we might have missed sync. - if ( - self->has_header && ( - self->bitrate_index != bitrate_index || - self->samplerate_index != samplerate_index || - self->mode != mode - ) - ) { - return 0; - } - - self->bitrate_index = bitrate_index; - self->samplerate_index = samplerate_index; - self->mode = mode; - self->has_header = TRUE; - - // Parse the mode_extension, set up the stereo bound - if (mode == PLM_AUDIO_MODE_JOINT_STEREO) { - self->bound = (plm_buffer_read(self->buffer, 2) + 1) << 2; - } - else { - plm_buffer_skip(self->buffer, 2); - self->bound = (mode == PLM_AUDIO_MODE_MONO) ? 0 : 32; - } - - // Discard the last 4 bits of the header and the CRC value, if present - plm_buffer_skip(self->buffer, 4); - if (hasCRC) { - plm_buffer_skip(self->buffer, 16); - } - - // Compute frame size, check if we have enough data to decode the whole - // frame. - int bitrate = PLM_AUDIO_BIT_RATE[self->bitrate_index]; - int samplerate = PLM_AUDIO_SAMPLE_RATE[self->samplerate_index]; - int frame_size = (144000 * bitrate / samplerate) + padding; - return frame_size - (hasCRC ? 6 : 4); -} - -void plm_audio_decode_frame(plm_audio_t *self) { - // Prepare the quantizer table lookups - int tab3 = 0; - int sblimit = 0; - - int tab1 = (self->mode == PLM_AUDIO_MODE_MONO) ? 0 : 1; - int tab2 = PLM_AUDIO_QUANT_LUT_STEP_1[tab1][self->bitrate_index]; - tab3 = QUANT_LUT_STEP_2[tab2][self->samplerate_index]; - sblimit = tab3 & 63; - tab3 >>= 6; - - if (self->bound > sblimit) { - self->bound = sblimit; - } - - // Read the allocation information - for (int sb = 0; sb < self->bound; sb++) { - self->allocation[0][sb] = plm_audio_read_allocation(self, sb, tab3); - self->allocation[1][sb] = plm_audio_read_allocation(self, sb, tab3); - } - - for (int sb = self->bound; sb < sblimit; sb++) { - self->allocation[0][sb] = - self->allocation[1][sb] = - plm_audio_read_allocation(self, sb, tab3); - } - - // Read scale factor selector information - int channels = (self->mode == PLM_AUDIO_MODE_MONO) ? 1 : 2; - for (int sb = 0; sb < sblimit; sb++) { - for (int ch = 0; ch < channels; ch++) { - if (self->allocation[ch][sb]) { - self->scale_factor_info[ch][sb] = plm_buffer_read(self->buffer, 2); - } - } - if (self->mode == PLM_AUDIO_MODE_MONO) { - self->scale_factor_info[1][sb] = self->scale_factor_info[0][sb]; - } - } - - // Read scale factors - for (int sb = 0; sb < sblimit; sb++) { - for (int ch = 0; ch < channels; ch++) { - if (self->allocation[ch][sb]) { - int *sf = self->scale_factor[ch][sb]; - switch (self->scale_factor_info[ch][sb]) { - case 0: - sf[0] = plm_buffer_read(self->buffer, 6); - sf[1] = plm_buffer_read(self->buffer, 6); - sf[2] = plm_buffer_read(self->buffer, 6); - break; - case 1: - sf[0] = - sf[1] = plm_buffer_read(self->buffer, 6); - sf[2] = plm_buffer_read(self->buffer, 6); - break; - case 2: - sf[0] = - sf[1] = - sf[2] = plm_buffer_read(self->buffer, 6); - break; - case 3: - sf[0] = plm_buffer_read(self->buffer, 6); - sf[1] = - sf[2] = plm_buffer_read(self->buffer, 6); - break; - } - } - } - if (self->mode == PLM_AUDIO_MODE_MONO) { - self->scale_factor[1][sb][0] = self->scale_factor[0][sb][0]; - self->scale_factor[1][sb][1] = self->scale_factor[0][sb][1]; - self->scale_factor[1][sb][2] = self->scale_factor[0][sb][2]; - } - } - - // Coefficient input and reconstruction - int out_pos = 0; - for (int part = 0; part < 3; part++) { - for (int granule = 0; granule < 4; granule++) { - - // Read the samples - for (int sb = 0; sb < self->bound; sb++) { - plm_audio_read_samples(self, 0, sb, part); - plm_audio_read_samples(self, 1, sb, part); - } - for (int sb = self->bound; sb < sblimit; sb++) { - plm_audio_read_samples(self, 0, sb, part); - self->sample[1][sb][0] = self->sample[0][sb][0]; - self->sample[1][sb][1] = self->sample[0][sb][1]; - self->sample[1][sb][2] = self->sample[0][sb][2]; - } - for (int sb = sblimit; sb < 32; sb++) { - self->sample[0][sb][0] = 0; - self->sample[0][sb][1] = 0; - self->sample[0][sb][2] = 0; - self->sample[1][sb][0] = 0; - self->sample[1][sb][1] = 0; - self->sample[1][sb][2] = 0; - } - - // Synthesis loop - for (int p = 0; p < 3; p++) { - // Shifting step - self->v_pos = (self->v_pos - 64) & 1023; - - for (int ch = 0; ch < 2; ch++) { - plm_audio_matrix_transform(self->sample[ch], p, self->V[ch], self->v_pos); - - // Build U, windowing, calculate output - memset(self->U, 0, sizeof(self->U)); - - int d_index = 512 - (self->v_pos >> 1); - int v_index = (self->v_pos % 128) >> 1; - while (v_index < 1024) { - for (int i = 0; i < 32; ++i) { - self->U[i] += self->D[d_index++] * self->V[ch][v_index++]; - } - - v_index += 128 - 32; - d_index += 64 - 32; - } - - d_index -= (512 - 32); - v_index = (128 - 32 + 1024) - v_index; - while (v_index < 1024) { - for (int i = 0; i < 32; ++i) { - self->U[i] += self->D[d_index++] * self->V[ch][v_index++]; - } - - v_index += 128 - 32; - d_index += 64 - 32; - } - - // Output samples - #ifdef PLM_AUDIO_SEPARATE_CHANNELS - float *out_channel = ch == 0 - ? self->samples.left - : self->samples.right; - for (int j = 0; j < 32; j++) { - out_channel[out_pos + j] = self->U[j] / 2147418112.0f; - } - #else - for (int j = 0; j < 32; j++) { - self->samples.interleaved[((out_pos + j) << 1) + ch] = - self->U[j] / 2147418112.0f; - } - #endif - } // End of synthesis channel loop - out_pos += 32; - } // End of synthesis sub-block loop - - } // Decoding of the granule finished - } - - plm_buffer_align(self->buffer); -} - -const plm_quantizer_spec_t *plm_audio_read_allocation(plm_audio_t *self, int sb, int tab3) { - int tab4 = PLM_AUDIO_QUANT_LUT_STEP_3[tab3][sb]; - int qtab = PLM_AUDIO_QUANT_LUT_STEP4[tab4 & 15][plm_buffer_read(self->buffer, tab4 >> 4)]; - return qtab ? (&PLM_AUDIO_QUANT_TAB[qtab - 1]) : 0; -} - -void plm_audio_read_samples(plm_audio_t *self, int ch, int sb, int part) { - const plm_quantizer_spec_t *q = self->allocation[ch][sb]; - int sf = self->scale_factor[ch][sb][part]; - int *sample = self->sample[ch][sb]; - int val = 0; - - if (!q) { - // No bits allocated for this subband - sample[0] = sample[1] = sample[2] = 0; - return; - } - - // Resolve scalefactor - if (sf == 63) { - sf = 0; - } - else { - int shift = (sf / 3) | 0; - sf = (PLM_AUDIO_SCALEFACTOR_BASE[sf % 3] + ((1 << shift) >> 1)) >> shift; - } - - // Decode samples - int adj = q->levels; - if (q->group) { - // Decode grouped samples - val = plm_buffer_read(self->buffer, q->bits); - sample[0] = val % adj; - val /= adj; - sample[1] = val % adj; - sample[2] = val / adj; - } - else { - // Decode direct samples - sample[0] = plm_buffer_read(self->buffer, q->bits); - sample[1] = plm_buffer_read(self->buffer, q->bits); - sample[2] = plm_buffer_read(self->buffer, q->bits); - } - - // Postmultiply samples - int scale = 65536 / (adj + 1); - adj = ((adj + 1) >> 1) - 1; - - val = (adj - sample[0]) * scale; - sample[0] = (val * (sf >> 12) + ((val * (sf & 4095) + 2048) >> 12)) >> 12; - - val = (adj - sample[1]) * scale; - sample[1] = (val * (sf >> 12) + ((val * (sf & 4095) + 2048) >> 12)) >> 12; - - val = (adj - sample[2]) * scale; - sample[2] = (val * (sf >> 12) + ((val * (sf & 4095) + 2048) >> 12)) >> 12; -} - -void plm_audio_matrix_transform(int s[32][3], int ss, float *d, int dp) { - float t01, t02, t03, t04, t05, t06, t07, t08, t09, t10, t11, t12, - t13, t14, t15, t16, t17, t18, t19, t20, t21, t22, t23, t24, - t25, t26, t27, t28, t29, t30, t31, t32, t33; - - t01 = (float)(s[0][ss] + s[31][ss]); t02 = (float)(s[0][ss] - s[31][ss]) * 0.500602998235f; - t03 = (float)(s[1][ss] + s[30][ss]); t04 = (float)(s[1][ss] - s[30][ss]) * 0.505470959898f; - t05 = (float)(s[2][ss] + s[29][ss]); t06 = (float)(s[2][ss] - s[29][ss]) * 0.515447309923f; - t07 = (float)(s[3][ss] + s[28][ss]); t08 = (float)(s[3][ss] - s[28][ss]) * 0.53104259109f; - t09 = (float)(s[4][ss] + s[27][ss]); t10 = (float)(s[4][ss] - s[27][ss]) * 0.553103896034f; - t11 = (float)(s[5][ss] + s[26][ss]); t12 = (float)(s[5][ss] - s[26][ss]) * 0.582934968206f; - t13 = (float)(s[6][ss] + s[25][ss]); t14 = (float)(s[6][ss] - s[25][ss]) * 0.622504123036f; - t15 = (float)(s[7][ss] + s[24][ss]); t16 = (float)(s[7][ss] - s[24][ss]) * 0.674808341455f; - t17 = (float)(s[8][ss] + s[23][ss]); t18 = (float)(s[8][ss] - s[23][ss]) * 0.744536271002f; - t19 = (float)(s[9][ss] + s[22][ss]); t20 = (float)(s[9][ss] - s[22][ss]) * 0.839349645416f; - t21 = (float)(s[10][ss] + s[21][ss]); t22 = (float)(s[10][ss] - s[21][ss]) * 0.972568237862f; - t23 = (float)(s[11][ss] + s[20][ss]); t24 = (float)(s[11][ss] - s[20][ss]) * 1.16943993343f; - t25 = (float)(s[12][ss] + s[19][ss]); t26 = (float)(s[12][ss] - s[19][ss]) * 1.48416461631f; - t27 = (float)(s[13][ss] + s[18][ss]); t28 = (float)(s[13][ss] - s[18][ss]) * 2.05778100995f; - t29 = (float)(s[14][ss] + s[17][ss]); t30 = (float)(s[14][ss] - s[17][ss]) * 3.40760841847f; - t31 = (float)(s[15][ss] + s[16][ss]); t32 = (float)(s[15][ss] - s[16][ss]) * 10.1900081235f; - - t33 = t01 + t31; t31 = (t01 - t31) * 0.502419286188f; - t01 = t03 + t29; t29 = (t03 - t29) * 0.52249861494f; - t03 = t05 + t27; t27 = (t05 - t27) * 0.566944034816f; - t05 = t07 + t25; t25 = (t07 - t25) * 0.64682178336f; - t07 = t09 + t23; t23 = (t09 - t23) * 0.788154623451f; - t09 = t11 + t21; t21 = (t11 - t21) * 1.06067768599f; - t11 = t13 + t19; t19 = (t13 - t19) * 1.72244709824f; - t13 = t15 + t17; t17 = (t15 - t17) * 5.10114861869f; - t15 = t33 + t13; t13 = (t33 - t13) * 0.509795579104f; - t33 = t01 + t11; t01 = (t01 - t11) * 0.601344886935f; - t11 = t03 + t09; t09 = (t03 - t09) * 0.899976223136f; - t03 = t05 + t07; t07 = (t05 - t07) * 2.56291544774f; - t05 = t15 + t03; t15 = (t15 - t03) * 0.541196100146f; - t03 = t33 + t11; t11 = (t33 - t11) * 1.30656296488f; - t33 = t05 + t03; t05 = (t05 - t03) * 0.707106781187f; - t03 = t15 + t11; t15 = (t15 - t11) * 0.707106781187f; - t03 += t15; - t11 = t13 + t07; t13 = (t13 - t07) * 0.541196100146f; - t07 = t01 + t09; t09 = (t01 - t09) * 1.30656296488f; - t01 = t11 + t07; t07 = (t11 - t07) * 0.707106781187f; - t11 = t13 + t09; t13 = (t13 - t09) * 0.707106781187f; - t11 += t13; t01 += t11; - t11 += t07; t07 += t13; - t09 = t31 + t17; t31 = (t31 - t17) * 0.509795579104f; - t17 = t29 + t19; t29 = (t29 - t19) * 0.601344886935f; - t19 = t27 + t21; t21 = (t27 - t21) * 0.899976223136f; - t27 = t25 + t23; t23 = (t25 - t23) * 2.56291544774f; - t25 = t09 + t27; t09 = (t09 - t27) * 0.541196100146f; - t27 = t17 + t19; t19 = (t17 - t19) * 1.30656296488f; - t17 = t25 + t27; t27 = (t25 - t27) * 0.707106781187f; - t25 = t09 + t19; t19 = (t09 - t19) * 0.707106781187f; - t25 += t19; - t09 = t31 + t23; t31 = (t31 - t23) * 0.541196100146f; - t23 = t29 + t21; t21 = (t29 - t21) * 1.30656296488f; - t29 = t09 + t23; t23 = (t09 - t23) * 0.707106781187f; - t09 = t31 + t21; t31 = (t31 - t21) * 0.707106781187f; - t09 += t31; t29 += t09; t09 += t23; t23 += t31; - t17 += t29; t29 += t25; t25 += t09; t09 += t27; - t27 += t23; t23 += t19; t19 += t31; - t21 = t02 + t32; t02 = (t02 - t32) * 0.502419286188f; - t32 = t04 + t30; t04 = (t04 - t30) * 0.52249861494f; - t30 = t06 + t28; t28 = (t06 - t28) * 0.566944034816f; - t06 = t08 + t26; t08 = (t08 - t26) * 0.64682178336f; - t26 = t10 + t24; t10 = (t10 - t24) * 0.788154623451f; - t24 = t12 + t22; t22 = (t12 - t22) * 1.06067768599f; - t12 = t14 + t20; t20 = (t14 - t20) * 1.72244709824f; - t14 = t16 + t18; t16 = (t16 - t18) * 5.10114861869f; - t18 = t21 + t14; t14 = (t21 - t14) * 0.509795579104f; - t21 = t32 + t12; t32 = (t32 - t12) * 0.601344886935f; - t12 = t30 + t24; t24 = (t30 - t24) * 0.899976223136f; - t30 = t06 + t26; t26 = (t06 - t26) * 2.56291544774f; - t06 = t18 + t30; t18 = (t18 - t30) * 0.541196100146f; - t30 = t21 + t12; t12 = (t21 - t12) * 1.30656296488f; - t21 = t06 + t30; t30 = (t06 - t30) * 0.707106781187f; - t06 = t18 + t12; t12 = (t18 - t12) * 0.707106781187f; - t06 += t12; - t18 = t14 + t26; t26 = (t14 - t26) * 0.541196100146f; - t14 = t32 + t24; t24 = (t32 - t24) * 1.30656296488f; - t32 = t18 + t14; t14 = (t18 - t14) * 0.707106781187f; - t18 = t26 + t24; t24 = (t26 - t24) * 0.707106781187f; - t18 += t24; t32 += t18; - t18 += t14; t26 = t14 + t24; - t14 = t02 + t16; t02 = (t02 - t16) * 0.509795579104f; - t16 = t04 + t20; t04 = (t04 - t20) * 0.601344886935f; - t20 = t28 + t22; t22 = (t28 - t22) * 0.899976223136f; - t28 = t08 + t10; t10 = (t08 - t10) * 2.56291544774f; - t08 = t14 + t28; t14 = (t14 - t28) * 0.541196100146f; - t28 = t16 + t20; t20 = (t16 - t20) * 1.30656296488f; - t16 = t08 + t28; t28 = (t08 - t28) * 0.707106781187f; - t08 = t14 + t20; t20 = (t14 - t20) * 0.707106781187f; - t08 += t20; - t14 = t02 + t10; t02 = (t02 - t10) * 0.541196100146f; - t10 = t04 + t22; t22 = (t04 - t22) * 1.30656296488f; - t04 = t14 + t10; t10 = (t14 - t10) * 0.707106781187f; - t14 = t02 + t22; t02 = (t02 - t22) * 0.707106781187f; - t14 += t02; t04 += t14; t14 += t10; t10 += t02; - t16 += t04; t04 += t08; t08 += t14; t14 += t28; - t28 += t10; t10 += t20; t20 += t02; t21 += t16; - t16 += t32; t32 += t04; t04 += t06; t06 += t08; - t08 += t18; t18 += t14; t14 += t30; t30 += t28; - t28 += t26; t26 += t10; t10 += t12; t12 += t20; - t20 += t24; t24 += t02; - - d[dp + 48] = -t33; - d[dp + 49] = d[dp + 47] = -t21; - d[dp + 50] = d[dp + 46] = -t17; - d[dp + 51] = d[dp + 45] = -t16; - d[dp + 52] = d[dp + 44] = -t01; - d[dp + 53] = d[dp + 43] = -t32; - d[dp + 54] = d[dp + 42] = -t29; - d[dp + 55] = d[dp + 41] = -t04; - d[dp + 56] = d[dp + 40] = -t03; - d[dp + 57] = d[dp + 39] = -t06; - d[dp + 58] = d[dp + 38] = -t25; - d[dp + 59] = d[dp + 37] = -t08; - d[dp + 60] = d[dp + 36] = -t11; - d[dp + 61] = d[dp + 35] = -t18; - d[dp + 62] = d[dp + 34] = -t09; - d[dp + 63] = d[dp + 33] = -t14; - d[dp + 32] = -t05; - d[dp + 0] = t05; d[dp + 31] = -t30; - d[dp + 1] = t30; d[dp + 30] = -t27; - d[dp + 2] = t27; d[dp + 29] = -t28; - d[dp + 3] = t28; d[dp + 28] = -t07; - d[dp + 4] = t07; d[dp + 27] = -t26; - d[dp + 5] = t26; d[dp + 26] = -t23; - d[dp + 6] = t23; d[dp + 25] = -t10; - d[dp + 7] = t10; d[dp + 24] = -t15; - d[dp + 8] = t15; d[dp + 23] = -t12; - d[dp + 9] = t12; d[dp + 22] = -t19; - d[dp + 10] = t19; d[dp + 21] = -t20; - d[dp + 11] = t20; d[dp + 20] = -t13; - d[dp + 12] = t13; d[dp + 19] = -t24; - d[dp + 13] = t24; d[dp + 18] = -t31; - d[dp + 14] = t31; d[dp + 17] = -t02; - d[dp + 15] = t02; d[dp + 16] = 0.0; -} - - -#endif // PL_MPEG_IMPLEMENTATION diff --git a/source/engine/thirdpersonfollow.c b/source/engine/thirdpersonfollow.c index 37f05e6..c48d236 100755 --- a/source/engine/thirdpersonfollow.c +++ b/source/engine/thirdpersonfollow.c @@ -35,12 +35,6 @@ // // TODO: Figure out how to translate rotation to a global rotation // } -mfloat_t *follow_calcpos() -{ - mfloat_t p1[3] = { 0 }; - mfloat_t p2[3] = { 0 }; -} - /* glm::vec3 ThirdPersonFollow::CalculatePosition() diff --git a/source/engine/thirdpersonfollow.h b/source/engine/thirdpersonfollow.h index f2b2f73..ac671bf 100755 --- a/source/engine/thirdpersonfollow.h +++ b/source/engine/thirdpersonfollow.h @@ -10,7 +10,6 @@ struct follow { mfloat_t target_rot[4]; }; -mfloat_t *follow_calcpos(); mfloat_t *follow_calccenter(); mfloat_t *follow_postoffset(); mfloat_t *extentsoffset(); diff --git a/source/engine/vec.c b/source/engine/vec.c index 565e627..1909604 100755 --- a/source/engine/vec.c +++ b/source/engine/vec.c @@ -1,8 +1,9 @@ #include "vec.h" #include "log.h" +#include +#include - -struct vec *vec_make(int width, int size) +struct vec *vec_make(size_t width, int size) { struct vec *new = calloc(1, sizeof(struct vec)); new->size = size; @@ -25,7 +26,7 @@ void *vec_get(struct vec *vec, int n) void vec_walk(struct vec *vec, void (*fn)(void *data)) { for(int i = 0; i < vec->len; i++) - fn((char *) (vec->data + (i * vec->width))); + fn((char*)vec->data + (i * vec->width)); } void vec_delete(struct vec *vec, int n) @@ -46,7 +47,7 @@ void vec_del_order(struct vec *vec, int n) } } -void *vec_add(struct vec *vec, void *data) +void *vec_add(struct vec *vec, const void *data) { if (vec->size == vec->len) vec_expand(vec); @@ -70,7 +71,7 @@ void *vec_add_sort(struct vec *vec, void *data, while (sort(vec_p(vec, n), data)) n--; - vec_insert(vec, data, n); + return vec_insert(vec, data, n); } void *vec_insert(struct vec *vec, void *data, int n) diff --git a/source/engine/vec.h b/source/engine/vec.h index 955e908..d22867d 100755 --- a/source/engine/vec.h +++ b/source/engine/vec.h @@ -6,15 +6,15 @@ struct vec { int len; int size; - int width; + size_t width; void *data; }; -struct vec *vec_make(int width, int size); +struct vec *vec_make(size_t width, int size); void *vec_get(struct vec *vec, int n); void vec_walk(struct vec *vec, void (*fn)(void *data)); void vec_clear(struct vec *vec); -void *vec_add(struct vec *vec, void *data); +void *vec_add(struct vec *vec, const void *data); /* sort returns 0 for a<=b, 1 for a>b */ void *vec_add_sort(struct vec *vec, void *data, @@ -29,4 +29,4 @@ char *vec_p(struct vec *vec, int n); void vec_expand(struct vec *vec); void vec_fit(struct vec *vec); -#endif \ No newline at end of file +#endif diff --git a/source/engine/window.c b/source/engine/window.c index a3946af..5a5572d 100755 --- a/source/engine/window.c +++ b/source/engine/window.c @@ -1,62 +1,54 @@ #include "window.h" -#include "openglrender.h" + #include #include "texture.h" #include "log.h" +#include +#include -struct mSDLWindow *window = NULL; +struct mSDLWindow *mainwin; static struct mSDLWindow *windows[5]; static int numWindows = 0; -static SDL_GLContext publicGLContext = NULL; - struct mSDLWindow *MakeSDLWindow(const char *name, int width, int height, uint32_t flags) { struct mSDLWindow *w = calloc(1, sizeof(struct mSDLWindow)); w->width = width; w->height = height; - w->window = SDL_CreateWindow(name, 0, 0, width, height, flags); + w->window = glfwCreateWindow(width, height, "New Game", NULL, NULL); - if (w->window == NULL) { - YughLog(0, SDL_LOG_PRIORITY_ERROR, - "Window could not be created! SDL Error: %s", - SDL_GetError()); + if (!w->window) { + printf("Couldn't make GLFW window\n"); } else { - if (publicGLContext == NULL) { - publicGLContext = SDL_GL_CreateContext(w->window); - } + glfwMakeContextCurrent(w->window); + gladLoadGL(glfwGetProcAddress); - w->glContext = publicGLContext; - SDL_GL_MakeCurrent(w->window, w->glContext); + glfwSwapInterval(1); + w->id = numWindows; - if (publicGLContext == NULL) { - YughLog(0, SDL_LOG_PRIORITY_ERROR, - "OpenGL context could not be created! SDL Error: %s", - SDL_GetError()); - } - - w->id = SDL_GetWindowID(w->window); - - glewExperimental = GL_TRUE; - glewInit(); - - SDL_GL_SetSwapInterval(1); if (numWindows < 5) windows[numWindows++] = w; + } - + mainwin = windows[0]; return w; } -void window_handle_event(struct mSDLWindow *w, SDL_Event * e) +void window_destroy(struct mSDLWindow *w) { + glfwDestroyWindow(w->window); +} + +void window_handle_event(struct mSDLWindow *w) +{ +/* if (e->type == SDL_WINDOWEVENT && e->window.windowID == w->id) { // TODO: Check ptr direct? switch (e->window.event) { case SDL_WINDOWEVENT_SHOWN: @@ -77,9 +69,9 @@ void window_handle_event(struct mSDLWindow *w, SDL_Event * e) "Changed size of window %d: width %d, height %d.", w->id, w->width, w->height); window_makecurrent(w); - /*w.projection = + w.projection = glm::ortho(0.f, (float) width, 0.f, (float) height, -1.f, - 1.f); */ + 1.f); w->render = true; break; @@ -134,18 +126,19 @@ void window_handle_event(struct mSDLWindow *w, SDL_Event * e) break; } } +*/ } -void window_all_handle_events(SDL_Event *e) +void window_all_handle_events() { for (int i = 0; i < numWindows; i++) { - window_handle_event(windows[i], e); + window_handle_event(windows[i]); } } void window_makefullscreen(struct mSDLWindow *w) { - SDL_SetWindowFullscreen(w->window, SDL_WINDOW_FULLSCREEN_DESKTOP); + glfwMaximizeWindow(w->window); w->fullscreen = true; } @@ -156,31 +149,48 @@ void window_togglefullscreen(struct mSDLWindow *w) if (w->fullscreen) { window_makefullscreen(w); } else { - SDL_SetWindowFullscreen(w->window, 0); + glfwRestoreWindow(w->window); } } void window_makecurrent(struct mSDLWindow *w) { +/* if (w->window != SDL_GL_GetCurrentWindow()) SDL_GL_MakeCurrent(w->window, w->glContext); glViewport(0, 0, w->width, w->height); +*/ } void window_swap(struct mSDLWindow *w) { - SDL_GL_SwapWindow(w->window); + glfwSwapBuffers(w->window); } void window_seticon(struct mSDLWindow *w, struct Texture *icon) { - SDL_Surface *winIcon = SDL_CreateRGBSurfaceWithFormatFrom(icon->data, icon->width, icon->height, 32, 4*icon->width, SDL_PIXELFORMAT_RGBA32); - SDL_SetWindowIcon(w->window, winIcon); - SDL_FreeSurface(winIcon); +/* + GLFWimage images[1]; + images[0] = load_icon(icon->path); + glfwSetWindowIcon(w->window, 1, images); +*/ } int window_hasfocus(struct mSDLWindow *w) { - return SDL_GetWindowFlags(w->window) & SDL_WINDOW_INPUT_FOCUS; -} \ No newline at end of file + return glfwGetWindowAttrib(w->window, GLFW_FOCUSED); +} + +double frame_time() +{ + return glfwGetTime(); +} + +double elapsed_time() +{ + static double last_time; + static double elapsed; + elapsed = frame_time() - last_time; + return elapsed; +} diff --git a/source/engine/window.h b/source/engine/window.h index a2e6771..7022d88 100755 --- a/source/engine/window.h +++ b/source/engine/window.h @@ -1,12 +1,12 @@ #ifndef WINDOW_H #define WINDOW_H -#include +#include "render.h" #include +#include struct mSDLWindow { - SDL_Window *window; - SDL_GLContext glContext; + GLFWwindow *window; int id; int width; int height; @@ -22,10 +22,15 @@ struct mSDLWindow { struct Texture; +extern struct mSDLWindow *mainwin; + + + struct mSDLWindow *MakeSDLWindow(const char *name, int width, int height, uint32_t flags); -void window_handle_event(struct mSDLWindow *w, SDL_Event * e); -void window_all_handle_events(SDL_Event *e); +void window_destroy(struct mSDLWindow *w); +void window_handle_event(struct mSDLWindow *w); +void window_all_handle_events(); void window_makecurrent(struct mSDLWindow *w); void window_makefullscreen(struct mSDLWindow *w); void window_togglefullscreen(struct mSDLWindow *w); @@ -33,4 +38,7 @@ void window_swap(struct mSDLWindow *w); void window_seticon(struct mSDLWindow *w, struct Texture *icon); int window_hasfocus(struct mSDLWindow *w); +double frame_time(); +double elapsed_time(); + #endif diff --git a/source/engine/yugine.c b/source/engine/yugine.c index 5e67a42..305b365 100755 --- a/source/engine/yugine.c +++ b/source/engine/yugine.c @@ -1,4 +1,4 @@ -#include +#include "render.h" #include "camera.h" #include "window.h" #include "engine.h" @@ -10,14 +10,11 @@ int physOn = 0; unsigned int frameCount = 0; -Uint32 lastTick = 0; -Uint32 frameTick = 0; -Uint32 elapsed = 0; -Uint32 physMS = FPS144; -Uint32 physlag = 0; -Uint32 renderMS = FPS144; -Uint32 renderlag = 0; +double physMS = sFPS144; +double physlag = 0; +double renderMS = sFPS144; +double renderlag = 0; struct mCamera camera = {0}; @@ -27,63 +24,47 @@ int main(int argc, char **args) engine_init(); - struct mSDLWindow *window = MakeSDLWindow("Untitled Game", 1920, 1080, - SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | - SDL_WINDOW_RESIZABLE); - + struct mSDLWindow *window = MakeSDLWindow("Untitled Game", 1920, 1080, 0); openglInit(); - editor_init(window); - int quit = 0; - SDL_Event e; //While application is running while (!quit) { - frameTick = SDL_GetTicks(); - elapsed = frameTick - lastTick; - lastTick = frameTick; - deltaT = elapsed / 1000.f; + deltaT = elapsed_time(); - physlag += elapsed; - renderlag += elapsed; + physlag += deltaT; + renderlag += deltaT; input_poll(); if (physlag >= physMS) { - phys2d_update(physMS / 1000.f); + phys2d_update(physMS); physlag -= physMS; } - if (renderlag >= renderMS) { if (physOn) { update_gameobjects(); } - - camera_2d_update(&camera, renderMS / 1000.f); + camera_2d_update(&camera, renderMS); openglRender(window, &camera); - - editor_render(); - window_swap(window); renderlag -= renderMS; } } - engine_stop(); - return 0; }