summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2013-07-26 00:20:21 +0100
committerCarl Hetherington <cth@carlh.net>2013-07-26 00:20:21 +0100
commit264a268f7c1244b47d9fa54ad342d80b0f98e16d (patch)
treeb184c193908fc96280ccffef4e51a67ab35eb69d /src/lib
parent78e5a331074a456097a162d47501daf1df1ab1a3 (diff)
Basic if sketchy support for image sequences.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/content_factory.cc3
-rw-r--r--src/lib/moving_image.h35
-rw-r--r--src/lib/moving_image_content.cc113
-rw-r--r--src/lib/moving_image_content.h57
-rw-r--r--src/lib/moving_image_decoder.cc85
-rw-r--r--src/lib/moving_image_decoder.h40
-rw-r--r--src/lib/moving_image_examiner.cc110
-rw-r--r--src/lib/moving_image_examiner.h47
-rw-r--r--src/lib/player.cc14
-rw-r--r--src/lib/still_image.h5
-rw-r--r--src/lib/still_image_content.cc8
-rw-r--r--src/lib/still_image_content.h3
-rw-r--r--src/lib/util.cc9
-rw-r--r--src/lib/util.h1
-rw-r--r--src/lib/wscript9
15 files changed, 526 insertions, 13 deletions
diff --git a/src/lib/content_factory.cc b/src/lib/content_factory.cc
index bf447641d..6ed01f174 100644
--- a/src/lib/content_factory.cc
+++ b/src/lib/content_factory.cc
@@ -20,6 +20,7 @@
#include <libcxml/cxml.h>
#include "ffmpeg_content.h"
#include "still_image_content.h"
+#include "moving_image_content.h"
#include "sndfile_content.h"
using std::string;
@@ -36,6 +37,8 @@ content_factory (shared_ptr<const Film> film, shared_ptr<cxml::Node> node)
content.reset (new FFmpegContent (film, node));
} else if (type == "StillImage") {
content.reset (new StillImageContent (film, node));
+ } else if (type == "MovingImage") {
+ content.reset (new MovingImageContent (film, node));
} else if (type == "Sndfile") {
content.reset (new SndfileContent (film, node));
}
diff --git a/src/lib/moving_image.h b/src/lib/moving_image.h
new file mode 100644
index 000000000..a81403dbd
--- /dev/null
+++ b/src/lib/moving_image.h
@@ -0,0 +1,35 @@
+/*
+ Copyright (C) 2012 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.
+
+*/
+
+class MovingImageContent;
+
+class MovingImage
+{
+public:
+ MovingImage (boost::shared_ptr<const MovingImageContent> c)
+ : _moving_image_content (c)
+ {}
+
+ boost::shared_ptr<const MovingImageContent> content () const {
+ return _moving_image_content;
+ }
+
+protected:
+ boost::shared_ptr<const MovingImageContent> _moving_image_content;
+};
diff --git a/src/lib/moving_image_content.cc b/src/lib/moving_image_content.cc
new file mode 100644
index 000000000..30030d9fd
--- /dev/null
+++ b/src/lib/moving_image_content.cc
@@ -0,0 +1,113 @@
+/*
+ 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 <libcxml/cxml.h>
+#include "moving_image_content.h"
+#include "moving_image_examiner.h"
+#include "config.h"
+#include "compose.hpp"
+#include "film.h"
+
+#include "i18n.h"
+
+using std::string;
+using std::cout;
+using std::list;
+using std::stringstream;
+using std::vector;
+using boost::shared_ptr;
+
+MovingImageContent::MovingImageContent (shared_ptr<const Film> f, boost::filesystem::path p)
+ : Content (f, p)
+ , VideoContent (f, p)
+{
+
+}
+
+MovingImageContent::MovingImageContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node)
+ : Content (f, node)
+ , VideoContent (f, node)
+{
+ list<shared_ptr<cxml::Node> > c = node->node_children ("File");
+ for (list<shared_ptr<cxml::Node> >::const_iterator i = c.begin(); i != c.end(); ++i) {
+ _files.push_back ((*i)->content ());
+ }
+}
+
+string
+MovingImageContent::summary () const
+{
+ /* Get the string() here so that the name does not have quotes around it */
+ return String::compose (_("%1 [moving images]"), path().filename().string());
+}
+
+string
+MovingImageContent::technical_summary () const
+{
+ return Content::technical_summary() + " - "
+ + VideoContent::technical_summary() + " - "
+ + "moving";
+}
+
+void
+MovingImageContent::as_xml (xmlpp::Node* node) const
+{
+ node->add_child("Type")->add_child_text ("MovingImage");
+ Content::as_xml (node);
+ VideoContent::as_xml (node);
+
+ for (vector<boost::filesystem::path>::const_iterator i = _files.begin(); i != _files.end(); ++i) {
+ node->add_child("File")->add_child_text (i->filename().string());
+ }
+}
+
+void
+MovingImageContent::examine (shared_ptr<Job> job)
+{
+ Content::examine (job);
+
+ shared_ptr<const Film> film = _film.lock ();
+ assert (film);
+
+ shared_ptr<MovingImageExaminer> examiner (new MovingImageExaminer (film, shared_from_this(), job));
+
+ take_from_video_examiner (examiner);
+
+ _video_length = examiner->files().size ();
+ _files = examiner->files ();
+}
+
+Time
+MovingImageContent::length () const
+{
+ shared_ptr<const Film> film = _film.lock ();
+ assert (film);
+
+ FrameRateConversion frc (video_frame_rate(), film->video_frame_rate ());
+ return video_length() * frc.factor() * TIME_HZ / video_frame_rate();
+}
+
+string
+MovingImageContent::identifier () const
+{
+ stringstream s;
+ s << VideoContent::identifier ();
+ s << "_" << video_length();
+ return s.str ();
+}
diff --git a/src/lib/moving_image_content.h b/src/lib/moving_image_content.h
new file mode 100644
index 000000000..2b3c48dd1
--- /dev/null
+++ b/src/lib/moving_image_content.h
@@ -0,0 +1,57 @@
+/*
+ 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.
+
+*/
+
+#ifndef DCPOMATIC_MOVING_IMAGE_CONTENT_H
+#define DCPOMATIC_MOVING_IMAGE_CONTENT_H
+
+#include <boost/enable_shared_from_this.hpp>
+#include "video_content.h"
+
+namespace cxml {
+ class Node;
+}
+
+/** A directory of image files which are to be presented as a movie */
+class MovingImageContent : public VideoContent
+{
+public:
+ MovingImageContent (boost::shared_ptr<const Film>, boost::filesystem::path);
+ MovingImageContent (boost::shared_ptr<const Film>, boost::shared_ptr<const cxml::Node>);
+
+ boost::shared_ptr<MovingImageContent> shared_from_this () {
+ return boost::dynamic_pointer_cast<MovingImageContent> (Content::shared_from_this ());
+ };
+
+ void examine (boost::shared_ptr<Job>);
+ std::string summary () const;
+ std::string technical_summary () const;
+ void as_xml (xmlpp::Node *) const;
+ Time length () const;
+
+ std::string identifier () const;
+
+ std::vector<boost::filesystem::path> const & files () const {
+ return _files;
+ }
+
+private:
+ std::vector<boost::filesystem::path> _files;
+};
+
+#endif
diff --git a/src/lib/moving_image_decoder.cc b/src/lib/moving_image_decoder.cc
new file mode 100644
index 000000000..096096063
--- /dev/null
+++ b/src/lib/moving_image_decoder.cc
@@ -0,0 +1,85 @@
+/*
+ Copyright (C) 2012-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 <iostream>
+#include <boost/filesystem.hpp>
+#include <Magick++.h>
+#include "moving_image_content.h"
+#include "moving_image_decoder.h"
+#include "image.h"
+#include "film.h"
+#include "exceptions.h"
+
+#include "i18n.h"
+
+using std::cout;
+using boost::shared_ptr;
+using libdcp::Size;
+
+MovingImageDecoder::MovingImageDecoder (shared_ptr<const Film> f, shared_ptr<const MovingImageContent> c)
+ : Decoder (f)
+ , VideoDecoder (f, c)
+ , MovingImage (c)
+{
+
+}
+
+void
+MovingImageDecoder::pass ()
+{
+ if (_video_position >= _moving_image_content->video_length ()) {
+ return;
+ }
+
+ boost::filesystem::path path = _moving_image_content->path ();
+ path /= _moving_image_content->files()[_video_position];
+
+ Magick::Image* magick_image = new Magick::Image (path.string());
+ libdcp::Size size (magick_image->columns(), magick_image->rows());
+
+ shared_ptr<Image> image (new Image (PIX_FMT_RGB24, size, false));
+
+ using namespace MagickCore;
+
+ uint8_t* p = image->data()[0];
+ for (int y = 0; y < size.height; ++y) {
+ for (int x = 0; x < size.width; ++x) {
+ Magick::Color c = magick_image->pixelColor (x, y);
+ *p++ = c.redQuantum() * 255 / QuantumRange;
+ *p++ = c.greenQuantum() * 255 / QuantumRange;
+ *p++ = c.blueQuantum() * 255 / QuantumRange;
+ }
+ }
+
+ delete magick_image;
+
+ video (image, false, _video_position);
+}
+
+void
+MovingImageDecoder::seek (VideoContent::Frame frame, bool)
+{
+ _video_position = frame;
+}
+
+bool
+MovingImageDecoder::done () const
+{
+ return _video_position >= _moving_image_content->video_length ();
+}
diff --git a/src/lib/moving_image_decoder.h b/src/lib/moving_image_decoder.h
new file mode 100644
index 000000000..5cc8b32b9
--- /dev/null
+++ b/src/lib/moving_image_decoder.h
@@ -0,0 +1,40 @@
+/*
+ Copyright (C) 2012-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 "video_decoder.h"
+#include "moving_image.h"
+
+namespace Magick {
+ class Image;
+}
+
+class MovingImageContent;
+
+class MovingImageDecoder : public VideoDecoder, public MovingImage
+{
+public:
+ MovingImageDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<const MovingImageContent>);
+
+ /* Decoder */
+
+ void pass ();
+ void seek (VideoContent::Frame, bool);
+ bool done () const;
+};
+
diff --git a/src/lib/moving_image_examiner.cc b/src/lib/moving_image_examiner.cc
new file mode 100644
index 000000000..077545aed
--- /dev/null
+++ b/src/lib/moving_image_examiner.cc
@@ -0,0 +1,110 @@
+/*
+ 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 <iostream>
+#include <boost/lexical_cast.hpp>
+#include <Magick++.h>
+#include "moving_image_content.h"
+#include "moving_image_examiner.h"
+#include "film.h"
+#include "job.h"
+#include "exceptions.h"
+
+#include "i18n.h"
+
+using std::cout;
+using std::list;
+using std::sort;
+using boost::shared_ptr;
+using boost::lexical_cast;
+
+MovingImageExaminer::MovingImageExaminer (shared_ptr<const Film> film, shared_ptr<const MovingImageContent> content, shared_ptr<Job> job)
+ : MovingImage (content)
+ , _film (film)
+ , _video_length (0)
+{
+ list<unsigned int> frames;
+ unsigned int files = 0;
+
+ for (boost::filesystem::directory_iterator i(content->path()); i != boost::filesystem::directory_iterator(); ++i) {
+ if (boost::filesystem::is_regular_file (i->path ())) {
+ ++files;
+ }
+ }
+
+ int j = 0;
+ for (boost::filesystem::directory_iterator i(content->path()); i != boost::filesystem::directory_iterator(); ++i) {
+ if (!boost::filesystem::is_regular_file (i->path ())) {
+ continue;
+ }
+
+ if (valid_image_file (i->path ())) {
+ int n = lexical_cast<int> (i->path().stem().string());
+ frames.push_back (n);
+ _files.push_back (i->path().filename ());
+
+ if (!_video_size) {
+ using namespace MagickCore;
+ Magick::Image* image = new Magick::Image (i->path().string());
+ _video_size = libdcp::Size (image->columns(), image->rows());
+ delete image;
+ }
+ }
+
+ job->set_progress (float (j) / files);
+ ++j;
+ }
+
+ frames.sort ();
+ sort (_files.begin(), _files.end ());
+
+ if (frames.size() < 2) {
+ throw StringError (String::compose (_("only %1 file(s) found in moving image directory"), frames.size ()));
+ }
+
+ if (frames.front() != 0 && frames.front() != 1) {
+ throw StringError (String::compose (_("first frame in moving image directory is number %1"), frames.front ()));
+ }
+
+ if (frames.back() != frames.size() && frames.back() != (frames.size() - 1)) {
+ throw StringError (String::compose (_("there are %1 images in the directory but the last one is number %2"), frames.size(), frames.back ()));
+ }
+
+ _video_length = frames.size ();
+}
+
+libdcp::Size
+MovingImageExaminer::video_size () const
+{
+ return _video_size.get ();
+}
+
+int
+MovingImageExaminer::video_length () const
+{
+ cout << "ex video length is " << _video_length << "\n";
+ return _video_length;
+}
+
+float
+MovingImageExaminer::video_frame_rate () const
+{
+ return 24;
+}
+
diff --git a/src/lib/moving_image_examiner.h b/src/lib/moving_image_examiner.h
new file mode 100644
index 000000000..db6845ee5
--- /dev/null
+++ b/src/lib/moving_image_examiner.h
@@ -0,0 +1,47 @@
+/*
+ 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 "moving_image.h"
+#include "video_examiner.h"
+
+namespace Magick {
+ class Image;
+}
+
+class MovingImageContent;
+
+class MovingImageExaminer : public MovingImage, public VideoExaminer
+{
+public:
+ MovingImageExaminer (boost::shared_ptr<const Film>, boost::shared_ptr<const MovingImageContent>, boost::shared_ptr<Job>);
+
+ float video_frame_rate () const;
+ libdcp::Size video_size () const;
+ VideoContent::Frame video_length () const;
+
+ std::vector<boost::filesystem::path> const & files () const {
+ return _files;
+ }
+
+private:
+ boost::weak_ptr<const Film> _film;
+ boost::optional<libdcp::Size> _video_size;
+ VideoContent::Frame _video_length;
+ std::vector<boost::filesystem::path> _files;
+};
diff --git a/src/lib/player.cc b/src/lib/player.cc
index 620efbd0d..647095793 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -24,6 +24,8 @@
#include "ffmpeg_content.h"
#include "still_image_decoder.h"
#include "still_image_content.h"
+#include "moving_image_decoder.h"
+#include "moving_image_content.h"
#include "sndfile_decoder.h"
#include "sndfile_content.h"
#include "subtitle_content.h"
@@ -462,6 +464,18 @@ Player::setup_pieces ()
piece->decoder = id;
}
+ shared_ptr<const MovingImageContent> mc = dynamic_pointer_cast<const MovingImageContent> (*i);
+ if (mc) {
+ shared_ptr<MovingImageDecoder> md;
+
+ if (!md) {
+ md.reset (new MovingImageDecoder (_film, mc));
+ md->Video.connect (bind (&Player::process_video, this, piece, _1, _2, _3, _4));
+ }
+
+ piece->decoder = md;
+ }
+
shared_ptr<const SndfileContent> sc = dynamic_pointer_cast<const SndfileContent> (*i);
if (sc) {
shared_ptr<AudioDecoder> sd (new SndfileDecoder (_film, sc));
diff --git a/src/lib/still_image.h b/src/lib/still_image.h
index b60069419..366d69331 100644
--- a/src/lib/still_image.h
+++ b/src/lib/still_image.h
@@ -17,6 +17,9 @@
*/
+#ifndef DCPOMATIC_STILL_IMAGE_H
+#define DCPOMATIC_STILL_IMAGE_H
+
class StillImageContent;
class StillImage
@@ -33,3 +36,5 @@ public:
protected:
boost::shared_ptr<const StillImageContent> _still_image_content;
};
+
+#endif
diff --git a/src/lib/still_image_content.cc b/src/lib/still_image_content.cc
index d0600f52e..5a3fed1b3 100644
--- a/src/lib/still_image_content.cc
+++ b/src/lib/still_image_content.cc
@@ -60,14 +60,6 @@ StillImageContent::technical_summary () const
+ "still";
}
-bool
-StillImageContent::valid_file (boost::filesystem::path f)
-{
- string ext = f.extension().string();
- transform (ext.begin(), ext.end(), ext.begin(), ::tolower);
- return (ext == ".tif" || ext == ".tiff" || ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".bmp");
-}
-
void
StillImageContent::as_xml (xmlpp::Node* node) const
{
diff --git a/src/lib/still_image_content.h b/src/lib/still_image_content.h
index b81879279..24d5174a0 100644
--- a/src/lib/still_image_content.h
+++ b/src/lib/still_image_content.h
@@ -27,6 +27,7 @@ namespace cxml {
class Node;
}
+/** A single image which is to be held on screen for some time (i.e. a slide) */
class StillImageContent : public VideoContent
{
public:
@@ -46,8 +47,6 @@ public:
std::string identifier () const;
void set_video_length (VideoContent::Frame);
-
- static bool valid_file (boost::filesystem::path);
};
#endif
diff --git a/src/lib/util.cc b/src/lib/util.cc
index 183ff7d8b..26dfa8bf7 100644
--- a/src/lib/util.cc
+++ b/src/lib/util.cc
@@ -775,3 +775,12 @@ LocaleGuard::~LocaleGuard ()
setlocale (LC_NUMERIC, _old);
free (_old);
}
+
+bool
+valid_image_file (boost::filesystem::path f)
+{
+ string ext = f.extension().string();
+ transform (ext.begin(), ext.end(), ext.begin(), ::tolower);
+ return (ext == ".tif" || ext == ".tiff" || ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".bmp");
+}
+
diff --git a/src/lib/util.h b/src/lib/util.h
index 65fb3d0dd..121deb532 100644
--- a/src/lib/util.h
+++ b/src/lib/util.h
@@ -67,6 +67,7 @@ extern std::string md5_digest_directory (boost::filesystem::path);
extern std::string md5_digest (void const *, int);
extern void ensure_ui_thread ();
extern std::string audio_channel_name (int);
+extern bool valid_image_file (boost::filesystem::path);
#ifdef DCPOMATIC_WINDOWS
extern boost::filesystem::path mo_path ();
#endif
diff --git a/src/lib/wscript b/src/lib/wscript
index 100663b87..04dae7587 100644
--- a/src/lib/wscript
+++ b/src/lib/wscript
@@ -28,12 +28,12 @@ sources = """
film.cc
filter.cc
image.cc
- still_image_content.cc
- still_image_decoder.cc
- still_image_examiner.cc
job.cc
job_manager.cc
log.cc
+ moving_image_content.cc
+ moving_image_decoder.cc
+ moving_image_examiner.cc
player.cc
playlist.cc
ratio.cc
@@ -44,6 +44,9 @@ sources = """
sndfile_content.cc
sndfile_decoder.cc
sound_processor.cc
+ still_image_content.cc
+ still_image_decoder.cc
+ still_image_examiner.cc
subtitle_content.cc
subtitle_decoder.cc
timer.cc