summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2012-12-17 23:36:18 +0000
committerCarl Hetherington <cth@carlh.net>2012-12-17 23:36:18 +0000
commit8dd455ba867122056e2093e259a9a045aeeea451 (patch)
tree1e4ca9f9a413fc34acace48b28297fd3e4d26982 /src/lib
parentc421f6a5551f0755737f57fbeac6a0157599e0e8 (diff)
Various fixes to still-image mode.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/check_hashes_job.cc2
-rw-r--r--src/lib/dcp_video_frame.cc2
-rw-r--r--src/lib/decoder.cc2
-rw-r--r--src/lib/decoder.h7
-rw-r--r--src/lib/ffmpeg_decoder.cc2
-rw-r--r--src/lib/ffmpeg_decoder.h1
-rw-r--r--src/lib/film.cc4
-rw-r--r--src/lib/film.h4
-rw-r--r--src/lib/image.cc151
-rw-r--r--src/lib/image.h18
-rw-r--r--src/lib/imagemagick_decoder.cc20
-rw-r--r--src/lib/imagemagick_decoder.h2
-rw-r--r--src/lib/j2k_still_encoder.cc33
-rw-r--r--src/lib/j2k_still_encoder.h2
-rw-r--r--src/lib/options.h12
-rw-r--r--src/lib/transcode_job.cc6
-rw-r--r--src/lib/video_decoder.cc2
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());
}
}