]> git.sesse.net Git - nageru/blobdiff - nageru/mixer.cpp
Fix some issues with cards changing pixel format on-the-fly.
[nageru] / nageru / mixer.cpp
index 63d1f724df4c41032382808d9adb5ba2d2286176..76ab1bab21c4c47d136160f96e93fbe40b21b3d1 100644 (file)
@@ -110,11 +110,17 @@ void ensure_texture_resolution(PBOFrameAllocator::Userdata *userdata, unsigned f
                assert(false);
        }
 
-       if (first ||
-           width != userdata->last_width[field] ||
-           height != userdata->last_height[field] ||
-           cbcr_width != userdata->last_cbcr_width[field] ||
-           cbcr_height != userdata->last_cbcr_height[field]) {
+       const bool recreate_main_texture =
+               first ||
+               width != userdata->last_width[field] ||
+               height != userdata->last_height[field] ||
+               cbcr_width != userdata->last_cbcr_width[field] ||
+               cbcr_height != userdata->last_cbcr_height[field];
+       const bool recreate_v210_texture =
+               global_flags.ten_bit_input &&
+               (first || v210_width != userdata->last_v210_width[field] || height != userdata->last_height[field]);
+
+       if (recreate_main_texture) {
                // We changed resolution since last use of this texture, so we need to create
                // a new object. Note that this each card has its own PBOFrameAllocator,
                // we don't need to worry about these flip-flopping between resolutions.
@@ -166,14 +172,14 @@ void ensure_texture_resolution(PBOFrameAllocator::Userdata *userdata, unsigned f
                userdata->last_cbcr_width[field] = cbcr_width;
                userdata->last_cbcr_height[field] = cbcr_height;
        }
-       if (global_flags.ten_bit_input &&
-           (first || v210_width != userdata->last_v210_width[field])) {
+       if (recreate_v210_texture) {
                // Same as above; we need to recreate the texture.
                glBindTexture(GL_TEXTURE_2D, userdata->tex_v210[field]);
                check_error();
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2, v210_width, height, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, nullptr);
                check_error();
                userdata->last_v210_width[field] = v210_width;
+               userdata->last_height[field] = height;
        }
 }
 
@@ -562,6 +568,15 @@ void Mixer::configure_card(unsigned card_index, CaptureInterface *capture, CardT
        card->capture->set_frame_callback(bind(&Mixer::bm_frame, this, card_index, _1, _2, _3, _4, _5, _6, _7));
        if (card->frame_allocator == nullptr) {
                card->frame_allocator.reset(new PBOFrameAllocator(pixel_format, 8 << 20, global_flags.width, global_flags.height, card_index, mjpeg_encoder.get()));  // 8 MB.
+       } else {
+               // The format could have changed, but we cannot reset the allocator
+               // and create a new one from scratch, since there may be allocated
+               // frames from it that expect to call release_frame() on it.
+               // Instead, ask the allocator to create new frames for us and discard
+               // any old ones as they come back. This takes the mutex while
+               // allocating, but nothing should really be sending frames in there
+               // right now anyway (start_bm_capture() has not been called yet).
+               card->frame_allocator->reconfigure(pixel_format, 8 << 20, global_flags.width, global_flags.height, card_index, mjpeg_encoder.get());
        }
        card->capture->set_video_frame_allocator(card->frame_allocator.get());
        if (card->surface == nullptr) {