]> git.sesse.net Git - nageru/commitdiff
Support interlaced inputs with the official DeckLink driver.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 15 Jan 2017 11:04:48 +0000 (12:04 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 15 Jan 2017 21:04:41 +0000 (22:04 +0100)
bmusb
decklink_capture.cpp
decklink_capture.h
mixer.cpp

diff --git a/bmusb b/bmusb
index 227166d4398263e1191bdfe244f62bc38aaf4c1f..21cffe09f272f510c0a6d3e7c2fa0fff79653f30 160000 (submodule)
--- a/bmusb
+++ b/bmusb
@@ -1 +1 @@
-Subproject commit 227166d4398263e1191bdfe244f62bc38aaf4c1f
+Subproject commit 21cffe09f272f510c0a6d3e7c2fa0fff79653f30
index 2df01aa2dab80a069eb087bfa12b8365dd35a2b2..1093ab11aa0f64f388a6e348520ac8cb57f023a6 100644 (file)
@@ -294,6 +294,7 @@ HRESULT STDMETHODCALLTYPE DeckLinkCapture::VideoInputFormatChanged(
                fprintf(stderr, "Could not get new frame rate\n");
                exit(1);
        }
+       field_dominance = display_mode->GetFieldDominance();
        return S_OK;
 }
 
@@ -314,6 +315,9 @@ HRESULT STDMETHODCALLTYPE DeckLinkCapture::VideoInputFrameArrived(
 
        video_format.frame_rate_nom = time_scale;
        video_format.frame_rate_den = frame_duration;
+       // TODO: Respect the TFF/BFF flag.
+       video_format.interlaced = (field_dominance == bmdLowerFieldFirst || field_dominance == bmdUpperFieldFirst);
+       video_format.second_field_start = 1;
 
        if (video_frame) {
                video_format.has_signal = !(video_frame->GetFlags() & bmdFrameHasNoInputSource);
@@ -473,6 +477,8 @@ void DeckLinkCapture::set_video_mode_no_restart(uint32_t video_mode_id)
                exit(1);
        }
 
+       field_dominance = display_mode->GetFieldDominance();
+
        if (running) {
                if (input->EnableVideoInput(video_mode_id, bmdFormat8BitYUV, 0) != S_OK) {
                        fprintf(stderr, "Failed to set video mode 0x%04x for card %d\n", video_mode_id, card_index);
index aac403fa666b655a3ed9fb7aea777dad30fc9444..31efc3711f1ef87cfaf8915182aaec6de1cd257f 100644 (file)
@@ -126,6 +126,7 @@ private:
        IDeckLinkInput *input = nullptr;
        BMDTimeValue frame_duration;
        BMDTimeScale time_scale;
+       BMDFieldDominance field_dominance;
        bool running = false;
 
        std::map<uint32_t, bmusb::VideoMode> video_modes;
index 44993b55b6b867d685623e26232d5c151f04c879..1be5660fb7f9219d17a1a39a15841f6d0c5c47b5 100644 (file)
--- a/mixer.cpp
+++ b/mixer.cpp
@@ -363,6 +363,7 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
 
        unsigned num_fields = video_format.interlaced ? 2 : 1;
        steady_clock::time_point frame_upload_start;
+       bool interlaced_stride = false;
        if (video_format.interlaced) {
                // Send the two fields along as separate frames; the other side will need to add
                // a deinterlacer to actually get this right.
@@ -371,6 +372,9 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
                assert(frame_length % 2 == 0);
                frame_length /= 2;
                num_fields = 2;
+               if (video_format.second_field_start == 1) {
+                       interlaced_stride = true;
+               }
                frame_upload_start = steady_clock::now();
        }
        userdata->last_interlaced = video_format.interlaced;
@@ -394,8 +398,13 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
                // Note that this means we must hold on to the actual frame data in <userdata>
                // until the upload command is run, but we hold on to <frame> much longer than that
                // (in fact, all the way until we no longer use the texture in rendering).
-               auto upload_func = [field, video_format, y_offset, cbcr_offset, cbcr_width, userdata]() {
-                       unsigned field_start_line = (field == 1) ? video_format.second_field_start : video_format.extra_lines_top + field * (video_format.height + 22);
+               auto upload_func = [field, video_format, y_offset, cbcr_offset, cbcr_width, interlaced_stride, userdata]() {
+                       unsigned field_start_line;
+                       if (field == 1) {
+                               field_start_line = video_format.second_field_start;
+                       } else {
+                               field_start_line = video_format.extra_lines_top;
+                       }
 
                        if (userdata->tex_y[field] == 0 ||
                            userdata->tex_cbcr[field] == 0 ||
@@ -433,16 +442,32 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
 
                        glBindTexture(GL_TEXTURE_2D, userdata->tex_cbcr[field]);
                        check_error();
+                       if (interlaced_stride) {
+                               glPixelStorei(GL_UNPACK_ROW_LENGTH, cbcr_width * 2);
+                               check_error();
+                       } else {
+                               glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+                               check_error();
+                       }
                        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, cbcr_width, video_format.height, GL_RG, GL_UNSIGNED_BYTE, BUFFER_OFFSET(field_cbcr_start));
                        check_error();
                        glBindTexture(GL_TEXTURE_2D, userdata->tex_y[field]);
                        check_error();
+                       if (interlaced_stride) {
+                               glPixelStorei(GL_UNPACK_ROW_LENGTH, video_format.width * 2);
+                               check_error();
+                       } else {
+                               glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+                               check_error();
+                       }
                        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, video_format.width, video_format.height, GL_RED, GL_UNSIGNED_BYTE, BUFFER_OFFSET(field_y_start));
                        check_error();
                        glBindTexture(GL_TEXTURE_2D, 0);
                        check_error();
                        glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
                        check_error();
+                       glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+                       check_error();
                };
 
                if (field == 1) {