From 66421f32d0f2e8a8bdb86b3f381a6ebb6426cf0c Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Mon, 8 May 2017 19:55:30 +0200 Subject: [PATCH] Start working on a frame analyzer. The idea is that this will be able to show a histogram and a color picker. So far, we have some logic to grab a frame, and that's it. --- Makefile | 5 +- analyzer.cpp | 145 ++++++++++++++++++++++++++++++++++++ analyzer.h | 39 ++++++++++ mainwindow.cpp | 8 ++ mainwindow.h | 3 + ui_analyzer.ui | 187 +++++++++++++++++++++++++++++++++++++++++++++++ ui_mainwindow.ui | 14 +++- 7 files changed, 395 insertions(+), 6 deletions(-) create mode 100644 analyzer.cpp create mode 100644 analyzer.h create mode 100644 ui_analyzer.ui diff --git a/Makefile b/Makefile index 1a041fe..3455132 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ endif LDLIBS=$(shell pkg-config --libs $(PKG_MODULES)) -pthread -lva -lva-drm -lva-x11 -lX11 -lavformat -lavcodec -lavutil -lswscale -lavresample -lzita-resampler -lasound -ldl # Qt objects -OBJS_WITH_MOC = glwidget.o mainwindow.o vumeter.o lrameter.o compression_reduction_meter.o correlation_meter.o aboutdialog.o input_mapping_dialog.o midi_mapping_dialog.o nonlinear_fader.o +OBJS_WITH_MOC = glwidget.o mainwindow.o vumeter.o lrameter.o compression_reduction_meter.o correlation_meter.o aboutdialog.o analyzer.o input_mapping_dialog.o midi_mapping_dialog.o nonlinear_fader.o OBJS += $(OBJS_WITH_MOC) OBJS += $(OBJS_WITH_MOC:.o=.moc.o) ellipsis_label.moc.o clickable_label.moc.o OBJS += context_menus.o vu_common.o piecewise_interpolator.o main.o @@ -63,6 +63,7 @@ benchmark_audio_mixer: $(BM_OBJS) # Extra dependencies that need to be generated. aboutdialog.o: ui_aboutdialog.h +analyzer.o: ui_analyzer.h alsa_pool.o: state.pb.h audio_mixer.o: state.pb.h input_mapping.o: state.pb.h @@ -76,7 +77,7 @@ DEPS=$(OBJS:.o=.d) $(BM_OBJS:.o=.d) -include $(DEPS) clean: - $(RM) $(OBJS) $(BM_OBJS) $(DEPS) nageru benchmark_audio_mixer ui_aboutdialog.h ui_mainwindow.h ui_display.h ui_about.h ui_audio_miniview.h ui_audio_expanded_view.h ui_input_mapping.h ui_midi_mapping.h chain-*.frag *.dot *.pb.cc *.pb.h $(OBJS_WITH_MOC:.o=.moc.cpp) ellipsis_label.moc.cpp clickable_label.moc.cpp + $(RM) $(OBJS) $(BM_OBJS) $(DEPS) nageru benchmark_audio_mixer ui_aboutdialog.h ui_analyzer.h ui_mainwindow.h ui_display.h ui_about.h ui_audio_miniview.h ui_audio_expanded_view.h ui_input_mapping.h ui_midi_mapping.h chain-*.frag *.dot *.pb.cc *.pb.h $(OBJS_WITH_MOC:.o=.moc.cpp) ellipsis_label.moc.cpp clickable_label.moc.cpp PREFIX=/usr/local install: diff --git a/analyzer.cpp b/analyzer.cpp new file mode 100644 index 0000000..353229e --- /dev/null +++ b/analyzer.cpp @@ -0,0 +1,145 @@ +#include "analyzer.h" + +#include +#include + +#include +#include + +#include "context.h" +#include "flags.h" +#include "mixer.h" +#include "ui_analyzer.h" + +using namespace std; + +Analyzer::Analyzer() + : ui(new Ui::Analyzer) +{ + ui->setupUi(this); + + //connect(ui->button_box, &QDialogButtonBox::accepted, [this]{ this->close(); }); + + ui->input_box->addItem("Live", Mixer::OUTPUT_LIVE); + ui->input_box->addItem("Preview", Mixer::OUTPUT_PREVIEW); + unsigned num_channels = global_mixer->get_num_channels(); + for (unsigned channel_idx = 0; channel_idx < num_channels; ++channel_idx) { + Mixer::Output channel = static_cast(Mixer::OUTPUT_INPUT0 + channel_idx); + string name = global_mixer->get_channel_name(channel); + ui->input_box->addItem(QString::fromStdString(name), channel); + } + + connect(ui->grab_btn, &QPushButton::clicked, bind(&Analyzer::grab_clicked, this)); + //ui->display->set_output(Mixer::OUTPUT_LIVE); + surface = create_surface(QSurfaceFormat::defaultFormat()); + context = create_context(surface); + + if (!make_current(context, surface)) { + printf("oops\n"); + exit(1); + } + + glGenBuffers(1, &pbo); + glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo); + glBufferData(GL_PIXEL_PACK_BUFFER_ARB, global_flags.width * global_flags.height * 4, NULL, GL_STREAM_READ); +} + +Analyzer::~Analyzer() +{ + if (!make_current(context, surface)) { + printf("oops\n"); + exit(1); + } + glDeleteBuffers(1, &pbo); + check_error(); + if (resource_pool != nullptr) { + resource_pool->clean_context(); + } + delete_context(context); + delete surface; // TODO? +} + +void Analyzer::grab_clicked() +{ + Mixer::Output channel = static_cast(ui->input_box->currentData().value()); + + if (!make_current(context, surface)) { + printf("oops\n"); + exit(1); + } + + Mixer::DisplayFrame frame; + if (!global_mixer->get_display_frame(channel, &frame)) { + printf("Not ready yet\n"); + return; + } + + // Set up an FBO to render into. + if (resource_pool == nullptr) { + resource_pool = frame.chain->get_resource_pool(); + } else { + assert(resource_pool == frame.chain->get_resource_pool()); + } + GLuint fbo_tex = resource_pool->create_2d_texture(GL_RGBA8, global_flags.width, global_flags.height); + check_error(); + GLuint fbo = resource_pool->create_fbo(fbo_tex); + check_error(); + + glWaitSync(frame.ready_fence.get(), /*flags=*/0, GL_TIMEOUT_IGNORED); + check_error(); + frame.setup_chain(); + check_error(); + glDisable(GL_FRAMEBUFFER_SRGB); + check_error(); + frame.chain->render_to_fbo(fbo, global_flags.width, global_flags.height); + check_error(); + + // Read back to memory. + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + check_error(); + glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo); + check_error(); + glReadPixels(0, 0, global_flags.width, global_flags.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, BUFFER_OFFSET(0)); + check_error(); + + unsigned char *buf = (unsigned char *)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); + check_error(); + + int r_hist[256] = {0}, g_hist[256] = {0}, b_hist[256] = {0}; + const unsigned char *ptr = buf; + for (int y = 0; y < global_flags.width; ++y) { + for (int x = 0; x < global_flags.height; ++x) { + uint8_t b = *ptr++; + uint8_t g = *ptr++; + uint8_t r = *ptr++; + uint8_t a = *ptr++; + + ++r_hist[r]; + ++g_hist[g]; + ++b_hist[b]; + } + } + + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); + check_error(); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + check_error(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + check_error(); + + printf("R hist:"); + for (unsigned i = 0; i < 256; ++i) { printf(" %d", r_hist[i]); } + printf("\n"); + printf("G hist:"); + for (unsigned i = 0; i < 256; ++i) { printf(" %d", g_hist[i]); } + printf("\n"); + printf("B hist:"); + for (unsigned i = 0; i < 256; ++i) { printf(" %d", b_hist[i]); } + printf("\n"); + + resource_pool->release_2d_texture(fbo_tex); + check_error(); + resource_pool->release_fbo(fbo); + check_error(); +} + diff --git a/analyzer.h b/analyzer.h new file mode 100644 index 0000000..d239c0e --- /dev/null +++ b/analyzer.h @@ -0,0 +1,39 @@ +#ifndef _ANALYZER_H +#define _ANALYZER_H 1 + +#include +#include + +#include + +class QObject; +class QOpenGLContext; +class QSurface; + +namespace Ui { +class Analyzer; +} // namespace Ui + +namespace movit { +class ResourcePool; +} // namespace movit + +class Analyzer : public QDialog +{ + Q_OBJECT + +public: + Analyzer(); + ~Analyzer(); + +private: + void grab_clicked(); + + Ui::Analyzer *ui; + QSurface *surface; + QOpenGLContext *context; + GLuint pbo; + movit::ResourcePool *resource_pool = nullptr; +}; + +#endif // !defined(_ANALYZER_H) diff --git a/mainwindow.cpp b/mainwindow.cpp index 136890d..bff32ab 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -46,6 +46,7 @@ #include "aboutdialog.h" #include "alsa_pool.h" +#include "analyzer.h" #include "clickable_label.h" #include "context_menus.h" #include "correlation_meter.h" @@ -200,6 +201,7 @@ MainWindow::MainWindow() connect(ui->exit_action, &QAction::triggered, this, &MainWindow::exit_triggered); connect(ui->manual_action, &QAction::triggered, this, &MainWindow::manual_triggered); connect(ui->about_action, &QAction::triggered, this, &MainWindow::about_triggered); + connect(ui->open_analyzer_action, &QAction::triggered, this, &MainWindow::open_analyzer_triggered); connect(ui->simple_audio_mode, &QAction::triggered, this, &MainWindow::simple_audio_mode_triggered); connect(ui->multichannel_audio_mode, &QAction::triggered, this, &MainWindow::multichannel_audio_mode_triggered); connect(ui->input_mapping_action, &QAction::triggered, this, &MainWindow::input_mapping_triggered); @@ -590,6 +592,12 @@ void MainWindow::about_triggered() AboutDialog().exec(); } +void MainWindow::open_analyzer_triggered() +{ + analyzer.reset(new Analyzer); + analyzer->show(); +} + void MainWindow::simple_audio_mode_triggered() { if (global_audio_mixer->get_mapping_mode() == AudioMixer::MappingMode::SIMPLE) { diff --git a/mainwindow.h b/mainwindow.h index b5e43fd..302e309 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -9,6 +9,7 @@ #include #include +#include "analyzer.h" #include "audio_mixer.h" #include "midi_mapper.h" #include "mixer.h" @@ -47,6 +48,7 @@ public slots: void exit_triggered(); void manual_triggered(); void about_triggered(); + void open_analyzer_triggered(); void simple_audio_mode_triggered(); void multichannel_audio_mode_triggered(); void input_mapping_triggered(); @@ -159,6 +161,7 @@ private: std::vector audio_expanded_views; int current_wb_pick_display = -1; MIDIMapper midi_mapper; + std::unique_ptr analyzer; }; extern MainWindow *global_mainwindow; diff --git a/ui_analyzer.ui b/ui_analyzer.ui new file mode 100644 index 0000000..254014f --- /dev/null +++ b/ui_analyzer.ui @@ -0,0 +1,187 @@ + + + Analyzer + + + + 0 + 0 + 843 + 450 + + + + Dialog + + + + + 10 + 200 + 251 + 23 + + + + + + + 270 + 200 + 61 + 23 + + + + Grab + + + + + + 10 + 240 + 320 + 180 + + + + false + + + background: rgb(173, 127, 168) + + + + + + 370 + 310 + 421 + 21 + + + + Selected coordinate (x,y): (123,456) + + + + + + 10 + 420 + 321 + 21 + + + + RGB histogram + + + Qt::AlignCenter + + + + + + 350 + 280 + 481 + 21 + + + + Grabbed frame (1280x720) + + + Qt::AlignCenter + + + + + + 600 + 350 + 191 + 80 + + + + + + + Green: + + + + + + + 127 + + + + + + + 127 + + + + + + + Hex: + + + + + + + 127 + + + + + + + Blue: + + + + + + + #7f7f7f + + + + + + + Red: + + + + + + + + + 600 + 330 + 191 + 16 + + + + Color (8-bit sRGB): + + + Qt::AlignCenter + + + + + + diff --git a/ui_mainwindow.ui b/ui_mainwindow.ui index 0118eae..19858aa 100644 --- a/ui_mainwindow.ui +++ b/ui_mainwindow.ui @@ -641,7 +641,7 @@ 0 0 505 - 236 + 238 @@ -1130,8 +1130,8 @@ 0 0 - 100 - 30 + 46 + 20 @@ -1390,7 +1390,7 @@ 0 0 1089 - 23 + 20 @@ -1417,6 +1417,7 @@ + @@ -1514,6 +1515,11 @@ On standard &output + + + Open frame &analyzer… + + -- 2.39.2