]> git.sesse.net Git - nageru/blobdiff - mixer.cpp
Hook up the cut button to something that is not really cut, but is more useful than...
[nageru] / mixer.cpp
index 4d7c19d35b30962334d61a0a6df9ab83cdf3664a..0c36c48f97e04d7b080cce543c0accdcb8598503 100644 (file)
--- a/mixer.cpp
+++ b/mixer.cpp
 #include "context.h"
 #include "bmusb.h"
 #include "pbo_frame_allocator.h"
+#include "mixer.h"
+#include "ref_counted_gl_sync.h"
 
 using namespace movit;
 using namespace std;
 using namespace std::placeholders;
 
-// shared between all EGL contexts
-EGLDisplay egl_display;
-EGLSurface egl_surface;
-EGLConfig ecfg;
-EGLint ctxattr[] = {
-       EGL_CONTEXT_CLIENT_VERSION, 2,
-       EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
-       EGL_CONTEXT_MINOR_VERSION_KHR, 1,
-       //EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
-       EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT,
-       EGL_NONE
-};
+Source current_source = SOURCE_INPUT1;
 
-EGLConfig pbuffer_ecfg;
+ResourcePool *resource_pool;
 
-std::mutex bmusb_mutex;  // protects <cards>
+std::mutex display_frame_mutex;
+DisplayFrame current_display_frame, ready_display_frame;  // protected by <frame_mutex>
+bool has_current_display_frame = false, has_ready_display_frame = false;  // protected by <frame_mutex>
 
+std::mutex bmusb_mutex;
 struct CaptureCard {
        BMUSBCapture *usb;
 
@@ -85,7 +79,10 @@ struct CaptureCard {
        GLsync new_data_ready_fence;  // Whether new_frame is ready for rendering.
        std::condition_variable new_data_ready_changed;  // Set whenever new_data_ready is changed.
 };
-CaptureCard cards[NUM_CARDS];
+CaptureCard cards[NUM_CARDS];  // protected by <bmusb_mutex>
+
+new_frame_ready_callback_t new_frame_ready_callback;
+bool has_new_frame_ready_callback = false;
 
 void bm_frame(int card_index, uint16_t timecode,
               FrameAllocator::Frame video_frame, size_t video_offset, uint16_t video_format,
@@ -219,7 +216,7 @@ void mixer_thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3
                exit(1);
        }
 
-       CHECK(init_movit("/usr/share/movit", MOVIT_DEBUG_ON));
+       CHECK(init_movit(MOVIT_SHADER_DIR, MOVIT_DEBUG_OFF));
        check_error();
 
        EffectChain chain(WIDTH, HEIGHT);
@@ -261,6 +258,7 @@ void mixer_thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3
 
        ycbcr_format.chroma_subsampling_x = 1;
 
+       chain.add_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
        chain.add_ycbcr_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, ycbcr_format, YCBCR_OUTPUT_SPLIT_Y_AND_CBCR);
        chain.set_dither_bits(8);
        chain.set_output_origin(OUTPUT_ORIGIN_TOP_LEFT);
@@ -307,13 +305,12 @@ void mixer_thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3
                GLint input_tex_pbo = (GLint)(intptr_t)bmusb_current_rendering_frame[card_index].userdata;
                input[card_index]->set_pixel_data(0, nullptr, input_tex_pbo);
                input[card_index]->set_pixel_data(1, nullptr, input_tex_pbo);
-               check_error();
        }
 
        //chain.enable_phase_timing(true);
 
        // Set up stuff for NV12 conversion.
-       ResourcePool *resource_pool = chain.get_resource_pool();
+       resource_pool = chain.get_resource_pool();
        GLuint chroma_tex = resource_pool->create_2d_texture(GL_RG8, WIDTH, HEIGHT);
 
        // Cb/Cr shader.
@@ -352,22 +349,43 @@ void mixer_thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3
                float right1 = 1280 - 16;
                float top1 = bottom1 - height1;
                float left1 = right1 - width1;
