summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2021-05-05 22:27:01 +0200
committerCarl Hetherington <cth@carlh.net>2021-05-07 09:29:59 +0200
commit1b998e92e4313e728389a39408bd67919649c5cb (patch)
tree58dffdfea4f1b9bfa5b2acc6b1126ad405de013d
parentd067680769d0be2931605caeebc03ea9e77c6aa7 (diff)
fixup! WIP: allow Piece to take multiple content/decoder.
-rw-r--r--src/lib/atmos_mxf_decoder.cc2
-rw-r--r--src/lib/atmos_mxf_decoder.h3
-rw-r--r--src/lib/dcp_decoder.cc2
-rw-r--r--src/lib/dcp_decoder.h2
-rw-r--r--src/lib/dcp_subtitle_decoder.cc2
-rw-r--r--src/lib/dcp_subtitle_decoder.h3
-rw-r--r--src/lib/decoder.cc10
-rw-r--r--src/lib/decoder.h15
-rw-r--r--src/lib/ffmpeg_decoder.cc3
-rw-r--r--src/lib/ffmpeg_decoder.h2
-rw-r--r--src/lib/image_decoder.cc2
-rw-r--r--src/lib/image_decoder.h2
-rw-r--r--src/lib/piece.cc59
-rw-r--r--src/lib/piece.h2
-rw-r--r--src/lib/player.cc1
-rw-r--r--src/lib/string_text_file_decoder.cc2
-rw-r--r--src/lib/string_text_file_decoder.h3
-rw-r--r--src/lib/video_mxf_decoder.cc2
-rw-r--r--src/lib/video_mxf_decoder.h2
-rw-r--r--src/wx/text_view.cc4
-rw-r--r--test/dcp_subtitle_test.cc10
-rw-r--r--test/ffmpeg_decoder_seek_test.cc30
-rw-r--r--test/video_level_test.cc6
23 files changed, 104 insertions, 65 deletions
diff --git a/src/lib/atmos_mxf_decoder.cc b/src/lib/atmos_mxf_decoder.cc
index 9fcd9d2a6..2c31157e0 100644
--- a/src/lib/atmos_mxf_decoder.cc
+++ b/src/lib/atmos_mxf_decoder.cc
@@ -45,7 +45,7 @@ AtmosMXFDecoder::AtmosMXFDecoder (std::shared_ptr<const Film> film, std::shared_
bool
-AtmosMXFDecoder::pass ()
+AtmosMXFDecoder::do_pass ()
{
auto const vfr = _content->active_video_frame_rate (film());
auto const frame = _next.frames_round (vfr);
diff --git a/src/lib/atmos_mxf_decoder.h b/src/lib/atmos_mxf_decoder.h
index b8e7fc53d..e5b306690 100644
--- a/src/lib/atmos_mxf_decoder.h
+++ b/src/lib/atmos_mxf_decoder.h
@@ -33,10 +33,11 @@ class AtmosMXFDecoder : public Decoder
public:
AtmosMXFDecoder (std::shared_ptr<const Film> film, std::shared_ptr<const AtmosMXFContent>);
- bool pass () override;
void seek (dcpomatic::ContentTime t, bool accurate) override;
private:
+ bool do_pass () override;
+
std::shared_ptr<const AtmosMXFContent> _content;
dcpomatic::ContentTime _next;
std::shared_ptr<dcp::AtmosAssetReader> _reader;
diff --git a/src/lib/dcp_decoder.cc b/src/lib/dcp_decoder.cc
index a0b983e49..23815bef3 100644
--- a/src/lib/dcp_decoder.cc
+++ b/src/lib/dcp_decoder.cc
@@ -129,7 +129,7 @@ DCPDecoder::DCPDecoder (shared_ptr<const Film> film, shared_ptr<const DCPContent
bool
-DCPDecoder::pass ()
+DCPDecoder::do_pass ()
{
if (!_dcp_content->can_be_played()) {
return true;
diff --git a/src/lib/dcp_decoder.h b/src/lib/dcp_decoder.h
index e4944e3bf..469e7549f 100644
--- a/src/lib/dcp_decoder.h
+++ b/src/lib/dcp_decoder.h
@@ -59,7 +59,6 @@ public:
void set_decode_referenced (bool r);
void set_forced_reduction (boost::optional<int> reduction);
- bool pass () override;
void seek (dcpomatic::ContentTime t, bool accurate) override;
std::vector<dcpomatic::FontData> fonts () const override;
@@ -73,6 +72,7 @@ public:
private:
friend struct dcp_subtitle_within_dcp_test;
+ bool do_pass () override;
void next_reel ();
void get_readers ();
void pass_texts (dcpomatic::ContentTime next, dcp::Size size);
diff --git a/src/lib/dcp_subtitle_decoder.cc b/src/lib/dcp_subtitle_decoder.cc
index 024d62f34..23938f304 100644
--- a/src/lib/dcp_subtitle_decoder.cc
+++ b/src/lib/dcp_subtitle_decoder.cc
@@ -80,7 +80,7 @@ DCPSubtitleDecoder::seek (ContentTime time, bool accurate)
bool
-DCPSubtitleDecoder::pass ()
+DCPSubtitleDecoder::do_pass ()
{
if (_next == _subtitles.end ()) {
return true;
diff --git a/src/lib/dcp_subtitle_decoder.h b/src/lib/dcp_subtitle_decoder.h
index 95e783d06..a5b2140b3 100644
--- a/src/lib/dcp_subtitle_decoder.h
+++ b/src/lib/dcp_subtitle_decoder.h
@@ -32,12 +32,13 @@ class DCPSubtitleDecoder : public DCPSubtitle, public Decoder
public:
DCPSubtitleDecoder (std::shared_ptr<const Film> film, std::shared_ptr<const DCPSubtitleContent>);
- bool pass ();
void seek (dcpomatic::ContentTime time, bool accurate);
std::vector<dcpomatic::FontData> fonts () const;
private:
+ bool do_pass ();
+
dcpomatic::ContentTimePeriod content_time_period (std::shared_ptr<const dcp::Subtitle> s) const;
std::vector<std::shared_ptr<const dcp::Subtitle>> _subtitles;
diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc
index 5d1915128..1e7bcbdea 100644
--- a/src/lib/decoder.cc
+++ b/src/lib/decoder.cc
@@ -87,6 +87,8 @@ Decoder::seek (ContentTime, bool)
for (auto i: text) {
i->seek ();
}
+
+ _done = false;
}
@@ -99,3 +101,11 @@ Decoder::only_text () const
}
return text.front();
}
+
+
+void
+Decoder::pass ()
+{
+ _done = do_pass ();
+}
+
diff --git a/src/lib/decoder.h b/src/lib/decoder.h
index 00d629f81..ed35662b3 100644
--- a/src/lib/decoder.h
+++ b/src/lib/decoder.h
@@ -63,10 +63,13 @@ public:
std::shared_ptr<TextDecoder> only_text () const;
- /** Do some decoding and perhaps emit video, audio or subtitle data.
- * @return true if this decoder will emit no more data unless a seek() happens.
- */
- virtual bool pass () = 0;
+ bool done () const {
+ return _done;
+ }
+
+ /** Do some decoding and perhaps emit video, audio or subtitle data */
+ void pass ();
+
virtual void seek (dcpomatic::ContentTime time, bool accurate);
virtual dcpomatic::ContentTime position () const;
@@ -76,6 +79,10 @@ public:
}
boost::signals2::signal<void ()> Flush;
+
+private:
+ virtual bool do_pass () = 0;
+ bool _done = false;
};
diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc
index 432749c29..c661240c3 100644
--- a/src/lib/ffmpeg_decoder.cc
+++ b/src/lib/ffmpeg_decoder.cc
@@ -181,7 +181,7 @@ FFmpegDecoder::flush ()
bool
-FFmpegDecoder::pass ()
+FFmpegDecoder::do_pass ()
{
auto packet = av_packet_alloc();
DCPOMATIC_ASSERT (packet);
@@ -479,6 +479,7 @@ FFmpegDecoder::process_audio_frame (shared_ptr<FFmpegAudioStream> stream)
data->move (data->frames() - remove, remove, 0);
data->set_frames (data->frames() - remove);
ct += ContentTime::from_frames (remove, stream->frame_rate());
+ std::cout << "FF discarded " << remove << "\n";
}
if (ct < ContentTime()) {
diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h
index f15257f98..f39aa7073 100644
--- a/src/lib/ffmpeg_decoder.h
+++ b/src/lib/ffmpeg_decoder.h
@@ -46,12 +46,12 @@ class FFmpegDecoder : public FFmpeg, public Decoder
public:
FFmpegDecoder (std::shared_ptr<const Film> film, std::shared_ptr<const FFmpegContent>);
- bool pass () override;
void seek (dcpomatic::ContentTime time, bool) override;
private:
friend struct ::ffmpeg_pts_offset_test;
+ bool do_pass () override;
bool flush ();
static std::shared_ptr<AudioBuffers> deinterleave_audio (AVFrame* frame);
diff --git a/src/lib/image_decoder.cc b/src/lib/image_decoder.cc
index 2e0a98092..36291276c 100644
--- a/src/lib/image_decoder.cc
+++ b/src/lib/image_decoder.cc
@@ -51,7 +51,7 @@ ImageDecoder::ImageDecoder (shared_ptr<const Film> film, shared_ptr<const ImageC
bool
-ImageDecoder::pass ()
+ImageDecoder::do_pass ()
{
if (_frame_video_position >= _image_content->video->length()) {
return true;
diff --git a/src/lib/image_decoder.h b/src/lib/image_decoder.h
index 067a24720..65279284f 100644
--- a/src/lib/image_decoder.h
+++ b/src/lib/image_decoder.h
@@ -36,10 +36,10 @@ public:
return _image_content;
}
- bool pass () override;
void seek (dcpomatic::ContentTime, bool) override;
private:
+ bool do_pass () override;
std::shared_ptr<const ImageContent> _image_content;
std::shared_ptr<ImageProxy> _image;
diff --git a/src/lib/piece.cc b/src/lib/piece.cc
index 5d70512d4..b8d587cbc 100644
--- a/src/lib/piece.cc
+++ b/src/lib/piece.cc
@@ -108,12 +108,28 @@ Piece::video (shared_ptr<const Content> content, shared_ptr<const ImageProxy> im
}
+/** @param frame Frame position in the content, as if there were no trim */
void
Piece::audio (shared_ptr<const Content> content, AudioStreamPtr stream_ptr, shared_ptr<const AudioBuffers> audio, Frame frame)
{
auto film = _film.lock ();
DCPOMATIC_ASSERT (film);
+ /* Here we have the frame index into the content, and shortly we're going to lose that information and
+ * start thinking about frame indices into the piece. Here's the last chance for us to apply this content's
+ * trim, so we'll take it.
+ */
+ auto const start_trim = content->trim_start().frames_round(stream_ptr->frame_rate());
+ auto const remove_from_start = std::max(Frame(0), start_trim - frame);
+ if (remove_from_start > 0) {
+ auto trimmed = make_shared<AudioBuffers>(audio);
+ trimmed->trim_start (remove_from_start);
+ frame += remove_from_start;
+ }
+
+ auto const end_trim = content->trim_send().frames_round(stream_ptr->frame_rate());
+
+
auto content_streams = content->audio->streams();
auto content_stream_iter = std::find(content_streams.begin(), content_streams.end(), stream_ptr);
DCPOMATIC_ASSERT (content_stream_iter != content_streams.end());
@@ -151,6 +167,7 @@ Piece::audio (shared_ptr<const Content> content, AudioStreamPtr stream_ptr, shar
stream.position = frame;
}
+ std::cout << "piece sends frame " << stream.position << " " << to_string(resampled_audio_to_dcp(stream.position) << "\n";
Audio (PieceAudio(index, audio, resampled_audio_to_dcp(stream.position), stream_ptr->mapping()));
stream.position += audio->frames();
}
@@ -357,14 +374,13 @@ Piece::pass ()
auto film = _film.lock ();
DCPOMATIC_ASSERT (film);
- for (auto const& i: _content) {
- auto t = content_time_to_dcp(i.content, std::max(i.decoder->position(), i.content->trim_start()));
- DCPOMATIC_ASSERT (t);
- if (*t < i.content->end(film)) {
- LOG_DEBUG_PLAYER ("Calling pass() on %1", i.content->path(0));
- i.decoder->pass();
- return;
+ for (auto& i: _content) {
+ if (i.decoder->done()) {
+ continue;
}
+ LOG_DEBUG_PLAYER ("Calling pass() on %1", i.content->path(0));
+ i.decoder->pass();
+ return;
}
}
@@ -388,7 +404,7 @@ Piece::seek (DCPTime time, bool accurate)
i.position = 0;
}
- for (auto const& i: _content) {
+ for (auto& i: _content) {
if (time < i.content->position()) {
/* Before; seek to the start of the content. Even if this request is for an inaccurate seek
we must seek this (following) content accurately, otherwise when we come to the end of the current
@@ -411,9 +427,9 @@ Piece::decoder_before(optional<dcpomatic::DCPTime> time)
DCPOMATIC_ASSERT (film);
for (auto const& i: _content) {
- auto t = content_time_to_dcp(i.content, std::max(i.decoder->position(), i.content->trim_start()));
- DCPOMATIC_ASSERT (t);
- if (*t < i.content->end(film)) {
+ if (!i.decoder->done()) {
+ auto t = content_time_to_dcp(i.content, std::max(i.decoder->position(), i.content->trim_start()));
+ DCPOMATIC_ASSERT (t);
/* This is the first unfinished decoder we have, so we'll make a decision with it.
Given two choices at the same time, pick the one with texts so we see it before
the video.
@@ -454,10 +470,12 @@ Piece::flush ()
{
int index = 0;
for (auto& i: _audio_streams) {
- auto ro = i.resampler->flush ();
- if (ro->frames() > 0) {
- Audio (PieceAudio(index, ro, resampled_audio_to_dcp(i.position), i.mapping));
- i.position += ro->frames();
+ if (i.resampler) {
+ auto ro = i.resampler->flush ();
+ if (ro->frames() > 0) {
+ Audio (PieceAudio(index, ro, resampled_audio_to_dcp(i.position), i.mapping));
+ i.position += ro->frames();
+ }
}
++index;
}
@@ -467,9 +485,12 @@ Piece::flush ()
bool
Piece::done () const
{
- auto film = _film.lock();
- DCPOMATIC_ASSERT (film);
- auto const& last = _content.back();
- return content_time_to_dcp(last.content, std::max(last.decoder->position(), last.content->trim_start())) > last.content->end(film);
+ for (auto const& i: _content) {
+ if (!i.decoder->done()) {
+ return false;
+ }
+ }
+
+ return true;
}
diff --git a/src/lib/piece.h b/src/lib/piece.h
index 48d7ba073..a2718d428 100644
--- a/src/lib/piece.h
+++ b/src/lib/piece.h
@@ -49,8 +49,6 @@ class Piece
{
public:
struct Pair {
- Pair () {}
-
Pair (std::shared_ptr<Content> c, std::shared_ptr<Decoder> d)
: content(c)
, decoder(d)
diff --git a/src/lib/player.cc b/src/lib/player.cc
index 16bb49945..8b785f0fe 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -906,6 +906,7 @@ Player::audio (weak_ptr<Piece> wp, PieceAudio audio)
/* The end of this block in the DCP */
int const rfr = piece->resampled_audio_frame_rate ();
auto end = audio.time + DCPTime::from_frames(audio.audio->frames(), rfr);
+ std::cout << "Player gets " << to_string(audio.time) << "\n";
/* Remove anything that comes before the start or after the end of the content */
if (audio.time < piece->position()) {
diff --git a/src/lib/string_text_file_decoder.cc b/src/lib/string_text_file_decoder.cc
index 86f732133..4a737dac0 100644
--- a/src/lib/string_text_file_decoder.cc
+++ b/src/lib/string_text_file_decoder.cc
@@ -71,7 +71,7 @@ StringTextFileDecoder::seek (ContentTime time, bool accurate)
}
bool
-StringTextFileDecoder::pass ()
+StringTextFileDecoder::do_pass ()
{
if (_next >= _subtitles.size ()) {
return true;
diff --git a/src/lib/string_text_file_decoder.h b/src/lib/string_text_file_decoder.h
index aa8c80e6e..86c81147a 100644
--- a/src/lib/string_text_file_decoder.h
+++ b/src/lib/string_text_file_decoder.h
@@ -32,11 +32,12 @@ public:
StringTextFileDecoder (std::shared_ptr<const Film> film, std::shared_ptr<const StringTextFileContent>);
void seek (dcpomatic::ContentTime time, bool accurate);
- bool pass ();
std::vector<dcpomatic::FontData> fonts () const;
private:
+ bool do_pass ();
+
dcpomatic::ContentTimePeriod content_time_period (sub::Subtitle s) const;
size_t _next;
diff --git a/src/lib/video_mxf_decoder.cc b/src/lib/video_mxf_decoder.cc
index 39c4a37fb..6fb2828af 100644
--- a/src/lib/video_mxf_decoder.cc
+++ b/src/lib/video_mxf_decoder.cc
@@ -76,7 +76,7 @@ VideoMXFDecoder::VideoMXFDecoder (shared_ptr<const Film> film, shared_ptr<const
bool
-VideoMXFDecoder::pass ()
+VideoMXFDecoder::do_pass ()
{
auto const vfr = _content->active_video_frame_rate (film());
auto const frame = _next.frames_round (vfr);
diff --git a/src/lib/video_mxf_decoder.h b/src/lib/video_mxf_decoder.h
index 774e269c6..3492a54d4 100644
--- a/src/lib/video_mxf_decoder.h
+++ b/src/lib/video_mxf_decoder.h
@@ -33,10 +33,10 @@ class VideoMXFDecoder : public Decoder
public:
VideoMXFDecoder (std::shared_ptr<const Film> film, std::shared_ptr<const VideoMXFContent>);
- bool pass () override;
void seek (dcpomatic::ContentTime t, bool accurate) override;
private:
+ bool do_pass () override;
std::shared_ptr<const VideoMXFContent> _content;
/** Time of next thing to return from pass */
diff --git a/src/wx/text_view.cc b/src/wx/text_view.cc
index abe73a5a9..555207ae2 100644
--- a/src/wx/text_view.cc
+++ b/src/wx/text_view.cc
@@ -103,7 +103,9 @@ TextView::TextView (
i->Stop.connect (bind(&TextView::data_stop, this, _1));
}
}
- while (!decoder->pass ()) {}
+ while (!decoder->done()) {
+ decoder->pass();
+ }
SetSizerAndFit (sizer);
}
diff --git a/test/dcp_subtitle_test.cc b/test/dcp_subtitle_test.cc
index 2b05d0bc9..cd2d71de6 100644
--- a/test/dcp_subtitle_test.cc
+++ b/test/dcp_subtitle_test.cc
@@ -110,7 +110,9 @@ BOOST_AUTO_TEST_CASE (dcp_subtitle_within_dcp_test)
decoder->only_text()->StringStart.connect (bind(store, _1, _2));
stored.clear();
- while (!decoder->pass() && stored.empty()) {}
+ while (!decoder->done() && stored.empty()) {
+ decoder->pass();
+ }
BOOST_REQUIRE_EQUAL (stored.size(), 2U);
BOOST_CHECK_EQUAL (stored.front().text(), "Noch mal.");
@@ -132,7 +134,8 @@ BOOST_AUTO_TEST_CASE (dcp_subtitle_test2)
decoder->only_text()->StringStart.connect (bind(store, _1, _2));
stored.clear();
- while (!decoder->pass()) {
+ while (!decoder->done()) {
+ decoder->pass();
if (!stored.empty() && stored_time == ContentTime(0)) {
BOOST_CHECK_EQUAL (stored.front().text(), "&lt;b&gt;Hello world!&lt;/b&gt;");
}
@@ -156,7 +159,8 @@ BOOST_AUTO_TEST_CASE (dcp_subtitle_test3)
auto decoder = make_shared<DCPSubtitleDecoder>(film, content);
stored.clear();
- while (!decoder->pass ()) {
+ while (!decoder->done()) {
+ decoder->pass();
decoder->only_text()->StringStart.connect (bind (store, _1, _2));
if (!stored.empty() && stored_time == ContentTime::from_seconds(0.08)) {
auto i = stored.begin ();
diff --git a/test/ffmpeg_decoder_seek_test.cc b/test/ffmpeg_decoder_seek_test.cc
index 4d796d116..2299fb1c5 100644
--- a/test/ffmpeg_decoder_seek_test.cc
+++ b/test/ffmpeg_decoder_seek_test.cc
@@ -63,48 +63,38 @@ static void
check (shared_ptr<FFmpegDecoder> decoder, int frame)
{
BOOST_REQUIRE (decoder->ffmpeg_content()->video_frame_rate ());
- decoder->seek (ContentTime::from_frames (frame, decoder->ffmpeg_content()->video_frame_rate().get()), true);
+ decoder->seek (ContentTime::from_frames(frame, decoder->ffmpeg_content()->video_frame_rate().get()), true);
stored_frame = {};
- while (!decoder->pass() && !stored_frame) {}
+ while (!decoder->done() && !stored_frame) {
+ decoder->pass();
+ }
BOOST_CHECK (*stored_frame <= frame);
}
static void
test (boost::filesystem::path file, vector<int> frames)
{
- boost::filesystem::path path = TestPaths::private_data() / file;
+ auto path = TestPaths::private_data() / file;
BOOST_REQUIRE (boost::filesystem::exists (path));
- shared_ptr<Film> film = new_test_film ("ffmpeg_decoder_seek_test_" + file.string());
+ auto film = new_test_film ("ffmpeg_decoder_seek_test_" + file.string());
auto content = make_shared<FFmpegContent>(path);
film->examine_and_add_content (content);
BOOST_REQUIRE (!wait_for_jobs());
auto decoder = make_shared<FFmpegDecoder>(film, content);
decoder->video->Data.connect (bind (&store, _2));
- for (vector<int>::const_iterator i = frames.begin(); i != frames.end(); ++i) {
- check (decoder, *i);
+ for (auto i: frames) {
+ check (decoder, i);
}
}
BOOST_AUTO_TEST_CASE (ffmpeg_decoder_seek_test)
{
- vector<int> frames;
-
- frames.clear ();
- frames.push_back (0);
- frames.push_back (42);
- frames.push_back (999);
- frames.push_back (0);
-
+ vector<int> frames = { 0, 42, 999, 0 };
test ("boon_telly.mkv", frames);
test ("Sintel_Trailer1.480p.DivX_Plus_HD.mkv", frames);
- frames.clear ();
- frames.push_back (15);
- frames.push_back (42);
- frames.push_back (999);
- frames.push_back (15);
-
+ frames = { 15, 42, 999, 15 };
test ("prophet_long_clip.mkv", frames);
}
diff --git a/test/video_level_test.cc b/test/video_level_test.cc
index 0022a2595..6c2576e43 100644
--- a/test/video_level_test.cc
+++ b/test/video_level_test.cc
@@ -203,7 +203,8 @@ pixel_range (shared_ptr<Film> film, shared_ptr<const FFmpegContent> content)
decoder->video->Data.connect (bind(&video_handler, _1));
decoded_image = {};
while (!decoded_image) {
- BOOST_REQUIRE (!decoder->pass());
+ decoder->pass();
+ BOOST_REQUIRE (!decoder->done());
}
return pixel_range (decoded_image->image().image);
@@ -218,7 +219,8 @@ pixel_range (shared_ptr<Film> film, shared_ptr<const ImageContent> content)
decoder->video->Data.connect (bind(&video_handler, _1));
decoded_image = {};
while (!decoded_image) {
- BOOST_REQUIRE (!decoder->pass());
+ decoder->pass();
+ BOOST_REQUIRE (!decoder->done());
}
return pixel_range (decoded_image->image().image);