Browse Source

Merge pull request #139 from tsoding/103

(#103) POC of OpenGL preview
Alexey Kutepov 5 years ago
parent
commit
1ef9226366

+ 6 - 3
.github/workflows/ci.yml

@@ -9,13 +9,14 @@ jobs:
       - name: install dependencies
         run: |
           sudo apt-get update
-          sudo apt-get install -qq nasm libfreetype6-dev libcurl4-openssl-dev libpcre2-dev
+          sudo apt-get install -qq nasm libfreetype6-dev libcurl4-openssl-dev libpcre2-dev libglfw3-dev
       - uses: actions/cache@v2
         with:
           # TODO(#84): centralize third party versions in the build
           path: |
             ./third_party/ffmpeg-4.3-dist/
             ./third_party/giflib-5.2.1-dist/
+            ./third_party/glfw-3.3.2-dist/
           key: ${{ runner.os }}-ffmpeg-4.3-giflib-5.2.1
       - name: build third-party things
         run: |
@@ -47,12 +48,13 @@ jobs:
       - uses: actions/checkout@v1
       - name: install dependencies
         run: |
-          brew install nasm freetype2 openssl pcre2
+          brew install nasm freetype2 openssl pcre2 glfw
       - uses: actions/cache@v2
         with:
           path: |
             ./third_party/ffmpeg-4.3-dist/
             ./third_party/giflib-5.2.1-dist/
+            ./third_party/glfw-3.3.2-dist/
           key: ${{ runner.os }}-ffmpeg-4.3-giflib-5.2.1
       - name: build third-party things
         run: |
@@ -86,12 +88,13 @@ jobs:
       - name: install dependencies
         run: |
           sudo apt-get update
-          sudo apt-get install -qq nasm libfreetype6-dev libcurl4-openssl-dev libpcre2-dev
+          sudo apt-get install -qq nasm libfreetype6-dev libcurl4-openssl-dev libpcre2-dev libglfw3-dev
       - uses: actions/cache@v2
         with:
           path: |
             ./third_party/ffmpeg-4.3-dist/
             ./third_party/giflib-5.2.1-dist/
+            ./third_party/glfw-3.3.2-dist/
           key: ${{ runner.os }}-ffmpeg-4.3-giflib-5.2.1
       - name: build third-party things
         run: |

+ 2 - 2
Makefile

@@ -7,9 +7,9 @@ VODUS_EXTRA_CXXFLAGS += -DVODUS_SSE -msse4
 endif
 
 # TODO(#87): we need an option to build with system libraries
-VODUS_PKGS=freetype2 libpcre2-8
+VODUS_PKGS=freetype2 libpcre2-8 glfw3 gl
 VODUS_CXXFLAGS=-Wall -fno-exceptions -std=c++17 $(VODUS_EXTRA_CXXFLAGS) -ggdb `pkg-config --cflags $(VODUS_PKGS)` -I./third_party/ffmpeg-4.3-dist/usr/local/include/ -I./third_party/giflib-5.2.1-dist/usr/local/include/
-VODUS_LIBS=`pkg-config --libs $(VODUS_PKGS)` -L./third_party/giflib-5.2.1-dist/usr/local/lib/ ./third_party/giflib-5.2.1-dist/usr/local/lib/libgif.a -L./third_party/ffmpeg-4.3-dist/usr/local/lib/ -lavcodec -lavutil -lswresample -pthread -lm -llzma -lz
+VODUS_LIBS=`pkg-config --libs $(VODUS_PKGS)` -L./third_party/giflib-5.2.1-dist/usr/local/lib/ ./third_party/giflib-5.2.1-dist/usr/local/lib/libgif.a -L./third_party/ffmpeg-4.3-dist/usr/local/lib/ -L./third_party/glfw-3.3.2-dist/usr/local/lib/ -lavcodec -lavutil -lswresample -pthread -lm -llzma -lz -ldl
 
 ifeq ($(UNAME), Darwin)
 VODUS_LIBS += -framework AVFoundation -framework VideoToolbox -framework CoreVideo -framework AudioToolbox -framework CoreMedia -framework CoreFoundation -liconv

+ 3 - 0
src/vodus.cpp

@@ -38,6 +38,9 @@ using namespace aids;
 #include <smmintrin.h>
 #endif // VODUS_SSE
 
+#define GL_GLEXT_PROTOTYPES
+#include <GLFW/glfw3.h>
+
 // PLEASE READ THIS --> https://en.wikipedia.org/wiki/Single_Compilation_Unit
 #include "./vodus_error.cpp"
 #include "./vodus_queue.cpp"

+ 155 - 0
src/vodus_encoder.cpp

@@ -113,3 +113,158 @@ void pngencoder_encode(PNGEncoder_Context *context, Image32 surface, int frame_i
         abort();
     }
 }
