AudioMapping audio_mapping,
int audio_channels,
function<AVPixelFormat (AVPixelFormat)> pixel_format,
+ VideoRange video_range,
bool aligned,
bool fast
)
, _audio_channels (audio_channels)
, _disable_audio (false)
, _pixel_format (pixel_format)
+ , _video_range (video_range)
, _aligned (aligned)
, _fast (fast)
{
/* If the weak_ptr cannot be locked the video obviously no longer requires any work */
if (video) {
LOG_TIMING("start-prepare in %1", thread_id());
- video->prepare (_pixel_format, _aligned, _fast);
+ video->prepare (_pixel_format, _video_range, _aligned, _fast);
LOG_TIMING("finish-prepare in %1", thread_id());
}
}
AudioMapping map,
int audio_channels,
boost::function<AVPixelFormat (AVPixelFormat)> pixel_format,
+ VideoRange video_range,
bool aligned,
bool fast
);
bool _disable_audio;
boost::function<AVPixelFormat (AVPixelFormat)> _pixel_format;
+ VideoRange _video_range;
bool _aligned;
bool _fast;
{
shared_ptr<dcp::OpenJPEGImage> xyz;
- shared_ptr<Image> image = frame->image (bind (&PlayerVideo::keep_xyz_or_rgb, _1), true, false);
+ shared_ptr<Image> image = frame->image (bind (&PlayerVideo::keep_xyz_or_rgb, _1), VIDEO_RANGE_FULL, true, false);
if (frame->colour_conversion()) {
xyz = dcp::rgb_to_xyz (
image->data()[0],
}
}
- _butler.reset (new Butler(_player, map, _output_audio_channels, bind(&PlayerVideo::force, _1, FFmpegFileEncoder::pixel_format(format)), true, false));
+ _butler.reset (
+ new Butler(_player, map, _output_audio_channels, bind(&PlayerVideo::force, _1, FFmpegFileEncoder::pixel_format(format)), VIDEO_RANGE_VIDEO, true, false)
+ );
}
void
FFmpegFileEncoder::video (shared_ptr<PlayerVideo> video, DCPTime time)
{
+ /* All our output formats are video range at the moment */
shared_ptr<Image> image = video->image (
bind (&PlayerVideo::force, _1, _pixel_format),
+ VIDEO_RANGE_VIDEO,
true,
false
);
* @param inter_size Size to scale the cropped image to.
* @param out_size Size of output frame; if this is larger than inter_size there will be black padding.
* @param yuv_to_rgb YUV to RGB transformation to use, if required.
+ * @param video_range Video range of the image.
* @param out_format Output pixel format.
* @param out_aligned true to make the output image aligned.
+ * @param out_video_range Video range to use for the output image.
* @param fast Try to be fast at the possible expense of quality; at present this means using
* fast bilinear rather than bicubic scaling.
*/
shared_ptr<Image>
Image::crop_scale_window (
- Crop crop, dcp::Size inter_size, dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, VideoRange video_range, AVPixelFormat out_format, bool out_aligned, bool fast
+ Crop crop,
+ dcp::Size inter_size,
+ dcp::Size out_size,
+ dcp::YUVToRGB yuv_to_rgb,
+ VideoRange video_range,
+ AVPixelFormat out_format,
+ VideoRange out_video_range,
+ bool out_aligned,
+ bool fast
) const
{
/* Empirical testing suggests that sws_scale() will crash if
1 -> destination range JPEG (i.e. "full", 0-255)
But remember: sws_setColorspaceDetails ignores these
- parameters unless the corresponding image isYUV or isGray.
- (If it's neither, it uses video range).
+ parameters unless the both source and destination images
+ are isYUV or isGray. (If either is not, it uses video range).
*/
sws_setColorspaceDetails (
scale_context,
sws_getCoefficients (lut[yuv_to_rgb]), video_range == VIDEO_RANGE_VIDEO ? 0 : 1,
- sws_getCoefficients (lut[yuv_to_rgb]), 1,
+ sws_getCoefficients (lut[yuv_to_rgb]), out_video_range == VIDEO_RANGE_VIDEO ? 0 : 1,
0, 1 << 16, 1 << 16
);
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> crop_scale_window (
- Crop crop, dcp::Size inter_size, dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, VideoRange video_range, AVPixelFormat out_format, bool aligned, bool fast
+ Crop crop,
+ dcp::Size inter_size,
+ dcp::Size out_size,
+ dcp::YUVToRGB yuv_to_rgb,
+ VideoRange video_range,
+ AVPixelFormat out_format,
+ VideoRange out_video_range,
+ bool aligned,
+ bool fast
) const;
void make_black ();
}
shared_ptr<Image>
-PlayerVideo::image (function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast) const
+PlayerVideo::image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const
{
/* XXX: this assumes that image() and prepare() are only ever called with the same parameters (except crop, inter size, out size, fade) */
boost::mutex::scoped_lock lm (_mutex);
if (!_image || _crop != _image_crop || _inter_size != _image_inter_size || _out_size != _image_out_size || _fade != _image_fade) {
- make_image (pixel_format, aligned, fast);
+ make_image (pixel_format, video_range, aligned, fast);
}
return _image;
}
* @param fast true to be fast at the expense of quality.
*/
void
-PlayerVideo::make_image (function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast) const
+PlayerVideo::make_image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const
{
_image_crop = _crop;
_image_inter_size = _inter_size;
}
_image = prox.image->crop_scale_window (
- total_crop, _inter_size, _out_size, yuv_to_rgb, _video_range, pixel_format (prox.image->pixel_format()), aligned, fast
+ total_crop, _inter_size, _out_size, yuv_to_rgb, _video_range, pixel_format (prox.image->pixel_format()), video_range, aligned, fast
);
if (_text) {
}
void
-PlayerVideo::prepare (function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast)
+PlayerVideo::prepare (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast)
{
_in->prepare (_inter_size);
boost::mutex::scoped_lock lm (_mutex);
if (!_image) {
- make_image (pixel_format, aligned, fast);
+ make_image (pixel_format, video_range, aligned, fast);
}
}
void set_text (PositionImage);
- void prepare (boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast);
- boost::shared_ptr<Image> image (boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast) const;
+ void prepare (boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast);
+ boost::shared_ptr<Image> image (boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const;
static AVPixelFormat force (AVPixelFormat, AVPixelFormat);
static AVPixelFormat keep_xyz_or_rgb (AVPixelFormat);
}
private:
- void make_image (boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, bool aligned, bool fast) const;
+ void make_image (boost::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const;
boost::shared_ptr<const ImageProxy> _in;
Crop _crop;
Config::instance()->audio_mapping(_audio_channels),
_audio_channels,
bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24),
+ VIDEO_RANGE_FULL,
false,
true
)
{
shared_ptr<PlayerVideo> pv = player_video().first;
if (pv) {
- set_image (pv->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true));
+ set_image (pv->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, true));
draw (pv->inter_position(), pv->inter_size());
_viewer->image_changed (pv);
}
_state_timer.set ("get image");
set_image (
- player_video().first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true)
+ player_video().first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, true)
);
_state_timer.set ("ImageChanged");
map.set (i, i, 1);
}
- Butler butler (shared_ptr<Player>(new Player(film)), map, 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, false);
+ Butler butler (shared_ptr<Player>(new Player(film)), map, 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, false);
BOOST_CHECK (butler.get_video(true, 0).second == DCPTime());
BOOST_CHECK (butler.get_video(true, 0).second == DCPTime::from_frames(1, 24));
AudioMapping(6, 6),
6,
bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24),
+ VIDEO_RANGE_FULL,
false,
true)
);
}
/* assuming DCP is 24fps/48kHz */
butler->get_audio (audio_buffer, 2000);
- p.first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true);
+ p.first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, true);
}
delete[] audio_buffer;
}
{
shared_ptr<FFmpegImageProxy> proxy(new FFmpegImageProxy("test/data/flat_red.png", VIDEO_RANGE_FULL));
shared_ptr<Image> raw = proxy->image().image;
- shared_ptr<Image> out = raw->crop_scale_window(Crop(), dcp::Size(1998, 836), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_YUV420P, true, false);
+ shared_ptr<Image> out = raw->crop_scale_window(
+ Crop(), dcp::Size(1998, 836), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_YUV420P, VIDEO_RANGE_FULL, true, false
+ );
shared_ptr<Image> save = out->scale(dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, AV_PIX_FMT_RGB24, false, false);
write_image(save, "build/test/crop_scale_window_test.png");
check_image("test/data/crop_scale_window_test.png", "build/test/crop_scale_window_test.png");
BOOST_AUTO_TEST_CASE (crop_scale_window_test2)
{
shared_ptr<Image> image (new Image(AV_PIX_FMT_XYZ12LE, dcp::Size(2048, 858), true));
- image->crop_scale_window (Crop(279, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_RGB24, false, false);
- image->crop_scale_window (Crop(2048, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_RGB24, false, false);
+ image->crop_scale_window (
+ Crop(279, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_RGB24, VIDEO_RANGE_FULL, false, false
+ );
+ image->crop_scale_window (
+ Crop(2048, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_RGB24, VIDEO_RANGE_FULL, false, false
+ );
}
BOOST_AUTO_TEST_CASE (crop_scale_window_test3)
{
shared_ptr<FFmpegImageProxy> proxy(new FFmpegImageProxy("test/data/player_seek_test_0.png", VIDEO_RANGE_FULL));
shared_ptr<Image> xyz = proxy->image().image->convert_pixel_format(dcp::YUV_TO_RGB_REC709, AV_PIX_FMT_RGB24, true, false);
- shared_ptr<Image> cropped = xyz->crop_scale_window(Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_RGB24, false, false);
+ shared_ptr<Image> cropped = xyz->crop_scale_window(
+ Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_RGB24, VIDEO_RANGE_FULL, false, false
+ );
write_image(cropped, "build/test/crop_scale_window_test3.png");
check_image("test/data/crop_scale_window_test3.png", "build/test/crop_scale_window_test3.png");
}
{
shared_ptr<FFmpegImageProxy> proxy(new FFmpegImageProxy("test/data/player_seek_test_0.png", VIDEO_RANGE_FULL));
shared_ptr<Image> xyz = proxy->image().image->convert_pixel_format(dcp::YUV_TO_RGB_REC709, AV_PIX_FMT_RGB24, true, false);
- shared_ptr<Image> cropped = xyz->crop_scale_window(Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_XYZ12LE, false, false);
+ shared_ptr<Image> cropped = xyz->crop_scale_window(
+ Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_XYZ12LE, VIDEO_RANGE_FULL, false, false
+ );
write_image(cropped, "build/test/crop_scale_window_test4.png");
check_image("test/data/crop_scale_window_test4.png", "build/test/crop_scale_window_test4.png", 35000);
}
{
shared_ptr<FFmpegImageProxy> proxy(new FFmpegImageProxy("test/data/player_seek_test_0.png", VIDEO_RANGE_FULL));
shared_ptr<Image> xyz = proxy->image().image->convert_pixel_format(dcp::YUV_TO_RGB_REC709, AV_PIX_FMT_XYZ12LE, true, false);
- shared_ptr<Image> cropped = xyz->crop_scale_window(Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_RGB24, false, false);
+ shared_ptr<Image> cropped = xyz->crop_scale_window(
+ Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_RGB24, VIDEO_RANGE_FULL, false, false
+ );
write_image(cropped, "build/test/crop_scale_window_test5.png");
check_image("test/data/crop_scale_window_test5.png", "build/test/crop_scale_window_test5.png");
}
{
shared_ptr<FFmpegImageProxy> proxy(new FFmpegImageProxy("test/data/player_seek_test_0.png", VIDEO_RANGE_FULL));
shared_ptr<Image> xyz = proxy->image().image->convert_pixel_format(dcp::YUV_TO_RGB_REC709, AV_PIX_FMT_XYZ12LE, true, false);
- shared_ptr<Image> cropped = xyz->crop_scale_window(Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_XYZ12LE, false, false);
+ shared_ptr<Image> cropped = xyz->crop_scale_window(
+ Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUV_TO_RGB_REC709, VIDEO_RANGE_FULL, AV_PIX_FMT_XYZ12LE, VIDEO_RANGE_FULL, false, false
+ );
write_image(cropped, "build/test/crop_scale_window_test6.png");
check_image("test/data/crop_scale_window_test6.png", "build/test/crop_scale_window_test6.png", 35000);
}
player->set_always_burn_open_subtitles ();
player->set_play_referenced ();
- shared_ptr<Butler> butler (new Butler (player, AudioMapping(), 2, bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true));
+ shared_ptr<Butler> butler (new Butler (player, AudioMapping(), 2, bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, true));
butler->disable_audio();
for (int i = 0; i < 10; ++i) {
butler->seek (t, true);
pair<shared_ptr<PlayerVideo>, DCPTime> video = butler->get_video(true, 0);
BOOST_CHECK_EQUAL(video.second.get(), t.get());
- write_image(video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true), String::compose("build/test/player_seek_test_%1.png", i));
+ write_image(video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, true), String::compose("build/test/player_seek_test_%1.png", i));
/* This 14.08 is empirically chosen (hopefully) to accept changes in rendering between the reference and a test machine
(17.10 and 16.04 seem to anti-alias a little differently) but to reject gross errors e.g. missing fonts or missing
text altogether.
player->set_always_burn_open_subtitles ();
player->set_play_referenced ();
- shared_ptr<Butler> butler (new Butler(player, AudioMapping(), 2, bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true));
+ shared_ptr<Butler> butler (new Butler(player, AudioMapping(), 2, bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, true));
butler->disable_audio();
butler->seek(DCPTime::from_seconds(5), true);
butler->seek (t, true);
pair<shared_ptr<PlayerVideo>, DCPTime> video = butler->get_video(true, 0);
BOOST_CHECK_EQUAL(video.second.get(), t.get());
- write_image(video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true), String::compose("build/test/player_seek_test2_%1.png", i));
+ write_image(
+ video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, true), String::compose("build/test/player_seek_test2_%1.png", i)
+ );
check_image(String::compose("test/data/player_seek_test2_%1.png", i), String::compose("build/test/player_seek_test2_%1.png", i), 14.08);
}
}
shared_ptr<Player> player (new Player(film));
player->set_fast ();
- shared_ptr<Butler> butler (new Butler(player, AudioMapping(), 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true));
+ shared_ptr<Butler> butler (new Butler(player, AudioMapping(), 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VIDEO_RANGE_FULL, false, true));
/* Wait for the butler to fill */
dcpomatic_sleep_seconds (5);