fprintf(stderr, "Could not get new frame rate\n");
exit(1);
}
+ field_dominance = display_mode->GetFieldDominance();
return S_OK;
}
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);
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);
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.
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;
// 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 ||
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) {