X-Git-Url: https://git.carlh.net/gitweb/?p=dcpomatic.git;a=blobdiff_plain;f=src%2Fwx%2Fvideo_waveform_plot.cc;h=2e45f3493b69e1e0af0f29f95dfb2c9dbe538c40;hp=e2083caa632b230ef1c33c6e59761dcda2befe9f;hb=39fb8198febde1937019db1c300ec363aab5aa56;hpb=533de5cc51d93a8403816fc0f04ca1d5aa733242 diff --git a/src/wx/video_waveform_plot.cc b/src/wx/video_waveform_plot.cc index e2083caa6..2e45f3493 100644 --- a/src/wx/video_waveform_plot.cc +++ b/src/wx/video_waveform_plot.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2015 Carl Hetherington + Copyright (C) 2015-2021 Carl Hetherington This file is part of DCP-o-matic. @@ -18,48 +18,62 @@ */ -#include "video_waveform_plot.h" + #include "film_viewer.h" +#include "video_waveform_plot.h" #include "wx_util.h" -#include "lib/image.h" #include "lib/dcp_video.h" +#include "lib/film.h" +#include "lib/image.h" +#include "lib/player_video.h" #include #include #include #include -#include +#include #include + using std::cout; +using std::make_shared; +using std::max; using std::min; +using std::shared_ptr; using std::string; -using boost::weak_ptr; -using boost::shared_ptr; +using std::weak_ptr; +#if BOOST_VERSION >= 106100 +using namespace boost::placeholders; +#endif using dcp::locale_convert; + int const VideoWaveformPlot::_vertical_margin = 8; +int const VideoWaveformPlot::_pixel_values = 4096; int const VideoWaveformPlot::_x_axis_width = 52; -VideoWaveformPlot::VideoWaveformPlot (wxWindow* parent, FilmViewer* viewer) + +VideoWaveformPlot::VideoWaveformPlot (wxWindow* parent, weak_ptr film, weak_ptr viewer) : wxPanel (parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE) - , _dirty (true) - , _enabled (false) - , _component (0) - , _contrast (0) + , _film (film) { #ifndef __WXOSX__ SetDoubleBuffered (true); #endif - _viewer_connection = viewer->ImageChanged.connect (boost::bind (&VideoWaveformPlot::set_image, this, _1)); + auto fv = viewer.lock (); + DCPOMATIC_ASSERT (fv); + + _viewer_connection = fv->ImageChanged.connect (boost::bind(&VideoWaveformPlot::set_image, this, _1)); - Bind (wxEVT_PAINT, boost::bind (&VideoWaveformPlot::paint, this)); - Bind (wxEVT_SIZE, boost::bind (&VideoWaveformPlot::sized, this, _1)); + Bind (wxEVT_PAINT, boost::bind(&VideoWaveformPlot::paint, this)); + Bind (wxEVT_SIZE, boost::bind(&VideoWaveformPlot::sized, this, _1)); + Bind (wxEVT_MOTION, boost::bind(&VideoWaveformPlot::mouse_moved, this, _1)); SetMinSize (wxSize (640, 512)); SetBackgroundColour (wxColour (0, 0, 0)); } + void VideoWaveformPlot::paint () { @@ -74,7 +88,7 @@ VideoWaveformPlot::paint () return; } - wxGraphicsContext* gc = wxGraphicsContext::Create (dc); + auto gc = wxGraphicsContext::Create (dc); if (!gc) { return; } @@ -105,13 +119,13 @@ VideoWaveformPlot::paint () } for (int i = 0; i < label_gaps + 1; ++i) { - wxGraphicsPath p = gc->CreatePath (); + auto p = gc->CreatePath (); int const y = _vertical_margin + height - (i * height / label_gaps) - 1; p.MoveToPoint (label_width + 8, y); p.AddLineToPoint (_x_axis_width - 4, y); gc->StrokePath (p); int x = 4; - int const n = i * 4096 / label_gaps; + int const n = i * _pixel_values / label_gaps; if (n < 10) { x += extra[0]; } else if (n < 100) { @@ -119,7 +133,7 @@ VideoWaveformPlot::paint () } else if (n < 1000) { x += extra[2]; } - gc->DrawText (std_to_wx (locale_convert (n)), x, y - (label_height / 2)); + gc->DrawText (std_to_wx(locale_convert(n)), x, y - (label_height / 2)); } wxImage waveform (_waveform->size().width, height, _waveform->data()[0], true); @@ -129,6 +143,7 @@ VideoWaveformPlot::paint () delete gc; } + void VideoWaveformPlot::create_waveform () { @@ -138,9 +153,9 @@ VideoWaveformPlot::create_waveform () return; } - dcp::Size const image_size = _image->size(); + auto const image_size = _image->size(); int const waveform_height = GetSize().GetHeight() - _vertical_margin * 2; - _waveform.reset (new Image (AV_PIX_FMT_RGB24, dcp::Size (image_size.width, waveform_height), true)); + _waveform = make_shared(AV_PIX_FMT_RGB24, dcp::Size (image_size.width, waveform_height), true); for (int x = 0; x < image_size.width; ++x) { @@ -153,7 +168,7 @@ VideoWaveformPlot::create_waveform () int* ip = _image->data (_component) + x; for (int y = 0; y < image_size.height; ++y) { - strip[*ip * waveform_height / 4096]++; + strip[*ip * waveform_height / _pixel_values]++; ip += image_size.width; } @@ -167,41 +182,41 @@ VideoWaveformPlot::create_waveform () _waveform = _waveform->scale ( dcp::Size (GetSize().GetWidth() - _x_axis_width, waveform_height), - dcp::YUV_TO_RGB_REC709, AV_PIX_FMT_RGB24, false, false + dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, false, false ); } -static void -note () -{ - -} void -VideoWaveformPlot::set_image (weak_ptr image) +VideoWaveformPlot::set_image (shared_ptr image) { if (!_enabled) { return; } - shared_ptr pv = image.lock (); - _image = DCPVideo::convert_to_xyz (pv, boost::bind (¬e)); + /* We must copy the PlayerVideo here as we will call ::image() on it, potentially + with a different pixel_format than was used when ::prepare() was called. + */ + _image = DCPVideo::convert_to_xyz (image->shallow_copy(), [](dcp::NoteType, string) {}); _dirty = true; Refresh (); } + void VideoWaveformPlot::sized (wxSizeEvent &) { _dirty = true; } + void VideoWaveformPlot::set_enabled (bool e) { _enabled = e; } + void VideoWaveformPlot::set_component (int c) { @@ -210,6 +225,7 @@ VideoWaveformPlot::set_component (int c) Refresh (); } + /** Set `contrast', i.e. a fudge multiplication factor to make low-level signals easier to see, * between 0 and 256. */ @@ -220,3 +236,35 @@ VideoWaveformPlot::set_contrast (int b) _dirty = true; Refresh (); } + + +void +VideoWaveformPlot::mouse_moved (wxMouseEvent& ev) +{ + if (!_image) { + return; + } + + if (_dirty) { + create_waveform (); + _dirty = false; + } + + auto film = _film.lock (); + if (!film) { + return; + } + + auto const full = film->frame_size (); + + auto const xs = static_cast (full.width) / _waveform->size().width; + int const x1 = max (0, min (full.width - 1, int (floor (ev.GetPosition().x - _x_axis_width - 0.5) * xs))); + int const x2 = max (0, min (full.width - 1, int (floor (ev.GetPosition().x - _x_axis_width + 0.5) * xs))); + + auto const ys = static_cast (_pixel_values) / _waveform->size().height; + int const fy = _waveform->size().height - (ev.GetPosition().y - _vertical_margin); + int const y1 = max (0, min (_pixel_values - 1, int (floor (fy - 0.5) * ys))); + int const y2 = max (0, min (_pixel_values - 1, int (floor (fy + 0.5) * ys))); + + MouseMoved (x1, x2, y1, y2); +}