diff options
| author | Carl Hetherington <cth@carlh.net> | 2012-12-17 23:36:18 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2012-12-17 23:36:18 +0000 |
| commit | 8dd455ba867122056e2093e259a9a045aeeea451 (patch) | |
| tree | 1e4ca9f9a413fc34acace48b28297fd3e4d26982 /src/lib | |
| parent | c421f6a5551f0755737f57fbeac6a0157599e0e8 (diff) | |
Various fixes to still-image mode.
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/check_hashes_job.cc | 2 | ||||
| -rw-r--r-- | src/lib/dcp_video_frame.cc | 2 | ||||
| -rw-r--r-- | src/lib/decoder.cc | 2 | ||||
| -rw-r--r-- | src/lib/decoder.h | 7 | ||||
| -rw-r--r-- | src/lib/ffmpeg_decoder.cc | 2 | ||||
| -rw-r--r-- | src/lib/ffmpeg_decoder.h | 1 | ||||
| -rw-r--r-- | src/lib/film.cc | 4 | ||||
| -rw-r--r-- | src/lib/film.h | 4 | ||||
| -rw-r--r-- | src/lib/image.cc | 151 | ||||
| -rw-r--r-- | src/lib/image.h | 18 | ||||
| -rw-r--r-- | src/lib/imagemagick_decoder.cc | 20 | ||||
| -rw-r--r-- | src/lib/imagemagick_decoder.h | 2 | ||||
| -rw-r--r-- | src/lib/j2k_still_encoder.cc | 33 | ||||
| -rw-r--r-- | src/lib/j2k_still_encoder.h | 2 | ||||
| -rw-r--r-- | src/lib/options.h | 12 | ||||
| -rw-r--r-- | src/lib/transcode_job.cc | 6 | ||||
| -rw-r--r-- | src/lib/video_decoder.cc | 2 |
17 files changed, 216 insertions, 54 deletions
diff --git a/src/lib/check_hashes_job.cc b/src/lib/check_hashes_job.cc index 50d86c523..701584c74 100644 --- a/src/lib/check_hashes_job.cc +++ b/src/lib/check_hashes_job.cc @@ -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)); diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 7099f73de..8b70b0aa4 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -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 (); diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index 507708345..7d4085045 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -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 diff --git a/src/lib/decoder.h b/src/lib/decoder.h index 0d35ebb3a..b8278ff80 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -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 diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index b93a81bc8..a05b331cc 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -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; } diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index 35688003e..2011ef72f 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -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; diff --git a/src/lib/film.cc b/src/lib/film.cc index b295bdc83..2e2ec368a 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -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> (); } diff --git a/src/lib/film.h b/src/lib/film.h index 642f2d7da..536855b1f 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -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; } diff --git a/src/lib/image.cc b/src/lib/image.cc index fb72d1aee..397c8bc9c 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -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. * @@ -298,6 +375,12 @@ SimpleImage::SimpleImage (AVPixelFormat p, Size s, bool aligned) , _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); } + diff --git a/src/lib/image.h b/src/lib/image.h index 22758a6cf..13b92d72f 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -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) diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index 33bc5ee7b..5713e68f9 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -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 (); + } } diff --git a/src/lib/imagemagick_decoder.h b/src/lib/imagemagick_decoder.h index 27ff71d83..cf417d373 100644 --- a/src/lib/imagemagick_decoder.h +++ b/src/lib/imagemagick_decoder.h @@ -81,6 +81,8 @@ protected: } private: + void film_changed (Film::Property); + std::list<std::string> _files; std::list<std::string>::iterator _iter; }; diff --git a/src/lib/j2k_still_encoder.cc b/src/lib/j2k_still_encoder.cc index 68088377b..968257691 100644 --- a/src/lib/j2k_still_encoder.cc +++ b/src/lib/j2k_still_encoder.cc @@ -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 (); - } } diff --git a/src/lib/j2k_still_encoder.h b/src/lib/j2k_still_encoder.h index 6069637d0..7c302474c 100644 --- a/src/lib/j2k_still_encoder.h +++ b/src/lib/j2k_still_encoder.h @@ -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; }; diff --git a/src/lib/options.h b/src/lib/options.h index 4457969f3..10cdfa8cd 100644 --- a/src/lib/options.h +++ b/src/lib/options.h @@ -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; diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index 54619c39f..477c73c75 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -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; } diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index c3be2a174..4c05d5fcd 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -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()); } } |
