#include <QMouseEvent>
#include <QScreen>
#include <atomic>
+#include <chrono>
#include <condition_variable>
#include <deque>
#include <jpeglib.h>
using namespace movit;
using namespace std;
+using namespace std::chrono;
namespace {
atomic<int64_t> metric_jpeg_software_fail_frames{ 0 };
atomic<int64_t> metric_jpeg_vaapi_decode_frames{ 0 };
atomic<int64_t> metric_jpeg_vaapi_fail_frames{ 0 };
+Summary metric_jpeg_decode_time_seconds;
} // namespace
shared_ptr<Frame> decode_jpeg(const string &jpeg)
{
+ steady_clock::time_point start = steady_clock::now();
shared_ptr<Frame> frame;
if (vaapi_jpeg_decoding_usable) {
frame = decode_jpeg_vaapi(jpeg);
if (frame != nullptr) {
++metric_jpeg_vaapi_decode_frames;
+ steady_clock::time_point stop = steady_clock::now();
+ metric_jpeg_decode_time_seconds.count_event(duration<double>(stop - start).count());
return frame;
}
fprintf(stderr, "VA-API hardware decoding failed; falling back to software.\n");
return get_black_frame();
}
+ jpeg_save_markers(&dinfo, JPEG_APP0 + 1, 0xFFFF);
+
if (dinfo.num_components != 3) {
fprintf(stderr, "Not a color JPEG. (%d components, Y=%dx%d, Cb=%dx%d, Cr=%dx%d)\n",
dinfo.num_components,
frame->pitch_y = luma_width_blocks * DCTSIZE;
frame->pitch_chroma = chroma_width_blocks * DCTSIZE;
+ if (dinfo.marker_list != nullptr &&
+ dinfo.marker_list->marker == JPEG_APP0 + 1 &&
+ dinfo.marker_list->data_length >= 4 &&
+ memcmp(dinfo.marker_list->data, "Exif", 4) == 0) {
+ frame->exif_data.assign(reinterpret_cast<char *>(dinfo.marker_list->data),
+ dinfo.marker_list->data_length);
+ }
+
if (!error_mgr.run([&dinfo, &frame, v_mcu_size, mcu_height_blocks] {
JSAMPROW yptr[v_mcu_size], cbptr[v_mcu_size], crptr[v_mcu_size];
JSAMPARRAY data[3] = { yptr, cbptr, crptr };
}
++metric_jpeg_software_decode_frames;
+ steady_clock::time_point stop = steady_clock::now();
+ metric_jpeg_decode_time_seconds.count_event(duration<double>(stop - start).count());
return frame;
}
++metric_jpeg_cache_miss_frames;
*did_decode = true;
- shared_ptr<Frame> frame = decode_jpeg(frame_reader->read_frame(frame_spec));
+ shared_ptr<Frame> frame = decode_jpeg(frame_reader->read_frame(frame_spec, /*read_video=*/true, /*read_audio=*/false).video);
lock_guard<mutex> lock(cache_mu);
cache_bytes_used += frame_size(*frame);
global_metrics.add("jpeg_decode_frames", { { "decoder", "software" }, { "result", "fail" } }, &metric_jpeg_software_fail_frames);
global_metrics.add("jpeg_decode_frames", { { "decoder", "vaapi" }, { "result", "decode" } }, &metric_jpeg_vaapi_decode_frames);
global_metrics.add("jpeg_decode_frames", { { "decoder", "vaapi" }, { "result", "fail" } }, &metric_jpeg_vaapi_fail_frames);
+ vector<double> quantiles{ 0.01, 0.1, 0.25, 0.5, 0.75, 0.9, 0.99 };
+ metric_jpeg_decode_time_seconds.init(quantiles, 60.0);
+ global_metrics.add("jpeg_decode_time_seconds", &metric_jpeg_decode_time_seconds);
});
}
overlay_input->set_width(overlay_width);
overlay_input->set_height(overlay_height);
overlay_input->set_pixel_data(overlay_image->bits());
+ overlay_input_needs_refresh = false;
}
glViewport(gl_width - overlay_width, 0, overlay_width, overlay_height);
overlay_chain->render_to_screen();
return;
}
+ // Figure out how large the texture needs to be.
+ {
+ QImage img(overlay_width, overlay_height, QImage::Format_Grayscale8);
+ QPainter painter(&img);
+ QFont font = painter.font();
+ font.setPointSize(12);
+ QFontMetrics metrics(font);
+ overlay_base_width = lrint(metrics.boundingRect(QString::fromStdString(text)).width() + 8.0);
+ overlay_base_height = lrint(metrics.height());
+ }
+
float dpr = QGuiApplication::primaryScreen()->devicePixelRatio();
overlay_width = lrint(overlay_base_width * dpr);
overlay_height = lrint(overlay_base_height * dpr);
+ // Work around OpenGL alignment issues.
+ while (overlay_width % 4 != 0) ++overlay_width;
+
+ // Now do the actual drawing.
overlay_image.reset(new QImage(overlay_width, overlay_height, QImage::Format_Grayscale8));
overlay_image->setDevicePixelRatio(dpr);
overlay_image->fill(0);