#include <movit/util.h>
#include <string>
-
using namespace movit;
using namespace std;
using namespace std::placeholders;
+namespace {
+
+double srgb_to_linear(double x)
+{
+ if (x < 0.04045) {
+ return x / 12.92;
+ } else {
+ return pow((x + 0.055) / 1.055, 2.4);
+ }
+}
+
+} // namespace
+
GLWidget::GLWidget(QWidget *parent)
: QGLWidget(parent, global_share_widget)
{
global_mixer->remove_frame_ready_callback(output, this);
}
+void GLWidget::grab_white_balance(unsigned channel, unsigned x, unsigned y)
+{
+ // Set the white balance to neutral for the grab. It's probably going to
+ // flicker a bit, but hopefully this display is not live anyway.
+ global_mixer->set_wb(output, 0.5, 0.5, 0.5);
+ global_mixer->wait_for_next_frame();
+
+ // Mark that the next paintGL() should grab the given pixel.
+ grab_x = x;
+ grab_y = y;
+ grab_output = Mixer::Output(Mixer::OUTPUT_INPUT0 + channel);
+ should_grab = true;
+
+ updateGL();
+}
+
void GLWidget::initializeGL()
{
static once_flag flag;
} else {
assert(resource_pool == frame.chain->get_resource_pool());
}
+
+ if (should_grab) {
+ QRgb reference_color = grabFrameBuffer().pixel(grab_x, grab_y);
+
+ double r = srgb_to_linear(qRed(reference_color) / 255.0);
+ double g = srgb_to_linear(qGreen(reference_color) / 255.0);
+ double b = srgb_to_linear(qBlue(reference_color) / 255.0);
+ global_mixer->set_wb(grab_output, r, g, b);
+ should_grab = false;
+ }
}
void GLWidget::mousePressEvent(QMouseEvent *event)
void shutdown();
+ // NOTE: Will make the white balance flicker for a frame.
+ void grab_white_balance(unsigned channel, unsigned x, unsigned y);
+
protected:
void initializeGL() override;
void resizeGL(int width, int height) override;
GLuint position_vbo, texcoord_vbo;
movit::ResourcePool *resource_pool = nullptr;
int current_width = 1, current_height = 1;
+ bool should_grab = false;
+ unsigned grab_x, grab_y;
+ Mixer::Output grab_output; // Should nominally be the same as output.
};
#endif
QApplication::restoreOverrideCursor();
if (watched == previews[current_wb_pick_display]->display) {
const QMouseEvent *mouse_event = (QMouseEvent *)event;
- set_white_balance(current_wb_pick_display, mouse_event->x(), mouse_event->y());
+ previews[current_wb_pick_display]->display->grab_white_balance(
+ current_wb_pick_display,
+ mouse_event->x(), mouse_event->y());
} else {
// The user clicked on something else, give up.
// (The click goes through, which might not be ideal, but, yes.)
event->accept();
}
-namespace {
-
-double srgb_to_linear(double x)
-{
- if (x < 0.04045) {
- return x / 12.92;
- } else {
- return pow((x + 0.055) / 1.055, 2.4);
- }
-}
-
-} // namespace
-
-void MainWindow::set_white_balance(int channel_number, int x, int y)
-{
- // Set the white balance to neutral for the grab. It's probably going to
- // flicker a bit, but hopefully this display is not live anyway.
- global_mixer->set_wb(Mixer::OUTPUT_INPUT0 + channel_number, 0.5, 0.5, 0.5);
- previews[channel_number]->display->updateGL();
- QRgb reference_color = previews[channel_number]->display->grabFrameBuffer().pixel(x, y);
-
- double r = srgb_to_linear(qRed(reference_color) / 255.0);
- double g = srgb_to_linear(qGreen(reference_color) / 255.0);
- double b = srgb_to_linear(qBlue(reference_color) / 255.0);
- global_mixer->set_wb(Mixer::OUTPUT_INPUT0 + channel_number, r, g, b);
- previews[channel_number]->display->updateGL();
-}
-
void MainWindow::audio_state_changed()
{
post_to_main_thread([this]{
void setup_audio_expanded_view();
bool eventFilter(QObject *watched, QEvent *event) override;
void closeEvent(QCloseEvent *event) override;
- void set_white_balance(int channel_number, int x, int y);
void update_cutoff_labels(float cutoff_hz);
void update_eq_label(unsigned bus_index, EQBand band, float gain_db);
void setup_theme_menu();
int64_t frame_duration = output_frame_info.frame_duration;
render_one_frame(frame_duration);
- ++frame_num;
+ {
+ lock_guard<mutex> lock(frame_num_mutex);
+ ++frame_num;
+ }
+ frame_num_updated.notify_all();
pts_int += frame_duration;
basic_stats.update(frame_num, stats_dropped_frames);
((FFmpegCapture *)(cards[card_index].capture.get()))->change_filename(filename);
}
+void Mixer::wait_for_next_frame()
+{
+ unique_lock<mutex> lock(frame_num_mutex);
+ unsigned old_frame_num = frame_num;
+ frame_num_updated.wait_for(lock, seconds(1), // Timeout is just in case.
+ [old_frame_num, this]{ return this->frame_num > old_frame_num; });
+}
+
Mixer::OutputChannel::~OutputChannel()
{
if (has_current_frame) {
theme->set_theme_menu_callback(callback);
}
+ void wait_for_next_frame();
+
private:
struct CaptureCard;
movit::YCbCrInput *display_input;
int64_t pts_int = 0; // In TIMEBASE units.
- unsigned frame_num = 0;
+
+ mutable std::mutex frame_num_mutex;
+ std::condition_variable frame_num_updated;
+ unsigned frame_num = 0; // Under <frame_num_mutex>.
// Accumulated errors in number of 1/TIMEBASE audio samples. If OUTPUT_FREQUENCY divided by
// frame rate is integer, will always stay zero.