#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 ()) {
_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();
}
{
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;
}
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();
+ }
+ }
+}
class AudioContent;
class AudioDecoderStream;
class Log;
+class Resampler;
/** @class AudioDecoder.
* @brief Parent class for audio decoders.
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
if (audio) {
decode_audio_packet ();
+ audio->flush ();
}
}
#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>
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 */
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)
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 */
_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 ();
}
}
-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)
{
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) {
class Font;
class AudioBuffers;
class ReferencedReelAsset;
-class Resampler;
/** @class Player
* @brief A class which can `play' a Playlist.
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
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;
}
}
-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;
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));
out->set_frames (out_offset);
delete[] buffer;
- return make_pair (out, _next_out.get ());
+ return out;
}
void
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 ();
int _in_rate;
int _out_rate;
int _channels;
- boost::optional<Frame> _next_in;
- boost::optional<Frame> _next_out;
};