summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2014-09-30 09:33:33 +0100
committerCarl Hetherington <cth@carlh.net>2014-09-30 20:38:12 +0100
commita4d8e5d24beddb719180e75f1047ae317bef85a4 (patch)
tree9884019a61aabfc0658d16e29cfd6a4b4a21c485 /src/lib
parent391d85619ac19a2a93696ddc35c222eb9bb5d9d6 (diff)
Basic video fade support.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/image.cc107
-rw-r--r--src/lib/image.h1
-rw-r--r--src/lib/magick_image_proxy.cc2
-rw-r--r--src/lib/player.cc2
-rw-r--r--src/lib/player_video.cc11
-rw-r--r--src/lib/player_video.h15
-rw-r--r--src/lib/video_content.cc52
-rw-r--r--src/lib/video_content.h19
-rw-r--r--src/lib/video_decoder.cc2
9 files changed, 209 insertions, 2 deletions
diff --git a/src/lib/image.cc b/src/lib/image.cc
index 0b06d39b1..0da2d1e48 100644
--- a/src/lib/image.cc
+++ b/src/lib/image.cc
@@ -717,3 +717,110 @@ operator== (Image const & a, Image const & b)
return true;
}
+
+void
+Image::fade (float f)
+{
+ switch (_pixel_format) {
+ case PIX_FMT_YUV420P:
+ case PIX_FMT_YUV422P:
+ case PIX_FMT_YUV444P:
+ case PIX_FMT_YUV411P:
+ case PIX_FMT_YUVJ420P:
+ case PIX_FMT_YUVJ422P:
+ case PIX_FMT_YUVJ444P:
+ case PIX_FMT_RGB24:
+ case PIX_FMT_ARGB:
+ case PIX_FMT_RGBA:
+ case PIX_FMT_ABGR:
+ case PIX_FMT_BGRA:
+ case PIX_FMT_RGB555LE:
+ /* 8-bit */
+ for (int c = 0; c < 3; ++c) {
+ uint8_t* p = data()[c];
+ for (int y = 0; y < lines(c); ++y) {
+ uint8_t* q = p;
+ for (int x = 0; x < line_size()[c]; ++x) {
+ *q = int (float (*q) * f);
+ ++q;
+ }
+ p += stride()[c];
+ }
+ }
+ break;
+
+ case PIX_FMT_YUV422P9LE:
+ case PIX_FMT_YUV444P9LE:
+ case PIX_FMT_YUV422P10LE:
+ case PIX_FMT_YUV444P10LE:
+ case PIX_FMT_YUV422P16LE:
+ case PIX_FMT_YUV444P16LE:
+ case AV_PIX_FMT_YUVA420P9LE:
+ case AV_PIX_FMT_YUVA422P9LE:
+ case AV_PIX_FMT_YUVA444P9LE:
+ case AV_PIX_FMT_YUVA420P10LE:
+ case AV_PIX_FMT_YUVA422P10LE:
+ case AV_PIX_FMT_YUVA444P10LE:
+ /* 16-bit little-endian */
+ for (int c = 0; c < 3; ++c) {
+ int const stride_pixels = stride()[c] / 2;
+ int const line_size_pixels = line_size()[c] / 2;
+ uint16_t* p = reinterpret_cast<uint16_t*> (data()[c]);
+ for (int y = 0; y < lines(c); ++y) {
+ uint16_t* q = p;
+ for (int x = 0; x < line_size_pixels; ++x) {
+ *q = int (float (*q) * f);
+ ++q;
+ }
+ p += stride_pixels;
+ }
+ }
+ break;
+
+ case PIX_FMT_YUV422P9BE:
+ case PIX_FMT_YUV444P9BE:
+ case PIX_FMT_YUV444P10BE:
+ case PIX_FMT_YUV422P10BE:
+ case AV_PIX_FMT_YUVA420P9BE:
+ case AV_PIX_FMT_YUVA422P9BE:
+ case AV_PIX_FMT_YUVA444P9BE:
+ case AV_PIX_FMT_YUVA420P10BE:
+ case AV_PIX_FMT_YUVA422P10BE:
+ case AV_PIX_FMT_YUVA444P10BE:
+ case AV_PIX_FMT_YUVA420P16BE:
+ case AV_PIX_FMT_YUVA422P16BE:
+ case AV_PIX_FMT_YUVA444P16BE:
+ /* 16-bit big-endian */
+ for (int c = 0; c < 3; ++c) {
+ int const stride_pixels = stride()[c] / 2;
+ int const line_size_pixels = line_size()[c] / 2;
+ uint16_t* p = reinterpret_cast<uint16_t*> (data()[c]);
+ for (int y = 0; y < lines(c); ++y) {
+ uint16_t* q = p;
+ for (int x = 0; x < line_size_pixels; ++x) {
+ *q = swap_16 (int (float (swap_16 (*q)) * f));
+ ++q;
+ }
+ p += stride_pixels;
+ }
+ }
+ break;
+
+ case PIX_FMT_UYVY422:
+ {
+ int const Y = lines(0);
+ int const X = line_size()[0];
+ uint8_t* p = data()[0];
+ for (int y = 0; y < Y; ++y) {
+ for (int x = 0; x < X; ++x) {
+ *p = int (float (*p) * f);
+ ++p;
+ }
+ }
+ break;
+ }
+
+ default:
+ throw PixelFormatError ("fade()", _pixel_format);
+ }
+}
diff --git a/src/lib/image.h b/src/lib/image.h
index e1f8d0ddd..172250eb1 100644
--- a/src/lib/image.h
+++ b/src/lib/image.h
@@ -67,6 +67,7 @@ public:
void make_transparent ();
void alpha_blend (boost::shared_ptr<const Image> image, Position<int> pos);
void copy (boost::shared_ptr<const Image> image, Position<int> pos);
+ void fade (float);
void read_from_socket (boost::shared_ptr<Socket>);
void write_to_socket (boost::shared_ptr<Socket>) const;
diff --git a/src/lib/magick_image_proxy.cc b/src/lib/magick_image_proxy.cc
index c3cfc422c..e5265187f 100644
--- a/src/lib/magick_image_proxy.cc
+++ b/src/lib/magick_image_proxy.cc
@@ -119,7 +119,7 @@ MagickImageProxy::image () const
delete magick_image;
LOG_TIMING ("[%1] MagickImageProxy completes decode and convert of %2 bytes", boost::this_thread::get_id(), _blob.length());
-
+
return _image;
}
diff --git a/src/lib/player.cc b/src/lib/player.cc
index f83c9563b..5961292ca 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -300,6 +300,7 @@ Player::black_player_video_frame (DCPTime time) const
shared_ptr<const ImageProxy> (new RawImageProxy (_black_image, _film->log ())),
time,
Crop (),
+ optional<float> (),
_video_container_size,
_video_container_size,
Scaler::from_id ("bicubic"),
@@ -356,6 +357,7 @@ Player::get_video (DCPTime time, bool accurate)
i->image,
content_video_to_dcp (piece, i->frame),
content->crop (),
+ content->fade (i->frame),
image_size,
_video_container_size,
_film->scaler(),
diff --git a/src/lib/player_video.cc b/src/lib/player_video.cc
index aab90a806..2feb52f42 100644
--- a/src/lib/player_video.cc
+++ b/src/lib/player_video.cc
@@ -34,6 +34,7 @@ PlayerVideo::PlayerVideo (
shared_ptr<const ImageProxy> in,
DCPTime time,
Crop crop,
+ boost::optional<float> fade,
dcp::Size inter_size,
dcp::Size out_size,
Scaler const * scaler,
@@ -44,6 +45,7 @@ PlayerVideo::PlayerVideo (
: _in (in)
, _time (time)
, _crop (crop)
+ , _fade (fade)
, _inter_size (inter_size)
, _out_size (out_size)
, _scaler (scaler)
@@ -58,6 +60,7 @@ PlayerVideo::PlayerVideo (shared_ptr<cxml::Node> node, shared_ptr<Socket> socket
{
_time = DCPTime (node->number_child<DCPTime::Type> ("Time"));
_crop = Crop (node);
+ _fade = node->optional_number_child<float> ("Fade");
_inter_size = dcp::Size (node->number_child<int> ("InterWidth"), node->number_child<int> ("InterHeight"));
_out_size = dcp::Size (node->number_child<int> ("OutWidth"), node->number_child<int> ("OutHeight"));
@@ -115,6 +118,10 @@ PlayerVideo::image (bool burn_subtitle) const
out->alpha_blend (_subtitle.image, _subtitle.position);
}
+ if (_fade) {
+ out->fade (_fade.get ());
+ }
+
return out;
}
@@ -123,6 +130,9 @@ PlayerVideo::add_metadata (xmlpp::Node* node, bool send_subtitles) const
{
node->add_child("Time")->add_child_text (raw_convert<string> (_time.get ()));
_crop.as_xml (node);
+ if (_fade) {
+ node->add_child("Fade")->add_child_text (raw_convert<string> (_fade.get ()));
+ }
_in->add_metadata (node->add_child ("In"));
node->add_child("InterWidth")->add_child_text (raw_convert<string> (_inter_size.width));
node->add_child("InterHeight")->add_child_text (raw_convert<string> (_inter_size.height));
@@ -184,6 +194,7 @@ PlayerVideo::same (shared_ptr<const PlayerVideo> other) const
{
if (_in != other->_in ||
_crop != other->_crop ||
+ _fade.get_value_or(0) != other->_fade.get_value_or(0) ||
_inter_size != other->_inter_size ||
_out_size != other->_out_size ||
_scaler != other->_scaler ||
diff --git a/src/lib/player_video.h b/src/lib/player_video.h
index 59894a227..0f5e83b10 100644
--- a/src/lib/player_video.h
+++ b/src/lib/player_video.h
@@ -37,7 +37,19 @@ class EncodedData;
class PlayerVideo
{
public:
- PlayerVideo (boost::shared_ptr<const ImageProxy>, DCPTime, Crop, dcp::Size, dcp::Size, Scaler const *, Eyes, Part, ColourConversion);
+ PlayerVideo (
+ boost::shared_ptr<const ImageProxy>,
+ DCPTime,
+ Crop,
+ boost::optional<float>,
+ dcp::Size,
+ dcp::Size,
+ Scaler const *,
+ Eyes,
+ Part,
+ ColourConversion
+ );
+
PlayerVideo (boost::shared_ptr<cxml::Node>, boost::shared_ptr<Socket>, boost::shared_ptr<Log>);
void set_subtitle (PositionImage);
@@ -76,6 +88,7 @@ private:
boost::shared_ptr<const ImageProxy> _in;
DCPTime _time;
Crop _crop;
+ boost::optional<float> _fade;
dcp::Size _inter_size;
dcp::Size _out_size;
Scaler const * _scaler;
diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc
index b5097b355..ba656e4c2 100644
--- a/src/lib/video_content.cc
+++ b/src/lib/video_content.cc
@@ -44,6 +44,8 @@ int const VideoContentProperty::VIDEO_FRAME_TYPE = 2;
int const VideoContentProperty::VIDEO_CROP = 3;
int const VideoContentProperty::VIDEO_SCALE = 4;
int const VideoContentProperty::COLOUR_CONVERSION = 5;
+int const VideoContentProperty::VIDEO_FADE_IN = 6;
+int const VideoContentProperty::VIDEO_FADE_OUT = 7;
using std::string;
using std::setprecision;
@@ -116,6 +118,10 @@ VideoContent::VideoContent (shared_ptr<const Film> f, cxml::ConstNodePtr node, i
}
_colour_conversion = ColourConversion (node->node_child ("ColourConversion"));
+ if (version >= 32) {
+ _fade_in = ContentTime (node->number_child<int64_t> ("FadeIn"));
+ _fade_out = ContentTime (node->number_child<int64_t> ("FadeOut"));
+ }
}
VideoContent::VideoContent (shared_ptr<const Film> f, vector<shared_ptr<Content> > c)
@@ -152,6 +158,10 @@ VideoContent::VideoContent (shared_ptr<const Film> f, vector<shared_ptr<Content>
throw JoinError (_("Content to be joined must have the same colour conversion."));
}
+ if (vc->fade_in() != ref->fade_in() || vc->fade_out() != ref->fade_out()) {
+ throw JoinError (_("Content to be joined must have the same fades."));
+ }
+
_video_length += vc->video_length ();
}
@@ -161,6 +171,8 @@ VideoContent::VideoContent (shared_ptr<const Film> f, vector<shared_ptr<Content>
_crop = ref->crop ();
_scale = ref->scale ();
_colour_conversion = ref->colour_conversion ();
+ _fade_in = ref->fade_in ();
+ _fade_out = ref->fade_out ();
}
void
@@ -175,6 +187,8 @@ VideoContent::as_xml (xmlpp::Node* node) const
_crop.as_xml (node);
_scale.as_xml (node->add_child("Scale"));
_colour_conversion.as_xml (node->add_child("ColourConversion"));
+ node->add_child("FadeIn")->add_child_text (raw_convert<string> (_fade_in.get ()));
+ node->add_child("FadeOut")->add_child_text (raw_convert<string> (_fade_out.get ()));
}
void
@@ -372,6 +386,28 @@ VideoContent::set_colour_conversion (ColourConversion c)
signal_changed (VideoContentProperty::COLOUR_CONVERSION);
}
+void
+VideoContent::set_fade_in (ContentTime t)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _fade_in = t;
+ }
+
+ signal_changed (VideoContentProperty::VIDEO_FADE_IN);
+}
+
+void
+VideoContent::set_fade_out (ContentTime t)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _fade_out = t;
+ }
+
+ signal_changed (VideoContentProperty::VIDEO_FADE_OUT);
+}
+
/** @return Video size after 3D split and crop */
dcp::Size
VideoContent::video_size_after_crop () const
@@ -431,3 +467,19 @@ VideoContent::set_video_frame_rate (float r)
signal_changed (VideoContentProperty::VIDEO_FRAME_RATE);
}
+optional<float>
+VideoContent::fade (VideoFrame f) const
+{
+ assert (f >= 0);
+
+ if (f < fade_in().frames (video_frame_rate ())) {
+ return float (f) / _fade_in.frames (video_frame_rate ());
+ }
+
+ VideoFrame fade_out_start = ContentTime (video_length() - fade_out()).frames (video_frame_rate ());
+ if (f >= fade_out_start) {
+ return 1 - float (f - fade_out_start) / fade_out().frames (video_frame_rate ());
+ }
+
+ return optional<float> ();
+}
diff --git a/src/lib/video_content.h b/src/lib/video_content.h
index b3c81d9c3..e88fb0227 100644
--- a/src/lib/video_content.h
+++ b/src/lib/video_content.h
@@ -36,6 +36,8 @@ public:
static int const VIDEO_CROP;
static int const VIDEO_SCALE;
static int const COLOUR_CONVERSION;
+ static int const VIDEO_FADE_IN;
+ static int const VIDEO_FADE_OUT;
};
class VideoContent : public virtual Content
@@ -88,6 +90,9 @@ public:
void set_scale (VideoContentScale);
void set_colour_conversion (ColourConversion);
+
+ void set_fade_in (ContentTime);
+ void set_fade_out (ContentTime);
VideoFrameType video_frame_type () const {
boost::mutex::scoped_lock lm (_mutex);
@@ -130,11 +135,23 @@ public:
return _colour_conversion;
}
+ ContentTime fade_in () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _fade_in;
+ }
+
+ ContentTime fade_out () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _fade_out;
+ }
+
dcp::Size video_size_after_3d_split () const;
dcp::Size video_size_after_crop () const;
ContentTime dcp_time_to_content_time (DCPTime) const;
+ boost::optional<float> fade (VideoFrame) const;
+
void scale_and_crop_to_fit_width ();
void scale_and_crop_to_fit_height ();
@@ -157,6 +174,8 @@ private:
Crop _crop;
VideoContentScale _scale;
ColourConversion _colour_conversion;
+ ContentTime _fade_in;
+ ContentTime _fade_out;
};
#endif
diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc
index 5dd078553..64c66ea55 100644
--- a/src/lib/video_decoder.cc
+++ b/src/lib/video_decoder.cc
@@ -19,12 +19,14 @@
#include "video_decoder.h"
#include "image.h"
+#include "image_proxy.h"
#include "content_video.h"
#include "i18n.h"
using std::cout;
using std::list;
+using std::max;
using boost::shared_ptr;
using boost::optional;