Various fixes to still-image mode.
authorCarl Hetherington <cth@carlh.net>
Mon, 17 Dec 2012 23:36:18 +0000 (23:36 +0000)
committerCarl Hetherington <cth@carlh.net>
Mon, 17 Dec 2012 23:36:18 +0000 (23:36 +0000)
21 files changed:
src/lib/check_hashes_job.cc
src/lib/dcp_video_frame.cc
src/lib/decoder.cc
src/lib/decoder.h
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_decoder.h
src/lib/film.cc
src/lib/film.h
src/lib/image.cc
src/lib/image.h
src/lib/imagemagick_decoder.cc
src/lib/imagemagick_decoder.h
src/lib/j2k_still_encoder.cc
src/lib/j2k_still_encoder.h
src/lib/options.h
src/lib/transcode_job.cc
src/lib/video_decoder.cc
src/wx/film_editor.cc
src/wx/film_viewer.cc
test/metadata.ref
test/test.cc

index 50d86c523588ec34de6d7148e9082f5e8dd7a834..701584c74dfb7ca7c2f0f4b32f2623d0e57c50cb 100644 (file)
@@ -63,7 +63,7 @@ CheckHashesJob::run ()
        
        for (SourceFrame i = _film->dcp_trim_start(); i < N; i += dfr.skip) {
                string const j2k_file = _encode_opt->frame_out_path (i, false);
-               string const hash_file = j2k_file + ".md5";
+               string const hash_file = _encode_opt->hash_out_path (i, false);
 
                if (!boost::filesystem::exists (j2k_file)) {
                        _film->log()->log (String::compose ("Frame %1 has a missing J2K file.", i));
index 7099f73defc9a8c7a1b70e53efc37e8ae2387d8d..8b70b0aa4697286e82f3b0da3abad72b7f3e95c9 100644 (file)
@@ -395,7 +395,7 @@ EncodedData::write (shared_ptr<const EncodeOptions> opt, SourceFrame frame)
        boost::filesystem::rename (tmp_j2k, real_j2k);
 
        /* Write a file containing the hash */
-       string const hash = real_j2k + ".md5";
+       string const hash = opt->hash_out_path (frame, false);
        ofstream h (hash.c_str());
        h << md5_digest (_data, _size) << "\n";
        h.close ();
index 50770834586f10c1cb5405d7846fa2696d26fd66..7d40850451554f959cdb88258c2b7105b6bf99b3 100644 (file)
@@ -54,7 +54,7 @@ Decoder::Decoder (boost::shared_ptr<Film> f, boost::shared_ptr<const DecodeOptio
        , _opt (o)
        , _job (j)
 {
-       
+       _film_connection = f->Changed.connect (bind (&Decoder::film_changed, this, _1));
 }
 
 bool
index 0d35ebb3a01675c3b75e7961f2975154dc4d9724..b8278ff80060807ffcc27718cd9430041d8c1c05 100644 (file)
@@ -33,6 +33,7 @@
 #include "stream.h"
 #include "video_source.h"
 #include "audio_source.h"
+#include "film.h"
 
 class Job;
 class DecodeOptions;
@@ -41,7 +42,6 @@ class Log;
 class DelayLine;
 class TimedSubtitle;
 class Subtitle;
-class Film;
 class FilterGraph;
 
 /** @class Decoder.
@@ -72,6 +72,11 @@ protected:
        boost::shared_ptr<const DecodeOptions> _opt;
        /** associated Job, or 0 */
        Job* _job;
+
+private:
+       virtual void film_changed (Film::Property) {}
+       
+       boost::signals2::scoped_connection _film_connection;
 };
 
 #endif
index b93a81bc834e446c0ca216d09a52ff3eca94733e..a05b331cce32ae84947115813543748f0af327ca 100644 (file)
@@ -78,8 +78,6 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<Film> f, shared_ptr<const DecodeOptions
        setup_audio ();
        setup_subtitle ();
 
-       _film_connection = f->Changed.connect (bind (&FFmpegDecoder::film_changed, this, _1));
-
        if (!o->video_sync) {
                _first_video = 0;
        }
index 35688003ec9b9975cbedd251d9b20cacf5879520..2011ef72f9f416661ce2394d15eb4e7bafb12c7c 100644 (file)
@@ -121,7 +121,6 @@ private:
        boost::shared_ptr<AudioBuffers> deinterleave_audio (uint8_t* data, int size);
 
        void film_changed (Film::Property);
-       boost::signals2::scoped_connection _film_connection;
 
        std::string stream_name (AVStream* s) const;
 
index b295bdc83e7c84c4f5fc555da540904aae38a722..2e2ec368abfafa74dd5e04989a9892a30a88b226 100644 (file)
@@ -678,6 +678,10 @@ Film::target_audio_sample_rate () const
 boost::optional<SourceFrame>
 Film::dcp_length () const
 {
+       if (content_type() == STILL) {
+               return _still_duration * frames_per_second();
+       }
+       
        if (!length()) {
                return boost::optional<SourceFrame> ();
        }
index 642f2d7da9918d56fbf7774b4d3d7c482a5f0a2a..536855b1f64a0abd4e80c6d7a0121b3fe787773e 100644 (file)
@@ -312,6 +312,10 @@ public:
        
        float frames_per_second () const {
                boost::mutex::scoped_lock lm (_state_mutex);
+               if (content_type() == STILL) {
+                       return 24;
+               }
+               
                return _frames_per_second;
        }
 
index fb72d1aee90315c59fbc4010785d4b926f37ce6f..397c8bc9c9468366a724b85c03ed3b4d20e0a22b 100644 (file)
@@ -43,6 +43,12 @@ extern "C" {
 using namespace std;
 using namespace boost;
 
+void
+Image::swap (Image& other)
+{
+       std::swap (_pixel_format, other._pixel_format);
+}
+
 /** @param n Component index.
  *  @return Number of lines in the image for the given component.
  */
@@ -127,6 +133,8 @@ Image::scale_and_convert_to_rgb (Size out_size, int padding, Scaler const * scal
 
        shared_ptr<Image> rgb (new SimpleImage (PIX_FMT_RGB24, content_size, aligned));
 
+       cout << "scale to " << out_size.width << "x" << out_size.height << "\n";
+
        struct SwsContext* scale_context = sws_getContext (
                size().width, size().height, pixel_format(),
                content_size.width, content_size.height, PIX_FMT_RGB24,
@@ -206,6 +214,33 @@ Image::post_process (string pp, bool aligned) const
        return out;
 }
 
+shared_ptr<Image>
+Image::crop (Crop crop, bool aligned) const
+{
+       Size cropped_size = size ();
+       cropped_size.width -= crop.left + crop.right;
+       cropped_size.height -= crop.top + crop.bottom;
+
+       shared_ptr<Image> out (new SimpleImage (pixel_format(), cropped_size, aligned));
+
+       for (int c = 0; c < components(); ++c) {
+               int const crop_left_in_bytes = bytes_per_pixel(c) * crop.left;
+               int const cropped_width_in_bytes = bytes_per_pixel(c) * cropped_size.width;
+                       
+               /* Start of the source line, cropped from the top but not the left */
+               uint8_t* in_p = data()[c] + crop.top * stride()[c];
+               uint8_t* out_p = out->data()[c];
+               
+               for (int y = 0; y < cropped_size.height; ++y) {
+                       memcpy (out_p, in_p + crop_left_in_bytes, cropped_width_in_bytes);
+                       in_p += line_size()[c];
+                       out_p += out->line_size()[c];
+               }
+       }
+
+       return out;
+}
+
 void
 Image::make_black ()
 {
@@ -287,6 +322,48 @@ Image::write_to_socket (shared_ptr<Socket> socket) const
        }
 }
 
+
+float
+Image::bytes_per_pixel (int c) const
+{
+       if (c == 3) {
+               return 0;
+       }
+       
+       switch (_pixel_format) {
+       case PIX_FMT_RGB24:
+               if (c == 0) {
+                       return 3;
+               } else {
+                       return 0;
+               }
+       case PIX_FMT_RGBA:
+               if (c == 0) {
+                       return 4;
+               } else {
+                       return 0;
+               }
+       case PIX_FMT_YUV420P:
+       case PIX_FMT_YUV422P:
+               if (c == 0) {
+                       return 1;
+               } else {
+                       return 0.5;
+               }
+       case PIX_FMT_YUV422P10LE:
+               if (c == 1) {
+                       return 2;
+               } else {
+                       return 1;
+               }
+       default:
+               assert (false);
+       }
+
+       return 0;
+}
+
+
 /** Construct a SimpleImage of a given size and format, allocating memory
  *  as required.
  *
@@ -297,6 +374,12 @@ SimpleImage::SimpleImage (AVPixelFormat p, Size s, bool aligned)
        : Image (p)
        , _size (s)
        , _aligned (aligned)
+{
+       allocate ();
+}
+
+void
+SimpleImage::allocate ()
 {
        _data = (uint8_t **) av_malloc (4 * sizeof (uint8_t *));
        _data[0] = _data[1] = _data[2] = _data[3] = 0;
@@ -307,34 +390,57 @@ SimpleImage::SimpleImage (AVPixelFormat p, Size s, bool aligned)
        _stride = (int *) av_malloc (4 * sizeof (int));
        _stride[0] = _stride[1] = _stride[2] = _stride[3] = 0;
 
-       switch (p) {
-       case PIX_FMT_RGB24:
-               _line_size[0] = s.width * 3;
-               break;
-       case PIX_FMT_RGBA:
-               _line_size[0] = s.width * 4;
-               break;
-       case PIX_FMT_YUV420P:
-       case PIX_FMT_YUV422P:
-               _line_size[0] = s.width;
-               _line_size[1] = s.width / 2;
-               _line_size[2] = s.width / 2;
-               break;
-       case PIX_FMT_YUV422P10LE:
-               _line_size[0] = s.width * 2;
-               _line_size[1] = s.width;
-               _line_size[2] = s.width;
-               break;
-       default:
-               assert (false);
-       }
-
        for (int i = 0; i < components(); ++i) {
+               _line_size[i] = _size.width * bytes_per_pixel(i);
                _stride[i] = stride_round_up (i, _line_size, _aligned ? 32 : 1);
                _data[i] = (uint8_t *) av_malloc (_stride[i] * lines (i));
        }
 }
 
+SimpleImage::SimpleImage (SimpleImage const & other)
+       : Image (other)
+{
+       _size = other._size;
+       _aligned = other._aligned;
+       
+       allocate ();
+
+       for (int i = 0; i < components(); ++i) {
+               memcpy (_data[i], other._data[i], _line_size[i] * lines(i));
+       }
+}
+
+SimpleImage&
+SimpleImage::operator= (SimpleImage const & other)
+{
+       if (this == &other) {
+               return *this;
+       }
+
+       SimpleImage tmp (other);
+       swap (tmp);
+       return *this;
+}
+
+void
+SimpleImage::swap (SimpleImage & other)
+{
+       Image::swap (other);
+       
+       assert (_size == other._size);
+       assert (_aligned == other._aligned);
+
+       std::swap (_size, other._size);
+
+       for (int i = 0; i < 4; ++i) {
+               std::swap (_data[i], other._data[i]);
+               std::swap (_line_size[i], other._line_size[i]);
+               std::swap (_stride[i], other._stride[i]);
+       }
+
+       std::swap (_aligned, other._aligned);
+}
+
 /** Destroy a SimpleImage */
 SimpleImage::~SimpleImage ()
 {
@@ -455,3 +561,4 @@ RGBPlusAlphaImage::~RGBPlusAlphaImage ()
 {
        av_free (_alpha);
 }
+
index 22758a6cf66f2f826939e670f344c1206185a2ab..13b92d72f11d0b48f98440932274ca9848eb6079 100644 (file)
@@ -74,6 +74,7 @@ public:
        boost::shared_ptr<Image> scale (Size, Scaler const *, bool aligned) const;
        boost::shared_ptr<Image> post_process (std::string, bool aligned) const;
        void alpha_blend (boost::shared_ptr<const Image> image, Position pos);
+       boost::shared_ptr<Image> crop (Crop c, bool aligned) const;
        
        void make_black ();
 
@@ -84,7 +85,11 @@ public:
                return _pixel_format;
        }
 
-private:
+protected:
+       virtual void swap (Image &);
+       float bytes_per_pixel (int) const;
+
+private:       
        AVPixelFormat _pixel_format; ///< FFmpeg's way of describing the pixel format of this Image
 };
 
@@ -103,6 +108,10 @@ public:
        Size size () const;
 
 private:
+       /* Not allowed */
+       FilterBufferImage (FilterBufferImage const &);
+       FilterBufferImage& operator= (FilterBufferImage const &);
+       
        AVFilterBufferRef* _buffer;
 };
 
@@ -113,6 +122,8 @@ class SimpleImage : public Image
 {
 public:
        SimpleImage (AVPixelFormat, Size, bool);
+       SimpleImage (SimpleImage const &);
+       SimpleImage& operator= (SimpleImage const &);
        SimpleImage (boost::shared_ptr<const Image>, bool aligned);
        ~SimpleImage ();
 
@@ -120,9 +131,12 @@ public:
        int * line_size () const;
        int * stride () const;
        Size size () const;
+
+protected:
+       void allocate ();
+       void swap (SimpleImage &);
        
 private:
-       
        Size _size; ///< size in pixels
        uint8_t** _data; ///< array of pointers to components
        int* _line_size; ///< array of sizes of the data in each line, in pixels (without any alignment padding bytes)
index 33bc5ee7bb4eb492f4bdb0490d5e00f91c4977e4..5713e68f9344696a224f468b0b29ff16c3d11876 100644 (file)
@@ -73,13 +73,13 @@ ImageMagickDecoder::pass ()
                return true;
        }
        
-       using namespace MagickCore;
-
        Magick::Image* magick_image = new Magick::Image (_film->content_path ());
        
        Size size = native_size ();
-       shared_ptr<SimpleImage> image (new SimpleImage (PIX_FMT_RGB24, size, false));
+       shared_ptr<Image> image (new SimpleImage (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) {
@@ -91,6 +91,8 @@ ImageMagickDecoder::pass ()
        }
 
        delete magick_image;
+
+       image = image->crop (_film->crop(), false);
        
        emit_video (image, 0);
 
@@ -111,10 +113,18 @@ ImageMagickDecoder::seek (SourceFrame f)
        _iter = _files.begin ();
        for (int i = 0; i < f; ++i) {
                if (_iter == _files.end()) {
-                       return false;
+                       return true;
                }
                ++_iter;
        }
        
-       return true;
+       return false;
+}
+
+void
+ImageMagickDecoder::film_changed (Film::Property p)
+{
+       if (p == Film::CROP) {
+               OutputChanged ();
+       }
 }
index 27ff71d83560bff8ff0cbe8d2323de62e2dcbd94..cf417d373e3906afee7aa9c4a09ba829bd436053 100644 (file)
@@ -81,6 +81,8 @@ protected:
        }
 
 private:
+       void film_changed (Film::Property);
+       
        std::list<std::string> _files;
        std::list<std::string>::iterator _iter;
 };