+
+const char *vertex_shader_source =
+    "#version 130\n"
+    "out vec2 texcoord;"
+    "void main(void)\n"
+    "{\n"
+    "    int gray = gl_VertexID ^ (gl_VertexID >> 1);\n"
+    "    gl_Position = vec4(\n"
+    "        2 * (gray / 2) - 1,\n"
+    "        2 * (gray % 2) - 1,\n"
+    "        0.0,\n"
+    "        1.0);\n"
+    "    texcoord = vec2(gray / 2, 1 - gray % 2);\n"
+    "}\n";
+const char *fragment_shader_source =
+    "#version 130\n"
+    "in vec2 texcoord;\n"
+    "uniform sampler2D frame;\n"
+    "out vec4 color;\n"
+    "void main(void) {\n"
+    "    color = texture(frame, texcoord);\n"
+    "    //color = vec4(0.5, 0.5, 0.5, 1.0);\n"
+    "}\n";
+
+struct Shader
+{
+    GLuint unwrap;
+};
+
+Shader compile_shader(const char *source_code, GLenum shader_type)
+{
+    GLuint shader = {};
+    shader = glCreateShader(shader_type);
+    if (shader == 0) {
+        println(stderr, "Could not create a shader");
+        exit(1);
+    }
+
+    glShaderSource(shader, 1, &source_code, 0);
+    glCompileShader(shader);
+
+    GLint compiled = 0;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+    if (!compiled) {
+        GLchar buffer[1024];
+        int length = 0;
+        glGetShaderInfoLog(shader, sizeof(buffer), &length, buffer);
+        println(stderr, "Could not compile shader: ", buffer);
+        exit(1);
+    }
+
+    return {shader};
+}
+
+struct Program
+{
+    GLuint unwrap;
+};
+
+Program link_program(Shader vertex_shader, Shader fragment_shader)
+{
+    GLuint program = glCreateProgram();
+
+    if (program == 0) {
+        println(stderr, "Could not create shader program");
+        exit(1);
+    }
+
+    glAttachShader(program, vertex_shader.unwrap);
+    glAttachShader(program, fragment_shader.unwrap);
+    glLinkProgram(program);
+
+    GLint linked = 0;
+    glGetProgramiv(program, GL_LINK_STATUS, &linked);
+    if (!linked) {
+        GLchar buffer[1024];
+        int length = 0;
+        glGetProgramInfoLog(program, sizeof(buffer), &length, buffer);
+        println(stdout, "Could not link the program: ", buffer);
+        exit(1);
+    }
+
+    return {program};
+}
+
+Preview_Context *new_preview_context(Video_Params params)
+{
+    Preview_Context *context = new Preview_Context();
+
+    if (!glfwInit()) {
+        println(stderr, "Could not initialize GLFW");
+        exit(1);
+    }
+
+    context->window = glfwCreateWindow(params.width, params.height, "Vodus", NULL, NULL);
+    if (!context->window) {
+        println(stderr, "Could not create GLFW window");
+        exit(1);
+    }
+
+    glfwMakeContextCurrent(context->window);
+
+    // glfwSetFramebufferSizeCallback(window, framebuffer_resize);
+
+    GLuint texture_id;
+
+    glGenTextures(1, &texture_id);
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, texture_id);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    println(stdout, "Compiling vertex shader...");
+    Shader vertex_shader = compile_shader(vertex_shader_source, GL_VERTEX_SHADER);
+    println(stdout, "Compiling fragment shader...");
+    Shader fragment_shader = compile_shader(fragment_shader_source, GL_FRAGMENT_SHADER);
+    println(stdout, "Linking the program...");
+    Program program = link_program(vertex_shader, fragment_shader);
+
+    glUseProgram(program.unwrap);
+
+    GLint frame_sampler = glGetUniformLocation(program.unwrap, "frame");
+    glUniform1i(frame_sampler, 0);
+
+    return context;
+}
+
+void previewencoder_encode(Preview_Context *context, Image32 surface, int frame_index)
+{
+    if (glfwWindowShouldClose(context->window)) {
+        // TODO(#140): encoder does not provide a mechanism to exit prematurely
+        exit(0);
+    }
+
+    // Rebind the texture
+    glTexImage2D(GL_TEXTURE_2D,
+                 0,
+                 GL_RGBA,
+                 surface.width,
+                 surface.height,
+                 0,
+                 GL_RGBA,
+                 GL_UNSIGNED_BYTE,
+                 surface.pixels);
+    glGenerateMipmap(GL_TEXTURE_2D);
+
+    // TODO(#141): Preview is not synced with real time
+    // TODO(#142): Preview does not allow to pause and move backward/forward
+
+    glDrawArrays(GL_QUADS, 0, 4);
+    glfwSwapBuffers(context->window);
+    glfwPollEvents();
+}

