99963c103cefa150eeb366359adcf4ab2e2967de
[dcpomatic.git] / src / lib / j2k_encoder_cpu_backend.cc
1 /*
2     Copyright (C) 2021 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21
22 #include "config.h"
23 #include "dcp_video.h"
24 #include "dcpomatic_log.h"
25 #include "j2k_encoder_cpu_backend.h"
26 #include "player_video.h"
27 #include "rng.h"
28 #include <dcp/openjpeg_image.h>
29 #include <dcp/j2k_transcode.h>
30
31 #include "i18n.h"
32
33
34 using std::shared_ptr;
35 using boost::optional;
36 #if BOOST_VERSION >= 106100
37 using namespace boost::placeholders;
38 #endif
39
40
41 optional<dcp::ArrayData>
42 J2KEncoderCPUBackend::encode (DCPVideo video)
43 {
44         try {
45                 auto const comment = Config::instance()->dcp_j2k_comment();
46
47                 /* This was empirically derived by a user: see #1902 */
48                 int const minimum_size = 16384;
49                 LOG_GENERAL ("Using minimum frame size %1", minimum_size);
50
51                 auto xyz = DCPVideo::convert_to_xyz (video.frame(), boost::bind(&Log::dcp_log, dcpomatic_log.get(), _1, _2));
52                 int noise_amount = 2;
53                 int pixel_skip = 16;
54                 while (true) {
55                         auto enc = dcp::compress_j2k (
56                                 xyz,
57                                 video.j2k_bandwidth(),
58                                 video.frames_per_second(),
59                                 video.frame()->eyes() == Eyes::LEFT || video.frame()->eyes() == Eyes::RIGHT,
60                                 video.resolution() == Resolution::FOUR_K,
61                                 comment.empty() ? "libdcp" : comment
62                         );
63
64                         if (enc.size() >= minimum_size) {
65                                 LOG_GENERAL (N_("Frame %1 encoded size was OK (%2)"), video.index(), enc.size());
66                                 return enc;
67                         }
68
69                         LOG_GENERAL (N_("Frame %1 encoded size was small (%2); adding noise at level %3 with pixel skip %4"), video.index(), enc.size(), noise_amount, pixel_skip);
70
71                         /* The JPEG2000 is too low-bitrate for some decoders <cough>DSS200</cough> so add some noise
72                          * and try again.  This is slow but hopefully won't happen too often.  We have to do
73                          * convert_to_xyz() again because compress_j2k() corrupts its xyz parameter.
74                          */
75
76                         xyz = DCPVideo::convert_to_xyz (video.frame(), boost::bind(&Log::dcp_log, dcpomatic_log.get(), _1, _2));
77                         auto const size = xyz->size ();
78                         auto const pixels = size.width * size.height;
79                         dcpomatic::RNG rng(42);
80                         for (auto c = 0; c < 3; ++c) {
81                                 auto p = xyz->data(c);
82                                 auto e = xyz->data(c) + pixels;
83                                 while (p < e) {
84                                         *p = std::min(4095, std::max(0, *p + (rng.get() % noise_amount)));
85                                         p += pixel_skip;
86                                 }
87                         }
88
89                         if (pixel_skip > 1) {
90                                 --pixel_skip;
91                         } else {
92                                 ++noise_amount;
93                         }
94                         /* Something's gone badly wrong if this much noise doesn't help */
95                         DCPOMATIC_ASSERT (noise_amount < 16);
96                 }
97
98                 switch (video.frame()->eyes()) {
99                 case Eyes::BOTH:
100                         LOG_DEBUG_ENCODE (N_("Finished locally-encoded frame %1 for mono"), video.index());
101                         break;
102                 case Eyes::LEFT:
103                         LOG_DEBUG_ENCODE (N_("Finished locally-encoded frame %1 for L"), video.index());
104                         break;
105                 case Eyes::RIGHT:
106                         LOG_DEBUG_ENCODE (N_("Finished locally-encoded frame %1 for R"), video.index());
107                         break;
108                 default:
109                         break;
110                 }
111         } catch (std::exception& e) {
112                 LOG_ERROR (N_("Local encode failed (%1)"), e.what());
113         }
114
115         return {};
116 }
117
118