index 68088377b17aeb18b89f05c8c1624d36fb95e435..968257691bdbe5deba66b21eb202e9d10ce82075 100644 (file)
@@ -64,19 +64,32 @@ J2KStillEncoder::do_process_video (shared_ptr<Image> yuv, shared_ptr<Subtitle> s
        }
 
        string const real = _opt->frame_out_path (0, false);
-       for (int i = 1; i < (_film->still_duration() * 24); ++i) {
+       string const real_hash = _opt->hash_out_path (0, false);
+       for (int i = 1; i < (_film->still_duration() * _film->frames_per_second()); ++i) {
+
                if (!boost::filesystem::exists (_opt->frame_out_path (i, false))) {
-                       string const link = _opt->frame_out_path (i, false);
+                       link (real, _opt->frame_out_path (i, false));
+               }
+               
+               if (!boost::filesystem::exists (_opt->hash_out_path (i, false))) {
+                       link (real_hash, _opt->hash_out_path (i, false));
+               }
+               
+               frame_done ();
+       }
+}
+
+void
+J2KStillEncoder::link (string a, string b) const
+{
 #ifdef DVDOMATIC_POSIX                 
-                       int const r = symlink (real.c_str(), link.c_str());
-                       if (r) {
-                               throw EncodeError ("could not create symlink");
-                       }
+       int const r = symlink (a.c_str(), b.c_str());
+       if (r) {
+               throw EncodeError ("could not create symlink");
+       }
 #endif
+       
 #ifdef DVDOMATIC_WINDOWS
-                       boost::filesystem::copy_file (real, link);
+       boost::filesystem::copy_file (a, b);
 #endif                 
-               }
-               frame_done ();
-       }
 }
