]> git.sesse.net Git - nageru/blob - analyzer.cpp
Start working on a frame analyzer.
[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         //ui->display->set_output(Mixer::OUTPUT_LIVE);
34         surface = create_surface(QSurfaceFormat::defaultFormat());
35         context = create_context(surface);
36
37         if (!make_current(context, surface)) {
38                 printf("oops\n");
39                 exit(1);
40         }
41
42         glGenBuffers(1, &pbo);
43         glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo);
44         glBufferData(GL_PIXEL_PACK_BUFFER_ARB, global_flags.width * global_flags.height * 4, NULL, GL_STREAM_READ);
45 }
46
47 Analyzer::~Analyzer()
48 {
49         if (!make_current(context, surface)) {
50                 printf("oops\n");
51                 exit(1);
52         }
53         glDeleteBuffers(1, &pbo);
54         check_error();
55         if (resource_pool != nullptr) {
56                 resource_pool->clean_context();
57         }
58         delete_context(context);
59         delete surface;  // TODO?
60 }
61
62 void Analyzer::grab_clicked()
63 {
64         Mixer::Output channel = static_cast<Mixer::Output>(ui->input_box->currentData().value<int>());
65
66         if (!make_current(context, surface)) {
67                 printf("oops\n");
68                 exit(1);
69         }
70
71         Mixer::DisplayFrame frame;
72         if (!global_mixer->get_display_frame(channel, &frame)) {
73                 printf("Not ready yet\n");
74                 return;
75         }
76
77         // Set up an FBO to render into.
78         if (resource_pool == nullptr) {
79                 resource_pool = frame.chain->get_resource_pool();
80         } else {
81                 assert(resource_pool == frame.chain->get_resource_pool());
82         }
83         GLuint fbo_tex = resource_pool->create_2d_texture(GL_RGBA8, global_flags.width, global_flags.height);
84         check_error();
85         GLuint fbo = resource_pool->create_fbo(fbo_tex);
86         check_error();
87
88         glWaitSync(frame.ready_fence.get(), /*flags=*/0, GL_TIMEOUT_IGNORED);
89         check_error();
90         frame.setup_chain();
91         check_error();
92         glDisable(GL_FRAMEBUFFER_SRGB);
93         check_error();
94         frame.chain->render_to_fbo(fbo, global_flags.width, global_flags.height);
95         check_error();
96
97         // Read back to memory.
98         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
99         check_error();
100         glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
101         check_error();
102         glReadPixels(0, 0, global_flags.width, global_flags.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, BUFFER_OFFSET(0));
103         check_error();
104
105         unsigned char *buf = (unsigned char *)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
106         check_error();
107
108         int r_hist[256] = {0}, g_hist[256] = {0}, b_hist[256] = {0};
109         const unsigned char *ptr = buf;
110         for (int y = 0; y < global_flags.width; ++y) {
111                 for (int x = 0; x < global_flags.height; ++x) {
112                         uint8_t b = *ptr++;
113                         uint8_t g = *ptr++;
114                         uint8_t r = *ptr++;
115                         uint8_t a = *ptr++;
116
117                         ++r_hist[r];
118                         ++g_hist[g];
119                         ++b_hist[b];
120                 }
121         }
122
123         glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
124         check_error();
125         glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
126         check_error();
127         glBindFramebuffer(GL_FRAMEBUFFER, 0);
128         check_error();
129
130         printf("R hist:");
131         for (unsigned i = 0; i < 256; ++i) { printf(" %d", r_hist[i]); }
132         printf("\n");
133         printf("G hist:");
134         for (unsigned i = 0; i < 256; ++i) { printf(" %d", g_hist[i]); }
135         printf("\n");
136         printf("B hist:");
137         for (unsigned i = 0; i < 256; ++i) { printf(" %d", b_hist[i]); }
138         printf("\n");
139
140         resource_pool->release_2d_texture(fbo_tex);
141         check_error();
142         resource_pool->release_fbo(fbo);
143         check_error();
144 }
145