diff options
| author | Carl Hetherington <cth@carlh.net> | 2013-05-27 21:54:50 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2013-05-27 21:54:50 +0100 |
| commit | 6166c045a8de42edd09924fdd995a77a3b753e54 (patch) | |
| tree | 91da3177d9802c0b9da84607eb3c3831ffc975b5 /src | |
| parent | a4642b6463430175d0f4e1ca284a4bf08bcf4de9 (diff) | |
Support for keeping video in sequence when changing lengths; tie selection in timeline with that in the editor.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/content.cc | 1 | ||||
| -rw-r--r-- | src/lib/content.h | 1 | ||||
| -rw-r--r-- | src/lib/ffmpeg_content.cc | 2 | ||||
| -rw-r--r-- | src/lib/film.cc | 6 | ||||
| -rw-r--r-- | src/lib/film.h | 2 | ||||
| -rw-r--r-- | src/lib/imagemagick_content.cc | 11 | ||||
| -rw-r--r-- | src/lib/player.cc | 10 | ||||
| -rw-r--r-- | src/lib/playlist.cc | 38 | ||||
| -rw-r--r-- | src/lib/playlist.h | 9 | ||||
| -rw-r--r-- | src/lib/video_content.cc | 7 | ||||
| -rw-r--r-- | src/lib/video_content.h | 1 | ||||
| -rw-r--r-- | src/wx/film_editor.cc | 52 | ||||
| -rw-r--r-- | src/wx/film_editor.h | 3 | ||||
| -rw-r--r-- | src/wx/film_viewer.cc | 2 | ||||
| -rw-r--r-- | src/wx/timecode.cc | 41 | ||||
| -rw-r--r-- | src/wx/timecode.h | 7 | ||||
| -rw-r--r-- | src/wx/timeline.cc | 15 | ||||
| -rw-r--r-- | src/wx/timeline.h | 6 | ||||
| -rw-r--r-- | src/wx/timeline_dialog.cc | 7 | ||||
| -rw-r--r-- | src/wx/timeline_dialog.h | 2 |
20 files changed, 176 insertions, 47 deletions
diff --git a/src/lib/content.cc b/src/lib/content.cc index aaf2e4f9c..6a33e9f7e 100644 --- a/src/lib/content.cc +++ b/src/lib/content.cc @@ -28,6 +28,7 @@ using boost::shared_ptr; using boost::lexical_cast; int const ContentProperty::START = 400; +int const ContentProperty::LENGTH = 401; Content::Content (shared_ptr<const Film> f, Time s) : _film (f) diff --git a/src/lib/content.h b/src/lib/content.h index 321252c02..5e8f98428 100644 --- a/src/lib/content.h +++ b/src/lib/content.h @@ -40,6 +40,7 @@ class ContentProperty { public: static int const START; + static int const LENGTH; }; class Content : public boost::enable_shared_from_this<Content> diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index d912ee418..7a67ee5b8 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -156,7 +156,7 @@ FFmpegContent::examine (shared_ptr<Job> job) take_from_video_decoder (decoder); - signal_changed (VideoContentProperty::VIDEO_LENGTH); + signal_changed (ContentProperty::LENGTH); signal_changed (FFmpegContentProperty::SUBTITLE_STREAMS); signal_changed (FFmpegContentProperty::SUBTITLE_STREAM); signal_changed (FFmpegContentProperty::AUDIO_STREAMS); diff --git a/src/lib/film.cc b/src/lib/film.cc index 26b3962a1..8eeb4fec5 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -905,3 +905,9 @@ Film::dcp_audio_frame_rate () const /* XXX */ return 48000; } + +void +Film::set_sequence_video (bool s) +{ + _playlist->set_sequence_video (s); +} diff --git a/src/lib/film.h b/src/lib/film.h index 9d1b86374..cb970da4d 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -119,6 +119,8 @@ public: void set_loop (int); int loop () const; + void set_sequence_video (bool); + /** Identifiers for the parts of our state; used for signalling changes. */ diff --git a/src/lib/imagemagick_content.cc b/src/lib/imagemagick_content.cc index ac04fb15b..a4777e3cd 100644 --- a/src/lib/imagemagick_content.cc +++ b/src/lib/imagemagick_content.cc @@ -75,15 +75,8 @@ ImageMagickContent::examine (shared_ptr<Job> job) shared_ptr<ImageMagickDecoder> decoder (new ImageMagickDecoder (film, shared_from_this())); - { - boost::mutex::scoped_lock lm (_mutex); - /* Initial length */ - _video_length = Config::instance()->default_still_length() * 24; - } - + set_video_length (Config::instance()->default_still_length() * 24); take_from_video_decoder (decoder); - - signal_changed (VideoContentProperty::VIDEO_LENGTH); } shared_ptr<Content> @@ -100,7 +93,7 @@ ImageMagickContent::set_video_length (ContentVideoFrame len) _video_length = len; } - signal_changed (VideoContentProperty::VIDEO_LENGTH); + signal_changed (ContentProperty::LENGTH); } Time diff --git a/src/lib/player.cc b/src/lib/player.cc index 786180a6a..34894ff0e 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -251,14 +251,6 @@ Player::add_silent_piece (Time s, Time len) } -struct ContentSorter -{ - bool operator() (shared_ptr<Content> a, shared_ptr<Content> b) - { - return a->start() < b->start(); - } -}; - void Player::setup_pieces () { @@ -358,7 +350,7 @@ Player::content_changed (weak_ptr<Content> w, int p) return; } - if (p == ContentProperty::START || p == VideoContentProperty::VIDEO_LENGTH) { + if (p == ContentProperty::START || p == ContentProperty::LENGTH) { _have_valid_pieces = false; } } diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index d2df75a09..d32ec6ba8 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -1,5 +1,3 @@ -/* -*- c-basic-offset: 8; default-tab-width: 8; -*- */ - /* Copyright (C) 2013 Carl Hetherington <cth@carlh.net> @@ -51,6 +49,8 @@ using boost::lexical_cast; Playlist::Playlist () : _loop (1) + , _sequence_video (true) + , _sequencing_video (false) { } @@ -72,6 +72,26 @@ Playlist::~Playlist () void Playlist::content_changed (weak_ptr<Content> c, int p) { + if (p == ContentProperty::LENGTH && _sequence_video && !_sequencing_video) { + cout << "sequencing.\n"; + _sequencing_video = true; + + ContentList cl = _content; + sort (cl.begin(), cl.end(), ContentSorter ()); + Time last = 0; + for (ContentList::iterator i = cl.begin(); i != cl.end(); ++i) { + if (!dynamic_pointer_cast<VideoContent> (*i)) { + continue; + } + + (*i)->set_start (last); + cout << (*i)->file() << " -> " << last << "\n"; + last = (*i)->end (); + } + + _sequencing_video = false; + } + ContentChanged (c, p); } @@ -143,6 +163,7 @@ Playlist::set_from_xml (shared_ptr<const Film> film, shared_ptr<const cxml::Node reconnect (); _loop = node->number_child<int> ("Loop"); + _sequence_video = node->bool_child ("SequenceVideo"); } /** @param node <Playlist> node */ @@ -154,6 +175,7 @@ Playlist::as_xml (xmlpp::Node* node) } node->add_child("Loop")->add_child_text(lexical_cast<string> (_loop)); + node->add_child("SequenceVideo")->add_child_text(_sequence_video ? "1" : "0"); } void @@ -297,3 +319,15 @@ Playlist::video_end () const return end; } + +void +Playlist::set_sequence_video (bool s) +{ + _sequence_video = s; +} + +bool +ContentSorter::operator() (shared_ptr<Content> a, shared_ptr<Content> b) +{ + return a->start() < b->start(); +} diff --git a/src/lib/playlist.h b/src/lib/playlist.h index f75b4ba63..3a7ca73bf 100644 --- a/src/lib/playlist.h +++ b/src/lib/playlist.h @@ -51,6 +51,11 @@ class Region; * are played simultaneously (i.e. they can be split up into multiple files for different channels) */ +struct ContentSorter +{ + bool operator() (boost::shared_ptr<Content> a, boost::shared_ptr<Content> b); +}; + class Playlist { public: @@ -85,6 +90,8 @@ public: int best_dcp_frame_rate () const; Time video_end () const; + void set_sequence_video (bool); + mutable boost::signals2::signal<void ()> Changed; mutable boost::signals2::signal<void (boost::weak_ptr<Content>, int)> ContentChanged; @@ -94,6 +101,8 @@ private: ContentList _content; int _loop; + bool _sequence_video; + bool _sequencing_video; std::list<boost::signals2::connection> _content_connections; }; diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc index 2e413678f..ae799dad3 100644 --- a/src/lib/video_content.cc +++ b/src/lib/video_content.cc @@ -23,10 +23,9 @@ #include "i18n.h" -int const VideoContentProperty::VIDEO_LENGTH = 0; -int const VideoContentProperty::VIDEO_SIZE = 1; -int const VideoContentProperty::VIDEO_FRAME_RATE = 2; -int const VideoContentProperty::VIDEO_CROP = 3; +int const VideoContentProperty::VIDEO_SIZE = 0; +int const VideoContentProperty::VIDEO_FRAME_RATE = 1; +int const VideoContentProperty::VIDEO_CROP = 2; using std::string; using std::stringstream; diff --git a/src/lib/video_content.h b/src/lib/video_content.h index 7dde927af..ce2550d12 100644 --- a/src/lib/video_content.h +++ b/src/lib/video_content.h @@ -28,7 +28,6 @@ class VideoDecoder; class VideoContentProperty { public: - static int const VIDEO_LENGTH; static int const VIDEO_SIZE; static int const VIDEO_FRAME_RATE; static int const VIDEO_CROP; diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index d036f318e..75867d1d5 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -222,7 +222,9 @@ FilmEditor::connect_to_widgets () _audio_delay->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::audio_delay_changed), 0, this); _audio_stream->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::audio_stream_changed), 0, this); _subtitle_stream->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::subtitle_stream_changed), 0, this); - _audio_mapping->Changed.connect (bind (&FilmEditor::audio_mapping_changed, this, _1)); + _audio_mapping->Changed.connect (boost::bind (&FilmEditor::audio_mapping_changed, this, _1)); + _start->Changed.connect (boost::bind (&FilmEditor::start_changed, this)); + _length->Changed.connect (boost::bind (&FilmEditor::length_changed, this)); } void @@ -693,7 +695,12 @@ FilmEditor::film_content_changed (weak_ptr<Content> weak_content, int property) } else { _start->set (0, 24); } - + } else if (property == ContentProperty::LENGTH) { + if (content) { + _length->set (content->length (), _film->dcp_video_frame_rate ()); + } else { + _length->set (0, 24); + } } else if (property == VideoContentProperty::VIDEO_CROP) { checked_set (_left_crop, video_content ? video_content->crop().left : 0); checked_set (_right_crop, video_content ? video_content->crop().right : 0); @@ -848,6 +855,7 @@ FilmEditor::set_film (shared_ptr<Film> f) film_changed (Film::DCP_VIDEO_FRAME_RATE); film_content_changed (boost::shared_ptr<Content> (), ContentProperty::START); + film_content_changed (boost::shared_ptr<Content> (), ContentProperty::LENGTH); film_content_changed (boost::shared_ptr<Content> (), VideoContentProperty::VIDEO_CROP); film_content_changed (boost::shared_ptr<Content> (), AudioContentProperty::AUDIO_GAIN); film_content_changed (boost::shared_ptr<Content> (), AudioContentProperty::AUDIO_DELAY); @@ -872,7 +880,6 @@ FilmEditor::set_things_sensitive (bool s) _edit_dci_button->Enable (s); _format->Enable (s); _content->Enable (s); - _content->Enable (s); _left_crop->Enable (s); _right_crop->Enable (s); _top_crop->Enable (s); @@ -1175,6 +1182,7 @@ FilmEditor::content_selection_changed (wxListEvent &) setup_content_sensitivity (); shared_ptr<Content> s = selected_content (); film_content_changed (s, ContentProperty::START); + film_content_changed (s, ContentProperty::LENGTH); film_content_changed (s, VideoContentProperty::VIDEO_CROP); film_content_changed (s, AudioContentProperty::AUDIO_GAIN); film_content_changed (s, AudioContentProperty::AUDIO_DELAY); @@ -1412,3 +1420,41 @@ FilmEditor::audio_mapping_changed (AudioMapping m) ac->set_audio_mapping (m); } + +void +FilmEditor::start_changed () +{ + shared_ptr<Content> c = selected_content (); + if (!c) { + return; + } + + c->set_start (_start->get (_film->dcp_video_frame_rate ())); +} + +void +FilmEditor::length_changed () +{ + shared_ptr<Content> c = selected_content (); + if (!c) { + return; + } + + shared_ptr<ImageMagickContent> ic = dynamic_pointer_cast<ImageMagickContent> (c); + if (ic) { + ic->set_video_length (_length->get(_film->dcp_video_frame_rate()) * ic->video_frame_rate() / TIME_HZ); + } +} + +void +FilmEditor::set_selection (weak_ptr<Content> wc) +{ + Playlist::ContentList content = _film->content (); + for (size_t i = 0; i < content.size(); ++i) { + if (content[i] == wc.lock ()) { + _content->SetItemState (i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + } else { + _content->SetItemState (i, 0, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED); + } + } +} diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index b169aee7f..c34cd73e0 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -47,6 +47,7 @@ public: FilmEditor (boost::shared_ptr<Film>, wxWindow *); void set_film (boost::shared_ptr<Film>); + void set_selection (boost::weak_ptr<Content>); boost::signals2::signal<void (std::string)> FileChanged; @@ -93,6 +94,8 @@ private: void audio_stream_changed (wxCommandEvent &); void subtitle_stream_changed (wxCommandEvent &); void audio_mapping_changed (AudioMapping); + void start_changed (); + void length_changed (); /* Handle changes to the model */ void film_changed (Film::Property); diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 4b1fb442e..97185ca94 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -464,7 +464,7 @@ FilmViewer::active_jobs_changed (bool a) void FilmViewer::film_content_changed (weak_ptr<Content>, int p) { - if (p == VideoContentProperty::VIDEO_LENGTH) { + if (p == ContentProperty::LENGTH) { /* Force an update to our frame */ wxScrollEvent ev; slider_moved (ev); diff --git a/src/wx/timecode.cc b/src/wx/timecode.cc index 460f7423b..f8cdccbe2 100644 --- a/src/wx/timecode.cc +++ b/src/wx/timecode.cc @@ -22,10 +22,12 @@ #include "wx_util.h" using std::string; +using std::cout; using boost::lexical_cast; Timecode::Timecode (wxWindow* parent) : wxPanel (parent) + , _in_set (false) { wxClientDC dc (parent); wxSize size = dc.GetTextExtent (wxT ("9999")); @@ -58,12 +60,19 @@ Timecode::Timecode (wxWindow* parent) _frames->SetMaxLength (2); sizer->Add (_frames); + _hours->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (Timecode::changed), 0, this); + _minutes->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (Timecode::changed), 0, this); + _seconds->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (Timecode::changed), 0, this); + _frames->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (Timecode::changed), 0, this); + SetSizerAndFit (sizer); } void Timecode::set (Time t, int fps) { + _in_set = true; + int const h = t / (3600 * TIME_HZ); t -= h * 3600 * TIME_HZ; int const m = t / (60 * TIME_HZ); @@ -72,19 +81,35 @@ Timecode::set (Time t, int fps) t -= s * TIME_HZ; int const f = t * fps / TIME_HZ; - _hours->SetValue (wxString::Format ("%02d", h)); - _minutes->SetValue (wxString::Format ("%02d", m)); - _seconds->SetValue (wxString::Format ("%02d", s)); - _frames->SetValue (wxString::Format ("%02d", f)); + _hours->SetValue (wxString::Format (wxT ("%d"), h)); + _minutes->SetValue (wxString::Format (wxT ("%d"), m)); + _seconds->SetValue (wxString::Format (wxT ("%d"), s)); + _frames->SetValue (wxString::Format (wxT ("%d"), f)); + + _in_set = false; } Time Timecode::get (int fps) const { Time t = 0; - t += lexical_cast<int> (wx_to_std (_hours->GetValue())) * 3600 * TIME_HZ; - t += lexical_cast<int> (wx_to_std (_minutes->GetValue())) * 60 * TIME_HZ; - t += lexical_cast<int> (wx_to_std (_seconds->GetValue())) * TIME_HZ; - t += lexical_cast<int> (wx_to_std (_frames->GetValue())) * TIME_HZ / fps; + string const h = wx_to_std (_hours->GetValue ()); + t += lexical_cast<int> (h.empty() ? "0" : h) * 3600 * TIME_HZ; + string const m = wx_to_std (_minutes->GetValue()); + t += lexical_cast<int> (m.empty() ? "0" : m) * 60 * TIME_HZ; + string const s = wx_to_std (_seconds->GetValue()); + t += lexical_cast<int> (s.empty() ? "0" : s) * TIME_HZ; + string const f = wx_to_std (_frames->GetValue()); + t += lexical_cast<int> (f.empty() ? "0" : f) * TIME_HZ / fps; return t; } + +void +Timecode::changed (wxCommandEvent &) +{ + if (_in_set) { + return; + } + + Changed (); +} diff --git a/src/wx/timecode.h b/src/wx/timecode.h index f243ee0b8..9b6fe6654 100644 --- a/src/wx/timecode.h +++ b/src/wx/timecode.h @@ -17,6 +17,7 @@ */ +#include <boost/signals2.hpp> #include <wx/wx.h> #include "lib/types.h" @@ -28,9 +29,15 @@ public: void set (Time, int); Time get (int) const; + boost::signals2::signal<void ()> Changed; + private: + void changed (wxCommandEvent &); + wxTextCtrl* _hours; wxTextCtrl* _minutes; wxTextCtrl* _seconds; wxTextCtrl* _frames; + + bool _in_set; }; diff --git a/src/wx/timeline.cc b/src/wx/timeline.cc index 54f3d75cf..42f489c2f 100644 --- a/src/wx/timeline.cc +++ b/src/wx/timeline.cc @@ -21,9 +21,10 @@ #include <wx/graphics.h> #include <boost/weak_ptr.hpp> #include "film.h" +#include "film_editor.h" #include "timeline.h" #include "wx_util.h" -#include "playlist.h" +#include "lib/playlist.h" using std::list; using std::cout; @@ -183,7 +184,7 @@ private: void content_changed (int p) { - if (p == ContentProperty::START || p == VideoContentProperty::VIDEO_LENGTH) { + if (p == ContentProperty::START || p == ContentProperty::LENGTH) { force_redraw (); } } @@ -312,8 +313,9 @@ private: int _y; }; -Timeline::Timeline (wxWindow* parent, shared_ptr<const Film> film) +Timeline::Timeline (wxWindow* parent, FilmEditor* ed, shared_ptr<Film> film) : wxPanel (parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE) + , _film_editor (ed) , _film (film) , _tracks (0) , _pixels_per_time_unit (0) @@ -482,6 +484,9 @@ Timeline::left_down (wxMouseEvent& ev) shared_ptr<ContentView> cv = dynamic_pointer_cast<ContentView> (*j); if (cv) { cv->set_selected (i == j); + if (i == j) { + _film_editor->set_selection (cv->content ()); + } } } @@ -518,6 +523,10 @@ Timeline::mouse_moved (wxMouseEvent& ev) shared_ptr<Content> c = _down_view->content().lock(); if (c) { c->set_start (max (static_cast<Time> (0), _down_view_start + time_diff)); + + shared_ptr<Film> film = _film.lock (); + assert (film); + film->set_sequence_video (false); } } } diff --git a/src/wx/timeline.h b/src/wx/timeline.h index 566ca060a..348286db8 100644 --- a/src/wx/timeline.h +++ b/src/wx/timeline.h @@ -26,11 +26,12 @@ class Film; class View; class ContentView; +class FilmEditor; class Timeline : public wxPanel { public: - Timeline (wxWindow *, boost::shared_ptr<const Film>); + Timeline (wxWindow *, FilmEditor *, boost::shared_ptr<Film>); boost::shared_ptr<const Film> film () const; @@ -68,7 +69,8 @@ private: void resized (wxSizeEvent &); void assign_tracks (); - boost::weak_ptr<const Film> _film; + FilmEditor* _film_editor; + boost::weak_ptr<Film> _film; std::list<boost::shared_ptr<View> > _views; int _tracks; double _pixels_per_time_unit; diff --git a/src/wx/timeline_dialog.cc b/src/wx/timeline_dialog.cc index 91d1f7b07..35d5eec21 100644 --- a/src/wx/timeline_dialog.cc +++ b/src/wx/timeline_dialog.cc @@ -19,6 +19,7 @@ #include <list> #include <wx/graphics.h> +#include "film_editor.h" #include "timeline_dialog.h" #include "wx_util.h" #include "playlist.h" @@ -27,9 +28,9 @@ using std::list; using std::cout; using boost::shared_ptr; -TimelineDialog::TimelineDialog (wxWindow* parent, shared_ptr<const Film> film) - : wxDialog (parent, wxID_ANY, _("Timeline"), wxDefaultPosition, wxSize (640, 512), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxFULL_REPAINT_ON_RESIZE) - , _timeline (this, film) +TimelineDialog::TimelineDialog (FilmEditor* ed, shared_ptr<Film> film) + : wxDialog (ed, wxID_ANY, _("Timeline"), wxDefaultPosition, wxSize (640, 512), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxFULL_REPAINT_ON_RESIZE) + , _timeline (this, ed, film) { wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL); diff --git a/src/wx/timeline_dialog.h b/src/wx/timeline_dialog.h index bc6b83eb5..17ca22c49 100644 --- a/src/wx/timeline_dialog.h +++ b/src/wx/timeline_dialog.h @@ -27,7 +27,7 @@ class Playlist; class TimelineDialog : public wxDialog { public: - TimelineDialog (wxWindow *, boost::shared_ptr<const Film>); + TimelineDialog (FilmEditor *, boost::shared_ptr<Film>); private: Timeline _timeline; |
