Change MagickImageProxy to FFmpegImageProxy and make it use FFmpeg
authorCarl Hetherington <cth@carlh.net>
Thu, 11 Oct 2018 23:46:00 +0000 (00:46 +0100)
committerCarl Hetherington <cth@carlh.net>
Thu, 11 Oct 2018 23:46:00 +0000 (00:46 +0100)
to decode images.  Hence remove {Image,Graphics}Magick.

27 files changed:
cscript
platform/osx/make_dmg.sh
platform/windows/wscript
src/lib/dcp_decoder.cc
src/lib/environment_info.cc
src/lib/ffmpeg_image_proxy.cc [new file with mode: 0644]
src/lib/ffmpeg_image_proxy.h [new file with mode: 0644]
src/lib/image.cc
src/lib/image.h
src/lib/image_decoder.cc
src/lib/image_examiner.cc
src/lib/image_proxy.cc
src/lib/image_proxy.h
src/lib/j2k_image_proxy.cc
src/lib/j2k_image_proxy.h
src/lib/magick_image_proxy.cc [deleted file]
src/lib/magick_image_proxy.h [deleted file]
src/lib/player_video.cc
src/lib/raw_image_proxy.cc
src/lib/raw_image_proxy.h
src/lib/util.cc
src/lib/wscript
src/tools/wscript
test/image_test.cc
test/test.cc
test/wscript
wscript

