- GLuint pbo = userdata->pbo;
- check_error();
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
- check_error();
- glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, video_frame.size);
- check_error();
- //glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT);
- //check_error();
+ glBindTexture(GL_TEXTURE_2D, userdata->tex_cbcr[field]);
+ check_error();
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, cbcr_width, height, GL_RG, GL_UNSIGNED_BYTE, BUFFER_OFFSET(cbcr_offset + cbcr_width * field_start_line * sizeof(uint16_t)));
+ check_error();
+ glBindTexture(GL_TEXTURE_2D, userdata->tex_y[field]);
+ check_error();
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, BUFFER_OFFSET(y_offset + width * field_start_line));
+ check_error();
+ glBindTexture(GL_TEXTURE_2D, 0);
+ check_error();
+ GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, /*flags=*/0);
+ check_error();
+ assert(fence != nullptr);
+
+ if (field == 1) {
+ // Don't upload the second field as fast as we can; wait until
+ // the field time has approximately passed. (Otherwise, we could
+ // get timing jitter against the other sources, and possibly also
+ // against the video display, although the latter is not as critical.)
+ // This requires our system clock to be reasonably close to the
+ // video clock, but that's not an unreasonable assumption.
+ timespec second_field_start;
+ second_field_start.tv_nsec = frame_upload_start.tv_nsec +
+ frame_length * 1000000000 / TIMEBASE;
+ second_field_start.tv_sec = frame_upload_start.tv_sec +
+ second_field_start.tv_nsec / 1000000000;
+ second_field_start.tv_nsec %= 1000000000;
+
+ while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
+ &second_field_start, nullptr) == -1 &&
+ errno == EINTR) ;
+ }