-               
-               float t = 0.5 + 0.5 * cos(frame * 0.006);
-               //float t = 0.0;
-               float scale0 = 1.0 + t * (1280.0 / 848.0 - 1.0);
-               float tx0 = 0.0 + t * (-16.0 * scale0);
-               float ty0 = 0.0 + t * (-48.0 * scale0);
-
-               top0 = top0 * scale0 + ty0;
-               bottom0 = bottom0 * scale0 + ty0;
-               left0 = left0 * scale0 + tx0;
-               right0 = right0 * scale0 + tx0;
-
-               top1 = top1 * scale0 + ty0;
-               bottom1 = bottom1 * scale0 + ty0;
-               left1 = left1 * scale0 + tx0;
-               right1 = right1 * scale0 + tx0;
+       
+               if (current_source == SOURCE_INPUT1) {
+                       top0 = 0.0;
+                       bottom0 = HEIGHT;
+                       left0 = 0.0;
+                       right0 = WIDTH;
+
+                       top1 = HEIGHT + 10;
+                       bottom1 = HEIGHT + 20;
+                       left1 = WIDTH + 10;
+                       right1 = WIDTH + 20;
+               } else if (current_source == SOURCE_INPUT2) {
+                       top1 = 0.0;
+                       bottom1 = HEIGHT;
+                       left1 = 0.0;
+                       right1 = WIDTH;
+
+                       top0 = HEIGHT + 10;
+                       bottom0 = HEIGHT + 20;
+                       left0 = WIDTH + 10;
+                       right0 = WIDTH + 20;
+               } else {
+                       float t = 0.5 + 0.5 * cos(frame * 0.006);
+                       float scale0 = 1.0 + t * (1280.0 / 848.0 - 1.0);
+                       float tx0 = 0.0 + t * (-16.0 * scale0);
+                       float ty0 = 0.0 + t * (-48.0 * scale0);
+
+                       top0 = top0 * scale0 + ty0;
+                       bottom0 = bottom0 * scale0 + ty0;
+                       left0 = left0 * scale0 + tx0;
+                       right0 = right0 * scale0 + tx0;
+
+                       top1 = top1 * scale0 + ty0;
+                       bottom1 = bottom1 * scale0 + ty0;
+                       left1 = left1 * scale0 + tx0;
+                       right1 = right1 * scale0 + tx0;
+               }
 
                place_rectangle(resample_effect, padding_effect, left0, top0, right0, bottom0);
                place_rectangle(resample2_effect, padding2_effect, left1, top1, right1, bottom1);
@@ -405,6 +423,7 @@ void mixer_thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3
                        // knowing when the current one is released.)
                        input_frames_to_release.push_back(bmusb_current_rendering_frame[card_index]);
                        bmusb_current_rendering_frame[card_index] = card->new_frame;
+                       check_error();
 
                        // The new texture might still be uploaded,
                        // tell the GPU to wait until it's there.
@@ -429,11 +448,10 @@ void mixer_thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3
                assert(got_frame);
 
                // Render chain.
