diff options
| author | Carl Hetherington <cth@carlh.net> | 2013-07-26 00:20:21 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2013-07-26 00:20:21 +0100 |
| commit | 264a268f7c1244b47d9fa54ad342d80b0f98e16d (patch) | |
| tree | b184c193908fc96280ccffef4e51a67ab35eb69d /src/lib | |
| parent | 78e5a331074a456097a162d47501daf1df1ab1a3 (diff) | |
Basic if sketchy support for image sequences.
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/content_factory.cc | 3 | ||||
| -rw-r--r-- | src/lib/moving_image.h | 35 | ||||
| -rw-r--r-- | src/lib/moving_image_content.cc | 113 | ||||
| -rw-r--r-- | src/lib/moving_image_content.h | 57 | ||||
| -rw-r--r-- | src/lib/moving_image_decoder.cc | 85 | ||||
| -rw-r--r-- | src/lib/moving_image_decoder.h | 40 | ||||
| -rw-r--r-- | src/lib/moving_image_examiner.cc | 110 | ||||
| -rw-r--r-- | src/lib/moving_image_examiner.h | 47 | ||||
| -rw-r--r-- | src/lib/player.cc | 14 | ||||
| -rw-r--r-- | src/lib/still_image.h | 5 | ||||
| -rw-r--r-- | src/lib/still_image_content.cc | 8 | ||||
| -rw-r--r-- | src/lib/still_image_content.h | 3 | ||||
| -rw-r--r-- | src/lib/util.cc | 9 | ||||
| -rw-r--r-- | src/lib/util.h | 1 | ||||
| -rw-r--r-- | src/lib/wscript | 9 |
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 |
