{
auto const comment = Config::instance()->dcp_j2k_comment();
- auto enc = dcp::compress_j2k (
- convert_to_xyz (_frame, boost::bind(&Log::dcp_log, dcpomatic_log.get(), _1, _2)),
- _j2k_bandwidth,
- _frames_per_second,
- _frame->eyes() == Eyes::LEFT || _frame->eyes() == Eyes::RIGHT,
- _resolution == Resolution::FOUR_K,
- comment.empty() ? "libdcp" : comment
+ ArrayData enc = {};
+ int constexpr minimum_size = 65536;
+
+ auto xyz = convert_to_xyz (_frame, boost::bind(&Log::dcp_log, dcpomatic_log.get(), _1, _2));
+ while (true) {
+ enc = dcp::compress_j2k (
+ xyz,
+ _j2k_bandwidth,
+ _frames_per_second,
+ _frame->eyes() == Eyes::LEFT || _frame->eyes() == Eyes::RIGHT,
+ _resolution == Resolution::FOUR_K,
+ comment.empty() ? "libdcp" : comment
);
+ if (enc.size() >= minimum_size) {
+ break;
+ }
+
+ /* The JPEG2000 is too low-bitrate for some decoders <cough>DSS200</cough> so add some noise
+ * and try again. This is slow but hopefully won't happen too often. We have to do
+ * convert_to_xyz() again because compress_j2k() corrupts its xyz parameter.
+ */
+
+ xyz = convert_to_xyz (_frame, boost::bind(&Log::dcp_log, dcpomatic_log.get(), _1, _2));
+ auto size = xyz->size ();
+ auto pixels = size.width * size.height;
+ for (auto c = 0; c < 3; ++c) {
+ auto p = xyz->data(c);
+ for (auto i = 0; i < pixels; ++i) {
+ *p = std::min(4095, std::max(0, *p + rand() % 2));
+ ++p;
+ }
+ }
+ }
+
switch (_frame->eyes()) {
case Eyes::BOTH:
LOG_DEBUG_ENCODE (N_("Finished locally-encoded frame %1 for mono"), _index);
--- /dev/null
+/*
+ Copyright (C) 2021 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ DCP-o-matic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#include "lib/dcp_video.h"
+#include "lib/image.h"
+#include "lib/player_video.h"
+#include "lib/raw_image_proxy.h"
+extern "C" {
+#include <libavutil/pixfmt.h>
+}
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+
+
+using std::make_shared;
+
+
+BOOST_AUTO_TEST_CASE (low_bitrate_test)
+{
+ auto image = make_shared<Image>(AV_PIX_FMT_RGB24, dcp::Size(1998, 1080), true);
+ image->make_black ();
+ auto proxy = make_shared<RawImageProxy>(image);
+ auto frame = make_shared<PlayerVideo>(proxy, Crop(), boost::optional<double>(), dcp::Size(1998, 1080), dcp::Size(1998, 1080), Eyes::BOTH, Part::WHOLE, boost::optional<ColourConversion>(), VideoRange::FULL, std::weak_ptr<Content>(), boost::optional<Frame>(), false);
+ auto dcp_video = make_shared<DCPVideo>(frame, 0, 24, 100000000, Resolution::TWO_K);
+ auto j2k = dcp_video->encode_locally();
+ BOOST_REQUIRE (j2k.size() >= 65536);
+}
+
+