{
}
+
+Time
+AudioContent::temporal_length () const
+{
+ return audio_length() / audio_frame_rate();
+}
virtual int audio_channels () const = 0;
virtual ContentAudioFrame audio_length () const = 0;
virtual int audio_frame_rate () const = 0;
+
+ Time temporal_length () const;
};
#endif
#include <boost/thread/mutex.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <libxml++/libxml++.h>
+#include "types.h"
namespace cxml {
class Node;
virtual std::string information () const = 0;
virtual void as_xml (xmlpp::Node *) const;
virtual boost::shared_ptr<Content> clone () const = 0;
+ virtual Time temporal_length () const = 0;
boost::filesystem::path file () const {
boost::mutex::scoped_lock lm (_mutex);
{
return shared_ptr<Content> (new FFmpegContent (*this));
}
+
+double
+FFmpegContent::temporal_length () const
+{
+ return video_length() / video_frame_rate();
+}
std::string information () const;
void as_xml (xmlpp::Node *) const;
boost::shared_ptr<Content> clone () const;
+ double temporal_length () const;
/* AudioContent */
int audio_channels () const;
return shared_ptr<Player> (new Player (shared_from_this (), _playlist));
}
+shared_ptr<Playlist>
+Film::playlist () const
+{
+ boost::mutex::scoped_lock lm (_state_mutex);
+ return _playlist;
+}
+
ContentList
Film::content () const
{
bool have_dcp () const;
boost::shared_ptr<Player> player () const;
+ boost::shared_ptr<Playlist> playlist () const;
/* Proxies for some Playlist methods */
typedef std::vector<boost::shared_ptr<Content> > ContentList;
typedef int64_t ContentAudioFrame;
typedef int ContentVideoFrame;
+typedef double Time;
/** @struct Crop
* @brief A description of the crop of an image or video.
return s.str ();
}
+
+Time
+VideoContent::temporal_length () const
+{
+ return video_length() / video_frame_rate();
+}
void as_xml (xmlpp::Node *) const;
virtual std::string information () const;
+ Time temporal_length () const;
ContentVideoFrame video_length () const {
boost::mutex::scoped_lock lm (_mutex);
#include "imagemagick_content_dialog.h"
#include "ffmpeg_content_dialog.h"
#include "audio_mapping_view.h"
+#include "timeline_dialog.h"
using std::string;
using std::cout;
_content_edit->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_edit_clicked), 0, this);
_content_earlier->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_earlier_clicked), 0, this);
_content_later->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_later_clicked), 0, this);
+ _timeline_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::timeline_clicked), 0, this);
_loop_content->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::loop_content_toggled), 0, this);
_loop_count->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::loop_count_changed), 0, this);
_left_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::left_crop_changed), 0, this);
font.SetPointSize(font.GetPointSize() - 1);
_playlist_description->SetFont(font);
+ _timeline_button = new wxButton (_content_panel, wxID_ANY, _("Timeline..."));
+ _content_sizer->Add (_timeline_button, 0, wxALL, 6);
+
_loop_count->SetRange (2, 1024);
}
_playlist_description->SetLabel (std_to_wx (_film->playlist_description ()));
}
+
+void
+FilmEditor::timeline_clicked (wxCommandEvent &)
+{
+ TimelineDialog* d = new TimelineDialog (this, _film->playlist ());
+ d->ShowModal ();
+ d->Destroy ();
+}
void edit_filters_clicked (wxCommandEvent &);
void loop_content_toggled (wxCommandEvent &);
void loop_count_changed (wxCommandEvent &);
+ void timeline_clicked (wxCommandEvent &);
/* Handle changes to the model */
void film_changed (Film::Property);
wxTextCtrl* _content_information;
wxCheckBox* _loop_content;
wxSpinCtrl* _loop_count;
+ wxButton* _timeline_button;
wxStaticText* _playlist_description;
wxButton* _edit_dci_button;
wxChoice* _format;
--- /dev/null
+/*
+ Copyright (C) 2013 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <list>
+#include <wx/graphics.h>
+#include "timeline.h"
+#include "wx_util.h"
+#include "playlist.h"
+
+using std::list;
+using std::cout;
+using std::max;
+using boost::shared_ptr;
+
+int const Timeline::_track_height = 64;
+
+Timeline::Timeline (wxWindow* parent, shared_ptr<Playlist> pl)
+ : wxPanel (parent)
+ , _playlist (pl)
+{
+ SetDoubleBuffered (true);
+
+ Connect (wxID_ANY, wxEVT_PAINT, wxPaintEventHandler (Timeline::paint), 0, this);
+
+ if (pl->audio_from() == Playlist::AUDIO_FFMPEG) {
+ SetMinSize (wxSize (640, _track_height * 2 + 96));
+ } else {
+ SetMinSize (wxSize (640, _track_height * (max (1UL, pl->audio().size()) + 1) + 96));
+ }
+}
+
+template <class T>
+int
+plot_content_list (
+ list<shared_ptr<const T> > content, wxGraphicsContext* gc, int x, int y, double pixels_per_second, int track_height, wxString type, bool consecutive
+ )
+{
+ Time t = 0;
+ for (typename list<shared_ptr<const T> >::iterator i = content.begin(); i != content.end(); ++i) {
+ Time const len = (*i)->temporal_length ();
+ wxGraphicsPath path = gc->CreatePath ();
+ path.MoveToPoint (x + t * pixels_per_second, y);
+ path.AddLineToPoint (x + (t + len) * pixels_per_second, y);
+ path.AddLineToPoint (x + (t + len) * pixels_per_second, y + track_height);
+ path.AddLineToPoint (x + t * pixels_per_second, y + track_height);
+ path.AddLineToPoint (x + t * pixels_per_second, y);
+ gc->StrokePath (path);
+ gc->FillPath (path);
+
+ wxString name = wxString::Format ("%s [%s]", std_to_wx ((*i)->file().filename().string()), type);
+ wxDouble name_width;
+ wxDouble name_height;
+ wxDouble name_descent;
+ wxDouble name_leading;
+ gc->GetTextExtent (name, &name_width, &name_height, &name_descent, &name_leading);
+
+ gc->Clip (wxRegion (x + t * pixels_per_second, y, len * pixels_per_second, track_height));
+ gc->DrawText (name, t * pixels_per_second + 12, y + track_height - name_height - 4);
+ gc->ResetClip ();
+
+ if (consecutive) {
+ t += len;
+ } else {
+ y += track_height;
+ }
+ }
+
+ if (consecutive) {
+ y += track_height;
+ }
+
+ return y;
+}
+
+void
+Timeline::paint (wxPaintEvent &)
+{
+ wxPaintDC dc (this);
+
+ shared_ptr<Playlist> pl = _playlist.lock ();
+ if (!pl) {
+ return;
+ }
+
+ wxGraphicsContext* gc = wxGraphicsContext::Create (dc);
+ if (!gc) {
+ return;
+ }
+
+ int const x_offset = 8;
+ int y = 8;
+ int const width = GetSize().GetWidth();
+ double const pixels_per_second = (width - x_offset * 2) / (pl->content_length() / pl->video_frame_rate());
+
+ gc->SetFont (gc->CreateFont (*wxNORMAL_FONT));
+
+ gc->SetPen (*wxBLACK_PEN);
+#if wxMAJOR_VERSION == 2 && wxMINOR_VERSION >= 9
+ gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 4, wxPENSTYLE_SOLID));
+ gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (wxColour (149, 121, 232, 255), wxBRUSHSTYLE_SOLID));
+#else
+ gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 4, SOLID));
+ gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (wxColour (149, 121, 232, 255), SOLID));
+#endif
+ y = plot_content_list (pl->video (), gc, x_offset, y, pixels_per_second, _track_height, _("video"), true);
+
+#if wxMAJOR_VERSION == 2 && wxMINOR_VERSION >= 9
+ gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (wxColour (242, 92, 120, 255), wxBRUSHSTYLE_SOLID));
+#else
+ gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (wxColour (242, 92, 120, 255), SOLID));
+#endif
+ y = plot_content_list (pl->audio (), gc, x_offset, y, pixels_per_second, _track_height, _("audio"), pl->audio_from() == Playlist::AUDIO_FFMPEG);
+
+ /* Time axis */
+
+#if wxMAJOR_VERSION == 2 && wxMINOR_VERSION >= 9
+ gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 1, wxPENSTYLE_SOLID));
+#else
+ gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 1, SOLID));
+#endif
+
+ int mark_interval = rint (128 / pixels_per_second);
+ if (mark_interval > 5) {
+ mark_interval -= mark_interval % 5;
+ }
+ if (mark_interval > 10) {
+ mark_interval -= mark_interval % 10;
+ }
+ if (mark_interval > 60) {
+ mark_interval -= mark_interval % 60;
+ }
+ if (mark_interval > 3600) {
+ mark_interval -= mark_interval % 3600;
+ }
+
+ if (mark_interval < 1) {
+ mark_interval = 1;
+ }
+
+ wxGraphicsPath path = gc->CreatePath ();
+ path.MoveToPoint (x_offset, y + 40);
+ path.AddLineToPoint (width, y + 40);
+ gc->StrokePath (path);
+
+ double t = 0;
+ while ((t * pixels_per_second) < width) {
+ wxGraphicsPath path = gc->CreatePath ();
+ path.MoveToPoint (x_offset + t * pixels_per_second, y + 36);
+ path.AddLineToPoint (x_offset + t * pixels_per_second, y + 44);
+ gc->StrokePath (path);
+
+ int tc = t;
+ int const h = tc / 3600;
+ tc -= h * 3600;
+ int const m = tc / 60;
+ tc -= m * 60;
+ int const s = tc;
+
+ wxString str = wxString::Format ("%02d:%02d:%02d", h, m, s);
+ wxDouble str_width;
+ wxDouble str_height;
+ wxDouble str_descent;
+ wxDouble str_leading;
+ gc->GetTextExtent (str, &str_width, &str_height, &str_descent, &str_leading);
+
+ int const tx = x_offset + t * pixels_per_second;
+ if ((tx + str_width) < width) {
+ gc->DrawText (str, x_offset + t * pixels_per_second, y + 60);
+ }
+ t += mark_interval;
+ }
+
+ delete gc;
+}
+
--- /dev/null
+/*
+ Copyright (C) 2013 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <wx/wx.h>
+
+class Playlist;
+
+class Timeline : public wxPanel
+{
+public:
+ Timeline (wxWindow *, boost::shared_ptr<Playlist>);
+
+private:
+ void paint (wxPaintEvent &);
+
+ static int const _track_height;
+
+ boost::weak_ptr<Playlist> _playlist;
+};
--- /dev/null
+/*
+ Copyright (C) 2013 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <list>
+#include <wx/graphics.h>
+#include "timeline_dialog.h"
+#include "wx_util.h"
+#include "playlist.h"
+
+using std::list;
+using std::cout;
+using boost::shared_ptr;
+
+TimelineDialog::TimelineDialog (wxWindow* parent, shared_ptr<Playlist> pl)
+ : wxDialog (parent, wxID_ANY, _("Timeline"), wxDefaultPosition, wxSize (640, 512), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
+ , _timeline (this, pl)
+{
+ wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL);
+
+ sizer->Add (&_timeline, 1, wxEXPAND | wxALL, 12);
+
+ SetSizer (sizer);
+ sizer->Layout ();
+ sizer->SetSizeHints (this);
+}
--- /dev/null
+/*
+ Copyright (C) 2013 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <wx/wx.h>
+#include "timeline.h"
+
+class Playlist;
+
+class TimelineDialog : public wxDialog
+{
+public:
+ TimelineDialog (wxWindow *, boost::shared_ptr<Playlist>);
+
+private:
+ Timeline _timeline;
+};
new_film_dialog.cc
properties_dialog.cc
server_dialog.cc
+ timeline.cc
+ timeline_dialog.cc
wx_util.cc
wx_ui_signaller.cc
"""