return true;
}
+
+void
+Image::fade (float f)
+{
+ switch (_pixel_format) {
+ case PIX_FMT_YUV420P:
+ case PIX_FMT_YUV422P:
+ case PIX_FMT_YUV444P:
+ case PIX_FMT_YUV411P:
+ case PIX_FMT_YUVJ420P:
+ case PIX_FMT_YUVJ422P:
+ case PIX_FMT_YUVJ444P:
+ case PIX_FMT_RGB24:
+ case PIX_FMT_ARGB:
+ case PIX_FMT_RGBA:
+ case PIX_FMT_ABGR:
+ case PIX_FMT_BGRA:
+ case PIX_FMT_RGB555LE:
+ /* 8-bit */
+ for (int c = 0; c < 3; ++c) {
+ uint8_t* p = data()[c];
+ for (int y = 0; y < lines(c); ++y) {
+ uint8_t* q = p;
+ for (int x = 0; x < line_size()[c]; ++x) {
+ *q = int (float (*q) * f);
+ ++q;
+ }
+ p += stride()[c];
+ }
+ }
+ break;
+
+ case PIX_FMT_YUV422P9LE:
+ case PIX_FMT_YUV444P9LE:
+ case PIX_FMT_YUV422P10LE:
+ case PIX_FMT_YUV444P10LE:
+ case PIX_FMT_YUV422P16LE:
+ case PIX_FMT_YUV444P16LE:
+ case AV_PIX_FMT_YUVA420P9LE:
+ case AV_PIX_FMT_YUVA422P9LE:
+ case AV_PIX_FMT_YUVA444P9LE:
+ case AV_PIX_FMT_YUVA420P10LE:
+ case AV_PIX_FMT_YUVA422P10LE:
+ case AV_PIX_FMT_YUVA444P10LE:
+ /* 16-bit little-endian */
+ for (int c = 0; c < 3; ++c) {
+ int const stride_pixels = stride()[c] / 2;
+ int const line_size_pixels = line_size()[c] / 2;
+ uint16_t* p = reinterpret_cast<uint16_t*> (data()[c]);
+ for (int y = 0; y < lines(c); ++y) {
+ uint16_t* q = p;
+ for (int x = 0; x < line_size_pixels; ++x) {
+ *q = int (float (*q) * f);
+ ++q;
+ }
+ p += stride_pixels;
+ }
+ }
+ break;
+
+ case PIX_FMT_YUV422P9BE:
+ case PIX_FMT_YUV444P9BE:
+ case PIX_FMT_YUV444P10BE:
+ case PIX_FMT_YUV422P10BE:
+ case AV_PIX_FMT_YUVA420P9BE:
+ case AV_PIX_FMT_YUVA422P9BE:
+ case AV_PIX_FMT_YUVA444P9BE:
+ case AV_PIX_FMT_YUVA420P10BE:
+ case AV_PIX_FMT_YUVA422P10BE:
+ case AV_PIX_FMT_YUVA444P10BE:
+ case AV_PIX_FMT_YUVA420P16BE:
+ case AV_PIX_FMT_YUVA422P16BE:
+ case AV_PIX_FMT_YUVA444P16BE:
+ /* 16-bit big-endian */
+ for (int c = 0; c < 3; ++c) {
+ int const stride_pixels = stride()[c] / 2;
+ int const line_size_pixels = line_size()[c] / 2;
+ uint16_t* p = reinterpret_cast<uint16_t*> (data()[c]);
+ for (int y = 0; y < lines(c); ++y) {
+ uint16_t* q = p;
+ for (int x = 0; x < line_size_pixels; ++x) {
+ *q = swap_16 (int (float (swap_16 (*q)) * f));
+ ++q;
+ }
+ p += stride_pixels;
+ }
+ }
+ break;
+
+ case PIX_FMT_UYVY422:
+ {
+ int const Y = lines(0);
+ int const X = line_size()[0];
+ uint8_t* p = data()[0];
+ for (int y = 0; y < Y; ++y) {
+ for (int x = 0; x < X; ++x) {
+ *p = int (float (*p) * f);
+ ++p;
+ }
+ }
+ break;
+ }
+
+ default:
+ throw PixelFormatError ("fade()", _pixel_format);
+ }
+}
void make_transparent ();
void alpha_blend (boost::shared_ptr<const Image> image, Position<int> pos);
void copy (boost::shared_ptr<const Image> image, Position<int> pos);
+ void fade (float);
void read_from_socket (boost::shared_ptr<Socket>);
void write_to_socket (boost::shared_ptr<Socket>) const;
delete magick_image;
LOG_TIMING ("[%1] MagickImageProxy completes decode and convert of %2 bytes", boost::this_thread::get_id(), _blob.length());
-
+
return _image;
}
shared_ptr<const ImageProxy> (new RawImageProxy (_black_image, _film->log ())),
time,
Crop (),
+ optional<float> (),
_video_container_size,
_video_container_size,
Scaler::from_id ("bicubic"),
i->image,
content_video_to_dcp (piece, i->frame),
content->crop (),
+ content->fade (i->frame),
image_size,
_video_container_size,
_film->scaler(),
shared_ptr<const ImageProxy> in,
DCPTime time,
Crop crop,
+ boost::optional<float> fade,
dcp::Size inter_size,
dcp::Size out_size,
Scaler const * scaler,
: _in (in)
, _time (time)
, _crop (crop)
+ , _fade (fade)
, _inter_size (inter_size)
, _out_size (out_size)
, _scaler (scaler)
{
_time = DCPTime (node->number_child<DCPTime::Type> ("Time"));
_crop = Crop (node);
+ _fade = node->optional_number_child<float> ("Fade");
_inter_size = dcp::Size (node->number_child<int> ("InterWidth"), node->number_child<int> ("InterHeight"));
_out_size = dcp::Size (node->number_child<int> ("OutWidth"), node->number_child<int> ("OutHeight"));
out->alpha_blend (_subtitle.image, _subtitle.position);
}
+ if (_fade) {
+ out->fade (_fade.get ());
+ }
+
return out;
}
{
node->add_child("Time")->add_child_text (raw_convert<string> (_time.get ()));
_crop.as_xml (node);
+ if (_fade) {
+ node->add_child("Fade")->add_child_text (raw_convert<string> (_fade.get ()));
+ }
_in->add_metadata (node->add_child ("In"));
node->add_child("InterWidth")->add_child_text (raw_convert<string> (_inter_size.width));
node->add_child("InterHeight")->add_child_text (raw_convert<string> (_inter_size.height));
{
if (_in != other->_in ||
_crop != other->_crop ||
+ _fade.get_value_or(0) != other->_fade.get_value_or(0) ||
_inter_size != other->_inter_size ||
_out_size != other->_out_size ||
_scaler != other->_scaler ||
class PlayerVideo
{
public:
- PlayerVideo (boost::shared_ptr<const ImageProxy>, DCPTime, Crop, dcp::Size, dcp::Size, Scaler const *, Eyes, Part, ColourConversion);
+ PlayerVideo (
+ boost::shared_ptr<const ImageProxy>,
+ DCPTime,
+ Crop,
+ boost::optional<float>,
+ dcp::Size,
+ dcp::Size,
+ Scaler const *,
+ Eyes,
+ Part,
+ ColourConversion
+ );
+
PlayerVideo (boost::shared_ptr<cxml::Node>, boost::shared_ptr<Socket>, boost::shared_ptr<Log>);
void set_subtitle (PositionImage);
boost::shared_ptr<const ImageProxy> _in;
DCPTime _time;
Crop _crop;
+ boost::optional<float> _fade;
dcp::Size _inter_size;
dcp::Size _out_size;
Scaler const * _scaler;
int const VideoContentProperty::VIDEO_CROP = 3;
int const VideoContentProperty::VIDEO_SCALE = 4;
int const VideoContentProperty::COLOUR_CONVERSION = 5;
+int const VideoContentProperty::VIDEO_FADE_IN = 6;
+int const VideoContentProperty::VIDEO_FADE_OUT = 7;
using std::string;
using std::setprecision;
}
_colour_conversion = ColourConversion (node->node_child ("ColourConversion"));
+ if (version >= 32) {
+ _fade_in = ContentTime (node->number_child<int64_t> ("FadeIn"));
+ _fade_out = ContentTime (node->number_child<int64_t> ("FadeOut"));
+ }
}
VideoContent::VideoContent (shared_ptr<const Film> f, vector<shared_ptr<Content> > c)
throw JoinError (_("Content to be joined must have the same colour conversion."));
}
+ if (vc->fade_in() != ref->fade_in() || vc->fade_out() != ref->fade_out()) {
+ throw JoinError (_("Content to be joined must have the same fades."));
+ }
+
_video_length += vc->video_length ();
}
_crop = ref->crop ();
_scale = ref->scale ();
_colour_conversion = ref->colour_conversion ();
+ _fade_in = ref->fade_in ();
+ _fade_out = ref->fade_out ();
}
void
_crop.as_xml (node);
_scale.as_xml (node->add_child("Scale"));
_colour_conversion.as_xml (node->add_child("ColourConversion"));
+ node->add_child("FadeIn")->add_child_text (raw_convert<string> (_fade_in.get ()));
+ node->add_child("FadeOut")->add_child_text (raw_convert<string> (_fade_out.get ()));
}
void
signal_changed (VideoContentProperty::COLOUR_CONVERSION);
}
+void
+VideoContent::set_fade_in (ContentTime t)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _fade_in = t;
+ }
+
+ signal_changed (VideoContentProperty::VIDEO_FADE_IN);
+}
+
+void
+VideoContent::set_fade_out (ContentTime t)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _fade_out = t;
+ }
+
+ signal_changed (VideoContentProperty::VIDEO_FADE_OUT);
+}
+
/** @return Video size after 3D split and crop */
dcp::Size
VideoContent::video_size_after_crop () const
signal_changed (VideoContentProperty::VIDEO_FRAME_RATE);
}
+optional<float>
+VideoContent::fade (VideoFrame f) const
+{
+ assert (f >= 0);
+
+ if (f < fade_in().frames (video_frame_rate ())) {
+ return float (f) / _fade_in.frames (video_frame_rate ());
+ }
+
+ VideoFrame fade_out_start = ContentTime (video_length() - fade_out()).frames (video_frame_rate ());
+ if (f >= fade_out_start) {
+ return 1 - float (f - fade_out_start) / fade_out().frames (video_frame_rate ());
+ }
+
+ return optional<float> ();
+}
static int const VIDEO_CROP;
static int const VIDEO_SCALE;
static int const COLOUR_CONVERSION;
+ static int const VIDEO_FADE_IN;
+ static int const VIDEO_FADE_OUT;
};
class VideoContent : public virtual Content
void set_scale (VideoContentScale);
void set_colour_conversion (ColourConversion);
+
+ void set_fade_in (ContentTime);
+ void set_fade_out (ContentTime);
VideoFrameType video_frame_type () const {
boost::mutex::scoped_lock lm (_mutex);
return _colour_conversion;
}
+ ContentTime fade_in () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _fade_in;
+ }
+
+ ContentTime fade_out () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _fade_out;
+ }
+
dcp::Size video_size_after_3d_split () const;
dcp::Size video_size_after_crop () const;
ContentTime dcp_time_to_content_time (DCPTime) const;
+ boost::optional<float> fade (VideoFrame) const;
+
void scale_and_crop_to_fit_width ();
void scale_and_crop_to_fit_height ();
Crop _crop;
VideoContentScale _scale;
ColourConversion _colour_conversion;
+ ContentTime _fade_in;
+ ContentTime _fade_out;
};
#endif
#include "video_decoder.h"
#include "image.h"
+#include "image_proxy.h"
#include "content_video.h"
#include "i18n.h"
using std::cout;
using std::list;
+using std::max;
using boost::shared_ptr;
using boost::optional;
Bind (wxEVT_CLOSE_WINDOW, boost::bind (&Frame::close, this, _1));
- wxAcceleratorEntry accel[1];
- accel[0].Set (wxACCEL_CTRL, static_cast<int>('A'), ID_add_file);
- Bind (wxEVT_MENU, boost::bind (&ContentPanel::add_file_clicked, _film_editor->content_panel()), ID_add_file);
- wxAcceleratorTable accel_table (1, accel);
- SetAcceleratorTable (accel_table);
-
/* Use a panel as the only child of the Frame so that we avoid
the dark-grey background on Windows.
*/
JobManager::instance()->ActiveJobsChanged.connect (boost::bind (&Frame::set_menu_sensitivity, this));
overall_panel->SetSizer (main_sizer);
+
+ wxAcceleratorEntry accel[1];
+ accel[0].Set (wxACCEL_CTRL, static_cast<int>('A'), ID_add_file);
+ Bind (wxEVT_MENU, boost::bind (&ContentPanel::add_file_clicked, _film_editor->content_panel()), ID_add_file);
+ wxAcceleratorTable accel_table (1, accel);
+ SetAcceleratorTable (accel_table);
}
void new_film (boost::filesystem::path path)
}
/** Add this widget to a wxGridBagSizer */
- void add (wxGridBagSizer* sizer, wxGBPosition position)
+ void add (wxGridBagSizer* sizer, wxGBPosition position, wxGBSpan span = wxDefaultSpan)
{
_sizer = sizer;
_position = position;
- _sizer->Add (_wrapped, _position);
+ _span = span;
+ _sizer->Add (_wrapped, _position, _span);
}
/** Update the view from the model */
_sizer->Detach (_button);
_button->Hide ();
- _sizer->Add (_wrapped, _position);
+ _sizer->Add (_wrapped, _position, _span);
_wrapped->Show ();
_sizer->Layout ();
}
_wrapped->Hide ();
_sizer->Detach (_wrapped);
_button->Show ();
- _sizer->Add (_button, _position);
+ _sizer->Add (_button, _position, _span);
_sizer->Layout ();
}
T* _wrapped;
wxGridBagSizer* _sizer;
wxGBPosition _position;
+ wxGBSpan _span;
wxButton* _button;
List _content;
int _property;
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
*/
-#include <boost/lexical_cast.hpp>
#include "lib/util.h"
#include "timecode.h"
#include "wx_util.h"
+#include <boost/lexical_cast.hpp>
using std::string;
using std::cout;
using boost::lexical_cast;
-Timecode::Timecode (wxWindow* parent)
+TimecodeBase::TimecodeBase (wxWindow* parent)
: wxPanel (parent)
{
wxClientDC dc (parent);
_fixed = add_label_to_sizer (_sizer, this, wxT ("42"), false);
- _hours->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&Timecode::changed, this));
- _minutes->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&Timecode::changed, this));
- _seconds->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&Timecode::changed, this));
- _frames->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&Timecode::changed, this));
- _set_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&Timecode::set_clicked, this));
+ _hours->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TimecodeBase::changed, this));
+ _minutes->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TimecodeBase::changed, this));
+ _seconds->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TimecodeBase::changed, this));
+ _frames->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TimecodeBase::changed, this));
+ _set_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&TimecodeBase::set_clicked, this));
_set_button->Enable (false);
}
void
-Timecode::set (DCPTime t, int fps)
-{
- int h;
- int m;
- int s;
- int f;
- t.split (fps, h, m, s, f);
-
- checked_set (_hours, lexical_cast<string> (h));
- checked_set (_minutes, lexical_cast<string> (m));
- checked_set (_seconds, lexical_cast<string> (s));
- checked_set (_frames, lexical_cast<string> (f));
-
- _fixed->SetLabel (std_to_wx (t.timecode (fps)));
-}
-
-DCPTime
-Timecode::get (int fps) const
-{
- DCPTime t;
- string const h = wx_to_std (_hours->GetValue ());
- t += DCPTime::from_seconds (lexical_cast<int> (h.empty() ? "0" : h) * 3600);
- string const m = wx_to_std (_minutes->GetValue());
- t += DCPTime::from_seconds (lexical_cast<int> (m.empty() ? "0" : m) * 60);
- string const s = wx_to_std (_seconds->GetValue());
- t += DCPTime::from_seconds (lexical_cast<int> (s.empty() ? "0" : s));
- string const f = wx_to_std (_frames->GetValue());
- t += DCPTime::from_seconds (lexical_cast<double> (f.empty() ? "0" : f) / fps);
-
- return t;
-}
-
-void
-Timecode::clear ()
+TimecodeBase::clear ()
{
checked_set (_hours, "");
checked_set (_minutes, "");
}
void
-Timecode::changed ()
+TimecodeBase::changed ()
{
_set_button->Enable (true);
}
void
-Timecode::set_clicked ()
+TimecodeBase::set_clicked ()
{
Changed ();
_set_button->Enable (false);
}
void
-Timecode::set_editable (bool e)
+TimecodeBase::set_editable (bool e)
{
_editable->Show (e);
_fixed->Show (!e);
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
*/
-#include <boost/signals2.hpp>
-#include <wx/wx.h>
+#ifndef DCPOMATIC_WX_TIMECODE_H
+#define DCPOMATIC_WX_TIMECODE_H
+
+#include "wx_util.h"
#include "lib/types.h"
+#include <wx/wx.h>
+#include <boost/signals2.hpp>
+#include <boost/lexical_cast.hpp>
-class Timecode : public wxPanel
+class TimecodeBase : public wxPanel
{
public:
- Timecode (wxWindow *);
+ TimecodeBase (wxWindow *);
- void set (DCPTime, int);
- DCPTime get (int) const;
void clear ();
void set_editable (bool);
boost::signals2::signal<void ()> Changed;
-private:
+protected:
void changed ();
void set_clicked ();
wxStaticText* _fixed;
};
+template <class T>
+class Timecode : public TimecodeBase
+{
+public:
+ Timecode (wxWindow* parent)
+ : TimecodeBase (parent)
+ {
+
+ }
+
+ void set (T t, int fps)
+ {
+ int h;
+ int m;
+ int s;
+ int f;
+ t.split (fps, h, m, s, f);
+
+ checked_set (_hours, boost::lexical_cast<std::string> (h));
+ checked_set (_minutes, boost::lexical_cast<std::string> (m));
+ checked_set (_seconds, boost::lexical_cast<std::string> (s));
+ checked_set (_frames, boost::lexical_cast<std::string> (f));
+
+ _fixed->SetLabel (std_to_wx (t.timecode (fps)));
+ }
+
+ T get (int fps) const
+ {
+ T t;
+ std::string const h = wx_to_std (_hours->GetValue ());
+ t += T::from_seconds (boost::lexical_cast<int> (h.empty() ? "0" : h) * 3600);
+ std::string const m = wx_to_std (_minutes->GetValue());
+ t += T::from_seconds (boost::lexical_cast<int> (m.empty() ? "0" : m) * 60);
+ std::string const s = wx_to_std (_seconds->GetValue());
+ t += T::from_seconds (boost::lexical_cast<int> (s.empty() ? "0" : s));
+ std::string const f = wx_to_std (_frames->GetValue());
+ t += T::from_seconds (boost::lexical_cast<double> (f.empty() ? "0" : f) / fps);
+
+ return t;
+ }
+};
+
+#endif
_sizer->Add (grid, 0, wxALL, 8);
add_label_to_sizer (grid, this, _("Position"), true);
- _position = new Timecode (this);
+ _position = new Timecode<DCPTime> (this);
grid->Add (_position);
add_label_to_sizer (grid, this, _("Full length"), true);
- _full_length = new Timecode (this);
+ _full_length = new Timecode<DCPTime> (this);
grid->Add (_full_length);
add_label_to_sizer (grid, this, _("Trim from start"), true);
- _trim_start = new Timecode (this);
+ _trim_start = new Timecode<DCPTime> (this);
grid->Add (_trim_start);
add_label_to_sizer (grid, this, _("Trim from end"), true);
- _trim_end = new Timecode (this);
+ _trim_end = new Timecode<DCPTime> (this);
grid->Add (_trim_end);
add_label_to_sizer (grid, this, _("Play length"), true);
- _play_length = new Timecode (this);
+ _play_length = new Timecode<DCPTime> (this);
grid->Add (_play_length);
{
*/
#include "content_sub_panel.h"
-
-class Timecode;
+#include "timecode.h"
class TimingPanel : public ContentSubPanel
{
void video_frame_rate_changed ();
void set_video_frame_rate ();
- Timecode* _position;
- Timecode* _full_length;
- Timecode* _trim_start;
- Timecode* _trim_end;
- Timecode* _play_length;
+ Timecode<DCPTime>* _position;
+ Timecode<DCPTime>* _full_length;
+ Timecode<DCPTime>* _trim_start;
+ Timecode<DCPTime>* _trim_end;
+ Timecode<DCPTime>* _play_length;
wxTextCtrl* _video_frame_rate;
wxButton* _set_video_frame_rate;
};
using std::pair;
using std::cout;
using std::list;
+using std::set;
using boost::shared_ptr;
using boost::dynamic_pointer_cast;
using boost::bind;
&caster<int, VideoFrameType>,
&caster<VideoFrameType, int>
);
- _frame_type->add (grid, wxGBPosition (r, 1));
+ _frame_type->add (grid, wxGBPosition (r, 1), wxGBSpan (1, 2));
++r;
add_label_to_grid_bag_sizer (grid, this, _("Left crop"), true, wxGBPosition (r, 0));
boost::mem_fn (&VideoContent::set_left_crop)
);
_left_crop->add (grid, wxGBPosition (r, 1));
- ++r;
- add_label_to_grid_bag_sizer (grid, this, _("Right crop"), true, wxGBPosition (r, 0));
+ add_label_to_grid_bag_sizer (grid, this, _("Right crop"), true, wxGBPosition (r, 2));
_right_crop = new ContentSpinCtrl<VideoContent> (
this,
new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)),
boost::mem_fn (&VideoContent::right_crop),
boost::mem_fn (&VideoContent::set_right_crop)
);
- _right_crop->add (grid, wxGBPosition (r, 1));
+ _right_crop->add (grid, wxGBPosition (r, 3));
+
++r;
add_label_to_grid_bag_sizer (grid, this, _("Top crop"), true, wxGBPosition (r, 0));
boost::mem_fn (&VideoContent::top_crop),
boost::mem_fn (&VideoContent::set_top_crop)
);
- _top_crop->add (grid, wxGBPosition (r,1 ));
- ++r;
+ _top_crop->add (grid, wxGBPosition (r, 1));
- add_label_to_grid_bag_sizer (grid, this, _("Bottom crop"), true, wxGBPosition (r, 0));
+ add_label_to_grid_bag_sizer (grid, this, _("Bottom crop"), true, wxGBPosition (r, 2));
_bottom_crop = new ContentSpinCtrl<VideoContent> (
this,
new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)),
boost::mem_fn (&VideoContent::bottom_crop),
boost::mem_fn (&VideoContent::set_bottom_crop)
);
- _bottom_crop->add (grid, wxGBPosition (r, 1));
+ _bottom_crop->add (grid, wxGBPosition (r, 3));
+
++r;
+ add_label_to_grid_bag_sizer (grid, this, _("Fade in"), true, wxGBPosition (r, 0));
+ _fade_in = new Timecode<ContentTime> (this);
+ grid->Add (_fade_in, wxGBPosition (r, 1), wxGBSpan (1, 3));
+ ++r;
+
+ add_label_to_grid_bag_sizer (grid, this, _("Fade out"), true, wxGBPosition (r, 0));
+ _fade_out = new Timecode<ContentTime> (this);
+ grid->Add (_fade_out, wxGBPosition (r, 1), wxGBSpan (1, 3));
+ ++r;
+
add_label_to_grid_bag_sizer (grid, this, _("Scale to"), true, wxGBPosition (r, 0));
_scale = new ContentChoice<VideoContent, VideoContentScale> (
this,
&index_to_scale,
&scale_to_index
);
- _scale->add (grid, wxGBPosition (r, 1));
+ _scale->add (grid, wxGBPosition (r, 1), wxGBSpan (1, 2));
++r;
- {
- add_label_to_grid_bag_sizer (grid, this, _("Filters"), true, wxGBPosition (r, 0));
- wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
-
- wxClientDC dc (this);
- wxSize size = dc.GetTextExtent (wxT ("A quite long name"));
- size.SetHeight (-1);
-
- _filters = new wxStaticText (this, wxID_ANY, _("None"), wxDefaultPosition, size);
- s->Add (_filters, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM | wxRIGHT, 6);
- _filters_button = new wxButton (this, wxID_ANY, _("Edit..."));
- s->Add (_filters_button, 0, wxALIGN_CENTER_VERTICAL);
- grid->Add (s, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
- }
+ wxClientDC dc (this);
+ wxSize size = dc.GetTextExtent (wxT ("A quite long name"));
+ size.SetHeight (-1);
+
+ add_label_to_grid_bag_sizer (grid, this, _("Filters"), true, wxGBPosition (r, 0));
+ _filters = new wxStaticText (this, wxID_ANY, _("None"), wxDefaultPosition, size);
+ grid->Add (_filters, wxGBPosition (r, 1), wxGBSpan (1, 2), wxALIGN_CENTER_VERTICAL);
+ _filters_button = new wxButton (this, wxID_ANY, _("Edit..."));
+ grid->Add (_filters_button, wxGBPosition (r, 3), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
++r;
- {
- add_label_to_grid_bag_sizer (grid, this, _("Colour conversion"), true, wxGBPosition (r, 0));
- wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
-
- wxClientDC dc (this);
- wxSize size = dc.GetTextExtent (wxT ("A quite long name"));
- size.SetHeight (-1);
-
- _colour_conversion = new wxStaticText (this, wxID_ANY, wxT (""), wxDefaultPosition, size);
-
- s->Add (_colour_conversion, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM | wxRIGHT, 6);
- _colour_conversion_button = new wxButton (this, wxID_ANY, _("Edit..."));
- s->Add (_colour_conversion_button, 0, wxALIGN_CENTER_VERTICAL);
- grid->Add (s, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
- }
+ add_label_to_grid_bag_sizer (grid, this, _("Colour conversion"), true, wxGBPosition (r, 0));
+ _colour_conversion = new wxStaticText (this, wxID_ANY, wxT (""), wxDefaultPosition, size);
+ grid->Add (_colour_conversion, wxGBPosition (r, 1), wxGBSpan (1, 2), wxALIGN_CENTER_VERTICAL);
+ _colour_conversion_button = new wxButton (this, wxID_ANY, _("Edit..."));
+ grid->Add (_colour_conversion_button, wxGBPosition (r, 3), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
++r;
_description = new wxStaticText (this, wxID_ANY, wxT ("\n \n \n \n \n"), wxDefaultPosition, wxDefaultSize);
- grid->Add (_description, wxGBPosition (r, 0), wxGBSpan (1, 2), wxEXPAND | wxALIGN_CENTER_VERTICAL | wxALL, 6);
+ grid->Add (_description, wxGBPosition (r, 0), wxGBSpan (1, 4), wxEXPAND | wxALIGN_CENTER_VERTICAL | wxALL, 6);
wxFont font = _description->GetFont();
font.SetStyle(wxFONTSTYLE_ITALIC);
font.SetPointSize(font.GetPointSize() - 1);
_frame_type->wrapped()->Append (_("3D left only"));
_frame_type->wrapped()->Append (_("3D right only"));
+ _fade_in->Changed.connect (boost::bind (&VideoPanel::fade_in_changed, this));
+ _fade_out->Changed.connect (boost::bind (&VideoPanel::fade_out_changed, this));
+
_filters_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&VideoPanel::edit_filters_clicked, this));
_colour_conversion_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&VideoPanel::edit_colour_conversion_clicked, this));
}
_filters->SetLabel (std_to_wx (p));
}
}
+ } else if (property == VideoContentProperty::VIDEO_FADE_IN) {
+ set<ContentTime> check;
+ for (VideoContentList::const_iterator i = vc.begin (); i != vc.end(); ++i) {
+ check.insert ((*i)->fade_in ());
+ }
+
+ if (check.size() == 1) {
+ _fade_in->set (vc.front()->fade_in (), vc.front()->video_frame_rate ());
+ } else {
+ _fade_in->clear ();
+ }
+ } else if (property == VideoContentProperty::VIDEO_FADE_OUT) {
+ set<ContentTime> check;
+ for (VideoContentList::const_iterator i = vc.begin (); i != vc.end(); ++i) {
+ check.insert ((*i)->fade_out ());
+ }
+
+ if (check.size() == 1) {
+ _fade_out->set (vc.front()->fade_out (), vc.front()->video_frame_rate ());
+ } else {
+ _fade_out->clear ();
+ }
}
}
film_content_changed (VideoContentProperty::VIDEO_CROP);
film_content_changed (VideoContentProperty::VIDEO_FRAME_RATE);
film_content_changed (VideoContentProperty::COLOUR_CONVERSION);
+ film_content_changed (VideoContentProperty::VIDEO_FADE_IN);
+ film_content_changed (VideoContentProperty::VIDEO_FADE_OUT);
film_content_changed (FFmpegContentProperty::FILTERS);
}
+
+void
+VideoPanel::fade_in_changed ()
+{
+ VideoContentList vc = _parent->selected_video ();
+ for (VideoContentList::const_iterator i = vc.begin(); i != vc.end(); ++i) {
+ (*i)->set_fade_in (_fade_in->get (_parent->film()->video_frame_rate ()));
+ }
+}
+
+void
+VideoPanel::fade_out_changed ()
+{
+ VideoContentList vc = _parent->selected_video ();
+ for (VideoContentList::const_iterator i = vc.begin(); i != vc.end(); ++i) {
+ (*i)->set_fade_out (_fade_out->get (_parent->film()->video_frame_rate ()));
+ }
+}
* @brief VideoPanel class.
*/
-#include "lib/film.h"
#include "content_sub_panel.h"
#include "content_widget.h"
+#include "timecode.h"
+#include "lib/film.h"
class wxChoice;
class wxStaticText;
private:
void edit_filters_clicked ();
void edit_colour_conversion_clicked ();
+ void fade_in_changed ();
+ void fade_out_changed ();
void setup_description ();
ContentSpinCtrl<VideoContent>* _right_crop;
ContentSpinCtrl<VideoContent>* _top_crop;
ContentSpinCtrl<VideoContent>* _bottom_crop;
+ Timecode<ContentTime>* _fade_in;
+ Timecode<ContentTime>* _fade_out;
ContentChoice<VideoContent, VideoContentScale>* _scale;
wxStaticText* _description;
wxStaticText* _filters;
using std::list;
using boost::shared_ptr;
using boost::thread;
+using boost::optional;
void
do_remote_encode (shared_ptr<DCPVideo> frame, ServerDescription description, shared_ptr<EncodedData> locally_encoded)
shared_ptr<ImageProxy> (new RawImageProxy (image, log)),
DCPTime (),
Crop (),
+ optional<float> (),
dcp::Size (1998, 1080),
dcp::Size (1998, 1080),
Scaler::from_id ("bicubic"),
shared_ptr<ImageProxy> (new RawImageProxy (image, log)),
DCPTime (),
Crop (),
+ optional<float> (),
dcp::Size (1998, 1080),
dcp::Size (1998, 1080),
Scaler::from_id ("bicubic"),