diff options
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/ffmpeg_image_proxy.cc | 24 | ||||
| -rw-r--r-- | src/lib/ffmpeg_image_proxy.h | 6 | ||||
| -rw-r--r-- | src/lib/image.cc | 43 | ||||
| -rw-r--r-- | src/lib/image.h | 1 | ||||
| -rw-r--r-- | src/lib/image_decoder.cc | 2 | ||||
| -rw-r--r-- | src/lib/image_examiner.cc | 2 | ||||
| -rw-r--r-- | src/lib/types.cc | 28 | ||||
| -rw-r--r-- | src/lib/types.h | 5 | ||||
| -rw-r--r-- | src/lib/util.cc | 2 |
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)); |
