X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fwx%2Fvideo_waveform_plot.cc;h=c6fa883fa871c227b321dea92819d126998cd922;hb=b93430a73313d705f7f51315db705cfcf9942297;hp=794922bff190fcfff2c3cb244f13029efab1a278;hpb=b81241ce69a689629307832f802ac4faa6ed885f;p=dcpomatic.git diff --git a/src/wx/video_waveform_plot.cc b/src/wx/video_waveform_plot.cc index 794922bff..c6fa883fa 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-2018 Carl Hetherington This file is part of DCP-o-matic. @@ -22,7 +22,9 @@ #include "film_viewer.h" #include "wx_util.h" #include "lib/image.h" +#include "lib/film.h" #include "lib/dcp_video.h" +#include "lib/player_video.h" #include #include #include @@ -32,15 +34,19 @@ using std::cout; using std::min; +using std::max; using std::string; using boost::weak_ptr; using boost::shared_ptr; 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) + , _film (film) , _dirty (true) , _enabled (false) , _component (0) @@ -50,10 +56,14 @@ VideoWaveformPlot::VideoWaveformPlot (wxWindow* parent, FilmViewer* viewer) SetDoubleBuffered (true); #endif - _viewer_connection = viewer->ImageChanged.connect (boost::bind (&VideoWaveformPlot::set_image, this, _1)); + shared_ptr 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_MOTION, boost::bind (&VideoWaveformPlot::mouse_moved, this, _1)); SetMinSize (wxSize (640, 512)); SetBackgroundColour (wxColour (0, 0, 0)); @@ -78,7 +88,6 @@ VideoWaveformPlot::paint () return; } - int const axis_x = 48; int const height = _waveform->size().height; gc->SetPen (wxPen (wxColour (255, 255, 255), 1, wxPENSTYLE_SOLID)); @@ -108,10 +117,10 @@ VideoWaveformPlot::paint () wxGraphicsPath p = gc->CreatePath (); int const y = _vertical_margin + height - (i * height / label_gaps) - 1; p.MoveToPoint (label_width + 8, y); - p.AddLineToPoint (axis_x, 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) { @@ -124,7 +133,7 @@ VideoWaveformPlot::paint () wxImage waveform (_waveform->size().width, height, _waveform->data()[0], true); wxBitmap bitmap (waveform); - gc->DrawBitmap (bitmap, axis_x + 4, _vertical_margin, _waveform->size().width, height); + gc->DrawBitmap (bitmap, _x_axis_width, _vertical_margin, _waveform->size().width, height); delete gc; } @@ -138,37 +147,36 @@ VideoWaveformPlot::create_waveform () return; } - dcp::Size const size = _image->size(); - _waveform.reset (new Image (AV_PIX_FMT_RGB24, dcp::Size (size.width, size.height), true)); + dcp::Size 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)); - for (int x = 0; x < size.width; ++x) { + for (int x = 0; x < image_size.width; ++x) { /* Work out one vertical `slice' of waveform pixels. Each value in strip is the number of samples in image with the corresponding group of values. */ - int strip[size.height]; - for (int i = 0; i < size.height; ++i) { - strip[i] = 0; - } + int strip[waveform_height]; + memset (strip, 0, waveform_height * sizeof(int)); int* ip = _image->data (_component) + x; - for (int y = 0; y < size.height; ++y) { - strip[*ip * size.height / 4096]++; - ip += size.width; + for (int y = 0; y < image_size.height; ++y) { + strip[*ip * waveform_height / _pixel_values]++; + ip += image_size.width; } /* Copy slice into the waveform */ uint8_t* wp = _waveform->data()[0] + x * 3; - for (int y = size.height - 1; y >= 0; --y) { - wp[0] = wp[1] = wp[2] = min (255, (strip[y] * 255 / size.height) * _contrast); + for (int y = waveform_height - 1; y >= 0; --y) { + wp[0] = wp[1] = wp[2] = min (255, (strip[y] * 255 / waveform_height) * _contrast); wp += _waveform->stride()[0]; } } _waveform = _waveform->scale ( - dcp::Size (GetSize().GetWidth() - 32, GetSize().GetHeight() - _vertical_margin * 2), - dcp::YUV_TO_RGB_REC709, AV_PIX_FMT_RGB24, false, true + dcp::Size (GetSize().GetWidth() - _x_axis_width, waveform_height), + dcp::YUV_TO_RGB_REC709, AV_PIX_FMT_RGB24, false, false ); } @@ -186,7 +194,11 @@ VideoWaveformPlot::set_image (weak_ptr image) } shared_ptr pv = image.lock (); - _image = DCPVideo::convert_to_xyz (pv, boost::bind (¬e)); + DCPOMATIC_ASSERT (pv); + /* 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 (pv->shallow_copy(), boost::bind (¬e)); _dirty = true; Refresh (); } @@ -221,3 +233,34 @@ VideoWaveformPlot::set_contrast (int b) _dirty = true; Refresh (); } + +void +VideoWaveformPlot::mouse_moved (wxMouseEvent& ev) +{ + if (!_image) { + return; + } + + if (_dirty) { + create_waveform (); + _dirty = false; + } + + shared_ptr film = _film.lock (); + if (!film) { + return; + } + + dcp::Size const full = film->frame_size (); + + double 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))); + + double 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); +}