{
}
+
+AudioContent::AudioContent (AudioContent const & o)
+ : Content (o)
+{
+
+}
public:
AudioContent (boost::filesystem::path);
AudioContent (boost::shared_ptr<const cxml::Node>);
+ AudioContent (AudioContent const &);
virtual int audio_channels () const = 0;
virtual ContentAudioFrame audio_length () const = 0;
_digest = node->string_child ("Digest");
}
+Content::Content (Content const & o)
+ : _file (o._file)
+ , _digest (o._digest)
+{
+
+}
+
void
Content::as_xml (xmlpp::Node* node) const
{
public:
Content (boost::filesystem::path);
Content (boost::shared_ptr<const cxml::Node>);
+ Content (Content const &);
virtual void examine (boost::shared_ptr<Film>, boost::shared_ptr<Job>, bool);
virtual std::string summary () const = 0;
virtual void as_xml (xmlpp::Node *) const;
+ virtual boost::shared_ptr<Content> clone () const = 0;
boost::filesystem::path file () const {
boost::mutex::scoped_lock lm (_mutex);
}
}
+FFmpegContent::FFmpegContent (FFmpegContent const & o)
+ : Content (o)
+ , VideoContent (o)
+ , AudioContent (o)
+ , boost::enable_shared_from_this<FFmpegContent> (o)
+ , _subtitle_streams (o._subtitle_streams)
+ , _subtitle_stream (o._subtitle_stream)
+ , _audio_streams (o._audio_streams)
+ , _audio_stream (o._audio_stream)
+{
+
+}
+
void
FFmpegContent::as_xml (xmlpp::Node* node) const
{
root->add_child("Name")->add_child_text (name);
root->add_child("Id")->add_child_text (lexical_cast<string> (id));
}
+
+shared_ptr<Content>
+FFmpegContent::clone () const
+{
+ return shared_ptr<Content> (new FFmpegContent (*this));
+}
public:
FFmpegContent (boost::filesystem::path);
FFmpegContent (boost::shared_ptr<const cxml::Node>);
+ FFmpegContent (FFmpegContent const &);
void examine (boost::shared_ptr<Film>, boost::shared_ptr<Job>, bool);
std::string summary () const;
void as_xml (xmlpp::Node *) const;
+ boost::shared_ptr<Content> clone () const;
/* AudioContent */
int audio_channels () const;
, _dci_date (o._dci_date)
, _dirty (o._dirty)
{
- for (ContentList::iterator i = o._content.begin(); i != o._content.end(); ++i) {
+ for (ContentList::const_iterator i = o._content.begin(); i != o._content.end(); ++i) {
_content.push_back ((*i)->clone ());
}
Film::examine_content (shared_ptr<Content> c)
{
shared_ptr<Job> j (new ExamineContentJob (shared_from_this(), c, trust_content_headers ()));
- j->Finished.connect (bind (&Film::examine_content_finished, this));
JobManager::instance()->add (j);
}
{
boost::mutex::scoped_lock lm (_state_mutex);
_content.push_back (c);
+ _content_connections.push_back (c->Changed.connect (bind (&Film::content_changed, this, _1)));
_playlist->setup (_content);
}
if (i != _content.end ()) {
_content.erase (i);
}
+
+ for (list<boost::signals2::connection>::iterator i = _content_connections.begin(); i != _content_connections.end(); ++i) {
+ i->disconnect ();
+ }
+
+ for (ContentList::iterator i = _content.begin(); i != _content.end(); ++i) {
+ _content_connections.push_back (c->Changed.connect (bind (&Film::content_changed, this, _1)));
+ }
}
signal_changed (CONTENT);
return _playlist->video_length ();
}
+void
+Film::content_changed (int p)
+{
+ if (ui_signaller) {
+ ui_signaller->emit (boost::bind (boost::ref (ContentChanged), p));
+ }
+}
AB,
AUDIO_GAIN,
AUDIO_DELAY,
- STILL_DURATION,
SUBTITLE_STREAM,
WITH_SUBTITLES,
SUBTITLE_OFFSET,
void analyse_audio_finished ();
std::string video_state_identifier () const;
void read_metadata ();
+ void content_changed (int);
/** Log to write to */
boost::shared_ptr<Log> _log;
bool _use_dci_name;
bool _trust_content_headers;
ContentList _content;
+ std::list<boost::signals2::connection> _content_connections;
/** The type of content that this Film represents (feature, trailer etc.) */
DCPContentType const * _dcp_content_type;
/** The format to present this Film in (flat, scope, etc.) */
}
take_from_video_decoder (decoder);
+
+ Changed (VideoContentProperty::VIDEO_LENGTH);
+}
+
+shared_ptr<Content>
+ImageMagickContent::clone () const
+{
+ return shared_ptr<Content> (new ImageMagickContent (*this));
}
void examine (boost::shared_ptr<Film>, boost::shared_ptr<Job>, bool);
std::string summary () const;
void as_xml (xmlpp::Node *) const;
+ boost::shared_ptr<Content> clone () const;
static bool valid_file (boost::filesystem::path);
};
bool
ImageMagickDecoder::pass ()
{
- if (_position > 0 && _position < _imagemagick_content->video_length ()) {
+ if (_position < 0 || _position >= _imagemagick_content->video_length ()) {
+ return true;
+ }
+
+ if (have_last_video ()) {
repeat_last_video ();
_position++;
return false;
- } else if (_position >= _imagemagick_content->video_length ()) {
- return true;
}
Magick::Image* magick_image = new Magick::Image (_imagemagick_content->file().string ());
{
_video_from = VIDEO_NONE;
_audio_from = AUDIO_NONE;
+
+ _ffmpeg.reset ();
+ _imagemagick.clear ();
+ _sndfile.clear ();
for (ContentList::const_iterator i = content.begin(); i != content.end(); ++i) {
shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (*i);
_imagemagick_decoder = _imagemagick_decoders.begin ();
while (_imagemagick_decoder != _imagemagick_decoders.end ()) {
double const this_length = (*_imagemagick_decoder)->video_length() / _film->video_frame_rate ();
- if (this_length < t) {
+ if (t < this_length) {
break;
}
t -= this_length;
transform (ext.begin(), ext.end(), ext.begin(), ::tolower);
return (ext == ".wav" || ext == ".aif" || ext == ".aiff");
}
+
+shared_ptr<Content>
+SndfileContent::clone () const
+{
+ return shared_ptr<Content> (new SndfileContent (*this));
+}
SndfileContent (boost::shared_ptr<const cxml::Node>);
std::string summary () const;
+ boost::shared_ptr<Content> clone () const;
/* AudioContent */
int audio_channels () const;
_video_frame_rate = node->number_child<float> ("VideoFrameRate");
}
+VideoContent::VideoContent (VideoContent const & o)
+ : Content (o)
+ , _video_length (o._video_length)
+ , _video_size (o._video_size)
+ , _video_frame_rate (o._video_frame_rate)
+{
+
+}
+
void
VideoContent::as_xml (xmlpp::Node* node) const
{
public:
VideoContent (boost::filesystem::path);
VideoContent (boost::shared_ptr<const cxml::Node>);
+ VideoContent (VideoContent const &);
void as_xml (xmlpp::Node *) const;
_last_source_time = t;
}
+bool
+VideoDecoder::have_last_video () const
+{
+ return _last_image;
+}
+
/** Called by subclasses to repeat the last video frame that we
* passed to emit_video(). If emit_video hasn't yet been called,
* we will generate a black frame.
void emit_video (boost::shared_ptr<Image>, double);
void emit_subtitle (boost::shared_ptr<TimedSubtitle>);
+ bool have_last_video () const;
void repeat_last_video ();
private:
#include "lib/examine_content_job.h"
#include "lib/filter.h"
#include "lib/playlist.h"
+#include "lib/video_content.h"
#include "film_viewer.h"
#include "wx_util.h"
#include "video_decoder.h"
break;
case Film::CONTENT:
{
- _player = _film->player ();
- _player->disable_audio ();
- _player->disable_subtitles ();
- _player->disable_video_sync ();
-
- _player->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3));
+ setup_player ();
calculate_sizes ();
get_frame ();
_panel->Refresh ();
}
}
+void
+FilmViewer::setup_player ()
+{
+ _player = _film->player ();
+ _player->disable_audio ();
+ _player->disable_subtitles ();
+ _player->disable_video_sync ();
+ _player->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3));
+}
+
+void
+FilmViewer::film_content_changed (int p)
+{
+ if (p == VideoContentProperty::VIDEO_LENGTH || p == VideoContentProperty::VIDEO_SIZE) {
+ setup_player ();
+ calculate_sizes ();
+ get_frame ();
+ _panel->Refresh ();
+ _v_sizer->Layout ();
+ }
+}
+
void
FilmViewer::set_film (shared_ptr<Film> f)
{
}
_film->Changed.connect (boost::bind (&FilmViewer::film_changed, this, _1));
+ _film->ContentChanged.connect (boost::bind (&FilmViewer::film_content_changed, this, _1));
film_changed (Film::CONTENT);
film_changed (Film::FORMAT);
_clear_required = true;
}
-#if 0
if (_raw_sub) {
/* Our output is already cropped by the decoder, so we need to account for that
when working out the scale that we are applying.
*/
- Size const cropped_size = _film->cropped_size (_film->size ());
+ Size const cropped_size = _film->cropped_size (_film->video_size ());
Rect tx = subtitle_transformed_area (
float (_film_size.width) / cropped_size.width,
} else {
_display_sub.reset ();
}
-#endif
}
void
}
if (_play_button->GetValue()) {
-// _timer.Start (1000 / _film->source_frame_rate());
+ _timer.Start (1000 / _film->video_frame_rate());
} else {
_timer.Stop ();
}
private:
void film_changed (Film::Property);
+ void film_content_changed (int);
void paint_panel (wxPaintEvent &);
void panel_sized (wxSizeEvent &);
void slider_moved (wxScrollEvent &);
void raw_to_display ();
void get_frame ();
void active_jobs_changed (bool);
+ void setup_player ();
boost::shared_ptr<Film> _film;
boost::shared_ptr<Player> _player;