diff options
| author | Carl Hetherington <cth@carlh.net> | 2013-12-04 20:52:18 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2013-12-04 20:52:18 +0000 |
| commit | 98060a4e6f02b418f30b4b736e5880a357454c40 (patch) | |
| tree | 612a017ac6ab695a7dc5dffe49779a5a74fd1906 /src/lib | |
| parent | 70ee6cc5cef66a4aed252dbfa2390cc9f0c8c286 (diff) | |
Do lots of the player processing with less copying.
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/image.cc | 51 | ||||
| -rw-r--r-- | src/lib/image.h | 6 | ||||
| -rw-r--r-- | src/lib/image_decoder.cc | 2 | ||||
| -rw-r--r-- | src/lib/player.cc | 31 | ||||
| -rw-r--r-- | src/lib/position.h | 7 |
5 files changed, 70 insertions, 27 deletions
diff --git a/src/lib/image.cc b/src/lib/image.cc index 048cc4ab6..9d3f675f0 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -78,8 +78,9 @@ Image::components () const return d->nb_components; } +/** Crop this image, scale it to `inter_size' and then place it in a black frame of `out_size' */ shared_ptr<Image> -Image::scale (libdcp::Size out_size, Scaler const * scaler, AVPixelFormat result_format, bool result_aligned) const +Image::crop_scale_window (Crop crop, libdcp::Size inter_size, libdcp::Size out_size, Scaler const * scaler, AVPixelFormat out_format, bool out_aligned) const { assert (scaler); /* Empirical testing suggests that sws_scale() will crash if @@ -87,11 +88,55 @@ Image::scale (libdcp::Size out_size, Scaler const * scaler, AVPixelFormat result */ assert (aligned ()); - shared_ptr<Image> scaled (new Image (result_format, out_size, result_aligned)); + shared_ptr<Image> out (new Image (out_format, out_size, out_aligned)); + out->make_black (); + + libdcp::Size cropped_size = crop.apply (size ()); + + struct SwsContext* scale_context = sws_getContext ( + cropped_size.width, cropped_size.height, pixel_format(), + inter_size.width, inter_size.height, out_format, + scaler->ffmpeg_id (), 0, 0, 0 + ); + + uint8_t* scale_in_data[components()]; + for (int c = 0; c < components(); ++c) { + scale_in_data[c] = data()[c] + int (rint (bytes_per_pixel(c) * crop.left)) + stride()[c] * (crop.top / line_factor(c)); + } + + Position<int> const corner ((out_size.width - inter_size.width) / 2, (out_size.height - inter_size.height) / 2); + + uint8_t* scale_out_data[components()]; + for (int c = 0; c < components(); ++c) { + scale_out_data[c] = out->data()[c] + int (rint (out->bytes_per_pixel(c) * corner.x)) + out->stride()[c] * corner.y; + } + + sws_scale ( + scale_context, + scale_in_data, stride(), + 0, cropped_size.height, + scale_out_data, out->stride() + ); + + sws_freeContext (scale_context); + + return out; +} + +shared_ptr<Image> +Image::scale (libdcp::Size out_size, Scaler const * scaler, AVPixelFormat out_format, bool out_aligned) const +{ + assert (scaler); + /* Empirical testing suggests that sws_scale() will crash if + the input image is not aligned. + */ + assert (aligned ()); + + shared_ptr<Image> scaled (new Image (out_format, out_size, out_aligned)); struct SwsContext* scale_context = sws_getContext ( size().width, size().height, pixel_format(), - out_size.width, out_size.height, result_format, + out_size.width, out_size.height, out_format, scaler->ffmpeg_id (), 0, 0, 0 ); diff --git a/src/lib/image.h b/src/lib/image.h index e455f22c6..b12db3a14 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -59,11 +59,13 @@ public: boost::shared_ptr<Image> scale (libdcp::Size, Scaler const *, AVPixelFormat, bool aligned) const; boost::shared_ptr<Image> post_process (std::string, bool aligned) const; - void alpha_blend (boost::shared_ptr<const Image> image, Position<int> pos); - void copy (boost::shared_ptr<const Image> image, Position<int> pos); boost::shared_ptr<Image> crop (Crop c, bool aligned) const; + + boost::shared_ptr<Image> crop_scale_window (Crop c, libdcp::Size, libdcp::Size, Scaler const *, AVPixelFormat, bool aligned) const; void make_black (); + void alpha_blend (boost::shared_ptr<const Image> image, Position<int> pos); + void copy (boost::shared_ptr<const Image> image, Position<int> pos); void read_from_socket (boost::shared_ptr<Socket>); void write_to_socket (boost::shared_ptr<Socket>) const; diff --git a/src/lib/image_decoder.cc b/src/lib/image_decoder.cc index 498ff2e25..fb6053ae5 100644 --- a/src/lib/image_decoder.cc +++ b/src/lib/image_decoder.cc @@ -52,7 +52,7 @@ ImageDecoder::pass () return; } - Magick::Image* magick_image = new Magick::Image (_image_content->path(_video_position).string ()); + Magick::Image* magick_image = new Magick::Image (_image_content->path (_image_content->still() ? 0 : _video_position).string ()); libdcp::Size size (magick_image->columns(), magick_image->rows()); _image.reset (new Image (PIX_FMT_RGB24, size, true)); diff --git a/src/lib/player.cc b/src/lib/player.cc index 87b10a398..978db035f 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -270,29 +270,19 @@ Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image return; } - /* Convert to RGB first, as FFmpeg doesn't seem to like handling YUV images with odd widths */ - shared_ptr<Image> work_image = image->scale (image->size (), _film->scaler(), PIX_FMT_RGB24, true); - - work_image = work_image->crop (content->crop(), true); - + Time const time = content->position() + relative_time + extra - content->trim_start (); float const ratio = content->ratio() ? content->ratio()->ratio() : content->video_size_after_crop().ratio(); - libdcp::Size image_size = fit_ratio_within (ratio, _video_container_size); + libdcp::Size const image_size = fit_ratio_within (ratio, _video_container_size); - work_image = work_image->scale (image_size, _film->scaler(), PIX_FMT_RGB24, true); + shared_ptr<Image> work_image = image->crop_scale_window (content->crop(), image_size, _video_container_size, _film->scaler(), PIX_FMT_RGB24, false); - Time time = content->position() + relative_time + extra - content->trim_start (); - - if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) { - work_image->alpha_blend (_out_subtitle.image, _out_subtitle.position); - } + Position<int> const container_offset ( + (_video_container_size.width - image_size.width) / 2, + (_video_container_size.height - image_size.width) / 2 + ); - if (image_size != _video_container_size) { - assert (image_size.width <= _video_container_size.width); - assert (image_size.height <= _video_container_size.height); - shared_ptr<Image> im (new Image (PIX_FMT_RGB24, _video_container_size, true)); - im->make_black (); - im->copy (work_image, Position<int> ((_video_container_size.width - image_size.width) / 2, (_video_container_size.height - image_size.height) / 2)); - work_image = im; + if (_film->with_subtitles () && _out_subtitle.image && time >= _out_subtitle.from && time <= _out_subtitle.to) { + work_image->alpha_blend (_out_subtitle.image, _out_subtitle.position + container_offset); } #ifdef DCPOMATIC_DEBUG @@ -301,9 +291,8 @@ Player::process_video (weak_ptr<Piece> weak_piece, shared_ptr<const Image> image Video (work_image, eyes, content->colour_conversion(), same, time); - time += TIME_HZ / _film->video_frame_rate(); _last_emit_was_black = false; - _video_position = piece->video_position = time; + _video_position = piece->video_position = (time + TIME_HZ / _film->video_frame_rate()); if (frc.repeat > 1 && !piece->repeating ()) { piece->set_repeat (_last_incoming_video, frc.repeat - 1); diff --git a/src/lib/position.h b/src/lib/position.h index 8768bf5a8..f9bd0987c 100644 --- a/src/lib/position.h +++ b/src/lib/position.h @@ -43,4 +43,11 @@ public: T y; }; +template<class T> +Position<T> +operator+ (Position<T> const & a, Position<T> const & b) +{ + return Position<T> (a.x + b.x, a.y + b.y); +} + #endif |
