Various fixes so that audio_delay_test works again.
authorCarl Hetherington <cth@carlh.net>
Wed, 30 Apr 2014 23:25:30 +0000 (00:25 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 30 Apr 2014 23:25:30 +0000 (00:25 +0100)
16 files changed:
src/lib/audio_buffers.cc
src/lib/audio_content.cc
src/lib/audio_content.h
src/lib/audio_decoder.cc
src/lib/audio_mapping.cc
src/lib/audio_mapping.h
src/lib/dcpomatic_time.h
src/lib/ffmpeg_content.cc
src/lib/player.cc
src/lib/player.h
src/lib/sndfile_content.cc
test/README
test/audio_decoder_test.cc [new file with mode: 0644]
test/player_silence_padding_test.cc [deleted file]
test/player_test.cc [new file with mode: 0644]
test/wscript

index 8d00fa8ba5a2bec7d0d5894cc1ea730d4beedb21..99e52d92ae0f7bea78e0356a05103fb8e43f65ce 100644 (file)
@@ -258,6 +258,8 @@ void
 AudioBuffers::accumulate_frames (AudioBuffers const * from, int read_offset, int write_offset, int frames)
 {
        assert (_channels == from->channels ());
+       assert (read_offset >= 0);
+       assert (write_offset >= 0);
 
        for (int i = 0; i < _channels; ++i) {
                for (int j = 0; j < frames; ++j) {
index 6da5afa0c986a22bd45a52f90f434d9fab0df4bf..c84f5713011d5a02ffd7636262eafb092a9f19e2 100644 (file)
@@ -157,3 +157,9 @@ AudioContent::technical_summary () const
                output_audio_frame_rate()
                );
 }
+
+void
+AudioContent::set_audio_mapping (AudioMapping)
+{
+       signal_changed (AudioContentProperty::AUDIO_MAPPING);
+}
index cecc8f13d65c1a0875a0dca0f0b2e383a37eb20c..b9ca997a75cfd9c02b4b1b2cb3a69b9186e207bd 100644 (file)
@@ -56,7 +56,7 @@ public:
        virtual int content_audio_frame_rate () const = 0;
        virtual int output_audio_frame_rate () const = 0;
        virtual AudioMapping audio_mapping () const = 0;
-       virtual void set_audio_mapping (AudioMapping) = 0;
+       virtual void set_audio_mapping (AudioMapping);
        virtual boost::filesystem::path audio_analysis_path () const;
 
        boost::signals2::connection analyse_audio (boost::function<void()>);
index 17a534aa477489289308a8ff6e31706229ad2ca3..c0c92476a23669f1fa3b2383bc3d2c91b79071a4 100644 (file)
@@ -32,6 +32,7 @@ using std::list;
 using std::pair;
 using std::cout;
 using std::min;
+using std::max;
 using boost::optional;
 using boost::shared_ptr;
 
@@ -63,6 +64,9 @@ AudioDecoder::get_audio (AudioFrame frame, AudioFrame length, bool accurate)
                seek (ContentTime::from_frames (frame, _audio_content->content_audio_frame_rate()), accurate);
        }
 
+       /* Offset of the data that we want from the start of _decoded_audio.audio
+          (to be set up shortly)
+       */
        AudioFrame decoded_offset = 0;
        
        /* Now enough pass() calls will either:
@@ -73,22 +77,32 @@ AudioDecoder::get_audio (AudioFrame frame, AudioFrame length, bool accurate)
         * otherwise any frames will do.
         */
        if (accurate) {
-               while (!pass() && _decoded_audio.audio->frames() < length) {}
-               /* Use decoded_offset of 0, as we don't really care what frames we return */
-       } else {
+               /* Keep stuffing data into _decoded_audio until we have enough data, or the subclass does not want to give us any more */
                while (!pass() && (_decoded_audio.frame > frame || (_decoded_audio.frame + _decoded_audio.audio->frames()) < end)) {}
                decoded_offset = frame - _decoded_audio.frame;
+       } else {
+               while (!pass() && _decoded_audio.audio->frames() < length) {}
+               /* Use decoded_offset of 0, as we don't really care what frames we return */
        }
 
+       /* The amount of data available in _decoded_audio.audio starting from `frame'.  This could be -ve
+          if pass() returned true before we got enough data
+       */
        AudioFrame const amount_left = _decoded_audio.audio->frames() - decoded_offset;
        
-       AudioFrame const to_return = min (amount_left, length);
+       /* We will return either that, or the requested amount, whichever is smaller */
+       AudioFrame const to_return = max ((AudioFrame) 0, min (amount_left, length));
+
+       /* Copy our data to the output */
        shared_ptr<AudioBuffers> out (new AudioBuffers (_decoded_audio.audio->channels(), to_return));
        out->copy_from (_decoded_audio.audio.get(), to_return, decoded_offset, 0);
        
-       /* Clean up decoded */
+       /* Clean up decoded; first, move the data after what we just returned to the start of the buffer */
        _decoded_audio.audio->move (decoded_offset + to_return, 0, amount_left - to_return);
+       /* And set up the number of frames we have left */
        _decoded_audio.audio->set_frames (amount_left - to_return);
+       /* Also bump where those frames are in terms of the content */
+       _decoded_audio.frame += decoded_offset + to_return;
 
        return shared_ptr<ContentAudio> (new ContentAudio (out, frame));
 }
