1 #include "timecode_renderer.h"
11 #include <movit/effect_util.h>
12 #include <movit/resource_pool.h>
13 #include <movit/util.h>
19 using namespace movit;
21 TimecodeRenderer::TimecodeRenderer(movit::ResourcePool *resource_pool, unsigned display_width, unsigned display_height)
22 : resource_pool(resource_pool), display_width(display_width), display_height(display_height), height(28)
27 "in vec2 position; \n"
28 "in vec2 texcoord; \n"
33 " // The result of glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0) is: \n"
35 " // 2.000 0.000 0.000 -1.000 \n"
36 " // 0.000 2.000 0.000 -1.000 \n"
37 " // 0.000 0.000 -2.000 -1.000 \n"
38 " // 0.000 0.000 0.000 1.000 \n"
39 " gl_Position = vec4(2.0 * position.x - 1.0, 2.0 * position.y - 1.0, -1.0, 1.0); \n"
45 "uniform sampler2D tex; \n"
46 "out vec4 Y, CbCr, YCbCr; \n"
48 " vec4 gray = texture(tex, tc0); \n";
49 if (global_flags.ten_bit_output) {
51 " gray.r = gray.r * ((940.0-16.0)/65535.0) + 16.0/65535.0; \n" // Limited-range Y'CbCr.
52 " CbCr = vec4(512.0/65535.0, 512.0/65535.0, 0.0, 1.0); \n";
55 " gray.r = gray.r * ((235.0-16.0)/255.0) + 16.0/255.0; \n" // Limited-range Y'CbCr.
56 " CbCr = vec4(128.0/255.0, 128.0/255.0, 0.0, 1.0); \n";
60 " YCbCr = vec4(Y.r, CbCr.r, CbCr.g, CbCr.a); \n"
63 vector<string> frag_shader_outputs;
64 program_num = resource_pool->compile_glsl_program(vert_shader, frag_shader, frag_shader_outputs);
67 texture_sampler_uniform = glGetUniformLocation(program_num, "tex");
69 position_attribute_index = glGetAttribLocation(program_num, "position");
71 texcoord_attribute_index = glGetAttribLocation(program_num, "texcoord");
74 // Shared between the two.
80 vbo = generate_vbo(2, GL_FLOAT, sizeof(vertices), vertices);
83 tex = resource_pool->create_2d_texture(GL_R8, display_width, height);
85 image.reset(new QImage(display_width, height, QImage::Format_Grayscale8));
88 TimecodeRenderer::~TimecodeRenderer()
90 resource_pool->release_2d_texture(tex);
92 resource_pool->release_glsl_program(program_num);
94 glDeleteBuffers(1, &vbo);
98 string TimecodeRenderer::get_timecode_text(double pts, unsigned frame_num)
100 // Find the wall time, and round it to the nearest millisecond.
102 gettimeofday(&now, nullptr);
103 time_t unixtime = now.tv_sec;
104 unsigned msecs = (now.tv_usec + 500) / 1000;
111 gmtime_r(&unixtime, &utc_tm);
112 char clock_text[256];
113 strftime(clock_text, sizeof(clock_text), "%Y-%m-%d %H:%M:%S", &utc_tm);
115 // Make the stream timecode, rounded to the nearest millisecond.
116 long stream_time = lrint(pts * 1e3);
117 assert(stream_time >= 0);
118 unsigned stream_time_ms = stream_time % 1000;
120 unsigned stream_time_sec = stream_time % 60;
122 unsigned stream_time_min = stream_time % 60;
123 unsigned stream_time_hour = stream_time / 60;
125 char timecode_text[256];
126 snprintf(timecode_text, sizeof(timecode_text), "Nageru - %s.%03u UTC - Stream time %02u:%02u:%02u.%03u (frame %u)",
127 clock_text, msecs, stream_time_hour, stream_time_min, stream_time_sec, stream_time_ms, frame_num);
128 return timecode_text;
131 void TimecodeRenderer::render_timecode(GLuint fbo, const string &text)
133 render_string_to_buffer(text);
134 render_buffer_to_fbo(fbo);
137 void TimecodeRenderer::render_string_to_buffer(const string &text)
140 QPainter painter(image.get());
142 painter.setPen(Qt::white);
143 QFont font = painter.font();
144 font.setPointSize(16);
145 painter.setFont(font);
147 painter.drawText(QRectF(0, 0, display_width, height), Qt::AlignCenter, QString::fromStdString(text));
150 void TimecodeRenderer::render_buffer_to_fbo(GLuint fbo)
152 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
156 glGenVertexArrays(1, &vao);
159 glBindVertexArray(vao);
162 glViewport(0, display_height - height, display_width, height);
165 glActiveTexture(GL_TEXTURE0);
167 glBindTexture(GL_TEXTURE_2D, tex);
169 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
171 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
173 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
176 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, display_width, height, GL_RED, GL_UNSIGNED_BYTE, image->bits());
179 glUseProgram(program_num);
181 glUniform1i(texture_sampler_uniform, 0);
184 glBindBuffer(GL_ARRAY_BUFFER, vbo);
187 for (GLint attr_index : { position_attribute_index, texcoord_attribute_index }) {
188 if (attr_index == -1) continue;
189 glEnableVertexAttribArray(attr_index);
191 glVertexAttribPointer(attr_index, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
195 glDrawArrays(GL_TRIANGLES, 0, 3);
198 for (GLint attr_index : { position_attribute_index, texcoord_attribute_index }) {
199 if (attr_index == -1) continue;
200 glDisableVertexAttribArray(attr_index);
204 glActiveTexture(GL_TEXTURE0);
209 glDeleteVertexArrays(1, &vao);
212 glBindFramebuffer(GL_FRAMEBUFFER, 0);