+ 9 - 0
src/vodus_encoder.hpp

@@ -34,4 +34,13 @@ struct PNGEncoder_Context
 
 void pngencoder_encode(PNGEncoder_Context *context, Image32 surface, int frame_index);
 
+struct Preview_Context
+{
+    GLFWwindow *window;
+};
+
+Preview_Context *new_preview_context(Video_Params parsm);
+
+void previewencoder_encode(Preview_Context *context, Image32 surface, int frame_index);
+
 #endif  // VODUS_ENCODER_HPP_

+ 11 - 0
src/vodus_main.cpp

@@ -1,3 +1,4 @@
+
 void sample_chat_log_animation(Message *messages,
                                size_t messages_size,
                                FT_Face face,
@@ -155,6 +156,11 @@ int main(int argc, char *argv[])
         encoder.context = new PNGEncoder_Context {cstr_as_string_view(output_filepath)};
         encoder.encode_func = (Encode_Func) &pngencoder_encode;
     } break;
+
+    case Output_Type::Preview: {
+        encoder.context = new_preview_context(params);
+        encoder.encode_func = (Encode_Func) &previewencoder_encode;
+    } break;
     }
 
     {
@@ -180,6 +186,11 @@ int main(int argc, char *argv[])
     case Output_Type::PNG: {
         delete ((PNGEncoder_Context*) encoder.context);
     } break;
+
+    case Output_Type::Preview: {
+        glfwTerminate();
+        delete ((Preview_Context*)encoder.context);
+    } break;
     }
 
     return 0;

+ 5 - 0
src/vodus_video_params.cpp

@@ -18,6 +18,9 @@ void print1(FILE *stream, Output_Type output_type)
     case Output_Type::PNG:
         print1(stream, "png");
         break;
+    case Output_Type::Preview:
+        print1(stream, "preview");
+        break;
     }
 }
 
@@ -178,6 +181,8 @@ void patch_video_params_from_flag(Video_Params *params, String_View flag, String
             params->output_type = Output_Type::Video;
         } else if (value == "png"_sv) {
             params->output_type = Output_Type::PNG;
+        } else if (value == "preview"_sv) {
+            params->output_type = Output_Type::Preview;
         } else {
             println(stderr, "Unknown output type `", value, "`");
             abort();

+ 2 - 1
src/vodus_video_params.hpp

@@ -4,7 +4,8 @@
 enum class Output_Type
 {
     Video,
-    PNG
+    PNG,
+    Preview
 };
 
 struct Video_Params

+ 3 - 1
third_party/.gitignore

@@ -1,5 +1,7 @@
 *.tar.xz
 *.tar.gz
+*.zip
 *-dist/
 ffmpeg-*/
-giflib-*/
+giflib-*/
+glfw-*/

+ 0 - 1
third_party/build_third_party.sh

@@ -44,4 +44,3 @@ if [ ! -d "giflib-${GIFLIB_VERSION}-dist" ]; then
       DESTDIR="../giflib-${GIFLIB_VERSION}-dist" $MAKE install
     cd ..
 fi
-