index 1db827046946a8008d54bff21597d4fd1d201bff..f6d747b9b49e6add9027c23360e9307818ffd386 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -39,11 +39,11 @@ AudioMapping::AudioMapping ()
 }
 
 /** Create a default AudioMapping for a given channel count.
- *  @param c Number of channels.
+ *  @param channels Number of channels.
  */
-AudioMapping::AudioMapping (int c)
+AudioMapping::AudioMapping (int channels)
 {
-       setup (c);
+       setup (channels);
 }
 
 void
index f3096764c79c248ddb3bb0a0519efbd6caaa9f8f..d3f497fc28ec0cdbb7398a31a12fffaa7f95ad2c 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -41,7 +41,7 @@ class AudioMapping
 {
 public:
        AudioMapping ();
-       AudioMapping (int);
+       AudioMapping (int channels);
        AudioMapping (boost::shared_ptr<const cxml::Node>, int);
 
        /* Default copy constructor is fine */
index 76fbe690275b071b1793cb21f15a134331f83956..109dc9b7fe1c34b9850409a2bb4787298a58d492 100644 (file)
@@ -186,6 +186,10 @@ public:
                return *this;
        }
 
+       DCPTime operator- () const {
+               return DCPTime (-_t);
+       }
+
        DCPTime operator- (DCPTime const & o) const {
                return DCPTime (_t - o._t);
        }
index 447f3631c5ca6924c6175e399902d3fa3fa76d56..4e14802e8a9a7e5b0aee5e6703069338f1bbc0cd 100644 (file)
@@ -449,7 +449,7 @@ void
 FFmpegContent::set_audio_mapping (AudioMapping m)
 {
        audio_stream()->mapping = m;
-       signal_changed (AudioContentProperty::AUDIO_MAPPING);
+       AudioContent::set_audio_mapping (m);
 }
 
 string
index 2450ace2e4ed0bd8d3c269e32e24b4db6cf68457..817a390d6fcabf44db00a8633a79ec36d8d89ead 100644 (file)
@@ -311,7 +311,11 @@ Player::get_video (DCPTime time, bool accurate)
                setup_pieces ();
        }
        