-               {
-                       GLuint ycbcr_fbo = resource_pool->create_fbo(y_tex, chroma_tex);
-                       chain.render_to_fbo(ycbcr_fbo, WIDTH, HEIGHT);
-                       resource_pool->release_fbo(ycbcr_fbo);
-               }
+               GLuint rgba_tex = resource_pool->create_2d_texture(GL_RGBA8, WIDTH, HEIGHT);
+               GLuint ycbcr_fbo = resource_pool->create_fbo(y_tex, chroma_tex, rgba_tex);
+               chain.render_to_fbo(ycbcr_fbo, WIDTH, HEIGHT);
+               resource_pool->release_fbo(ycbcr_fbo);
 
                // Set up for extraction.
                float vertices[] = {
@@ -450,45 +468,59 @@ void mixer_thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3
                glBindFramebuffer(GL_FRAMEBUFFER, cbcr_fbo);
                glViewport(0, 0, WIDTH/2, HEIGHT/2);
                check_error();
-               GLsync fence;
-               {
-                       glUseProgram(cbcr_program_num);
-                       check_error();
 
-                       glActiveTexture(GL_TEXTURE0);
-                       check_error();
-                       glBindTexture(GL_TEXTURE_2D, chroma_tex);
-                       check_error();
-                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-                       check_error();
-                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-                       check_error();
-                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-                       check_error();
+               glUseProgram(cbcr_program_num);
+               check_error();
 
-                       float chroma_offset_0[] = { -0.5f / WIDTH, 0.0f };
-                       set_uniform_vec2(cbcr_program_num, "foo", "chroma_offset_0", chroma_offset_0);
+               glActiveTexture(GL_TEXTURE0);
+               check_error();
+               glBindTexture(GL_TEXTURE_2D, chroma_tex);
+               check_error();
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+               check_error();
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+               check_error();
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+               check_error();
 
-                       GLuint position_vbo = fill_vertex_attribute(cbcr_program_num, "position", 2, GL_FLOAT, sizeof(vertices), vertices);
-                       GLuint texcoord_vbo = fill_vertex_attribute(cbcr_program_num, "texcoord", 2, GL_FLOAT, sizeof(vertices), vertices);  // Same as vertices.
+               float chroma_offset_0[] = { -0.5f / WIDTH, 0.0f };
+               set_uniform_vec2(cbcr_program_num, "foo", "chroma_offset_0", chroma_offset_0);
 
-                       glDrawArrays(GL_TRIANGLES, 0, 3);
-                       check_error();
+               GLuint position_vbo = fill_vertex_attribute(cbcr_program_num, "position", 2, GL_FLOAT, sizeof(vertices), vertices);
+               GLuint texcoord_vbo = fill_vertex_attribute(cbcr_program_num, "texcoord", 2, GL_FLOAT, sizeof(vertices), vertices);  // Same as vertices.
 
-                       cleanup_vertex_attribute(cbcr_program_num, "position", position_vbo);
-                       cleanup_vertex_attribute(cbcr_program_num, "texcoord", texcoord_vbo);
+               glDrawArrays(GL_TRIANGLES, 0, 3);
+               check_error();
 
-                       glUseProgram(0);
-                       check_error();
+               RefCountedGLsync fence(GL_SYNC_GPU_COMMANDS_COMPLETE, /*flags=*/0);
+               check_error();
 
-                       fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, /*flags=*/0);              
-                       check_error();
+               cleanup_vertex_attribute(cbcr_program_num, "position", position_vbo);
+               cleanup_vertex_attribute(cbcr_program_num, "texcoord", texcoord_vbo);
 
-                       resource_pool->release_fbo(cbcr_fbo);
-               }
+               glUseProgram(0);
+               check_error();
+
+               resource_pool->release_fbo(cbcr_fbo);
 
                h264_encoder.end_frame(fence, input_frames_to_release);
 
+               // Store this frame for display. Remove the ready frame if any
+               // (it was seemingly never used).
+               {
+                       std::unique_lock<std::mutex> lock(display_frame_mutex);
+                       if (has_ready_display_frame) {
+                               resource_pool->release_2d_texture(ready_display_frame.texnum);
+                               ready_display_frame.ready_fence.reset();
+                       }
+                       ready_display_frame.texnum = rgba_tex;
+                       ready_display_frame.ready_fence = fence;
+                       has_ready_display_frame = true;
+               }
+
+               if (has_new_frame_ready_callback) {
+                       new_frame_ready_callback();
+               }
 
 #if 1
 #if _POSIX_C_SOURCE >= 199309L
@@ -516,6 +548,7 @@ void mixer_thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3
                        start = now;
                }
 #endif
+               check_error();
        }
        glDeleteVertexArrays(1, &vao);
        resource_pool->release_glsl_program(cbcr_program_num);
@@ -523,6 +556,37 @@ void mixer_thread_func(QSurface *surface, QSurface *surface2, QSurface *surface3
        BMUSBCapture::stop_bm_thread();
 }
 
+bool mixer_get_display_frame(DisplayFrame *frame)
+{
+       std::unique_lock<std::mutex> lock(display_frame_mutex);
+       if (!has_current_display_frame && !has_ready_display_frame) {
+               return false;
+       }
+
+       if (has_current_display_frame && has_ready_display_frame) {
+               // We have a new ready frame. Toss the current one.
+               resource_pool->release_2d_texture(current_display_frame.texnum);
+               current_display_frame.ready_fence.reset();
+               has_current_display_frame = false;
+       }
+       if (has_ready_display_frame) {
+               assert(!has_current_display_frame);
+               current_display_frame = ready_display_frame;
+               ready_display_frame.ready_fence.reset();  // Drop the refcount.
+               has_current_display_frame = true;
+               has_ready_display_frame = false;
+       }
+
+       *frame = current_display_frame;
+       return true;
+}
+
+void set_frame_ready_fallback(new_frame_ready_callback_t callback)
+{
+       new_frame_ready_callback = callback;
+       has_new_frame_ready_callback = true;
+}
+
 std::thread mixer_thread;
 
 void start_mixer(QSurface *surface, QSurface *surface2, QSurface *surface3, QSurface *surface4)
@@ -537,3 +601,8 @@ void mixer_quit()
        quit = true;
        mixer_thread.join();
 }
+
+void mixer_cut(Source source)
+{
+       current_source = source;
+}