summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2017-05-21 19:48:14 +0100
committerCarl Hetherington <cth@carlh.net>2017-05-21 19:48:14 +0100
commitfa4d2529d63bcfa7cf7c516b7227e20a1b6dec7e (patch)
tree1ac1107370c7384fbce6cc67ee3e3aa6475f807e /src/lib
parent5bcbd6821a6ff1419f9069cf9e1a94c8557a992c (diff)
Do resampling in AudioDecoder rather than Player.
This fixes the problem where the decoder's position would not take into account that all samples pushed into the resampler do not always immediately come out. This would result in Player thinking that there would be gaps when there are not.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/audio_decoder.cc50
-rw-r--r--src/lib/audio_decoder.h4
-rw-r--r--src/lib/ffmpeg_decoder.cc1
-rw-r--r--src/lib/player.cc77
-rw-r--r--src/lib/player.h5
-rw-r--r--src/lib/resampler.cc25
-rw-r--r--src/lib/resampler.h6
7 files changed, 62 insertions, 106 deletions
diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc
index 3e4584a3f..4b77a8afb 100644
--- a/src/lib/audio_decoder.cc
+++ b/src/lib/audio_decoder.cc
@@ -22,19 +22,24 @@
#include "audio_buffers.h"
#include "audio_content.h"
#include "log.h"
+#include "resampler.h"
#include "compose.hpp"
#include <boost/foreach.hpp>
#include <iostream>
#include "i18n.h"
+#define LOG_GENERAL(...) _log->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL);
+
using std::cout;
using std::map;
+using std::pair;
using boost::shared_ptr;
using boost::optional;
AudioDecoder::AudioDecoder (Decoder* parent, shared_ptr<const AudioContent> content, shared_ptr<Log> log)
: DecoderPart (parent, log)
+ , _content (content)
{
/* Set up _positions so that we have one for each stream */
BOOST_FOREACH (AudioStreamPtr i, content->streams ()) {
@@ -58,6 +63,32 @@ AudioDecoder::emit (AudioStreamPtr stream, shared_ptr<const AudioBuffers> data,
_positions[stream] = time.frames_round (stream->frame_rate ());
}
+ shared_ptr<Resampler> resampler;
+ map<AudioStreamPtr, shared_ptr<Resampler> >::iterator i = _resamplers.find(stream);
+ if (i != _resamplers.end ()) {
+ resampler = i->second;
+ } else {
+ if (stream->frame_rate() != _content->resampled_frame_rate()) {
+ LOG_GENERAL (
+ "Creating new resampler from %1 to %2 with %3 channels",
+ stream->frame_rate(),
+ _content->resampled_frame_rate(),
+ stream->channels()
+ );
+
+ resampler.reset (new Resampler (stream->frame_rate(), _content->resampled_frame_rate(), stream->channels()));
+ _resamplers[stream] = resampler;
+ }
+ }
+
+ if (resampler) {
+ shared_ptr<const AudioBuffers> ro = resampler->run (data);
+ if (ro->frames() == 0) {
+ return;
+ }
+ data = ro;
+ }
+
Data (stream, ContentAudio (data, _positions[stream]));
_positions[stream] += data->frames();
}
@@ -67,7 +98,7 @@ AudioDecoder::position () const
{
optional<ContentTime> p;
for (map<AudioStreamPtr, Frame>::const_iterator i = _positions.begin(); i != _positions.end(); ++i) {
- ContentTime const ct = ContentTime::from_frames (i->second, i->first->frame_rate ());
+ ContentTime const ct = ContentTime::from_frames (i->second, _content->resampled_frame_rate());
if (!p || ct < *p) {
p = ct;
}
@@ -79,7 +110,24 @@ AudioDecoder::position () const
void
AudioDecoder::seek ()
{
+ for (map<AudioStreamPtr, shared_ptr<Resampler> >::iterator i = _resamplers.begin(); i != _resamplers.end(); ++i) {
+ i->second->flush ();
+ i->second->reset ();
+ }
+
for (map<AudioStreamPtr, Frame>::iterator i = _positions.begin(); i != _positions.end(); ++i) {
i->second = 0;
}
}
+
+void
+AudioDecoder::flush ()
+{
+ for (map<AudioStreamPtr, shared_ptr<Resampler> >::iterator i = _resamplers.begin(); i != _resamplers.end(); ++i) {
+ shared_ptr<const AudioBuffers> ro = i->second->flush ();
+ if (ro->frames() > 0) {
+ Data (i->first, ContentAudio (ro, _positions[i->first]));
+ _positions[i->first] += ro->frames();
+ }
+ }
+}
diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h
index c104d8201..fcbd8267b 100644
--- a/src/lib/audio_decoder.h
+++ b/src/lib/audio_decoder.h
@@ -36,6 +36,7 @@ class AudioBuffers;
class AudioContent;
class AudioDecoderStream;
class Log;
+class Resampler;
/** @class AudioDecoder.
* @brief Parent class for audio decoders.
@@ -48,12 +49,15 @@ public:
ContentTime position () const;
void emit (AudioStreamPtr stream, boost::shared_ptr<const AudioBuffers>, ContentTime);
void seek ();
+ void flush ();
boost::signals2::signal<void (AudioStreamPtr, ContentAudio)> Data;
private:
+ boost::shared_ptr<const AudioContent> _content;
/** Frame after the last one that was emitted from Data for each AudioStream */
std::map<AudioStreamPtr, Frame> _positions;
+ std::map<AudioStreamPtr, boost::shared_ptr<Resampler> > _resamplers;
};
#endif
diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc
index 1c886284b..baec57f3d 100644
--- a/src/lib/ffmpeg_decoder.cc
+++ b/src/lib/ffmpeg_decoder.cc
@@ -113,6 +113,7 @@ FFmpegDecoder::flush ()
if (audio) {
decode_audio_packet ();
+ audio->flush ();
}
}
diff --git a/src/lib/player.cc b/src/lib/player.cc
index d51c94400..7f8b06458 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -47,7 +47,6 @@
#include "content_subtitle.h"
#include "dcp_decoder.h"
#include "image_decoder.h"
-#include "resampler.h"
#include "compose.hpp"
#include <dcp/reel.h>
#include <dcp/reel_sound_asset.h>
@@ -580,12 +579,6 @@ Player::pass ()
if (earliest) {
earliest->done = earliest->decoder->pass ();
- if (earliest->done && earliest->content->audio) {
- /* Flush the Player audio system for this piece */
- BOOST_FOREACH (AudioStreamPtr i, earliest->content->audio->streams()) {
- audio_flush (earliest, i);
- }
- }
}
/* Emit any audio that is ready */
@@ -709,32 +702,6 @@ Player::video (weak_ptr<Piece> wp, ContentVideo video)
emit_video (_last_video[wp], time);
}
-void
-Player::audio_flush (shared_ptr<Piece> piece, AudioStreamPtr stream)
-{
- shared_ptr<AudioContent> content = piece->content->audio;
- DCPOMATIC_ASSERT (content);
-
- shared_ptr<Resampler> r = resampler (content, stream, false);
- if (!r) {
- return;
- }
-
- pair<shared_ptr<const AudioBuffers>, Frame> ro = r->flush ();
- if (ro.first->frames() == 0) {
- return;
- }
-
- ContentAudio content_audio;
- content_audio.audio = ro.first;
- content_audio.frame = ro.second;
-
- /* Compute time in the DCP */
- DCPTime time = resampled_audio_to_dcp (piece, content_audio.frame) + DCPTime::from_seconds (content->delay() / 1000.0);
-
- audio_transform (content, stream, content_audio, time);
-}
-
/** Do our common processing on some audio */
void
Player::audio_transform (shared_ptr<AudioContent> content, AudioStreamPtr stream, ContentAudio content_audio, DCPTime time)
@@ -802,17 +769,6 @@ Player::audio (weak_ptr<Piece> wp, AudioStreamPtr stream, ContentAudio content_a
shared_ptr<AudioContent> content = piece->content->audio;
DCPOMATIC_ASSERT (content);
- /* Resample */
- if (stream->frame_rate() != content->resampled_frame_rate()) {
- shared_ptr<Resampler> r = resampler (content, stream, true);
- pair<shared_ptr<const AudioBuffers>, Frame> ro = r->run (content_audio.audio, content_audio.frame);
- if (ro.first->frames() == 0) {
- return;
- }
- content_audio.audio = ro.first;
- content_audio.frame = ro.second;
- }
-
/* Compute time in the DCP */
DCPTime time = resampled_audio_to_dcp (piece, content_audio.frame) + DCPTime::from_seconds (content->delay() / 1000.0);
/* And the end of this block in the DCP */
@@ -937,11 +893,6 @@ Player::seek (DCPTime time, bool accurate)
_audio_processor->flush ();
}
- for (ResamplerMap::iterator i = _resamplers.begin(); i != _resamplers.end(); ++i) {
- i->second->flush ();
- i->second->reset ();
- }
-
_audio_merger.clear ();
_active_subtitles.clear ();
@@ -969,33 +920,6 @@ Player::seek (DCPTime time, bool accurate)
}
}
-shared_ptr<Resampler>
-Player::resampler (shared_ptr<const AudioContent> content, AudioStreamPtr stream, bool create)
-{
- ResamplerMap::const_iterator i = _resamplers.find (make_pair (content, stream));
- if (i != _resamplers.end ()) {
- return i->second;
- }
-
- if (!create) {
- return shared_ptr<Resampler> ();
- }
-
- LOG_GENERAL (
- "Creating new resampler from %1 to %2 with %3 channels",
- stream->frame_rate(),
- content->resampled_frame_rate(),
- stream->channels()
- );
-
- shared_ptr<Resampler> r (
- new Resampler (stream->frame_rate(), content->resampled_frame_rate(), stream->channels())
- );
-
- _resamplers[make_pair(content, stream)] = r;
- return r;
-}
-
void
Player::emit_video (shared_ptr<PlayerVideo> pv, DCPTime time)
{
@@ -1026,6 +950,7 @@ Player::fill_audio (DCPTimePeriod period)
return;
}
+ cout << "fillin " << to_string(period.from) << " to " << to_string(period.to) << "\n";
BOOST_FOREACH (DCPTimePeriod i, subtract(period, _no_audio)) {
DCPTime t = i.from;
while (t < i.to) {
diff --git a/src/lib/player.h b/src/lib/player.h
index 20c55e26d..20d9c9388 100644
--- a/src/lib/player.h
+++ b/src/lib/player.h
@@ -45,7 +45,6 @@ class Playlist;
class Font;
class AudioBuffers;
class ReferencedReelAsset;
-class Resampler;
/** @class Player
* @brief A class which can `play' a Playlist.
@@ -107,10 +106,8 @@ private:
void image_subtitle_start (boost::weak_ptr<Piece>, ContentImageSubtitle);
void text_subtitle_start (boost::weak_ptr<Piece>, ContentTextSubtitle);
void subtitle_stop (boost::weak_ptr<Piece>, ContentTime);
- boost::shared_ptr<Resampler> resampler (boost::shared_ptr<const AudioContent> content, AudioStreamPtr stream, bool create);
DCPTime one_video_frame () const;
void fill_audio (DCPTimePeriod period);
- void audio_flush (boost::shared_ptr<Piece>, AudioStreamPtr stream);
void audio_transform (boost::shared_ptr<AudioContent> content, AudioStreamPtr stream, ContentAudio content_audio, DCPTime time);
std::pair<boost::shared_ptr<AudioBuffers>, DCPTime> discard_audio (
boost::shared_ptr<const AudioBuffers> audio, DCPTime time, DCPTime discard_to
@@ -173,8 +170,6 @@ private:
ActiveSubtitles _active_subtitles;
boost::shared_ptr<AudioProcessor> _audio_processor;
- typedef std::map<std::pair<boost::shared_ptr<const AudioContent>, AudioStreamPtr>, boost::shared_ptr<Resampler> > ResamplerMap;
- ResamplerMap _resamplers;
boost::signals2::scoped_connection _film_changed_connection;
boost::signals2::scoped_connection _playlist_changed_connection;
diff --git a/src/lib/resampler.cc b/src/lib/resampler.cc
index e991591c2..553180f08 100644
--- a/src/lib/resampler.cc
+++ b/src/lib/resampler.cc
@@ -67,19 +67,9 @@ Resampler::set_fast ()
}
}
-pair<shared_ptr<const AudioBuffers>, Frame>
-Resampler::run (shared_ptr<const AudioBuffers> in, Frame frame)
+shared_ptr<const AudioBuffers>
+Resampler::run (shared_ptr<const AudioBuffers> in)
{
- if (!_next_in || !_next_out || _next_in.get() != frame) {
- /* Either there was a discontinuity in the input or this is the first input;
- reset _next_out.
- */
- _next_out = lrintf (frame * _out_rate / _in_rate);
- }
-
- /* Expected next input frame */
- _next_in = frame + in->frames ();
-
int in_frames = in->frames ();
int in_offset = 0;
int out_offset = 0;
@@ -154,15 +144,10 @@ Resampler::run (shared_ptr<const AudioBuffers> in, Frame frame)
delete[] data.data_out;
}
- Frame out_frame = _next_out.get ();
-
- /* Expected next output frame */
- _next_out = _next_out.get() + resampled->frames();
-
- return make_pair (resampled, out_frame);
+ return resampled;
}
-pair<shared_ptr<const AudioBuffers>, Frame>
+shared_ptr<const AudioBuffers>
Resampler::flush ()
{
shared_ptr<AudioBuffers> out (new AudioBuffers (_channels, 0));
@@ -200,7 +185,7 @@ Resampler::flush ()
out->set_frames (out_offset);
delete[] buffer;
- return make_pair (out, _next_out.get ());
+ return out;
}
void
diff --git a/src/lib/resampler.h b/src/lib/resampler.h
index 9e9304fb4..4b19dc511 100644
--- a/src/lib/resampler.h
+++ b/src/lib/resampler.h
@@ -31,8 +31,8 @@ public:
Resampler (int, int, int);
~Resampler ();
- std::pair<boost::shared_ptr<const AudioBuffers>, Frame> run (boost::shared_ptr<const AudioBuffers>, Frame);
- std::pair<boost::shared_ptr<const AudioBuffers>, Frame> flush ();
+ boost::shared_ptr<const AudioBuffers> run (boost::shared_ptr<const AudioBuffers>);
+ boost::shared_ptr<const AudioBuffers> flush ();
void reset ();
void set_fast ();
@@ -41,6 +41,4 @@ private:
int _in_rate;
int _out_rate;
int _channels;
- boost::optional<Frame> _next_in;
- boost::optional<Frame> _next_out;
};