-       list<shared_ptr<Piece> > ov = overlaps<VideoContent> (time);
+       list<shared_ptr<Piece> > ov = overlaps<VideoContent> (
+               time,
+               time + DCPTime::from_frames (1, _film->video_frame_rate ())
+               );
+               
        if (ov.empty ()) {
                /* No video content at this time */
                return black_dcp_video (time);
@@ -351,7 +355,11 @@ Player::get_video (DCPTime time, bool accurate)
 
        /* Add subtitles */
 
-       ov = overlaps<SubtitleContent> (time);
+       ov = overlaps<SubtitleContent> (
+               time,
+               time + DCPTime::from_frames (1, _film->video_frame_rate ())
+               );
+       
        list<PositionImage> sub_images;
        
        for (list<shared_ptr<Piece> >::const_iterator i = ov.begin(); i != ov.end(); ++i) {
@@ -398,7 +406,7 @@ Player::get_audio (DCPTime time, DCPTime length, bool accurate)
        shared_ptr<AudioBuffers> audio (new AudioBuffers (_film->audio_channels(), length_frames));
        audio->make_silent ();
        
-       list<shared_ptr<Piece> > ov = overlaps<AudioContent> (time);
+       list<shared_ptr<Piece> > ov = overlaps<AudioContent> (time, time + length);
        if (ov.empty ()) {
                return audio;
        }
@@ -417,10 +425,21 @@ Player::get_audio (DCPTime time, DCPTime length, bool accurate)
                        continue;
                }
 
-               AudioFrame const content_time = dcp_to_content_audio (*i, time);
+               /* The time that we should request from the content */
+               DCPTime request = time - DCPTime::from_seconds (content->audio_delay() / 1000.0);
+               DCPTime offset;
+               if (request < DCPTime ()) {
+                       /* We went off the start of the content, so we will need to offset
+                          the stuff we get back.
+                       */
+                       offset = -request;
+                       request = DCPTime ();
+               }
+
+               AudioFrame const content_frame = dcp_to_content_audio (*i, request);
 
-               /* Audio from this piece's decoder (which might be more than what we asked for) */
-               shared_ptr<ContentAudio> all = decoder->get_audio (content_time, length_frames, accurate);
+               /* Audio from this piece's decoder (which might be more or less than what we asked for) */
+               shared_ptr<ContentAudio> all = decoder->get_audio (content_frame, length_frames, accurate);
 
                /* Gain */
                if (content->audio_gain() != 0) {
@@ -447,25 +466,13 @@ Player::get_audio (DCPTime time, DCPTime length, bool accurate)
                }
                
                all->audio = dcp_mapped;
-               
-               /* Delay */
-               /* XXX
-               audio->dcp_time += content->audio_delay() * TIME_HZ / 1000;
-               if (audio->dcp_time < 0) {
-                       int const frames = - audio->dcp_time * _film->audio_frame_rate() / TIME_HZ;
-                       if (frames >= audio->audio->frames ()) {
-                               return;
-                       }
-                       
-                       shared_ptr<AudioBuffers> trimmed (new AudioBuffers (audio->audio->channels(), audio->audio->frames() - frames));
-                       trimmed->copy_from (audio->audio.get(), audio->audio->frames() - frames, frames, 0);
-                       
-                       audio->audio = trimmed;
-                       audio->dcp_time = 0;
-               }
-               */
 
-               audio->accumulate_frames (all->audio.get(), all->frame - content_time, 0, min (AudioFrame (all->audio->frames()), length_frames));
+               audio->accumulate_frames (
+                       all->audio.get(),
+                       content_frame - all->frame,
+                       offset.frames (_film->audio_frame_rate()),
+                       min (AudioFrame (all->audio->frames()), length_frames) - offset.frames (_film->audio_frame_rate ())
+                       );
        }
 
        return audio;
index 62ba89e6c6e783c2603a390f41d43d1583c079af..b70bd3f64325bb3f67d8a8d04cee21d66860b9df 100644 (file)
@@ -126,6 +126,7 @@ public:
 private:
        friend class PlayerWrapper;
        friend class Piece;
+       friend class player_overlaps_test;
 
        void setup_pieces ();
        void playlist_changed ();
@@ -142,13 +143,22 @@ private:
        ContentTime dcp_to_content_subtitle (boost::shared_ptr<const Piece> piece, DCPTime t) const;
        boost::shared_ptr<DCPVideo> black_dcp_video (DCPTime) const;
 
+       /** @return Pieces of content type C that overlap a specified time range in the DCP */
        template<class C>
        std::list<boost::shared_ptr<Piece> >
-       overlaps (DCPTime t)
+       overlaps (DCPTime from, DCPTime to)
        {
+               if (!_have_valid_pieces) {
+                       setup_pieces ();
+               }
+
                std::list<boost::shared_ptr<Piece> > overlaps;
                for (typename std::list<boost::shared_ptr<Piece> >::const_iterator i = _pieces.begin(); i != _pieces.end(); ++i) {
-                       if (boost::dynamic_pointer_cast<C> ((*i)->content) && (*i)->content->position() <= t && t < (*i)->content->end()) {
+                       if (!boost::dynamic_pointer_cast<C> ((*i)->content)) {
+                               continue;
+                       }
+
+                       if ((*i)->content->position() <= to && (*i)->content->end() >= from) {
                                overlaps.push_back (*i);
                        }
                }
index 2d7fa1c1cf9446e0a26cedf13db62bd911cc6df6..5b408f2da564ddc2fcec0ebd01c6b073a4222ae6 100644 (file)
@@ -163,6 +163,6 @@ SndfileContent::set_audio_mapping (AudioMapping m)
                _audio_mapping = m;
        }
 
-       signal_changed (AudioContentProperty::AUDIO_MAPPING);
+       AudioContent::set_audio_mapping (m);
 }
 
