]> git.sesse.net Git - nageru/blob - analyzer.cpp
Add a preview display to the frame analyzer window.
[nageru] / analyzer.cpp
1 #include "analyzer.h"
2
3 #include <QDialogButtonBox>
4 #include <QSurface>
5
6 #include <movit/resource_pool.h>
7 #include <movit/util.h>
8
9 #include "context.h"
10 #include "flags.h"
11 #include "mixer.h"
12 #include "ui_analyzer.h"
13
14 using namespace std;
15
16 Analyzer::Analyzer()
17         : ui(new Ui::Analyzer)
18 {
19         ui->setupUi(this);
20
21         //connect(ui->button_box, &QDialogButtonBox::accepted, [this]{ this->close(); });
22
23         ui->input_box->addItem("Live", Mixer::OUTPUT_LIVE);
24         ui->input_box->addItem("Preview", Mixer::OUTPUT_PREVIEW);
25         unsigned num_channels = global_mixer->get_num_channels();
26         for (unsigned channel_idx = 0; channel_idx < num_channels; ++channel_idx) {
27                 Mixer::Output channel = static_cast<Mixer::Output>(Mixer::OUTPUT_INPUT0 + channel_idx); 
28                 string name = global_mixer->get_channel_name(channel);
29                 ui->input_box->addItem(QString::fromStdString(name), channel);
30         }
31
32         connect(ui->grab_btn, &QPushButton::clicked, bind(&Analyzer::grab_clicked, this));
33         connect(ui->input_box, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), bind(&Analyzer::signal_changed, this));
34         signal_changed();
35
36         surface = create_surface(QSurfaceFormat::defaultFormat());
37         context = create_context(surface);
38
39         if (!make_current(context, surface)) {
40                 printf("oops\n");
41                 exit(1);
42         }
43
44         glGenBuffers(1, &pbo);
45         glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo);
46         glBufferData(GL_PIXEL_PACK_BUFFER_ARB, global_flags.width * global_flags.height * 4, NULL, GL_STREAM_READ);
47 }
48
49 Analyzer::~Analyzer()
50 {
51         if (!make_current(context, surface)) {
52                 printf("oops\n");
53                 exit(1);
54         }
55         glDeleteBuffers(1, &pbo);
56         check_error();
57         if (resource_pool != nullptr) {
58                 resource_pool->clean_context();
59         }
60         delete_context(context);
61         delete surface;  // TODO?
62 }
63
64 void Analyzer::grab_clicked()
65 {
66         Mixer::Output channel = static_cast<Mixer::Output>(ui->input_box->currentData().value<int>());
67
68         if (!make_current(context, surface)) {
69                 printf("oops\n");
70                 exit(1);
71         }
72
73         Mixer::DisplayFrame frame;
74         if (!global_mixer->get_display_frame(channel, &frame)) {
75                 printf("Not ready yet\n");
76                 return;
77         }
78
79         // Set up an FBO to render into.
80         if (resource_pool == nullptr) {
81                 resource_pool = frame.chain->get_resource_pool();
82         } else {
83                 assert(resource_pool == frame.chain->get_resource_pool());
84         }
85         GLuint fbo_tex = resource_pool->create_2d_texture(GL_RGBA8, global_flags.width, global_flags.height);
86         check_error();
87         GLuint fbo = resource_pool->create_fbo(fbo_tex);
88         check_error();
89
90         glWaitSync(frame.ready_fence.get(), /*flags=*/0, GL_TIMEOUT_IGNORED);
91         check_error();
92         frame.setup_chain();
93         check_error();
94         glDisable(GL_FRAMEBUFFER_SRGB);
95         check_error();
96         frame.chain->render_to_fbo(fbo, global_flags.width, global_flags.height);
97         check_error();
98
99         // Read back to memory.
100         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
101         check_error();
102         glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
103         check_error();
104         glReadPixels(0, 0, global_flags.width, global_flags.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, BUFFER_OFFSET(0));
105         check_error();
106
107         unsigned char *buf = (unsigned char *)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
108         check_error();
109
110         int r_hist[256] = {0}, g_hist[256] = {0}, b_hist[256] = {0};
111         const unsigned char *ptr = buf;
112         for (int y = 0; y < global_flags.width; ++y) {
113                 for (int x = 0; x < global_flags.height; ++x) {
114                         uint8_t b = *ptr++;
115                         uint8_t g = *ptr++;
116                         uint8_t r = *ptr++;
117                         uint8_t a = *ptr++;
118
119                         ++r_hist[r];
120                         ++g_hist[g];
121                         ++b_hist[b];
122                 }
123         }
124
125         glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
126         check_error();
127         glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
128         check_error();
129         glBindFramebuffer(GL_FRAMEBUFFER, 0);
130         check_error();
131
132         printf("R hist:");
133         for (unsigned i = 0; i < 256; ++i) { printf(" %d", r_hist[i]); }
134         printf("\n");
135         printf("G hist:");
136         for (unsigned i = 0; i < 256; ++i) { printf(" %d", g_hist[i]); }
137         printf("\n");
138         printf("B hist:");
139         for (unsigned i = 0; i < 256; ++i) { printf(" %d", b_hist[i]); }
140         printf("\n");
141
142         resource_pool->release_2d_texture(fbo_tex);
143         check_error();
144         resource_pool->release_fbo(fbo);
145         check_error();
146 }
147
148 void Analyzer::signal_changed()
149 {
150         Mixer::Output channel = static_cast<Mixer::Output>(ui->input_box->currentData().value<int>());
151         ui->display->set_output(channel);
152 }