index 6069637d0c03e9db3453b5aac68cd60337a3c238..7c302474ca2cc7c2f3e44412a4c71e579ac84327 100644 (file)
@@ -40,4 +40,6 @@ public:
 private:
        void do_process_video (boost::shared_ptr<Image>, boost::shared_ptr<Subtitle>);
        void do_process_audio (boost::shared_ptr<AudioBuffers>) {}
+
+       void link (std::string, std::string) const;
 };
index 4457969f3399254b89f77be38b3d308ee1c54ce9..10cdfa8cdb659e31e1ebda9c9510dbda7e56c13c 100644 (file)
@@ -54,15 +54,11 @@ public:
         *  @param t true to return a temporary file path, otherwise a permanent one.
         *  @return The path to write this video frame to.
         */
-       std::string frame_out_path (SourceFrame f, bool t, std::string e = "") const {
-               if (e.empty ()) {
-                       e = _frame_out_extension;
-               }
-               
+       std::string frame_out_path (SourceFrame f, bool t) const {
                std::stringstream s;
                s << _frame_out_path << "/";
                s.width (8);
-               s << std::setfill('0') << f << e;
+               s << std::setfill('0') << f << _frame_out_extension;
 
                if (t) {
                        s << ".tmp";
@@ -71,6 +67,10 @@ public:
                return s.str ();
        }
 
+       std::string hash_out_path (SourceFrame f, bool t) const {
+               return frame_out_path (f, t) + ".md5";
+       }
+
        /** @return Path to write multichannel audio data to */
        std::string multichannel_audio_out_path () const {
                return _multichannel_audio_out_path;
index 54619c39f795067b11bc6c32e7d71b3dd139b539..477c73c753a686a889982f6b700efde3fa41483e 100644 (file)
@@ -117,7 +117,11 @@ TranscodeJob::remaining_time () const
                return 0;
        }
 
-       /* We assume that dcp_length() is valid */
+       if (!_film->dcp_length()) {
+               return 0;
+       }
+
+       /* We assume that dcp_length() is valid, if it is set */
        SourceFrame const left = _film->dcp_trim_start() + _film->dcp_length().get() - _encoder->video_frame();
        return left / fps;
 }
index c3be2a1743eb45b10bc2b65ceda60c5326c70d55..4c05d5fcdf335e931414e72e569125b4ef535fe2 100644 (file)
@@ -94,7 +94,7 @@ VideoDecoder::set_subtitle_stream (shared_ptr<SubtitleStream> s)
 void
 VideoDecoder::set_progress () const
 {
-       if (_job && _film->dcp_length()) {
+       if (_job && _film->length()) {
                _job->set_progress (float (_video_frame) / _film->length().get());
        }
 }
index 0243c6afc9e368ca0c3df2463d0002577252e463..4e7296a7ec488dbd97dc9ad94c46166d95ab6c95 100644 (file)
@@ -219,9 +219,9 @@ FilmEditor::make_video_panel ()
        pad->Add (_video_sizer, 0, wxALL, 8);
        _video_panel->SetSizer (pad);
 
-       video_control (add_label_to_sizer (_video_sizer, _video_panel, "Format"));
+       add_label_to_sizer (_video_sizer, _video_panel, "Format");
        _format = new wxComboBox (_video_panel, wxID_ANY, wxT (""), wxDefaultPosition, wxDefaultSize, 0, 0, wxCB_READONLY);
-       _video_sizer->Add (video_control (_format));
+       _video_sizer->Add (_format);
 
        {
                add_label_to_sizer (_video_sizer, _video_panel, "Crop");
index 8cc4776d1a53a1dc8078116ef8cea2d7b0fb23c3..9d024bca136a33d3ea08a09e7cb5ae2b5a8b3dd3 100644 (file)
@@ -205,6 +205,7 @@ void
 FilmViewer::seek_and_update (SourceFrame f)
 {
        if (_decoders.video->seek (f)) {
+               cout << "could not s&u to " << f << "\n";
                return;
        }
 
index 3f129c6e269318da147f87b83f74ac0ef8242754..ab5e01eb060f9c6bf24bd1b21837f53bf5df2a90 100644 (file)
@@ -2,6 +2,7 @@ version 1
 name fred
 use_dci_name 1
 content 
+trust_content_header 1
 dcp_content_type Short
 format 185
 left_crop 1
index 595492f7c1830ec9e85a87b83288ec148160b824..a3442b007500117924b88ce7df360210604411d2 100644 (file)
@@ -531,3 +531,93 @@ BOOST_AUTO_TEST_CASE (job_manager_test)
        BOOST_CHECK_EQUAL (b->running(), false);
 }
 
+BOOST_AUTO_TEST_CASE (compact_image_test)
+{
+       SimpleImage* s = new SimpleImage (PIX_FMT_RGB24, Size (50, 50), false);
+       BOOST_CHECK_EQUAL (s->components(), 1);
+       BOOST_CHECK_EQUAL (s->stride()[0], 50 * 3);
+       BOOST_CHECK_EQUAL (s->line_size()[0], 50 * 3);
+       BOOST_CHECK (s->data()[0]);
+       BOOST_CHECK (!s->data()[1]);
+       BOOST_CHECK (!s->data()[2]);
+       BOOST_CHECK (!s->data()[3]);
+
+       /* copy constructor */
+       SimpleImage* t = new SimpleImage (*s);
+       BOOST_CHECK_EQUAL (t->components(), 1);
+       BOOST_CHECK_EQUAL (t->stride()[0], 50 * 3);
+       BOOST_CHECK_EQUAL (t->line_size()[0], 50 * 3);
+       BOOST_CHECK (t->data()[0]);
+       BOOST_CHECK (!t->data()[1]);
+       BOOST_CHECK (!t->data()[2]);
+       BOOST_CHECK (!t->data()[3]);
+       BOOST_CHECK (t->data() != t->data());
+       BOOST_CHECK (t->data()[0] != t->data()[0]);
+       BOOST_CHECK (t->line_size() != t->line_size());
+       BOOST_CHECK (t->line_size()[0] != t->line_size()[0]);
+       BOOST_CHECK (t->stride() != t->stride());
+       BOOST_CHECK (t->stride()[0] != t->stride()[0]);
+
+       /* assignment operator */
+       SimpleImage* u = new SimpleImage (PIX_FMT_YUV422P, Size (150, 150), true);
+       *s = *u;
+       BOOST_CHECK_EQUAL (s->components(), 1);
+       BOOST_CHECK_EQUAL (s->stride()[0], 50 * 3);
+       BOOST_CHECK_EQUAL (s->line_size()[0], 50 * 3);
+       BOOST_CHECK (s->data()[0]);
+       BOOST_CHECK (!s->data()[1]);
+       BOOST_CHECK (!s->data()[2]);
+       BOOST_CHECK (!s->data()[3]);
+       BOOST_CHECK (s->data() != t->data());
+       BOOST_CHECK (s->data()[0] != t->data()[0]);
+       BOOST_CHECK (s->line_size() != t->line_size());
+       BOOST_CHECK (s->line_size()[0] != t->line_size()[0]);
+       BOOST_CHECK (s->stride() != t->stride());
+       BOOST_CHECK (s->stride()[0] != t->stride()[0]);
+}
+
+BOOST_AUTO_TEST_CASE (aligned_image_test)
+{
+       SimpleImage* s = new SimpleImage (PIX_FMT_RGB24, Size (50, 50), true);
+       BOOST_CHECK_EQUAL (s->components(), 1);
+       /* 160 is 150 aligned to the nearest 32 bytes */
+       BOOST_CHECK_EQUAL (s->stride()[0], 160);
+       BOOST_CHECK_EQUAL (s->line_size()[0], 150);
+       BOOST_CHECK (s->data()[0]);
+       BOOST_CHECK (!s->data()[1]);
+       BOOST_CHECK (!s->data()[2]);
+       BOOST_CHECK (!s->data()[3]);
+
+       /* copy constructor */
+       SimpleImage* t = new SimpleImage (*s);
+       BOOST_CHECK_EQUAL (t->components(), 1);
+       BOOST_CHECK_EQUAL (t->stride()[0], 160);
+       BOOST_CHECK_EQUAL (t->line_size()[0], 150);
+       BOOST_CHECK (t->data()[0]);
+       BOOST_CHECK (!t->data()[1]);
+       BOOST_CHECK (!t->data()[2]);
+       BOOST_CHECK (!t->data()[3]);
+       BOOST_CHECK (t->data() != t->data());
+       BOOST_CHECK (t->data()[0] != t->data()[0]);
+       BOOST_CHECK (t->line_size() != t->line_size());
+       BOOST_CHECK (t->line_size()[0] != t->line_size()[0]);
+       BOOST_CHECK (t->stride() != t->stride());
+       BOOST_CHECK (t->stride()[0] != t->stride()[0]);
+
+       /* assignment operator */
+       SimpleImage* u = new SimpleImage (PIX_FMT_YUV422P, Size (150, 150), false);
+       *s = *u;
+       BOOST_CHECK_EQUAL (s->components(), 1);
+       BOOST_CHECK_EQUAL (s->stride()[0], 160);
+       BOOST_CHECK_EQUAL (s->line_size()[0], 150);
+       BOOST_CHECK (s->data()[0]);
+       BOOST_CHECK (!s->data()[1]);
+       BOOST_CHECK (!s->data()[2]);
+       BOOST_CHECK (!s->data()[3]);
+       BOOST_CHECK (s->data() != t->data());
+       BOOST_CHECK (s->data()[0] != t->data()[0]);
+       BOOST_CHECK (s->line_size() != t->line_size());
+       BOOST_CHECK (s->line_size()[0] != t->line_size()[0]);
+       BOOST_CHECK (s->stride() != t->stride());
+       BOOST_CHECK (s->stride()[0] != t->stride()[0]);
+}