From 956a923ae947b58a21ed08ba5d30700633608468 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Mon, 5 Oct 2015 20:50:00 +0200 Subject: [PATCH] Use the new Movit functionality to save a texture upload for the preview. --- mixer.cpp | 33 +++++++++++++++++++++++---------- pbo_frame_allocator.cpp | 37 ++++++++++++++++++++++++++++++++++--- pbo_frame_allocator.h | 11 +++++++++-- 3 files changed, 66 insertions(+), 15 deletions(-) diff --git a/mixer.cpp b/mixer.cpp index 988d7e4..c340656 100644 --- a/mixer.cpp +++ b/mixer.cpp @@ -123,7 +123,7 @@ Mixer::Mixer(const QSurfaceFormat &format) printf("Configuring first card...\n"); cards[0].usb = new BMUSBCapture(0x1edb, 0xbd3b); // 0xbd4f cards[0].usb->set_frame_callback(std::bind(&Mixer::bm_frame, this, 0, _1, _2, _3, _4, _5, _6, _7)); - cards[0].frame_allocator.reset(new PBOFrameAllocator(1280 * 750 * 2 + 44)); + cards[0].frame_allocator.reset(new PBOFrameAllocator(1280 * 750 * 2 + 44, 1280, 720)); cards[0].usb->set_video_frame_allocator(cards[0].frame_allocator.get()); cards[0].usb->configure_card(); cards[0].surface = create_surface(format); @@ -135,7 +135,7 @@ Mixer::Mixer(const QSurfaceFormat &format) printf("Configuring second card...\n"); cards[1].usb = new BMUSBCapture(0x1edb, 0xbd4f); cards[1].usb->set_frame_callback(std::bind(&Mixer::bm_frame, this, 1, _1, _2, _3, _4, _5, _6, _7)); - cards[1].frame_allocator.reset(new PBOFrameAllocator(1280 * 750 * 2 + 44)); + cards[1].frame_allocator.reset(new PBOFrameAllocator(1280 * 750 * 2 + 44, 1280, 720)); cards[1].usb->set_video_frame_allocator(cards[1].frame_allocator.get()); cards[1].usb->configure_card(); } @@ -201,7 +201,8 @@ void Mixer::bm_frame(int card_index, uint16_t timecode, std::unique_lock lock(bmusb_mutex); card->new_data_ready_changed.wait(lock, [card]{ return !card->new_data_ready; }); } - GLuint pbo = (GLint)(intptr_t)video_frame.userdata; + const PBOFrameAllocator::Userdata *userdata = (const PBOFrameAllocator::Userdata *)video_frame.userdata; + GLuint pbo = userdata->pbo; check_error(); glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo); check_error(); @@ -209,6 +210,18 @@ void Mixer::bm_frame(int card_index, uint16_t timecode, check_error(); //glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT); //check_error(); + + // Upload the textures. + glBindTexture(GL_TEXTURE_2D, userdata->tex_y); + check_error(); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1280, 720, GL_RED, GL_UNSIGNED_BYTE, BUFFER_OFFSET((1280 * 750 * 2 + 44) / 2 + 1280 * 25 + 22)); + check_error(); + glBindTexture(GL_TEXTURE_2D, userdata->tex_cbcr); + check_error(); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1280/2, 720, GL_RG, GL_UNSIGNED_BYTE, BUFFER_OFFSET(1280 * 25 + 22)); + check_error(); + glBindTexture(GL_TEXTURE_2D, 0); + check_error(); GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, /*flags=*/0); check_error(); assert(fence != nullptr); @@ -404,19 +417,19 @@ void Mixer::thread_func() check_error(); glDeleteSync(card->new_data_ready_fence); check_error(); - GLint input_tex_pbo = (GLint)(intptr_t)card->new_frame.userdata; - input[card_index]->set_pixel_data(0, (unsigned char *)BUFFER_OFFSET((1280 * 750 * 2 + 44) / 2 + 1280 * 25 + 22), input_tex_pbo); - input[card_index]->set_pixel_data(1, (unsigned char *)BUFFER_OFFSET(1280 * 25 + 22), input_tex_pbo); + const PBOFrameAllocator::Userdata *userdata = (const PBOFrameAllocator::Userdata *)card->new_frame.userdata; + input[card_index]->set_texture_num(0, userdata->tex_y); + input[card_index]->set_texture_num(1, userdata->tex_cbcr); if (NUM_CARDS == 1) { // Set to the other one, too. - input[1]->set_pixel_data(0, (unsigned char *)BUFFER_OFFSET((1280 * 750 * 2 + 44) / 2 + 1280 * 25 + 22), input_tex_pbo); - input[1]->set_pixel_data(1, (unsigned char *)BUFFER_OFFSET(1280 * 25 + 22), input_tex_pbo); + input[1]->set_texture_num(0, userdata->tex_y); + input[1]->set_texture_num(1, userdata->tex_cbcr); } if (card_index == 0) { - preview_input->set_pixel_data(0, (unsigned char *)BUFFER_OFFSET((1280 * 750 * 2 + 44) / 2 + 1280 * 25 + 22), input_tex_pbo); - preview_input->set_pixel_data(1, (unsigned char *)BUFFER_OFFSET(1280 * 25 + 22), input_tex_pbo); + preview_input->set_texture_num(0, userdata->tex_y); + preview_input->set_texture_num(1, userdata->tex_cbcr); } } diff --git a/pbo_frame_allocator.cpp b/pbo_frame_allocator.cpp index 1018403..5f9d1bd 100644 --- a/pbo_frame_allocator.cpp +++ b/pbo_frame_allocator.cpp @@ -8,9 +8,10 @@ using namespace std; -PBOFrameAllocator::PBOFrameAllocator(size_t frame_size, size_t num_queued_frames, GLenum buffer, GLenum permissions, GLenum map_bits) +PBOFrameAllocator::PBOFrameAllocator(size_t frame_size, GLuint width, GLuint height, size_t num_queued_frames, GLenum buffer, GLenum permissions, GLenum map_bits) : frame_size(frame_size), buffer(buffer) { + userdata.reset(new Userdata[num_queued_frames]); for (size_t i = 0; i < num_queued_frames; ++i) { GLuint pbo; glGenBuffers(1, &pbo); @@ -25,13 +26,36 @@ PBOFrameAllocator::PBOFrameAllocator(size_t frame_size, size_t num_queued_frames frame.data2 = frame.data + frame_size / 2; check_error(); frame.size = frame_size; - frame.userdata = (void *)(intptr_t)pbo; + frame.userdata = &userdata[i]; + userdata[i].pbo = pbo; frame.owner = this; frame.interleaved = true; + + // Create textures. + glGenTextures(1, &userdata[i].tex_y); + check_error(); + glBindTexture(GL_TEXTURE_2D, userdata[i].tex_y); + check_error(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + check_error(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, NULL); + check_error(); + + glGenTextures(1, &userdata[i].tex_cbcr); + check_error(); + glBindTexture(GL_TEXTURE_2D, userdata[i].tex_cbcr); + check_error(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + check_error(); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, width / 2, height, 0, GL_RG, GL_UNSIGNED_BYTE, NULL); + check_error(); + freelist.push(frame); } glBindBuffer(buffer, 0); check_error(); + glBindTexture(GL_TEXTURE_2D, 0); + check_error(); } PBOFrameAllocator::~PBOFrameAllocator() @@ -39,7 +63,7 @@ PBOFrameAllocator::~PBOFrameAllocator() while (!freelist.empty()) { Frame frame = freelist.front(); freelist.pop(); - GLuint pbo = (intptr_t)frame.userdata; + GLuint pbo = ((Userdata *)frame.userdata)->pbo; glBindBuffer(buffer, pbo); check_error(); glUnmapBuffer(buffer); @@ -47,6 +71,13 @@ PBOFrameAllocator::~PBOFrameAllocator() glBindBuffer(buffer, 0); check_error(); glDeleteBuffers(1, &pbo); + check_error(); + GLuint tex_y = ((Userdata *)frame.userdata)->tex_y; + glDeleteTextures(1, &tex_y); + check_error(); + GLuint tex_cbcr = ((Userdata *)frame.userdata)->tex_cbcr; + glDeleteTextures(1, &tex_cbcr); + check_error(); } } //static int sumsum = 0; diff --git a/pbo_frame_allocator.h b/pbo_frame_allocator.h index 825d01f..5050f6f 100644 --- a/pbo_frame_allocator.h +++ b/pbo_frame_allocator.h @@ -15,13 +15,19 @@ public: // Note: You need to have an OpenGL context when calling // the constructor. PBOFrameAllocator(size_t frame_size, + GLuint width, GLuint height, size_t num_queued_frames = 16, // FIXME: should be 6 GLenum buffer = GL_PIXEL_UNPACK_BUFFER_ARB, GLenum permissions = GL_MAP_WRITE_BIT, GLenum map_bits = GL_MAP_FLUSH_EXPLICIT_BIT); ~PBOFrameAllocator() override; - Frame alloc_frame() override; - void release_frame(Frame frame) override; + Frame alloc_frame() override; + void release_frame(Frame frame) override; + + struct Userdata { + GLuint pbo; + GLuint tex_y, tex_cbcr; + }; private: size_t frame_size; @@ -29,6 +35,7 @@ private: std::mutex freelist_mutex; std::queue freelist; GLenum buffer; + std::unique_ptr userdata; }; #endif // !defined(_PBO_FRAME_ALLOCATOR) -- 2.39.2