diff options
| author | Carl Hetherington <cth@carlh.net> | 2018-07-11 09:19:22 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2018-07-11 09:19:22 +0100 |
| commit | 26f2e20607096cd285110c8ced9e32beb837b55e (patch) | |
| tree | 71ba60bf699b9a73ed44966492c30d579718dac0 /src/lib | |
| parent | 8e79595c7867a634d89fe9da37dc142d63182a02 (diff) | |
Keep information about the video range (full/JPEG or video/MPEG) in
Image and use it when setting up swscale.
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/dcp_video.cc | 2 | ||||
| -rw-r--r-- | src/lib/ffmpeg_decoder.cc | 8 | ||||
| -rw-r--r-- | src/lib/ffmpeg_encoder.cc | 2 | ||||
| -rw-r--r-- | src/lib/image.cc | 45 | ||||
| -rw-r--r-- | src/lib/image.h | 13 | ||||
| -rw-r--r-- | src/lib/j2k_image_proxy.cc | 2 | ||||
| -rw-r--r-- | src/lib/magick_image_proxy.cc | 2 | ||||
| -rw-r--r-- | src/lib/player.cc | 3 | ||||
| -rw-r--r-- | src/lib/player_video.cc | 6 | ||||
| -rw-r--r-- | src/lib/player_video.h | 2 | ||||
| -rw-r--r-- | src/lib/raw_image_proxy.cc | 3 | ||||
| -rw-r--r-- | src/lib/render_subtitles.cc | 2 |
12 files changed, 60 insertions, 30 deletions
diff --git a/src/lib/dcp_video.cc b/src/lib/dcp_video.cc index 655c37382..25fd02715 100644 --- a/src/lib/dcp_video.cc +++ b/src/lib/dcp_video.cc @@ -99,7 +99,7 @@ DCPVideo::convert_to_xyz (shared_ptr<const PlayerVideo> frame, dcp::NoteHandler { shared_ptr<dcp::OpenJPEGImage> xyz; - shared_ptr<Image> image = frame->image (note, bind (&PlayerVideo::keep_xyz_or_rgb, _1), true, false); + shared_ptr<Image> image = frame->image (note, bind (&PlayerVideo::keep_xyz_or_rgb, _1), true, true, false); if (frame->colour_conversion()) { xyz = dcp::rgb_to_xyz ( image->data()[0], diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 0746458e5..862cb3c26 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -87,7 +87,7 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const FFmpegContent> c, shared_ptr<Log> video.reset (new VideoDecoder (this, c, log)); _pts_offset = pts_offset (c->ffmpeg_audio_streams(), c->first_video(), c->active_video_frame_rate()); /* It doesn't matter what size or pixel format this is, it just needs to be black */ - _black_image.reset (new Image (AV_PIX_FMT_RGB24, dcp::Size (128, 128), true)); + _black_image.reset (new Image (AV_PIX_FMT_RGB24, true, dcp::Size (128, 128), true)); _black_image->make_black (); } else { _pts_offset = ContentTime (); @@ -498,6 +498,10 @@ FFmpegDecoder::decode_video_packet () return false; } + if (_frame->color_range == AVCOL_RANGE_UNSPECIFIED) { + _frame->color_range = AVCOL_RANGE_JPEG; + } + boost::mutex::scoped_lock lm (_filter_graphs_mutex); shared_ptr<VideoFilterGraph> graph; @@ -605,7 +609,7 @@ FFmpegDecoder::decode_bitmap_subtitle (AVSubtitleRect const * rect, ContentTime /* Note BGRA is expressed little-endian, so the first byte in the word is B, second G, third R, fourth A. */ - shared_ptr<Image> image (new Image (AV_PIX_FMT_BGRA, dcp::Size (rect->w, rect->h), true)); + shared_ptr<Image> image (new Image (AV_PIX_FMT_BGRA, true, dcp::Size (rect->w, rect->h), true)); #ifdef DCPOMATIC_HAVE_AVSUBTITLERECT_PICT /* Start of the first line in the subtitle */ diff --git a/src/lib/ffmpeg_encoder.cc b/src/lib/ffmpeg_encoder.cc index e55622abf..ea6bc7200 100644 --- a/src/lib/ffmpeg_encoder.cc +++ b/src/lib/ffmpeg_encoder.cc @@ -270,10 +270,12 @@ FFmpegEncoder::go () void FFmpegEncoder::video (shared_ptr<PlayerVideo> video, DCPTime time) { + /* XXX: what should full_range be here? */ shared_ptr<Image> image = video->image ( bind (&Log::dcp_log, _film->log().get(), _1, _2), bind (&force_pixel_format, _1, _pixel_format), true, + true, false ); diff --git a/src/lib/image.cc b/src/lib/image.cc index 08507ec5f..5ba4fd316 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -121,7 +121,7 @@ Image::planes () const */ shared_ptr<Image> Image::crop_scale_window ( - Crop crop, dcp::Size inter_size, dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_aligned, bool fast + Crop crop, dcp::Size inter_size, dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_full_range, bool out_aligned, bool fast ) const { /* Empirical testing suggests that sws_scale() will crash if @@ -154,7 +154,7 @@ Image::crop_scale_window ( To get around this, we ask Image to overallocate its buffers by the overrun. */ - shared_ptr<Image> out (new Image (out_format, out_size, out_aligned, (out_size.width - inter_size.width) / 2)); + shared_ptr<Image> out (new Image (out_format, out_full_range, out_size, out_aligned, (out_size.width - inter_size.width) / 2)); out->make_black (); /* Size of the image after any crop */ @@ -179,8 +179,8 @@ Image::crop_scale_window ( sws_setColorspaceDetails ( scale_context, - sws_getCoefficients (lut[yuv_to_rgb]), 0, - sws_getCoefficients (lut[yuv_to_rgb]), 0, + sws_getCoefficients (lut[yuv_to_rgb]), _full_range, + sws_getCoefficients (lut[yuv_to_rgb]), out_full_range, 0, 1 << 16, 1 << 16 ); @@ -229,9 +229,9 @@ Image::crop_scale_window ( } shared_ptr<Image> -Image::convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_aligned, bool fast) const +Image::convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_full_range, bool out_aligned, bool fast) const { - return scale(size(), yuv_to_rgb, out_format, out_aligned, fast); + return scale(size(), yuv_to_rgb, out_format, out_full_range, out_aligned, fast); } /** @param out_size Size to scale to. @@ -242,14 +242,14 @@ Image::convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, * fast bilinear rather than bicubic scaling. */ shared_ptr<Image> -Image::scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_aligned, bool fast) const +Image::scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_full_range, bool out_aligned, bool fast) const { /* Empirical testing suggests that sws_scale() will crash if the input image is not aligned. */ DCPOMATIC_ASSERT (aligned ()); - shared_ptr<Image> scaled (new Image (out_format, out_size, out_aligned)); + shared_ptr<Image> scaled (new Image (out_format, out_full_range, out_size, out_aligned)); struct SwsContext* scale_context = sws_getContext ( size().width, size().height, pixel_format(), @@ -581,7 +581,7 @@ Image::alpha_blend (shared_ptr<const Image> other, Position<int> position) } case AV_PIX_FMT_YUV420P: { - shared_ptr<Image> yuv = other->convert_pixel_format (dcp::YUV_TO_RGB_REC709, _pixel_format, false, false); + shared_ptr<Image> yuv = other->convert_pixel_format (dcp::YUV_TO_RGB_REC709, _pixel_format, _full_range, false, false); dcp::Size const ts = size(); dcp::Size const os = yuv->size(); for (int ty = start_ty, oy = start_oy; ty < ts.height && oy < os.height; ++ty, ++oy) { @@ -616,7 +616,7 @@ Image::alpha_blend (shared_ptr<const Image> other, Position<int> position) } case AV_PIX_FMT_YUV420P10: { - shared_ptr<Image> yuv = other->convert_pixel_format (dcp::YUV_TO_RGB_REC709, _pixel_format, false, false); + shared_ptr<Image> yuv = other->convert_pixel_format (dcp::YUV_TO_RGB_REC709, _pixel_format, _full_range, false, false); dcp::Size const ts = size(); dcp::Size const os = yuv->size(); for (int ty = start_ty, oy = start_oy; ty < ts.height && oy < os.height; ++ty, ++oy) { @@ -651,7 +651,7 @@ Image::alpha_blend (shared_ptr<const Image> other, Position<int> position) } case AV_PIX_FMT_YUV422P10LE: { - shared_ptr<Image> yuv = other->convert_pixel_format (dcp::YUV_TO_RGB_REC709, _pixel_format, false, false); + shared_ptr<Image> yuv = other->convert_pixel_format (dcp::YUV_TO_RGB_REC709, _pixel_format, _full_range, false, false); dcp::Size const ts = size(); dcp::Size const os = yuv->size(); for (int ty = start_ty, oy = start_oy; ty < ts.height && oy < os.height; ++ty, ++oy) { @@ -782,9 +782,10 @@ Image::bytes_per_pixel (int c) const * @param aligned true to make each row of this image aligned to a 32-byte boundary. * @param extra_pixels Amount of extra "run-off" memory to allocate at the end of each plane in pixels. */ -Image::Image (AVPixelFormat p, dcp::Size s, bool aligned, int extra_pixels) +Image::Image (AVPixelFormat p, bool f, dcp::Size s, bool aligned, int extra_pixels) : _size (s) , _pixel_format (p) + , _full_range (f) , _aligned (aligned) , _extra_pixels (extra_pixels) { @@ -829,6 +830,7 @@ Image::Image (Image const & other) : boost::enable_shared_from_this<Image>(other) , _size (other._size) , _pixel_format (other._pixel_format) + , _full_range (other._full_range) , _aligned (other._aligned) , _extra_pixels (other._extra_pixels) { @@ -865,11 +867,23 @@ Image::Image (AVFrame* frame) q += frame->linesize[i]; } } + + switch (frame->color_range) { + case AVCOL_RANGE_MPEG: + _full_range = false; + break; + case AVCOL_RANGE_JPEG: + _full_range = true; + break; + default: + DCPOMATIC_ASSERT (false); + } } Image::Image (shared_ptr<const Image> other, bool aligned) : _size (other->_size) , _pixel_format (other->_pixel_format) + , _full_range (other->_full_range) , _aligned (aligned) , _extra_pixels (other->_extra_pixels) { @@ -905,6 +919,7 @@ Image::swap (Image & other) { std::swap (_size, other._size); std::swap (_pixel_format, other._pixel_format); + std::swap (_full_range, other._full_range); for (int i = 0; i < 4; ++i) { std::swap (_data[i], other._data[i]); @@ -974,7 +989,7 @@ merge (list<PositionImage> images) all.extend (dcpomatic::Rect<int> (i->position, i->image->size().width, i->image->size().height)); } - shared_ptr<Image> merged (new Image (images.front().image->pixel_format (), dcp::Size (all.width, all.height), true)); + shared_ptr<Image> merged (new Image (images.front().image->pixel_format(), images.front().image->full_range(), dcp::Size (all.width, all.height), true)); merged->make_transparent (); for (list<PositionImage>::const_iterator i = images.begin(); i != images.end(); ++i) { merged->alpha_blend (i->image, i->position - all.position()); @@ -986,7 +1001,7 @@ merge (list<PositionImage> images) bool operator== (Image const & a, Image const & b) { - if (a.planes() != b.planes() || a.pixel_format() != b.pixel_format() || a.aligned() != b.aligned()) { + if (a.planes() != b.planes() || a.pixel_format() != b.pixel_format() || a.full_range() != b.full_range() || a.aligned() != b.aligned()) { return false; } @@ -1156,6 +1171,8 @@ Image::as_png () const using namespace MagickLib; #endif + /* XXX: take full_range into account here */ + string format; switch (_pixel_format) { case AV_PIX_FMT_RGB24: diff --git a/src/lib/image.h b/src/lib/image.h index 73f2313c1..c1742401b 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -41,7 +41,7 @@ class Socket; class Image : public boost::enable_shared_from_this<Image> { public: - Image (AVPixelFormat p, dcp::Size s, bool aligned, int extra_pixels = 0); + Image (AVPixelFormat p, bool full_range, dcp::Size s, bool aligned, int extra_pixels = 0); explicit Image (AVFrame *); explicit Image (Image const &); Image (boost::shared_ptr<const Image>, bool); @@ -60,10 +60,10 @@ public: dcp::Size sample_size (int) const; float bytes_per_pixel (int) const; - boost::shared_ptr<Image> convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool aligned, bool fast) const; - boost::shared_ptr<Image> scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool aligned, bool fast) const; + boost::shared_ptr<Image> convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_full_range, bool aligned, bool fast) const; + boost::shared_ptr<Image> scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_full_range, bool aligned, bool fast) const; boost::shared_ptr<Image> crop_scale_window ( - Crop crop, dcp::Size inter_size, dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool aligned, bool fast + Crop crop, dcp::Size inter_size, dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_full_range, bool out_aligned, bool fast ) const; void make_black (); @@ -79,6 +79,10 @@ public: return _pixel_format; } + bool full_range () const { + return _full_range; + } + size_t memory_used () const; dcp::Data as_png () const; @@ -95,6 +99,7 @@ private: dcp::Size _size; AVPixelFormat _pixel_format; ///< FFmpeg's way of describing the pixel format of this Image + bool _full_range; uint8_t** _data; ///< array of pointers to components int* _line_size; ///< array of sizes of the data in each line, in bytes (without any alignment padding bytes) int* _stride; ///< array of strides for each line, in bytes (including any alignment padding bytes) diff --git a/src/lib/j2k_image_proxy.cc b/src/lib/j2k_image_proxy.cc index 9100414e4..916723052 100644 --- a/src/lib/j2k_image_proxy.cc +++ b/src/lib/j2k_image_proxy.cc @@ -157,7 +157,7 @@ J2KImageProxy::image (optional<dcp::NoteHandler>, optional<dcp::Size> target_siz { int const reduce = prepare (target_size); - shared_ptr<Image> image (new Image (_pixel_format, _decompressed->size(), true)); + shared_ptr<Image> image (new Image (_pixel_format, true, _decompressed->size(), true)); /* Copy data in whatever format (sRGB or XYZ) into our Image; I'm assuming the data is 12-bit either way. diff --git a/src/lib/magick_image_proxy.cc b/src/lib/magick_image_proxy.cc index b12a81db5..d47c43275 100644 --- a/src/lib/magick_image_proxy.cc +++ b/src/lib/magick_image_proxy.cc @@ -122,7 +122,7 @@ MagickImageProxy::image (optional<dcp::NoteHandler>, optional<dcp::Size>) const dcp::Size size (magick_image->columns(), magick_image->rows()); - _image.reset (new Image (AV_PIX_FMT_RGB24, size, true)); + _image.reset (new Image (AV_PIX_FMT_RGB24, true, size, true)); /* Write line-by-line here as _image must be aligned, and write() cannot be told about strides */ uint8_t* p = _image->data()[0]; diff --git a/src/lib/player.cc b/src/lib/player.cc index df58ed223..118535f31 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -251,7 +251,7 @@ Player::set_video_container_size (dcp::Size s) _video_container_size = s; - _black_image.reset (new Image (AV_PIX_FMT_RGB24, _video_container_size, true)); + _black_image.reset (new Image (AV_PIX_FMT_RGB24, true,_video_container_size, true)); _black_image->make_black (); Changed (PlayerProperty::VIDEO_CONTAINER_SIZE, false); @@ -309,6 +309,7 @@ Player::transform_image_subtitles (list<ImageSubtitle> subs) const dcp::YUV_TO_RGB_REC601, i->image->pixel_format (), true, + true, _fast ), Position<int> ( diff --git a/src/lib/player_video.cc b/src/lib/player_video.cc index a50b196a2..498b563dd 100644 --- a/src/lib/player_video.cc +++ b/src/lib/player_video.cc @@ -87,7 +87,7 @@ PlayerVideo::PlayerVideo (shared_ptr<cxml::Node> node, shared_ptr<Socket> socket if (node->optional_number_child<int> ("SubtitleX")) { shared_ptr<Image> image ( - new Image (AV_PIX_FMT_BGRA, dcp::Size (node->number_child<int> ("SubtitleWidth"), node->number_child<int> ("SubtitleHeight")), true) + new Image (AV_PIX_FMT_BGRA, true, dcp::Size (node->number_child<int> ("SubtitleWidth"), node->number_child<int> ("SubtitleHeight")), true) ); image->read_from_socket (socket); @@ -111,7 +111,7 @@ PlayerVideo::set_subtitle (PositionImage image) * @param fast true to be fast at the expense of quality. */ shared_ptr<Image> -PlayerVideo::image (dcp::NoteHandler note, function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast) const +PlayerVideo::image (dcp::NoteHandler note, function<AVPixelFormat (AVPixelFormat)> pixel_format, bool full_range, bool aligned, bool fast) const { pair<shared_ptr<Image>, int> prox = _in->image (optional<dcp::NoteHandler> (note), _inter_size); shared_ptr<Image> im = prox.first; @@ -150,7 +150,7 @@ PlayerVideo::image (dcp::NoteHandler note, function<AVPixelFormat (AVPixelFormat } shared_ptr<Image> out = im->crop_scale_window ( - total_crop, _inter_size, _out_size, yuv_to_rgb, pixel_format (_in->pixel_format()), aligned, fast + total_crop, _inter_size, _out_size, yuv_to_rgb, pixel_format (_in->pixel_format()), full_range, aligned, fast ); if (_subtitle) { diff --git a/src/lib/player_video.h b/src/lib/player_video.h index f4bf2a471..7946573ee 100644 --- a/src/lib/player_video.h +++ b/src/lib/player_video.h @@ -63,7 +63,7 @@ public: void set_subtitle (PositionImage); void prepare (); - boost::shared_ptr<Image> image (dcp::NoteHandler note, boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast) const; + boost::shared_ptr<Image> image (dcp::NoteHandler note, boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, bool full_range, bool aligned, bool fast) const; static AVPixelFormat always_rgb (AVPixelFormat); static AVPixelFormat keep_xyz_or_rgb (AVPixelFormat); diff --git a/src/lib/raw_image_proxy.cc b/src/lib/raw_image_proxy.cc index c3b565f3c..6403e7358 100644 --- a/src/lib/raw_image_proxy.cc +++ b/src/lib/raw_image_proxy.cc @@ -50,7 +50,7 @@ RawImageProxy::RawImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> soc xml->number_child<int> ("Width"), xml->number_child<int> ("Height") ); - _image.reset (new Image (static_cast<AVPixelFormat> (xml->number_child<int> ("PixelFormat")), size, true)); + _image.reset (new Image (static_cast<AVPixelFormat> (xml->number_child<int>("PixelFormat")), xml->bool_child("FullRange"), size, true)); _image->read_from_socket (socket); } @@ -67,6 +67,7 @@ RawImageProxy::add_metadata (xmlpp::Node* node) const node->add_child("Width")->add_child_text (raw_convert<string> (_image->size().width)); node->add_child("Height")->add_child_text (raw_convert<string> (_image->size().height)); node->add_child("PixelFormat")->add_child_text (raw_convert<string> (static_cast<int> (_image->pixel_format ()))); + node->add_child("FullRange")->add_child_text (_image->full_range() ? "1" : "0"); } void diff --git a/src/lib/render_subtitles.cc b/src/lib/render_subtitles.cc index 35fcd8b93..61b09ecc1 100644 --- a/src/lib/render_subtitles.cc +++ b/src/lib/render_subtitles.cc @@ -130,7 +130,7 @@ render_line (list<SubtitleString> subtitles, list<shared_ptr<Font> > fonts, dcp: height += target.height / 11; /* FFmpeg BGRA means first byte blue, second byte green, third byte red, fourth byte alpha */ - shared_ptr<Image> image (new Image (AV_PIX_FMT_BGRA, dcp::Size (target.width, height), false)); + shared_ptr<Image> image (new Image (AV_PIX_FMT_BGRA, true, dcp::Size (target.width, height), false)); image->make_black (); #ifdef DCPOMATIC_HAVE_FORMAT_STRIDE_FOR_WIDTH |
