summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/ffmpeg_image_proxy.cc24
-rw-r--r--src/lib/ffmpeg_image_proxy.h6
-rw-r--r--src/lib/image.cc43
-rw-r--r--src/lib/image.h1
-rw-r--r--src/lib/image_decoder.cc2
-rw-r--r--src/lib/image_examiner.cc2
-rw-r--r--src/lib/types.cc28
-rw-r--r--src/lib/types.h5
-rw-r--r--src/lib/util.cc2
9 files changed, 103 insertions, 10 deletions
diff --git a/src/lib/ffmpeg_image_proxy.cc b/src/lib/ffmpeg_image_proxy.cc
index 602185bb8..c978fc383 100644
--- a/src/lib/ffmpeg_image_proxy.cc
+++ b/src/lib/ffmpeg_image_proxy.cc
@@ -30,6 +30,7 @@
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
+#include <libavutil/pixdesc.h>
}
DCPOMATIC_DISABLE_WARNINGS
#include <libxml++/libxml++.h>
@@ -48,23 +49,26 @@ using boost::optional;
using boost::dynamic_pointer_cast;
using dcp::raw_convert;
-FFmpegImageProxy::FFmpegImageProxy (boost::filesystem::path path)
+FFmpegImageProxy::FFmpegImageProxy (boost::filesystem::path path, VideoRange video_range)
: _data (path)
+ , _video_range (video_range)
, _pos (0)
, _path (path)
{
}
-FFmpegImageProxy::FFmpegImageProxy (dcp::ArrayData data)
+FFmpegImageProxy::FFmpegImageProxy (dcp::ArrayData data, VideoRange video_range)
: _data (data)
+ , _video_range (video_range)
, _pos (0)
{
}
-FFmpegImageProxy::FFmpegImageProxy (shared_ptr<cxml::Node>, shared_ptr<Socket> socket)
- : _pos (0)
+FFmpegImageProxy::FFmpegImageProxy (shared_ptr<cxml::Node> node, shared_ptr<Socket> socket)
+ : _video_range (string_to_video_range(node->string_child("VideoRange")))
+ , _pos (0)
{
uint32_t const size = socket->read_uint32 ();
_data = dcp::ArrayData (size);
@@ -188,7 +192,16 @@ FFmpegImageProxy::image (optional<dcp::Size>) const
throw DecodeError (N_("could not decode video"));
}
- _image.reset (new Image (frame));
+ AVPixelFormat const pix_fmt = static_cast<AVPixelFormat>(frame->format);
+
+ _image.reset (new Image(frame));
+ if (_video_range == VIDEO_RANGE_VIDEO && av_pix_fmt_desc_get(pix_fmt)->flags & AV_PIX_FMT_FLAG_RGB) {
+ /* Asking for the video range to be converted by libswscale (in Image) will not work for
+ * RGB sources since that method only processes video range in YUV and greyscale. So we have
+ * to do it ourselves here.
+ */
+ _image->video_range_to_full_range();
+ }
av_packet_unref (&packet);
av_frame_free (&frame);
@@ -206,6 +219,7 @@ void
FFmpegImageProxy::add_metadata (xmlpp::Node* node) const
{
node->add_child("Type")->add_child_text (N_("FFmpeg"));
+ node->add_child("VideoRange")->add_child_text(video_range_to_string(_video_range));
}
void
diff --git a/src/lib/ffmpeg_image_proxy.h b/src/lib/ffmpeg_image_proxy.h
index 62b99d280..4fca899f4 100644
--- a/src/lib/ffmpeg_image_proxy.h
+++ b/src/lib/ffmpeg_image_proxy.h
@@ -19,6 +19,7 @@
*/
#include "image_proxy.h"
+#include "types.h"
#include <dcp/array_data.h>
#include <boost/thread/mutex.hpp>
#include <boost/filesystem.hpp>
@@ -26,8 +27,8 @@
class FFmpegImageProxy : public ImageProxy
{
public:
- explicit FFmpegImageProxy (boost::filesystem::path);
- explicit FFmpegImageProxy (dcp::ArrayData);
+ explicit FFmpegImageProxy (boost::filesystem::path, VideoRange video_range);
+ explicit FFmpegImageProxy (dcp::ArrayData, VideoRange video_range);
FFmpegImageProxy (boost::shared_ptr<cxml::Node> xml, boost::shared_ptr<Socket> socket);
Result image (
@@ -44,6 +45,7 @@ public:
private:
dcp::ArrayData _data;
+ VideoRange _video_range;
mutable int64_t _pos;
/** Path of a file that this image came from, if applicable; stored so that
failed-decode errors can give more detail.
diff --git a/src/lib/image.cc b/src/lib/image.cc
index 03f1bf6dc..891715a46 100644
--- a/src/lib/image.cc
+++ b/src/lib/image.cc
@@ -1319,3 +1319,46 @@ Image::as_png () const
return dcp::ArrayData (state.data, state.size);
}
+
+
+void
+Image::video_range_to_full_range ()
+{
+ switch (_pixel_format) {
+ case AV_PIX_FMT_RGB24:
+ {
+ float const factor = 256.0 / 219.0;
+ uint8_t* p = data()[0];
+ int const lines = sample_size(0).height;
+ for (int y = 0; y < lines; ++y) {
+ uint8_t* q = p;
+ for (int x = 0; x < line_size()[0]; ++x) {
+ *q = int((*q - 16) * factor);
+ ++q;
+ }
+ p += stride()[0];
+ }
+ break;
+ }
+ case AV_PIX_FMT_GBRP12LE:
+ {
+ float const factor = 4096.0 / 3504.0;
+ for (int c = 0; c < 3; ++c) {
+ uint16_t* p = reinterpret_cast<uint16_t*>(data()[c]);
+ int const lines = sample_size(c).height;
+ for (int y = 0; y < lines; ++y) {
+ uint16_t* q = p;
+ int const line_size_pixels = line_size()[c] / 2;
+ for (int x = 0; x < line_size_pixels; ++x) {
+ *q = int((*q - 256) * factor);
+ ++q;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ throw PixelFormatError ("video_range_to_full_range()", _pixel_format);
+ }
+}
+
diff --git a/src/lib/image.h b/src/lib/image.h
index ab9b3c78a..c648fda1b 100644
--- a/src/lib/image.h
+++ b/src/lib/image.h
@@ -74,6 +74,7 @@ public:
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 video_range_to_full_range ();
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 15187b11b..7757cc4aa 100644
--- a/src/lib/image_decoder.cc
+++ b/src/lib/image_decoder.cc
@@ -70,7 +70,7 @@ ImageDecoder::pass ()
*/
_image.reset (new J2KImageProxy (path, _image_content->video->size(), pf));
} else {
- _image.reset (new FFmpegImageProxy (path));
+ _image.reset (new FFmpegImageProxy(path, _image_content->video->range()));
}
}
diff --git a/src/lib/image_examiner.cc b/src/lib/image_examiner.cc
index 6586a0d09..aa80d0daa 100644
--- a/src/lib/image_examiner.cc
+++ b/src/lib/image_examiner.cc
@@ -63,7 +63,7 @@ ImageExaminer::ImageExaminer (shared_ptr<const Film> film, shared_ptr<const Imag
}
delete[] buffer;
} else {
- FFmpegImageProxy proxy(content->path(0));
+ FFmpegImageProxy proxy(content->path(0), content->video->range());
_video_size = proxy.image().image->size();
}
diff --git a/src/lib/types.cc b/src/lib/types.cc
index e7acf6992..5687a5d48 100644
--- a/src/lib/types.cc
+++ b/src/lib/types.cc
@@ -229,3 +229,31 @@ bool operator== (NamedChannel const& a, NamedChannel const& b)
return a.name == b.name && a.index == b.index;
}
+
+string
+video_range_to_string (VideoRange r)
+{
+ switch (r) {
+ case VIDEO_RANGE_FULL:
+ return "full";
+ case VIDEO_RANGE_VIDEO:
+ return "video";
+ default:
+ DCPOMATIC_ASSERT (false);
+ }
+}
+
+
+VideoRange
+string_to_video_range (string s)
+{
+ if (s == "full") {
+ return VIDEO_RANGE_FULL;
+ } else if (s == "video") {
+ return VIDEO_RANGE_VIDEO;
+ }
+
+ DCPOMATIC_ASSERT (false);
+ return VIDEO_RANGE_FULL;
+}
+
diff --git a/src/lib/types.h b/src/lib/types.h
index 2ba0408ad..a10b26a63 100644
--- a/src/lib/types.h
+++ b/src/lib/types.h
@@ -139,12 +139,17 @@ enum ChangeType
CHANGE_TYPE_CANCELLED
};
+
enum VideoRange
{
VIDEO_RANGE_FULL, ///< full, or "JPEG" (0-255 for 8-bit)
VIDEO_RANGE_VIDEO ///< video, or "MPEG" (16-235 for 8-bit)
};
+extern std::string video_range_to_string (VideoRange r);
+extern VideoRange string_to_video_range (std::string s);
+
+
/** Type of captions.
*
* The generally accepted definitions seem to be:
diff --git a/src/lib/util.cc b/src/lib/util.cc
index ac868c173..0a060e960 100644
--- a/src/lib/util.cc
+++ b/src/lib/util.cc
@@ -953,7 +953,7 @@ void
emit_subtitle_image (ContentTimePeriod period, dcp::SubtitleImage sub, dcp::Size size, shared_ptr<TextDecoder> decoder)
{
/* XXX: this is rather inefficient; decoding the image just to get its size */
- FFmpegImageProxy proxy (sub.png_image());
+ FFmpegImageProxy proxy (sub.png_image(), VIDEO_RANGE_FULL);
shared_ptr<Image> image = proxy.image().image;
/* set up rect with height and width */
dcpomatic::Rect<double> rect(0, 0, image->size().width / double(size.width), image->size().height / double(size.height));