2 Copyright (C) 2021 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
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.
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.
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/>.
23 #include "decoder_factory.h"
24 #include "image_proxy.h"
25 #include "guess_crop.h"
27 #include "video_decoder.h"
30 using std::shared_ptr;
31 using namespace dcpomatic;
35 guess_crop (shared_ptr<const Image> image, double threshold)
37 auto const width = image->size().width;
38 auto const height = image->size().height;
40 auto image_in_line = [image, threshold](int start_x, int start_y, int pixels, bool rows) {
43 switch (image->pixel_format()) {
44 case AV_PIX_FMT_RGB24:
46 uint8_t const* data = image->data()[0] + start_x * 3 + start_y * image->stride()[0];
47 for (int p = 0; p < pixels; ++p) {
48 /* Averaging R, G and B */
49 brightest = std::max(brightest, static_cast<double>(data[0] + data[1] + data[2]) / (3 * 256));
50 data += rows ? 3 : image->stride()[0];
54 case AV_PIX_FMT_YUV420P:
56 uint8_t const* data = image->data()[0] + start_x + start_y * image->stride()[0];
57 for (int p = 0; p < pixels; ++p) {
59 brightest = std::max(brightest, static_cast<double>(*data) / 256);
60 data += rows ? 1 : image->stride()[0];
65 DCPOMATIC_ASSERT (false);
68 return brightest > threshold;
73 for (auto y = 0; y < height; ++y) {
74 if (image_in_line(0, y, width, true)) {
80 for (auto y = height - 1; y >= 0; --y) {
81 if (image_in_line(0, y, width, true)) {
82 crop.bottom = height - 1 - y;
87 for (auto x = 0; x < width; ++x) {
88 if (image_in_line(x, 0, height, false)) {
94 for (auto x = width - 1; x >= 0; --x) {
95 if (image_in_line(x, 0, height, false)) {
96 crop.right = width - 1 - x;
105 /** @param position Time within the content to get a video frame from when guessing the crop */
107 guess_crop (shared_ptr<const Film> film, shared_ptr<const Content> content, double threshold, ContentTime position)
109 DCPOMATIC_ASSERT (content->video);
111 auto decoder = decoder_factory (film, content, false, false, {});
112 DCPOMATIC_ASSERT (decoder->video);
117 auto handle_video = [&done, &crop, threshold](ContentVideo video) {
118 crop = guess_crop(video.image->image(Image::Alignment::COMPACT).image, threshold);
122 decoder->video->Data.connect (handle_video);
123 decoder->seek (position, false);
126 while (!done && tries_left >= 0) {