summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/black_content.h61
-rw-r--r--src/lib/black_decoder.cc43
-rw-r--r--src/lib/black_decoder.h28
-rw-r--r--src/lib/frame_interval_checker.h7
-rw-r--r--src/lib/player.cc111
-rw-r--r--src/lib/player.h2
-rw-r--r--src/lib/video_decoder.h12
-rw-r--r--src/lib/wscript1
8 files changed, 223 insertions, 42 deletions
diff --git a/src/lib/black_content.h b/src/lib/black_content.h
new file mode 100644
index 000000000..756bec55f
--- /dev/null
+++ b/src/lib/black_content.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2013-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 "content.h"
+#include "dcpomatic_time.h"
+#include "video_content.h"
+#include <iostream>
+#include <string>
+
+
+class BlackContent : public Content
+{
+public:
+ BlackContent (dcpomatic::DCPTimePeriod period, Eyes eyes)
+ : Content(period.from)
+ , _length(period.duration())
+ {
+ video = std::make_shared<VideoContent>(this);
+ if (eyes == Eyes::BOTH) {
+ video->set_frame_type(VideoFrameType::TWO_D);
+ } else if (eyes == Eyes::LEFT) {
+ video->set_frame_type(VideoFrameType::THREE_D_LEFT);
+ } else if (eyes == Eyes::RIGHT) {
+ video->set_frame_type(VideoFrameType::THREE_D_RIGHT);
+ }
+ }
+
+ std::string summary () const override {
+ return "black";
+ }
+
+ dcpomatic::DCPTime full_length (std::shared_ptr<const Film>) const override {
+ return _length;
+ }
+
+ dcpomatic::DCPTime approximate_length () const override {
+ return _length;
+ }
+
+private:
+ dcpomatic::DCPTime _length;
+};
+
diff --git a/src/lib/black_decoder.cc b/src/lib/black_decoder.cc
new file mode 100644
index 000000000..f316767bf
--- /dev/null
+++ b/src/lib/black_decoder.cc
@@ -0,0 +1,43 @@
+#include "black_content.h"
+#include "black_decoder.h"
+#include "image.h"
+#include "raw_image_proxy.h"
+#include "video_decoder.h"
+
+
+using std::make_shared;
+using std::shared_ptr;
+using namespace dcpomatic;
+
+
+BlackDecoder::BlackDecoder (shared_ptr<const Film> film, shared_ptr<const BlackContent> content)
+ : Decoder(film)
+ , _content(content)
+ , _video_frame_rate(film->video_frame_rate())
+{
+ video = make_shared<VideoDecoder>(this, content);
+ _image = make_shared<Image>(AV_PIX_FMT_RGB24, dcp::Size(128, 128), Image::Alignment::PADDED);
+ _image->make_black ();
+ _proxy = make_shared<const RawImageProxy>(_image);
+}
+
+
+void
+BlackDecoder::seek (ContentTime time, bool)
+{
+ _position = DCPTime(time.get());
+}
+
+
+bool
+BlackDecoder::pass ()
+{
+ if (_position >= _content->end(film())) {
+ return true;
+ }
+
+ video->emit(film(), _proxy, _position.frames_round(_video_frame_rate));
+ _position += DCPTime::from_frames(1, _video_frame_rate);
+ return false;
+}
+
diff --git a/src/lib/black_decoder.h b/src/lib/black_decoder.h
new file mode 100644
index 000000000..58741e11f
--- /dev/null
+++ b/src/lib/black_decoder.h
@@ -0,0 +1,28 @@
+#include "dcpomatic_time.h"
+#include "decoder.h"
+
+
+class BlackContent;
+class Image;
+class RawImageProxy;
+
+
+class BlackDecoder : public Decoder
+{
+public:
+ BlackDecoder (std::shared_ptr<const Film> film, std::shared_ptr<const BlackContent> content);
+
+ bool pass () override;
+ void seek (dcpomatic::ContentTime time, bool accurate) override;
+
+ dcpomatic::ContentTime position () const override {
+ return dcpomatic::ContentTime(_position.get());
+ }
+
+private:
+ std::shared_ptr<const BlackContent> _content;
+ int _video_frame_rate;
+ dcpomatic::DCPTime _position;
+ std::shared_ptr<Image> _image;
+ std::shared_ptr<const RawImageProxy> _proxy;
+};
diff --git a/src/lib/frame_interval_checker.h b/src/lib/frame_interval_checker.h
index e8f537c1a..8d8c6743e 100644
--- a/src/lib/frame_interval_checker.h
+++ b/src/lib/frame_interval_checker.h
@@ -19,6 +19,10 @@
*/
+#ifndef DCPOMATIC_FRAME_INTERVAL_CHECKER_H
+#define DCPOMATIC_FRAME_INTERVAL_CHECKER_H
+
+
#include "dcpomatic_time.h"
#include <boost/optional.hpp>
#include <vector>
@@ -53,3 +57,6 @@ private:
static int const _frames;
};
+
+#endif
+
diff --git a/src/lib/player.cc b/src/lib/player.cc
index feafd6f1f..43589c70a 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -24,6 +24,8 @@
#include "audio_content.h"
#include "audio_decoder.h"
#include "audio_processor.h"
+#include "black_content.h"
+#include "black_decoder.h"
#include "compose.hpp"
#include "config.h"
#include "content_audio.h"
@@ -145,6 +147,58 @@ Player::setup_pieces ()
void
+Player::add_black_pieces ()
+{
+ list<DCPTimePeriod> full_left;
+ list<DCPTimePeriod> full_right;
+ list<DCPTimePeriod> full_both;
+ for (auto i: playlist()->content()) {
+ if (i->video && i->video->use() && i->can_be_played() && i->paths_valid()) {
+ auto period = DCPTimePeriod(i->position(), i->end(_film));
+ if (i->video->frame_type() == VideoFrameType::THREE_D_LEFT) {
+ full_left.push_back (period);
+ } else if (i->video->frame_type() == VideoFrameType::THREE_D_RIGHT) {
+ full_right.push_back (period);
+ } else {
+ full_both.push_back (period);
+ }
+ }
+ }
+
+ auto const whole = DCPTimePeriod(DCPTime(), _playback_length);
+
+ auto empty_both = subtract(subtract(subtract({whole}, full_left), full_right), full_both);
+ auto empty_left = subtract(subtract(subtract({whole}, full_left), full_both), empty_both);
+ auto empty_right = subtract(subtract(subtract({whole}, full_right), full_both), empty_both);
+
+ list<pair<DCPTimePeriod, Eyes>> periods;
+
+ for (auto left: empty_left) {
+ periods.push_back (make_pair(left, Eyes::LEFT));
+ }
+
+ for (auto right: empty_right) {
+ periods.push_back (make_pair(right, Eyes::RIGHT));
+ }
+
+ for (auto both: empty_both) {
+ periods.push_back (make_pair(both, Eyes::BOTH));
+ }
+
+ periods.sort([](std::pair<DCPTimePeriod, Eyes> const& a, std::pair<DCPTimePeriod, Eyes> const& b) {
+ return a.first < b.first;
+ });
+
+ for (auto period: periods) {
+ LOG_DEBUG_PLAYER("BlackContent in period %1", to_string(period.first));
+ auto content = make_shared<BlackContent>(period.first, period.second);
+ auto decoder = make_shared<BlackDecoder>(_film, content);
+ _pieces.push_back(make_shared<Piece>(content, decoder, FrameRateChange(_film->video_frame_rate(), _film->video_frame_rate())));
+ }
+}
+
+
+void
Player::setup_pieces_unlocked ()
{
_playback_length = _playlist ? _playlist->length(_film) : _film->length();
@@ -214,38 +268,39 @@ Player::setup_pieces_unlocked ()
auto piece = make_shared<Piece>(i, decoder, frc);
_pieces.push_back (piece);
+ }
+
+
+ add_black_pieces ();
- if (decoder->video) {
+ for (auto piece: _pieces) {
+ if (piece->decoder->video) {
if (have_threed) {
/* We need a Shuffler to cope with 3D L/R video data arriving out of sequence */
- decoder->video->Data.connect (bind(&Shuffler::video, &_shuffler.get(), weak_ptr<Piece>(piece), _1));
+ piece->decoder->video->Data.connect(bind(&Shuffler::video, &_shuffler.get(), weak_ptr<Piece>(piece), _1));
} else {
- decoder->video->Data.connect (bind(&Player::video, this, weak_ptr<Piece>(piece), _1));
+ piece->decoder->video->Data.connect(bind(&Player::video, this, weak_ptr<Piece>(piece), _1));
}
}
- if (decoder->audio) {
- decoder->audio->Data.connect (bind (&Player::audio, this, weak_ptr<Piece> (piece), _1, _2));
+ if (piece->decoder->audio) {
+ piece->decoder->audio->Data.connect(bind(&Player::audio, this, weak_ptr<Piece>(piece), _1, _2));
}
- auto j = decoder->text.begin();
-
- while (j != decoder->text.end()) {
- (*j)->BitmapStart.connect (
- bind(&Player::bitmap_text_start, this, weak_ptr<Piece>(piece), weak_ptr<const TextContent>((*j)->content()), _1)
+ for (auto j: piece->decoder->text) {
+ j->BitmapStart.connect (
+ bind(&Player::bitmap_text_start, this, weak_ptr<Piece>(piece), weak_ptr<const TextContent>(j->content()), _1)
);
- (*j)->PlainStart.connect (
- bind(&Player::plain_text_start, this, weak_ptr<Piece>(piece), weak_ptr<const TextContent>((*j)->content()), _1)
+ j->PlainStart.connect (
+ bind(&Player::plain_text_start, this, weak_ptr<Piece>(piece), weak_ptr<const TextContent>(j->content()), _1)
);
- (*j)->Stop.connect (
- bind(&Player::subtitle_stop, this, weak_ptr<Piece>(piece), weak_ptr<const TextContent>((*j)->content()), _1)
+ j->Stop.connect (
+ bind(&Player::subtitle_stop, this, weak_ptr<Piece>(piece), weak_ptr<const TextContent>(j->content()), _1)
);
-
- ++j;
}
- if (decoder->atmos) {
- decoder->atmos->Data.connect (bind(&Player::atmos, this, weak_ptr<Piece>(piece), _1));
+ if (piece->decoder->atmos) {
+ piece->decoder->atmos->Data.connect(bind(&Player::atmos, this, weak_ptr<Piece>(piece), _1));
}
}
@@ -274,7 +329,6 @@ Player::setup_pieces_unlocked ()
}
}
- _black = EmptyVideo (_film, playlist(), _playback_length);
_silent = EmptyAudio (_film, playlist(), _playback_length);
_next_video_time = boost::none;
@@ -676,7 +730,6 @@ Player::pass ()
enum {
NONE,
CONTENT,
- BLACK,
SILENT
} which = NONE;
@@ -684,11 +737,6 @@ Player::pass ()
which = CONTENT;
}
- if (!_black.done() && !_ignore_video && (!earliest_time || _black.position() < *earliest_time)) {
- earliest_time = _black.position ();
- which = BLACK;
- }
-
if (!_silent.done() && !_ignore_audio && (!earliest_time || _silent.position() < *earliest_time)) {
earliest_time = _silent.position ();
which = SILENT;
@@ -697,7 +745,9 @@ Player::pass ()
switch (which) {
case CONTENT:
{
- LOG_DEBUG_PLAYER ("Calling pass() on %1", earliest_content->content->path(0));
+ if (earliest_content->content->number_of_paths()) {
+ LOG_DEBUG_PLAYER ("Calling pass() on %1", earliest_content->content->path(0));
+ }
earliest_content->done = earliest_content->decoder->pass ();
auto dcp = dynamic_pointer_cast<DCPContent>(earliest_content->content);
if (dcp && !_play_referenced && dcp->reference_audio()) {
@@ -709,14 +759,6 @@ Player::pass ()
}
break;
}
- case BLACK:
- {
- LOG_DEBUG_PLAYER ("Emit black for gap at %1", to_string(_black.position()));
- auto period = _black.period_at_position();
- emit_video (black_player_video_frame(period.second), _black.position());
- _black.set_position (_black.position() + one_video_frame());
- break;
- }
case SILENT:
{
LOG_DEBUG_PLAYER ("Emit silence for gap at %1", to_string(_silent.position()));
@@ -1270,7 +1312,6 @@ Player::seek (DCPTime time, bool accurate)
_next_audio_time = boost::none;
}
- _black.set_position (time);
_silent.set_position (time);
_last_video.clear ();
diff --git a/src/lib/player.h b/src/lib/player.h
index 3f83d9547..ed0027424 100644
--- a/src/lib/player.h
+++ b/src/lib/player.h
@@ -143,6 +143,7 @@ private:
dcpomatic::ContentTime dcp_to_content_time (std::shared_ptr<const Piece> piece, dcpomatic::DCPTime t) const;
dcpomatic::DCPTime content_time_to_dcp (std::shared_ptr<const Piece> piece, dcpomatic::ContentTime t) const;
std::shared_ptr<PlayerVideo> black_player_video_frame (Eyes eyes) const;
+ void add_black_pieces ();
void video (std::weak_ptr<Piece>, ContentVideo);
void audio (std::weak_ptr<Piece>, AudioStreamPtr, ContentAudio);
@@ -226,7 +227,6 @@ private:
};
std::map<AudioStreamPtr, StreamState> _stream_states;
- EmptyVideo _black;
EmptyAudio _silent;
ActiveText _active_texts[static_cast<int>(TextType::COUNT)];
diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h
index 828ac66a2..d8ed025e6 100644
--- a/src/lib/video_decoder.h
+++ b/src/lib/video_decoder.h
@@ -28,19 +28,19 @@
#define DCPOMATIC_VIDEO_DECODER_H
-#include "decoder.h"
-#include "video_content.h"
-#include "util.h"
+#include "frame_interval_checker.h"
#include "content_video.h"
+#include "decoder.h"
#include "decoder_part.h"
+#include "util.h"
+#include "video_content.h"
#include <boost/signals2.hpp>
-class VideoContent;
-class ImageProxy;
class Image;
+class ImageProxy;
class Log;
-class FrameIntervalChecker;
+class VideoContent;
/** @class VideoDecoder
diff --git a/src/lib/wscript b/src/lib/wscript
index f83adedbd..566d87c32 100644
--- a/src/lib/wscript
+++ b/src/lib/wscript
@@ -44,6 +44,7 @@ sources = """
audio_processor.cc
audio_ring_buffers.cc
audio_stream.cc
+ black_decoder.cc
butler.cc
text_content.cc
text_decoder.cc