index 6337656f1e6eb93d6f0bc1391178ffef79d1cb2b..a129b66177e43ad206f1949d1d204ec0ca85cd62 100644 (file)
@@ -7,10 +7,12 @@ They can be grouped roughly into the following:
 
 AudioAnalysis:    audio_analysis_test
 AudioBuffers:     audio_buffers_test
+AudioDecoder:     audio_decoder_test
 AudioMapping:     audio_mapping_test
 ColourConversion: colour_conversion_test
 FileGroup:        file_group_test
 Image:            image_test, pixel_formats_test, make_black_test
+Player:           player_test
 Job/JobManager:   job_test
 SubRip:           subrip_test
 Ratio:            ratio_test
@@ -30,7 +32,6 @@ black_fill_test
 client_server_test
 film_metadata_test
 frame_rate_test
-player_silence_padding_test
 recover_test
 repeat_frame_test
 scaling_test
diff --git a/test/audio_decoder_test.cc b/test/audio_decoder_test.cc
new file mode 100644 (file)
index 0000000..46f9d5a
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+    Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+    This program 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.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file  test/audio_decoder_test.cc
+ *  @brief Tests of the AudioDecoder class.
+ */
+
+#include <cassert>
+#include <boost/test/unit_test.hpp>
+#include "test.h"
+#include "lib/audio_decoder.h"
+#include "lib/audio_content.h"
+
+using std::string;
+using std::cout;
+using std::min;
+using boost::shared_ptr;
+
+class TestAudioDecoder : public AudioDecoder
+{
+public:
+       TestAudioDecoder (shared_ptr<AudioContent> content)
+               : AudioDecoder (content)
+               , _position (0)
+       {}
+
+       bool pass ()
+       {
+               AudioFrame const N = min (
+                       AudioFrame (2000),
+                       _audio_content->audio_length().frames (_audio_content->output_audio_frame_rate ()) - _position
+                       );
+
+               shared_ptr<AudioBuffers> buffers (new AudioBuffers (_audio_content->audio_channels(), N));
+               for (int i = 0; i < _audio_content->audio_channels(); ++i) {
+                       for (int j = 0; j < N; ++j) {
+                               buffers->data(i)[j] = j + _position;
+                       }
+               }
+
+               audio (buffers, ContentTime::from_frames (_position, _audio_content->output_audio_frame_rate ()));
+               _position += N;
+
+               return N < 2000;
+       }
+
+       void seek (ContentTime t, bool accurate)
+       {
+               AudioDecoder::seek (t, accurate);
+               _position = t.frames (_audio_content->output_audio_frame_rate ());
+       }
+
+private:
+       AudioFrame _position;
+};
+
+class TestAudioContent : public AudioContent
+{
+public:
+       TestAudioContent (shared_ptr<Film> film)
+               : Content (film)
+               , AudioContent (film, DCPTime ())
+       {}
+
+       string summary () const {
+               return "";
+       }
+
+       string information () const {
+               return "";
+       }
+
+       DCPTime full_length () const {
+               return DCPTime (audio_length().get ());
+       }
+
+       int audio_channels () const {
+               return 2;
+       }
+
+       ContentTime audio_length () const {
+               return ContentTime::from_seconds (61.2942);
+       }
+
+       int content_audio_frame_rate () const {
+               return 48000;
+       }
+
+       int output_audio_frame_rate () const {
+               return 48000;
+       }
+
+       AudioMapping audio_mapping () const {
+               return AudioMapping (audio_channels ());
+       }
+
+       void set_audio_mapping (AudioMapping) {}
+};
+
+shared_ptr<TestAudioContent> content;
+shared_ptr<TestAudioDecoder> decoder;
+
+static shared_ptr<ContentAudio>
+get (AudioFrame from, AudioFrame length)
+{
+       decoder->seek (ContentTime::from_frames (from, content->output_audio_frame_rate ()), true);
+       shared_ptr<ContentAudio> ca = decoder->get_audio (from, length, true);
+       BOOST_CHECK_EQUAL (ca->frame, from);
+       return ca;
+}
+
+static void
+check (AudioFrame from, AudioFrame length)
+{
+       shared_ptr<ContentAudio> ca = get (from, length);
+       for (int i = 0; i < content->audio_channels(); ++i) {
+               for (int j = 0; j < length; ++j) {
+                       BOOST_CHECK_EQUAL (ca->audio->data(i)[j], j + from);
+                       assert (ca->audio->data(i)[j] == j + from);
+               }
+       }
+}
+
+/** Check the logic in AudioDecoder::get_audio */
+BOOST_AUTO_TEST_CASE (audio_decoder_get_audio_test)
+{
+       shared_ptr<Film> film = new_test_film ("audio_decoder_test");
+
+       content.reset (new TestAudioContent (film));
+       decoder.reset (new TestAudioDecoder (content));
+       
+       /* Simple reads */
+       check (0, 48000);
+       check (44, 9123);
+       check (9991, 22);
+
+       /* Read off the end */
+
+       AudioFrame const from = content->output_audio_frame_rate() * 61;
+       AudioFrame const length = content->output_audio_frame_rate() * 4;
+       shared_ptr<ContentAudio> ca = get (from, length);
+       
+       for (int i = 0; i < content->audio_channels(); ++i) {
+               for (int j = 0; j < ca->audio->frames(); ++j) {
+                       BOOST_CHECK_EQUAL (ca->audio->data(i)[j], j + from);
+                       assert (ca->audio->data(i)[j] == j + from);
+               }
+       }
+}
diff --git a/test/player_silence_padding_test.cc b/test/player_silence_padding_test.cc
deleted file mode 100644 (file)
index fa8a9b6..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-    Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
-
-    This program 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.
-
-    This program 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 this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/* @file  test/player_silence_padding_test.cc
- * @brief Check that the Player correctly generates silence when used with a silent FFmpegContent.
- */
-
-#include <iostream>
-#include <boost/test/unit_test.hpp>
-#include "lib/film.h"
-#include "lib/ffmpeg_content.h"
-#include "lib/dcp_content_type.h"
-#include "lib/ratio.h"
-#include "lib/audio_buffers.h"
-#include "lib/player.h"
-#include "test.h"
-
-using std::cout;
-using boost::shared_ptr;
-
-BOOST_AUTO_TEST_CASE (player_silence_padding_test)
-{
-       shared_ptr<Film> film = new_test_film ("player_silence_padding_test");
-       film->set_name ("player_silence_padding_test");
-       shared_ptr<FFmpegContent> c (new FFmpegContent (film, "test/data/test.mp4"));
-       film->set_container (Ratio::from_id ("185"));
-       film->set_audio_channels (6);
-       
-       film->examine_and_add_content (c);
-       wait_for_jobs ();
-
-       shared_ptr<Player> player = film->make_player ();
-       shared_ptr<AudioBuffers> test = player->get_audio (DCPTime (0), DCPTime::from_seconds (1), true);
-       BOOST_CHECK_EQUAL (test->frames(), 48000);
-       BOOST_CHECK_EQUAL (test->channels(), film->audio_channels ());
-
-       for (int i = 0; i < test->frames(); ++i) {
-               for (int c = 0; c < test->channels(); ++c) {
-                       BOOST_CHECK_EQUAL (test->data()[c][i], 0);
-               }
-       }
-}
-
diff --git a/test/player_test.cc b/test/player_test.cc
new file mode 100644 (file)
index 0000000..2412fc3
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+    Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+
+    This program 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.
+
+    This program 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 this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/** @file  test/player_test.cc
+ *  @brief Various tests of Player.
+ */
+
+#include <iostream>
+#include <boost/test/unit_test.hpp>
+#include "lib/film.h"
+#include "lib/ffmpeg_content.h"
+#include "lib/dcp_content_type.h"
+#include "lib/ratio.h"
+#include "lib/audio_buffers.h"
+#include "lib/player.h"
+#include "test.h"
+
+using std::cout;
+using std::list;
+using boost::shared_ptr;
+
+/** Player::overlaps */
+BOOST_AUTO_TEST_CASE (player_overlaps_test)
+{
+       shared_ptr<Film> film = new_test_film ("player_overlaps_test");
+       film->set_container (Ratio::from_id ("185"));
+       shared_ptr<FFmpegContent> A (new FFmpegContent (film, "test/data/test.mp4"));
+       shared_ptr<FFmpegContent> B (new FFmpegContent (film, "test/data/test.mp4"));
+       shared_ptr<FFmpegContent> C (new FFmpegContent (film, "test/data/test.mp4"));
+
+       film->examine_and_add_content (A);
+       film->examine_and_add_content (B);
+       film->examine_and_add_content (C);
+       wait_for_jobs ();
+
+       BOOST_CHECK_EQUAL (A->full_length(), DCPTime::from_seconds (3));
+
+       A->set_position (DCPTime::from_seconds (0));
+       B->set_position (DCPTime::from_seconds (10));
+       C->set_position (DCPTime::from_seconds (20));
+
+       shared_ptr<Player> player = film->make_player ();
+
+       list<shared_ptr<Piece> > o = player->overlaps<FFmpegContent> (DCPTime::from_seconds (0), DCPTime::from_seconds (5));
+       BOOST_CHECK_EQUAL (o.size(), 1);
+       BOOST_CHECK_EQUAL (o.front()->content, A);
+
+       o = player->overlaps<FFmpegContent> (DCPTime::from_seconds (5), DCPTime::from_seconds (8));
+       BOOST_CHECK_EQUAL (o.size(), 0);
+
+       o = player->overlaps<FFmpegContent> (DCPTime::from_seconds (8), DCPTime::from_seconds (12));
+       BOOST_CHECK_EQUAL (o.size(), 1);
+       BOOST_CHECK_EQUAL (o.front()->content, B);
+
+       o = player->overlaps<FFmpegContent> (DCPTime::from_seconds (2), DCPTime::from_seconds (12));
+       BOOST_CHECK_EQUAL (o.size(), 2);
+       BOOST_CHECK_EQUAL (o.front()->content, A);
+       BOOST_CHECK_EQUAL (o.back()->content, B);
+
+       o = player->overlaps<FFmpegContent> (DCPTime::from_seconds (8), DCPTime::from_seconds (11));
+       BOOST_CHECK_EQUAL (o.size(), 1);
+       BOOST_CHECK_EQUAL (o.front()->content, B);
+}
+
+/** Check that the Player correctly generates silence when used with a silent FFmpegContent */
+BOOST_AUTO_TEST_CASE (player_silence_padding_test)
+{
+       shared_ptr<Film> film = new_test_film ("player_silence_padding_test");
+       film->set_name ("player_silence_padding_test");
+       shared_ptr<FFmpegContent> c (new FFmpegContent (film, "test/data/test.mp4"));
+       film->set_container (Ratio::from_id ("185"));
+       film->set_audio_channels (6);
+       
+       film->examine_and_add_content (c);
+       wait_for_jobs ();
+
+       shared_ptr<Player> player = film->make_player ();
+       shared_ptr<AudioBuffers> test = player->get_audio (DCPTime (0), DCPTime::from_seconds (1), true);
+       BOOST_CHECK_EQUAL (test->frames(), 48000);
+       BOOST_CHECK_EQUAL (test->channels(), film->audio_channels ());
+
+       for (int i = 0; i < test->frames(); ++i) {
+               for (int c = 0; c < test->channels(); ++c) {
+                       BOOST_CHECK_EQUAL (test->data()[c][i], 0);
+               }
+       }
+}
+
index ec61915a6254c429b974cb74720e306cf35a9b87..c825506fb601999b1c1995247fdbe2027e3346a9 100644 (file)
@@ -19,6 +19,7 @@ def build(bld):
                  audio_analysis_test.cc
                  audio_buffers_test.cc
                  audio_delay_test.cc
+                 audio_decoder_test.cc
                  audio_mapping_test.cc
                  black_fill_test.cc
                  client_server_test.cc
@@ -35,7 +36,7 @@ def build(bld):
                  image_test.cc
                  job_test.cc
                  make_black_test.cc
-                 player_silence_padding_test.cc
+                 player_test.cc
                  pixel_formats_test.cc
                  ratio_test.cc
                  repeat_frame_test.cc