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
# 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
-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:
--- /dev/null
+#include "analyzer.h"
+
+#include <QDialogButtonBox>
+#include <QSurface>
+
+#include <movit/resource_pool.h>
+#include <movit/util.h>
+
+#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>(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<Mixer::Output>(ui->input_box->currentData().value<int>());
+
+ 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();
+}
+
--- /dev/null
+#ifndef _ANALYZER_H
+#define _ANALYZER_H 1
+
+#include <QDialog>
+#include <QString>
+
+#include <epoxy/gl.h>
+
+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)
#include "aboutdialog.h"
#include "alsa_pool.h"
+#include "analyzer.h"
#include "clickable_label.h"
#include "context_menus.h"
#include "correlation_meter.h"
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);
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) {
#include <string>
#include <vector>
+#include "analyzer.h"
#include "audio_mixer.h"
#include "midi_mapper.h"
#include "mixer.h"
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();
std::vector<Ui::AudioExpandedView *> audio_expanded_views;
int current_wb_pick_display = -1;
MIDIMapper midi_mapper;
+ std::unique_ptr<Analyzer> analyzer;
};
extern MainWindow *global_mainwindow;
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Analyzer</class>
+ <widget class="QDialog" name="Analyzer">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>843</width>
+ <height>450</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <widget class="QComboBox" name="input_box">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>200</y>
+ <width>251</width>
+ <height>23</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QPushButton" name="grab_btn">
+ <property name="geometry">
+ <rect>
+ <x>270</x>
+ <y>200</y>
+ <width>61</width>
+ <height>23</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Grab</string>
+ </property>
+ </widget>
+ <widget class="QWidget" name="widget_3" native="true">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>240</y>
+ <width>320</width>
+ <height>180</height>
+ </rect>
+ </property>
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background: rgb(173, 127, 168)</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label">
+ <property name="geometry">
+ <rect>
+ <x>370</x>
+ <y>310</y>
+ <width>421</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Selected coordinate (x,y): (123,456)</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_3">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>420</y>
+ <width>321</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>RGB histogram</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_4">
+ <property name="geometry">
+ <rect>
+ <x>350</x>
+ <y>280</y>
+ <width>481</width>
+ <height>21</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Grabbed frame (1280x720)</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ <widget class="QWidget" name="gridLayoutWidget">
+ <property name="geometry">
+ <rect>
+ <x>600</x>
+ <y>350</y>
+ <width>191</width>
+ <height>80</height>
+ </rect>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Green:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>127</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="label_10">
+ <property name="text">
+ <string>127</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Hex:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="label_8">
+ <property name="text">
+ <string>127</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>Blue:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="label_11">
+ <property name="text">
+ <string>#7f7f7f</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Red:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QLabel" name="label_12">
+ <property name="geometry">
+ <rect>
+ <x>600</x>
+ <y>330</y>
+ <width>191</width>
+ <height>16</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Color (8-bit sRGB):</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
<x>0</x>
<y>0</y>
<width>505</width>
- <height>236</height>
+ <height>238</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<rect>
<x>0</x>
<y>0</y>
- <width>100</width>
- <height>30</height>
+ <width>46</width>
+ <height>20</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<x>0</x>
<y>0</y>
<width>1089</width>
- <height>23</height>
+ <height>20</height>
</rect>
</property>
<widget class="QMenu" name="video_menu">
<addaction name="separator"/>
</widget>
<addaction name="cut_action"/>
+ <addaction name="open_analyzer_action"/>
<addaction name="x264_bitrate_action"/>
<addaction name="hdmi_sdi_output_device_menu"/>
<addaction name="hdmi_sdi_output_resolution_menu"/>
<string>On standard &output</string>
</property>
</action>
+ <action name="open_analyzer_action">
+ <property name="text">
+ <string>Open frame &analyzer…</string>
+ </property>
+ </action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>