From: Steinar H. Gunderson Date: Sun, 15 Jan 2017 11:04:48 +0000 (+0100) Subject: Support interlaced inputs with the official DeckLink driver. X-Git-Tag: 1.5.0~81 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=bae17501d52eeaf01f77e8c039f724352b02cb33;p=nageru Support interlaced inputs with the official DeckLink driver. --- diff --git a/bmusb b/bmusb index 227166d..21cffe0 160000 --- a/bmusb +++ b/bmusb @@ -1 +1 @@ -Subproject commit 227166d4398263e1191bdfe244f62bc38aaf4c1f +Subproject commit 21cffe09f272f510c0a6d3e7c2fa0fff79653f30 diff --git a/decklink_capture.cpp b/decklink_capture.cpp index 2df01aa..1093ab1 100644 --- a/decklink_capture.cpp +++ b/decklink_capture.cpp @@ -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); diff --git a/decklink_capture.h b/decklink_capture.h index aac403f..31efc37 100644 --- a/decklink_capture.h +++ b/decklink_capture.h @@ -126,6 +126,7 @@ private: IDeckLinkInput *input = nullptr; BMDTimeValue frame_duration; BMDTimeScale time_scale; + BMDFieldDominance field_dominance; bool running = false; std::map video_modes; diff --git a/mixer.cpp b/mixer.cpp index 44993b5..1be5660 100644 --- 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 // until the upload command is run, but we hold on to 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) {