summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2013-07-27 18:25:11 +0100
committerCarl Hetherington <cth@carlh.net>2013-07-27 18:25:11 +0100
commit65379c3a9d78ae627519c0820c0814db0083f8af (patch)
treeffef68bf4de9b9cf957abbe67aad0e43363664b7 /src/lib
parent4e4b758bb59cde29fcd85ed1a59a42a32536f230 (diff)
Extract audio merging code from Player.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/audio_buffers.h5
-rw-r--r--src/lib/audio_merger.h103
-rw-r--r--src/lib/player.cc51
-rw-r--r--src/lib/player.h6
4 files changed, 122 insertions, 43 deletions
diff --git a/src/lib/audio_buffers.h b/src/lib/audio_buffers.h
index 6b57bd142..0950f5d67 100644
--- a/src/lib/audio_buffers.h
+++ b/src/lib/audio_buffers.h
@@ -17,6 +17,9 @@
*/
+#ifndef DVDOMATIC_AUDIO_BUFFERS_H
+#define DVDOMATIC_AUDIO_BUFFERS_H
+
#include <boost/shared_ptr.hpp>
/** @class AudioBuffers
@@ -72,3 +75,5 @@ private:
/** Audio data (so that, e.g. _data[2][6] is channel 2, sample 6) */
float** _data;
};
+
+#endif
diff --git a/src/lib/audio_merger.h b/src/lib/audio_merger.h
new file mode 100644
index 000000000..126325a9d
--- /dev/null
+++ b/src/lib/audio_merger.h
@@ -0,0 +1,103 @@
+/*
+ Copyright (C) 2013 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.
+
+*/
+
+#include "audio_buffers.h"
+
+template <class T, class F>
+class AudioMerger
+{
+public:
+ AudioMerger (int channels, boost::function<F (T)> t_to_f, boost::function<T (F)> f_to_t)
+ : _buffers (new AudioBuffers (channels, 0))
+ , _next_emission (0)
+ , _t_to_f (t_to_f)
+ , _f_to_t (f_to_t)
+ {}
+
+ void push (boost::shared_ptr<const AudioBuffers> audio, T time)
+ {
+ if (time > _next_emission) {
+ /* We can emit some audio from our buffer; this is how many frames
+ we are going to emit.
+ */
+ F const to_emit = _t_to_f (time - _next_emission);
+ boost::shared_ptr<AudioBuffers> emit (new AudioBuffers (_buffers->channels(), to_emit));
+
+ /* And this is how many we will get from our buffer */
+ F const to_emit_from_buffers = min (to_emit, _buffers->frames ());
+
+ /* Copy the data that we have to the back end of `emit' */
+ emit->copy_from (_buffers.get(), to_emit_from_buffers, 0, to_emit - to_emit_from_buffers);
+
+ /* Silence any gap at the start */
+ emit->make_silent (0, to_emit - to_emit_from_buffers);
+
+ /* Emit that */
+ Audio (emit, _next_emission);
+
+ _next_emission += _f_to_t (to_emit);
+
+ /* And remove the data we've emitted from our buffers */
+ if (_buffers->frames() > to_emit_from_buffers) {
+ _buffers->move (to_emit_from_buffers, 0, _buffers->frames() - to_emit_from_buffers);
+ }
+ _buffers->set_frames (_buffers->frames() - to_emit_from_buffers);
+ }
+
+ /* Now accumulate the new audio into our buffers */
+ F frame = _t_to_f (time);
+ F after = max (_buffers->frames(), frame + audio->frames() - _t_to_f (_next_emission));
+ _buffers->ensure_size (after);
+ _buffers->accumulate_frames (audio.get(), 0, frame - _t_to_f (_next_emission), audio->frames ());
+ _buffers->set_frames (after);
+ }
+
+ F min (F a, int b)
+ {
+ if (a < b) {
+ return a;
+ }
+
+ return b;
+ }
+
+ F max (int a, F b)
+ {
+ if (a > b) {
+ return a;
+ }
+
+ return b;
+ }
+
+ void flush ()
+ {
+ if (_buffers->frames() > 0) {
+ Audio (_buffers, _next_emission);
+ }
+ }
+
+ boost::signals2::signal<void (boost::shared_ptr<const AudioBuffers>, T)> Audio;
+
+private:
+ boost::shared_ptr<AudioBuffers> _buffers;
+ T _next_emission;
+ boost::function<F (T)> _t_to_f;
+ boost::function<T (F)> _f_to_t;
+};
diff --git a/src/lib/player.cc b/src/lib/player.cc
index 647095793..dbc78b8d0 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -97,11 +97,12 @@ Player::Player (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
, _have_valid_pieces (false)
, _video_position (0)
, _audio_position (0)
- , _audio_buffers (f->audio_channels(), 0)
+ , _audio_merger (f->audio_channels(), bind (&Film::time_to_audio_frames, f.get(), _1), bind (&Film::audio_frames_to_time, f.get(), _1))
{
_playlist->Changed.connect (bind (&Player::playlist_changed, this));
_playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2, _3));
_film->Changed.connect (bind (&Player::film_changed, this, _1));
+ _audio_merger.Audio.connect (bind (&Player::merger_process_audio, this, _1, _2));
set_video_container_size (_film->container()->size (_film->full_frame ()));
}
@@ -318,52 +319,20 @@ Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers
time = 0;
}
- /* The time of this audio may indicate that some of our buffered audio is not going to
- be added to any more, so it can be emitted.
- */
-
- if (time > _audio_position) {
- /* We can emit some audio from our buffers; this is how many frames */
- OutputAudioFrame const N = _film->time_to_audio_frames (time - _audio_position);
- if (N > _audio_buffers.frames()) {
- /* We need some extra silence before whatever is in the buffers */
- _audio_buffers.ensure_size (N);
- _audio_buffers.move (0, N - _audio_buffers.frames(), _audio_buffers.frames ());
- _audio_buffers.make_silent (0, _audio_buffers.frames());
- _audio_buffers.set_frames (N);
- }
- assert (N <= _audio_buffers.frames());
-
- /* XXX: not convinced that a copy is necessary here */
- shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), N));
- emit->copy_from (&_audio_buffers, N, 0, 0);
- Audio (emit, _audio_position);
-
- _audio_position = piece->audio_position = _audio_position + _film->audio_frames_to_time (N);
-
- /* And remove it from our buffers */
- if (_audio_buffers.frames() > N) {
- _audio_buffers.move (N, 0, _audio_buffers.frames() - N);
- }
- _audio_buffers.set_frames (_audio_buffers.frames() - N);
- }
+ _audio_merger.push (audio, time);
+}
- /* Now accumulate the new audio into our buffers */
- _audio_buffers.ensure_size (_audio_buffers.frames() + audio->frames());
- _audio_buffers.accumulate_frames (audio.get(), 0, 0, audio->frames ());
- _audio_buffers.set_frames (_audio_buffers.frames() + audio->frames());
+void
+Player::merger_process_audio (shared_ptr<const AudioBuffers> audio, Time time)
+{
+ Audio (audio, time);
+ _audio_position += _film->audio_frames_to_time (audio->frames ());
}
void
Player::flush ()
{
- if (_audio_buffers.frames() > 0) {
- shared_ptr<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), _audio_buffers.frames()));
- emit->copy_from (&_audio_buffers, _audio_buffers.frames(), 0, 0);
- Audio (emit, _audio_position);
- _audio_position += _film->audio_frames_to_time (_audio_buffers.frames ());
- _audio_buffers.set_frames (0);
- }
+ _audio_merger.flush ();
while (_video_position < _audio_position) {
emit_black ();
diff --git a/src/lib/player.h b/src/lib/player.h
index cd480dd1a..206254713 100644
--- a/src/lib/player.h
+++ b/src/lib/player.h
@@ -24,10 +24,11 @@
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include "playlist.h"
-#include "audio_buffers.h"
#include "content.h"
#include "film.h"
#include "rect.h"
+#include "audio_merger.h"
+#include "audio_content.h"
class Job;
class Film;
@@ -93,6 +94,7 @@ private:
boost::shared_ptr<Resampler> resampler (boost::shared_ptr<AudioContent>, bool);
void film_changed (Film::Property);
void update_subtitle ();
+ void merger_process_audio (boost::shared_ptr<const AudioBuffers>, Time);
boost::shared_ptr<const Film> _film;
boost::shared_ptr<const Playlist> _playlist;
@@ -109,7 +111,7 @@ private:
/** The time after the last audio that we emitted */
Time _audio_position;
- AudioBuffers _audio_buffers;
+ AudioMerger<Time, AudioContent::Frame> _audio_merger;
libdcp::Size _video_container_size;
boost::shared_ptr<Image> _black_frame;