diff --git a/cscript b/cscript
index 4ad65f5..aa274e8 100644 (file)
--- a/cscript
+++ b/cscript
@@ -54,7 +54,6 @@ deb_depends['14.04'] = copy.deepcopy(deb_depends_base)
 deb_depends['14.04'].extend(['libboost-filesystem1.54.0',
                              'libboost-thread1.54.0',
                              'libboost-regex1.54.0',
-                             'libmagick++5',
                              'libxml++2.6-2',
                              'libboost-date-time1.54.0',
                              'libzip2',
@@ -70,7 +69,6 @@ deb_depends['16.04'] = copy.deepcopy(deb_depends_base)
 deb_depends['16.04'].extend(['libboost-filesystem1.58.0',
                              'libboost-thread1.58.0',
                              'libboost-regex1.58.0',
-                             'libmagick++-6.q16-5v5',
                              'libxml++2.6-2v5',
                              'libboost-date-time1.58.0',
                              'libzip4',
@@ -87,7 +85,6 @@ deb_depends['17.10'] = copy.deepcopy(deb_depends_base)
 deb_depends['17.10'].extend(['libboost-filesystem1.62.0',
                              'libboost-thread1.62.0',
                              'libboost-regex1.62.0',
-                             'libmagick++-6.q16-7',
                              'libxml++2.6-2v5',
                              'libboost-date-time1.62.0',
                              'libzip4',
@@ -103,7 +100,6 @@ deb_depends['18.04'].extend(['libboost-filesystem1.65.1',
                              'libboost-thread1.65.1',
                              'libboost-regex1.65.1',
                              'libboost-date-time1.65.1',
-                             'libmagick++-6.q16-7',
                              'libcairomm-1.0-1v5',
                              'libpangomm-1.4-1v5',
                              'libxml++2.6-2v5',
@@ -119,7 +115,6 @@ deb_depends['7'] = copy.deepcopy(deb_depends_base)
 deb_depends['7'].extend(['libboost-filesystem1.49.0',
                          'libboost-thread1.49.0',
                          'libboost-regex1.49.0',
-                         'libmagick++5',
                          'libxml++2.6-2',
                          'libboost-date-time1.49.0',
                          'libzip2',
@@ -136,7 +131,6 @@ deb_depends['8'].extend(['libboost-filesystem1.55.0',
                          'libboost-thread1.55.0',
                          'libboost-date-time1.55.0',
                          'libboost-regex1.55.0',
-                         'libmagick++-6.q16-5',
                          'libxml++2.6-2',
                          'libzip2',
                          'libcairomm-1.0-1',
@@ -155,7 +149,6 @@ deb_depends['9'].extend(['libboost-filesystem1.62.0',
                          'libboost-thread1.62.0',
                          'libboost-regex1.62.0',
                          'libboost-date-time1.62.0',
-                         'libmagick++-6.q16-7',
                          'libxml++2.6-2v5',
                          'libgtk2.0-0',
                          'libzip4',
@@ -179,7 +172,6 @@ deb_depends['unstable'].extend(['libboost-filesystem1.62.0',
                                 'libboost-thread1.62.0',
                                 'libboost-regex1.62.0',
                                 'libboost-date-time1.62.0',
-                                'libmagick++-6.q16-7',
                                 'libxml++2.6-2v5',
                                 'libgtk2.0-0',
                                 'libzip4',
@@ -382,11 +374,6 @@ def build(target, options):
                         'sources': [{'type': 'archive',
                                      'url': '%s/libzip-1.4.0.tar.xz' % prefix,
                                     'sha256': 'e508aba025f5f94b267d5120fc33761bcd98440ebe49dbfe2ed3df3afeacc7b1'}]})
-        modules.append({'name': 'imagemagick',
-                        'cleanup': ['/bin'],
-                        'sources': [{'type': 'archive',
-                                    'url': '%s/ImageMagick-7.0.8-11.tar.bz2' % prefix,
-                                    'sha256': 'a1aef96c89a9a9fac51a6e141deffa0b2f8db2062a24f6ba9fe3846dde7491ac'}]})
         modules.append({'name': 'libsigc++',
                         'sources': [{'type': 'archive',
                                      'url': '%s/libsigc++-2.10.0.tar.xz' % prefix,
index 487f03e..513ae75 100644 (file)
@@ -79,9 +79,6 @@ function copy_libs {
     universal_copy_lib $ENV libglib-2 "$dest"
     universal_copy_lib $ENV libintl "$dest"
     universal_copy_lib $ENV libsndfile "$dest"
-    universal_copy_lib $ENV libMagick++ "$dest"
-    universal_copy_lib $ENV libMagickCore "$dest"
-    universal_copy_lib $ENV libMagickWand "$dest"
     universal_copy_lib $ENV libssh "$dest"
     universal_copy_lib $ENV libwx "$dest"
     universal_copy_lib $ENV libfontconfig "$dest"
index 15f2ce7..5f321cc 100644 (file)
@@ -93,9 +93,6 @@ File "%static_deps%/bin/libglib-2.0-0.dll"
 File "%static_deps%/bin/libgobject-2.0-0.dll"
 File "%static_deps%/bin/libiconv-2.dll"
 File "%static_deps%/bin/libjpeg-9.dll"
-File "%static_deps%/bin/libGraphicsMagick-3.dll"
-File "%static_deps%/bin/libGraphicsMagickWand-2.dll"
-File "%static_deps%/bin/libGraphicsMagick++-11.dll"
 File "%static_deps%/bin/libpng16-16.dll"
 File "%static_deps%/bin/libsigc-2.0-0.dll"
 File "%static_deps%/bin/libsndfile-1.dll"
index 4e595da..72db536 100644 (file)
@@ -25,6 +25,7 @@
 #include "audio_decoder.h"
 #include "j2k_image_proxy.h"
 #include "text_decoder.h"
+#include "ffmpeg_image_proxy.h"
 #include "image.h"
 #include "config.h"
 #include <dcp/dcp.h>
@@ -243,7 +244,8 @@ DCPDecoder::pass_texts (ContentTime next, shared_ptr<dcp::SubtitleAsset> asset,
 
                        shared_ptr<dcp::SubtitleImage> ii = dynamic_pointer_cast<dcp::SubtitleImage> (i);
                        if (ii) {
-                               shared_ptr<Image> image(new Image(ii->png_image()));
+                               FFmpegImageProxy proxy (ii->png_image());
+                               shared_ptr<Image> image = proxy.image().first;
                                /* set up rect with height and width */
                                dcpomatic::Rect<double> rect(0, 0, image->size().width / double(size.width), image->size().height / double(size.height));
 
index 6fb75a0..68496f9 100644 (file)
 #include "cross.h"
 #include <dcp/version.h>
 #include <libssh/libssh.h>
-#ifdef DCPOMATIC_IMAGE_MAGICK
-/* ImageMagick */
-#ifdef DCPOMATIC_MAGICKCORE_MAGICK
-#include <magick/MagickCore.h>
-#include <magick/version.h>
-#else
-#include <MagickCore/MagickCore.h>
-#include <MagickCore/version.h>
-#endif
-#else
-/* GraphicsMagick */
-#include <magick/common.h>
-#include <magick/magick_config.h>
-#include <magick/version.h>
-#endif
 extern "C" {
 #include <libavcodec/avcodec.h>
 #include <libavformat/avformat.h>
@@ -77,13 +62,12 @@ dependency_version_summary ()
 {
        char buffer[512];
        snprintf (
-               buffer, sizeof(buffer), "libavcodec %s, libavfilter %s, libavformat %s, libavutil %s, libswscale %s, %s, libssh %s, libdcp %s git %s",
+               buffer, sizeof(buffer), "libavcodec %s, libavfilter %s, libavformat %s, libavutil %s, libswscale %s, libssh %s, libdcp %s git %s",
                ffmpeg_version_to_string(avcodec_version()).c_str(),
                ffmpeg_version_to_string(avfilter_version()).c_str(),
                ffmpeg_version_to_string(avformat_version()).c_str(),
                ffmpeg_version_to_string(avutil_version()).c_str(),
                ffmpeg_version_to_string(swscale_version()).c_str(),
-               MagickVersion,
                ssh_version(0),
                dcp::version, dcp::git_commit
                );
diff --git a/src/lib/ffmpeg_image_proxy.cc b/src/lib/ffmpeg_image_proxy.cc
new file mode 100644 (file)
index 0000000..c83bebc
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+    Copyright (C) 2014-2018 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic 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.
+
+    DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "ffmpeg_image_proxy.h"
+#include "cross.h"
+#include "exceptions.h"
+#include "dcpomatic_socket.h"
+#include "image.h"
+#include "compose.hpp"
+#include "util.h"
+#include <dcp/raw_convert.h>
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+}
+#include <libxml++/libxml++.h>
+#include <iostream>
+
+#include "i18n.h"
+
+using std::string;
+using std::cout;
+using std::pair;
+using std::min;
+using std::make_pair;
+using boost::shared_ptr;
+using boost::optional;
+using boost::dynamic_pointer_cast;
+using dcp::raw_convert;
+
+FFmpegImageProxy::FFmpegImageProxy (boost::filesystem::path path)
+       : _data (path)
+       , _pos (0)
+       , _path (path)
+{
+
+}
+
+FFmpegImageProxy::FFmpegImageProxy (dcp::Data data)
+       : _data (data)
+       , _pos (0)
+{
+
+}
+
+FFmpegImageProxy::FFmpegImageProxy (shared_ptr<cxml::Node>, shared_ptr<Socket> socket)
+       : _pos (0)
+{
+       uint32_t const size = socket->read_uint32 ();
+       _data = dcp::Data (size);
+       socket->read (_data.data().get(), size);
+}
+
+static int
+avio_read_wrapper (void* data, uint8_t* buffer, int amount)
+{
+       return reinterpret_cast<FFmpegImageProxy*>(data)->avio_read (buffer, amount);
+}
+
+static int64_t
+avio_seek_wrapper (void* data, int64_t offset, int whence)
+{
+       return reinterpret_cast<FFmpegImageProxy*>(data)->avio_seek (offset, whence);
+}
+
+int
+FFmpegImageProxy::avio_read (uint8_t* buffer, int const amount)
+{
+       int const to_do = min(int64_t(amount), _data.size() - _pos);
+       memcpy (buffer, _data.data().get() + _pos, to_do);
+       _pos += to_do;
+       return to_do;
+}
+
+int64_t
+FFmpegImageProxy::avio_seek (int64_t const pos, int whence)
+{
+       switch (whence) {
+       case AVSEEK_SIZE:
+               return _data.size();
+       case SEEK_CUR:
+               _pos += pos;
+               break;
+       case SEEK_SET:
+               _pos = pos;
+               break;
+       case SEEK_END:
+               _pos = _data.size() - pos;
+               break;
+       }
+
+       return _pos;
+}
+
+pair<shared_ptr<Image>, int>
+FFmpegImageProxy::image (optional<dcp::NoteHandler>, optional<dcp::Size>) const
+{
+       boost::mutex::scoped_lock lm (_mutex);
+
+       if (_image) {
+               return make_pair (_image, 0);
+       }
+
+       uint8_t* avio_buffer = static_cast<uint8_t*> (wrapped_av_malloc(4096));
+       AVIOContext* avio_context = avio_alloc_context (avio_buffer, 4096, 0, const_cast<FFmpegImageProxy*>(this), avio_read_wrapper, 0, avio_seek_wrapper);
+       AVFormatContext* format_context = avformat_alloc_context ();
+       format_context->pb = avio_context;
+
+       AVDictionary* options = 0;
+       /* These durations are in microseconds, and represent how far into the content file
+          we will look for streams.
+       */
+       av_dict_set (&options, "analyzeduration", raw_convert<string>(5 * 60 * 1000000).c_str(), 0);
+       av_dict_set (&options, "probesize", raw_convert<string>(5 * 60 * 1000000).c_str(), 0);
+
+       int e = avformat_open_input (&format_context, 0, 0, &options);
+       if (e < 0) {
+               throw OpenFileError (_path->string(), e, true);
+       }
+
+       if (avformat_find_stream_info(format_context, 0) < 0) {
+               throw DecodeError (_("could not find stream information"));
+       }
+
+       DCPOMATIC_ASSERT (format_context->nb_streams == 1);
+
+       AVFrame* frame = av_frame_alloc ();
+       if (!frame) {
+               throw DecodeError (N_("could not allocate frame"));
+       }
+
+       AVCodecContext* codec_context = format_context->streams[0]->codec;
+       AVCodec* codec = avcodec_find_decoder (codec_context->codec_id);
+       DCPOMATIC_ASSERT (codec);
+
+       if (avcodec_open2 (codec_context, codec, 0) < 0) {
+               throw DecodeError (N_("could not open decoder"));
+       }
+
+       AVPacket packet;
+       int r = av_read_frame (format_context, &packet);
+       if (r < 0) {
+               throw DecodeError (N_("could not read frame"));
+       }
+
+       int frame_finished;
+       if (avcodec_decode_video2(codec_context, frame, &frame_finished, &packet) < 0 || !frame_finished) {
+               throw DecodeError (N_("could not decode video"));
+       }
+
+       _image.reset (new Image (frame));
+
+       av_frame_free (&frame);
+       avformat_close_input (&format_context);
+       av_free (avio_context->buffer);
+       av_free (avio_context);
+
+       return make_pair (_image, 0);
+}
+
+void
+FFmpegImageProxy::add_metadata (xmlpp::Node* node) const
+{
+       node->add_child("Type")->add_child_text (N_("FFmpeg"));
+}
+
+void
+FFmpegImageProxy::send_binary (shared_ptr<Socket> socket) const
+{
+       socket->write (_data.size());
+       socket->write (_data.data().get(), _data.size());
+}
+
+bool
+FFmpegImageProxy::same (shared_ptr<const ImageProxy> other) const
+{
+       shared_ptr<const FFmpegImageProxy> mp = dynamic_pointer_cast<const FFmpegImageProxy> (other);
+       if (!mp) {
+               return false;
+       }
+
+       if (_data.size() != mp->_data.size()) {
+               return false;
+       }
+
+       return memcmp (_data.data().get(), mp->_data.data().get(), _data.size()) == 0;
+}
+
+size_t
+FFmpegImageProxy::memory_used () const
+{
+       size_t m = _data.size();
+       if (_image) {
+               m += _image->memory_used();
+       }
+       return m;
+}
diff --git a/src/lib/ffmpeg_image_proxy.h b/src/lib/ffmpeg_image_proxy.h
new file mode 100644 (file)
index 0000000..0fa8774
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+    Copyright (C) 2014-2018 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic 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.
+
+    DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "image_proxy.h"
+#include <dcp/data.h>
+#include <boost/thread/mutex.hpp>
+#include <boost/filesystem.hpp>
+
+class FFmpegImageProxy : public ImageProxy
+{
+public:
+       explicit FFmpegImageProxy (boost::filesystem::path);
+       explicit FFmpegImageProxy (dcp::Data);
+       FFmpegImageProxy (boost::shared_ptr<cxml::Node> xml, boost::shared_ptr<Socket> socket);
+
+       std::pair<boost::shared_ptr<Image>, int> image (
+               boost::optional<dcp::NoteHandler> note = boost::optional<dcp::NoteHandler> (),
+               boost::optional<dcp::Size> size = boost::optional<dcp::Size> ()
+               ) const;
+
+       void add_metadata (xmlpp::Node *) const;
+       void send_binary (boost::shared_ptr<Socket>) const;
+       bool same (boost::shared_ptr<const ImageProxy> other) const;
+       size_t memory_used () const;
+
+       int avio_read (uint8_t* buffer, int const amount);
+       int64_t avio_seek (int64_t const pos, int whence);
+
+private:
+       dcp::Data _data;
+       mutable int64_t _pos;
+       /** Path of a file that this image came from, if applicable; stored so that
+           failed-decode errors can give more detail.
+       */
+       boost::optional<boost::filesystem::path> _path;
+       mutable boost::shared_ptr<Image> _image;
+       mutable boost::mutex _mutex;
+};
index 75345cb..0590a4e 100644 (file)
@@ -30,7 +30,6 @@
 #include "dcpomatic_socket.h"
 #include <dcp/rgb_xyz.h>
 #include <dcp/transfer_function.h>
-#include <Magick++.h>
 extern "C" {
 #include <libswscale/swscale.h>
 #include <libavutil/pixfmt.h>
@@ -794,34 +793,6 @@ Image::Image (AVPixelFormat p, dcp::Size s, bool aligned, int extra_pixels)
        allocate ();
 }
 
-/** Construct an Image from some PNG data */
-Image::Image (dcp::Data png)
-{
-       Magick::Blob blob;
-       blob.update (png.data().get(), png.size());
-       Magick::Image* magick_image = new Magick::Image (blob);
-       _size = dcp::Size(magick_image->columns(), magick_image->rows());
-       _pixel_format = AV_PIX_FMT_BGRA;
-       _aligned = true;
-       _extra_pixels = 0;
-       allocate ();
-
-       /* Write line-by-line here as _image must be aligned, and write() cannot be told about strides */
-       uint8_t* p = data()[0];
-       for (int i = 0; i < _size.height; ++i) {
-#ifdef DCPOMATIC_HAVE_MAGICKCORE_NAMESPACE
-               using namespace MagickCore;
-#endif
-#ifdef DCPOMATIC_HAVE_MAGICKLIB_NAMESPACE
-               using namespace MagickLib;
-#endif
-               magick_image->write (0, i, _size.width, 1, "BGRA", CharPixel, p);
-               p += stride()[0];
-       }
-
-       delete magick_image;
-}
-
 void
 Image::allocate ()
 {
@@ -1187,34 +1158,6 @@ Image::memory_used () const
 dcp::Data
 Image::as_png () const
 {
-#ifdef DCPOMATIC_IMAGE_MAGICK
-               using namespace MagickCore;
-#else
-               using namespace MagickLib;
-#endif
-
-       string format;
-       switch (_pixel_format) {
-       case AV_PIX_FMT_RGB24:
-               format = "RGB";
-               break;
-       case AV_PIX_FMT_BGRA:
-               format = "BGRA";
-               break;
-       default:
-               DCPOMATIC_ASSERT (false);
-               break;
-       }
-
-       shared_ptr<const Image> use;
-       if (aligned()) {
-               use.reset (new Image(shared_from_this(), false));
-       }
-
-       Magick::Image m (size().width, size().height, format, CharPixel, (void *) use->data()[0]);
-       m.magick ("PNG");
-       Magick::Blob blob;
-       m.write (&blob);
-       /* XXX: could use a subclass of Data here (storing its data in a Blob) */
-       return dcp::Data (static_cast<const uint8_t*>(blob.data()), blob.length());
+       /* XXX */
+       return dcp::Data();
 }
index 1869ca8..73f2313 100644 (file)
@@ -44,7 +44,6 @@ public:
        Image (AVPixelFormat p, dcp::Size s, bool aligned, int extra_pixels = 0);
        explicit Image (AVFrame *);
        explicit Image (Image const &);
-       explicit Image (dcp::Data);
        Image (boost::shared_ptr<const Image>, bool);
        Image& operator= (Image const &);
        ~Image ();
index fd51c1b..e06f602 100644 (file)
 #include "image_decoder.h"
 #include "video_decoder.h"
 #include "image.h"
-#include "magick_image_proxy.h"
+#include "ffmpeg_image_proxy.h"
 #include "j2k_image_proxy.h"
 #include "film.h"
 #include "exceptions.h"
 #include "video_content.h"
-#include <Magick++.h>
 #include <boost/filesystem.hpp>
 #include <iostream>
 
@@ -68,7 +67,7 @@ ImageDecoder::pass ()
                        */
                        _image.reset (new J2KImageProxy (path, _image_content->video->size(), pf));
                } else {
-                       _image.reset (new MagickImageProxy (path));
+                       _image.reset (new FFmpegImageProxy (path));
                }
        }
 
index 71f0ca4..26beeb3 100644 (file)
 #include "config.h"
 #include "cross.h"
 #include "compose.hpp"
-#include "magick_image_proxy.h"
+#include "ffmpeg_image_proxy.h"
 #include "image.h"
 #include <dcp/openjpeg_image.h>
 #include <dcp/exceptions.h>
 #include <dcp/j2k.h>
-#include <Magick++.h>
 #include <iostream>
 
 #include "i18n.h"
@@ -46,9 +45,6 @@ ImageExaminer::ImageExaminer (shared_ptr<const Film> film, shared_ptr<const Imag
        : _film (film)
        , _image_content (content)
 {
-#ifdef DCPOMATIC_HAVE_MAGICKCORE_NAMESPACE
-       using namespace MagickCore;
-#endif
        boost::filesystem::path path = content->path(0).string ();
        if (valid_j2k_file (path)) {
                boost::uintmax_t size = boost::filesystem::file_size (path);
@@ -67,7 +63,7 @@ ImageExaminer::ImageExaminer (shared_ptr<const Film> film, shared_ptr<const Imag
                }
                delete[] buffer;
        } else {
-               MagickImageProxy proxy(content->path(0));
+               FFmpegImageProxy proxy(content->path(0));
                _video_size = proxy.image().first->size();
        }
 
index 3a09cb8..e16fab0 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "image_proxy.h"
 #include "raw_image_proxy.h"
-#include "magick_image_proxy.h"
+#include "ffmpeg_image_proxy.h"
 #include "j2k_image_proxy.h"
 #include "image.h"
 #include "exceptions.h"
@@ -40,8 +40,8 @@ image_proxy_factory (shared_ptr<cxml::Node> xml, shared_ptr<Socket> socket)
 {
        if (xml->string_child("Type") == N_("Raw")) {
                return shared_ptr<ImageProxy> (new RawImageProxy (xml, socket));
-       } else if (xml->string_child("Type") == N_("Magick")) {
-               return shared_ptr<MagickImageProxy> (new MagickImageProxy (xml, socket));
+       } else if (xml->string_child("Type") == N_("FFmpeg")) {
+               return shared_ptr<FFmpegImageProxy> (new FFmpegImageProxy(xml, socket));
        } else if (xml->string_child("Type") == N_("J2K")) {
                return shared_ptr<J2KImageProxy> (new J2KImageProxy (xml, socket));
        }
index b377d53..be053ee 100644 (file)
@@ -81,7 +81,6 @@ public:
         *  @return log2 of any scaling down that will be applied to the image.
         */
        virtual int prepare (boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const { return 0; }
-       virtual AVPixelFormat pixel_format () const = 0;
        virtual size_t memory_used () const = 0;
 };
 
index a46cda1..52b6f34 100644 (file)
@@ -31,7 +31,6 @@
 #include <dcp/j2k.h>
 #include <libcxml/cxml.h>
 #include <libxml++/libxml++.h>
-#include <Magick++.h>
 #include <iostream>
 
 #include "i18n.h"
index 77d53a9..a67cc24 100644 (file)
@@ -60,9 +60,6 @@ public:
        /** @return true if our image is definitely the same as another, false if it is probably not */
        bool same (boost::shared_ptr<const ImageProxy>) const;
        int prepare (boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const;
-       AVPixelFormat pixel_format () const {
-               return _pixel_format;
-       }
 
        dcp::Data j2k () const {
                return _data;
diff --git a/src/lib/magick_image_proxy.cc b/src/lib/magick_image_proxy.cc
deleted file mode 100644 (file)
index cd5749b..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
-    Copyright (C) 2014-2015 Carl Hetherington <cth@carlh.net>
-
-    This file is part of DCP-o-matic.
-
-    DCP-o-matic 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.
-
-    DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-#include "magick_image_proxy.h"
-#include "cross.h"
-#include "exceptions.h"
-#include "dcpomatic_socket.h"
-#include "image.h"
-#include "compose.hpp"
-#include <Magick++.h>
-#include <libxml++/libxml++.h>
-#include <iostream>
-
-#include "i18n.h"
-
-using std::string;
-using std::cout;
-using std::pair;
-using std::make_pair;
-using boost::shared_ptr;
-using boost::optional;
-using boost::dynamic_pointer_cast;
-
-MagickImageProxy::MagickImageProxy (boost::filesystem::path path)
-       : _path (path)
-{
-       /* Read the file into a Blob */
-
-       boost::uintmax_t const size = boost::filesystem::file_size (path);
-       FILE* f = fopen_boost (path, "rb");
-       if (!f) {
-               throw OpenFileError (path, errno, true);
-       }
-
-       uint8_t* data = new uint8_t[size];
-       if (fread (data, 1, size, f) != size) {
-               delete[] data;
-               throw ReadFileError (path);
-       }
-
-       fclose (f);
-       _blob.update (data, size);
-       delete[] data;
-}
-
-MagickImageProxy::MagickImageProxy (shared_ptr<cxml::Node>, shared_ptr<Socket> socket)
-{
-       uint32_t const size = socket->read_uint32 ();
-       uint8_t* data = new uint8_t[size];
-       socket->read (data, size);
-       _blob.update (data, size);
-       delete[] data;
-}
-
-pair<shared_ptr<Image>, int>
-MagickImageProxy::image (optional<dcp::NoteHandler>, optional<dcp::Size>) const
-{
-       boost::mutex::scoped_lock lm (_mutex);
-
-       if (_image) {
-               return make_pair (_image, 0);
-       }
-
-       Magick::Image* magick_image = 0;
-       string error;
-       try {
-               magick_image = new Magick::Image (_blob);
-       } catch (Magick::Exception& e) {
-               error = e.what ();
-       }
-
-       if (!magick_image) {
-               /* ImageMagick cannot auto-detect Targa files, it seems, so try here with an
-                  explicit format.  I can't find it documented that passing a (0, 0) geometry
-                  is allowed, but it seems to work.
-               */
-               try {
-                       magick_image = new Magick::Image (_blob, Magick::Geometry (0, 0), "TGA");
-               } catch (...) {
-
-               }
-       }
-
-       if (!magick_image) {
-               /* If we failed both an auto-detect and a forced-Targa we give the error from
-                  the auto-detect.
-               */
-               if (_path) {
-                       throw DecodeError (String::compose (_("Could not decode image file %1 (%2)"), _path->string(), error));
-               } else {
-                       throw DecodeError (String::compose (_("Could not decode image file (%1)"), error));
-               }
-       }
-
-       unsigned char const * data = static_cast<unsigned char const *>(_blob.data());
-       if (data[801] == 1 || magick_image->image()->colorspace == Magick::sRGBColorspace) {
-               /* Either:
-                  1.  The transfer characteristic in this file is "printing density"; in this case ImageMagick sets the colour space
-                      to LogColorspace, or
-                  2.  The file is sRGB.
-
-                  Empirically we find that in these cases if we subsequently call colorSpace(Magick::RGBColorspace) the colours
-                  are very wrong.  To prevent this, set the image colour space to RGB to stop the ::colorSpace call below doing
-                  anything.  See #1123 and others.
-               */
-               magick_image->image()->colorspace = Magick::RGBColorspace;
-       }
-
-       magick_image->colorSpace(Magick::RGBColorspace);
-
-       dcp::Size size (magick_image->columns(), magick_image->rows());
-
-       _image.reset (new Image (AV_PIX_FMT_RGB24, size, true));
-
-       /* Write line-by-line here as _image must be aligned, and write() cannot be told about strides */
-       uint8_t* p = _image->data()[0];
-       for (int i = 0; i < size.height; ++i) {
-#ifdef DCPOMATIC_HAVE_MAGICKCORE_NAMESPACE
-               using namespace MagickCore;
-#endif
-#ifdef DCPOMATIC_HAVE_MAGICKLIB_NAMESPACE
-               using namespace MagickLib;
-#endif
-               magick_image->write (0, i, size.width, 1, "RGB", CharPixel, p);
-               p += _image->stride()[0];
-       }
-
-       delete magick_image;
-
-       return make_pair (_image, 0);
-}
-
-void
-MagickImageProxy::add_metadata (xmlpp::Node* node) const
-{
-       node->add_child("Type")->add_child_text (N_("Magick"));
-}
-
-void
-MagickImageProxy::send_binary (shared_ptr<Socket> socket) const
-{
-       socket->write (_blob.length ());
-       socket->write ((uint8_t *) _blob.data (), _blob.length ());
-}
-
-bool
-MagickImageProxy::same (shared_ptr<const ImageProxy> other) const
-{
-       shared_ptr<const MagickImageProxy> mp = dynamic_pointer_cast<const MagickImageProxy> (other);
-       if (!mp) {
-               return false;
-       }
-
-       if (_blob.length() != mp->_blob.length()) {
-               return false;
-       }
-
-       return memcmp (_blob.data(), mp->_blob.data(), _blob.length()) == 0;
-}
-
-AVPixelFormat
-MagickImageProxy::pixel_format () const
-{
-       return AV_PIX_FMT_RGB24;
-}
-
-size_t
-MagickImageProxy::memory_used () const
-{
-       size_t m = _blob.length();
-       if (_image) {
-               m += _image->memory_used();
-       }
-       return m;
-}
diff --git a/src/lib/magick_image_proxy.h b/src/lib/magick_image_proxy.h
deleted file mode 100644 (file)
index 62f3afa..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
-    Copyright (C) 2014-2015 Carl Hetherington <cth@carlh.net>
-
-    This file is part of DCP-o-matic.
-
-    DCP-o-matic 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.
-
-    DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-#include "image_proxy.h"
-#include <Magick++.h>
-#include <boost/thread/mutex.hpp>
-#include <boost/filesystem.hpp>
-
-class MagickImageProxy : public ImageProxy
-{
-public:
-       explicit MagickImageProxy (boost::filesystem::path);
-       MagickImageProxy (boost::shared_ptr<cxml::Node> xml, boost::shared_ptr<Socket> socket);
-
-       std::pair<boost::shared_ptr<Image>, int> image (
-               boost::optional<dcp::NoteHandler> note = boost::optional<dcp::NoteHandler> (),
-               boost::optional<dcp::Size> size = boost::optional<dcp::Size> ()
-               ) const;
-
-       void add_metadata (xmlpp::Node *) const;
-       void send_binary (boost::shared_ptr<Socket>) const;
-       bool same (boost::shared_ptr<const ImageProxy> other) const;
-       AVPixelFormat pixel_format () const;
-       size_t memory_used () const;
-
-private:
-       Magick::Blob _blob;
-       /** Path of a file that this image came from, if applicable; stored so that
-           failed-decode errors can give more detail.
-       */
-       boost::optional<boost::filesystem::path> _path;
-       mutable boost::shared_ptr<Image> _image;
-       mutable boost::mutex _mutex;
-};
index 02c85be..12ec96a 100644 (file)
@@ -150,7 +150,7 @@ PlayerVideo::image (dcp::NoteHandler note, function<AVPixelFormat (AVPixelFormat
        }
 
        shared_ptr<Image> out = im->crop_scale_window (
-               total_crop, _inter_size, _out_size, yuv_to_rgb, pixel_format (_in->pixel_format()), aligned, fast
+               total_crop, _inter_size, _out_size, yuv_to_rgb, pixel_format (im->pixel_format()), aligned, fast
                );
 
        if (_text) {
index c3b565f..084f515 100644 (file)
@@ -86,12 +86,6 @@ RawImageProxy::same (shared_ptr<const ImageProxy> other) const
        return (*_image.get()) == (*rp->image().first.get());
 }
 
-AVPixelFormat
-RawImageProxy::pixel_format () const
-{
-       return _image->pixel_format ();
-}
-
 size_t
 RawImageProxy::memory_used () const
 {
index 78b7db0..5711b54 100644 (file)
@@ -37,7 +37,6 @@ public:
        void add_metadata (xmlpp::Node *) const;
        void send_binary (boost::shared_ptr<Socket>) const;
        bool same (boost::shared_ptr<const ImageProxy>) const;
-       AVPixelFormat pixel_format () const;
        size_t memory_used () const;
 
 private:
index 909a93b..051a4bb 100644 (file)
@@ -49,9 +49,6 @@ extern "C" {
 #include <libavcodec/avcodec.h>
 }
 #include <curl/curl.h>
-#ifdef DCPOMATIC_GRAPHICS_MAGICK
-#include <Magick++.h>
-#endif
 #include <glib.h>
 #include <pangomm/init.h>
 #include <boost/algorithm/string.hpp>
@@ -372,10 +369,6 @@ dcpomatic_setup ()
 
        curl_global_init (CURL_GLOBAL_ALL);
 
-#ifdef DCPOMATIC_GRAPHICS_MAGICK
-       Magick::InitializeMagick (0);
-#endif
-
        ui_thread = boost::this_thread::get_id ();
 }
 
index 768c27f..75e122e 100644 (file)
@@ -95,6 +95,7 @@ sources = """
           ffmpeg_subtitle_stream.cc
           film.cc
           filter.cc
+          ffmpeg_image_proxy.cc
           font.cc
           font_files.cc
           frame_rate_change.cc
@@ -114,7 +115,6 @@ sources = """
           json_server.cc
           log.cc
           log_entry.cc
-          magick_image_proxy.cc
           mid_side_decoder.cc
           monitor_checker.cc
           overlaps.cc
@@ -177,7 +177,7 @@ def build(bld):
     obj.uselib = """
                  AVCODEC AVUTIL AVFORMAT AVFILTER SWSCALE
                  BOOST_FILESYSTEM BOOST_THREAD BOOST_DATETIME BOOST_SIGNALS2 BOOST_REGEX
-                 SAMPLERATE POSTPROC TIFF MAGICK SSH DCP CXML GLIB LZMA XML++
+                 SAMPLERATE POSTPROC TIFF SSH DCP CXML GLIB LZMA XML++
                  CURL ZIP FONTCONFIG PANGOMM CAIROMM XMLSEC SUB ICU NETTLE
                  """
 
index ed70e56..84351e9 100644 (file)
@@ -30,7 +30,7 @@ def configure(conf):
 def build(bld):
     uselib =  'BOOST_THREAD BOOST_DATETIME DCP XMLSEC CXML XMLPP AVFORMAT AVFILTER AVCODEC '
     uselib += 'AVUTIL SWSCALE SWRESAMPLE POSTPROC CURL BOOST_FILESYSTEM SSH ZIP CAIROMM FONTCONFIG PANGOMM SUB '
-    uselib += 'MAGICK SNDFILE SAMPLERATE BOOST_REGEX ICU NETTLE RTAUDIO '
+    uselib += 'SNDFILE SAMPLERATE BOOST_REGEX ICU NETTLE RTAUDIO '
 
     if bld.env.TARGET_WINDOWS:
         uselib += 'WINSOCK2 DBGHELP SHLWAPI MSWSOCK BOOST_LOCALE WINSOCK2 OLE32 DSOUND WINMM KSUSER '
index 5adc356..9d07f8a 100644 (file)
@@ -25,9 +25,8 @@
  */
 
 #include "lib/image.h"
-#include "lib/magick_image_proxy.h"
+#include "lib/ffmpeg_image_proxy.h"
 #include "test.h"
-#include <Magick++.h>
 #include <boost/test/unit_test.hpp>
 #include <iostream>
 
@@ -138,7 +137,7 @@ BOOST_AUTO_TEST_CASE (compact_image_test)
 void
 alpha_blend_test_one (AVPixelFormat format, string suffix)
 {
-       shared_ptr<MagickImageProxy> proxy (new MagickImageProxy (private_data / "prophet_frame.tiff"));
+       shared_ptr<FFmpegImageProxy> proxy (new FFmpegImageProxy (private_data / "prophet_frame.tiff"));
        shared_ptr<Image> raw = proxy->image().first;
        shared_ptr<Image> background = raw->convert_pixel_format (dcp::YUV_TO_RGB_REC709, format, true, false);
 
@@ -260,7 +259,7 @@ BOOST_AUTO_TEST_CASE (merge_test2)
 /** Test Image::crop_scale_window with YUV420P and some windowing */
 BOOST_AUTO_TEST_CASE (crop_scale_window_test)
 {
-       shared_ptr<MagickImageProxy> proxy(new MagickImageProxy("test/data/flat_red.png"));
+       shared_ptr<FFmpegImageProxy> proxy(new FFmpegImageProxy("test/data/flat_red.png"));
        shared_ptr<Image> raw = proxy->image().first;
        shared_ptr<Image> out = raw->crop_scale_window(Crop(), dcp::Size(1998, 836), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, AV_PIX_FMT_YUV420P, true, false);
        shared_ptr<Image> save = out->scale(dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, AV_PIX_FMT_RGB24, false, false);
index 8b15553..a3235eb 100644 (file)
@@ -46,7 +46,6 @@
 #include <asdcp/AS_DCP.h>
 #include <sndfile.h>
 #include <libxml++/libxml++.h>
-#include <Magick++.h>
 extern "C" {
 #include <libavformat/avformat.h>
 }
@@ -233,25 +232,7 @@ check_mxf_audio_file (boost::filesystem::path ref, boost::filesystem::path check
 void
 check_image (boost::filesystem::path ref, boost::filesystem::path check, double threshold)
 {
-#ifdef DCPOMATIC_IMAGE_MAGICK
-       using namespace MagickCore;
-#else
-       using namespace MagickLib;
-#endif
-
-       Magick::Image ref_image;
-       ref_image.read (ref.string ());
-       Magick::Image check_image;
-       check_image.read (check.string ());
-       /* XXX: this is a hack; we really want the ImageMagick call but GraphicsMagick doesn't have it;
-          this may cause random test failures on platforms that use GraphicsMagick.
-       */
-#ifdef DCPOMATIC_ADVANCED_MAGICK_COMPARE
-       double const dist = ref_image.compare(check_image, Magick::RootMeanSquaredErrorMetric);
-       BOOST_CHECK_MESSAGE (dist < threshold, ref << " differs from " << check << " " << dist);
-#else
-       BOOST_CHECK_MESSAGE (!ref_image.compare(check_image), ref << " differs from " << check);
-#endif
+       /* XXX */
 }
 
 void
@@ -427,14 +408,7 @@ wait_for_jobs ()
 void
 write_image (shared_ptr<const Image> image, boost::filesystem::path file, string format)
 {
-#ifdef DCPOMATIC_IMAGE_MAGICK
-               using namespace MagickCore;
-#else
-               using namespace MagickLib;
-#endif
-
-       Magick::Image m (image->size().width, image->size().height, format.c_str(), CharPixel, (void *) image->data()[0]);
-       m.write (file.string ());
+       /* XXX */
 }
 
 void
index 74e0675..cfa7183 100644 (file)
@@ -34,7 +34,7 @@ def build(bld):
     obj = bld(features='cxx cxxprogram')
     obj.name   = 'unit-tests'
     obj.uselib =  'BOOST_TEST BOOST_THREAD BOOST_FILESYSTEM BOOST_DATETIME SNDFILE SAMPLERATE DCP FONTCONFIG CAIROMM PANGOMM XMLPP '
-    obj.uselib += 'AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE SWRESAMPLE POSTPROC CXML MAGICK SUB GLIB CURL SSH XMLSEC BOOST_REGEX ICU NETTLE '
+    obj.uselib += 'AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE SWRESAMPLE POSTPROC CXML SUB GLIB CURL SSH XMLSEC BOOST_REGEX ICU NETTLE '
     if bld.env.TARGET_WINDOWS:
         obj.uselib += 'WINSOCK2 DBGHELP SHLWAPI MSWSOCK BOOST_LOCALE '
     obj.use    = 'libdcpomatic2'
diff --git a/wscript b/wscript
index 92a79bb..f7bfea4 100644 (file)
--- a/wscript
+++ b/wscript
@@ -216,79 +216,6 @@ def configure(conf):
     # glib
     conf.check_cfg(package='glib-2.0', args='--cflags --libs', uselib_store='GLIB', mandatory=True)
 
-    # ImageMagick / GraphicsMagick
-    if distutils.spawn.find_executable('Magick++-config'):
-        conf.check_cfg(package='', path='Magick++-config', args='--cppflags --cxxflags --libs', uselib_store='MAGICK', mandatory=True)
-        conf.env.append_value('CXXFLAGS', '-DDCPOMATIC_IMAGE_MAGICK')
-    else:
-        image = conf.check_cfg(package='ImageMagick++', args='--cflags --libs', uselib_store='MAGICK', mandatory=False)
-        graphics = None
-        if image is None:
-            graphics = conf.check_cfg(package='GraphicsMagick++', args='--cflags --libs', uselib_store='MAGICK', mandatory=False)
-        if image is None and graphics is None:
-            Logs.pprint('RED', 'Neither ImageMagick++ nor GraphicsMagick++ found: one or the other is required')
-        if image is not None:
-            conf.env.append_value('CXXFLAGS', '-DDCPOMATIC_IMAGE_MAGICK')
-        if graphics is not None:
-            conf.env.append_value('CXXFLAGS', '-DDCPOMATIC_GRAPHICS_MAGICK')
-
-    # See if we are using the MagickCore or MagickLib namespaces
-    conf.check_cxx(fragment="""
-                            #include <Magick++/Include.h>\n
-                            using namespace MagickCore;\n
-                            int main () { return 0; }\n
-                            """,
-                   mandatory=False,
-                   msg='Checking for MagickCore namespace',
-                   okmsg='yes',
-                   includes=conf.env['INCLUDES_MAGICK'],
-                   define_name='DCPOMATIC_HAVE_MAGICKCORE_NAMESPACE')
-
-    conf.check_cxx(fragment="""
-                            #include <Magick++/Include.h>\n
-                            using namespace MagickLib;\n
-                            int main () { return 0; }\n
-                            """,
-                   mandatory=False,
-                   msg='Checking for MagickLib namespace',
-                   okmsg='yes',
-                   includes=conf.env['INCLUDES_MAGICK'],
-                   define_name='DCPOMATIC_HAVE_MAGICKLIB_NAMESPACE')
-
-    # See where MagickCore.h is
-    conf.check_cxx(fragment="""
-                            #include <magick/MagickCore.h>\n
-                            int main() { return 0; }\n
-                            """,
-                   mandatory=False,
-                   msg='Checking for MagickCore.h location',
-                   okmsg='magick',
-                   errmsg='not magick',
-                   includes=conf.env['INCLUDES_MAGICK'],
-                   define_name='DCPOMATIC_MAGICKCORE_MAGICK')
-
-    conf.check_cxx(fragment="""
-                            #include <MagickCore/MagickCore.h>\n
-                            int main() { return 0; }\n
-                            """,
-                   mandatory=False,
-                   msg='Checking for MagickCore.h location',
-                   okmsg='MagickCore',
-                   errmsg='not MagickCore',
-                   includes=conf.env['INCLUDES_MAGICK'],
-                   define_name='DCPOMATIC_MAGICKCORE_MAGICKCORE')
-
-    # See if we have advanced compare() methods in Magick
-    conf.check_cxx(fragment="""
-                            #include <Magick++.h>\n
-                            int main() { Magick::Image a; Magick::Image b; a.compare(b, Magick::RootMeanSquaredErrorMetric); }
-                            """,
-                   mandatory=False,
-                   msg='Checking for advanced compare() method in {Image/Graphics}Magick',
-                   uselib='MAGICK',
-                   define_name='DCPOMATIC_ADVANCED_MAGICK_COMPARE'
-                   )
-
     # libzip
     conf.check_cfg(package='libzip', args='--cflags --libs', uselib_store='ZIP', mandatory=True)
     conf.check_cxx(fragment="""