#
# e.g. --run_tests=foo
-export LD_LIBRARY_PATH=build/src/lib:$LD_LIBRARY_PATH
+export LD_LIBRARY_PATH=build/src/lib:/home/c.hetherington/lib:$LD_LIBRARY_PATH
export DCPOMATIC_LINUX_SHARE_PREFIX=`pwd`
if [ "$1" == "--debug" ]; then
shift;
#include "audio_decoder.h"
#include "audio_buffers.h"
-#include "audio_decoder_stream.h"
#include "audio_content.h"
#include "log.h"
#include "compose.hpp"
using boost::shared_ptr;
using boost::optional;
-AudioDecoder::AudioDecoder (Decoder* parent, shared_ptr<const AudioContent> content, shared_ptr<Log> log)
+AudioDecoder::AudioDecoder (Decoder* parent, shared_ptr<AudioContent> content, shared_ptr<Log> log)
: DecoderPart (parent, log)
{
BOOST_FOREACH (AudioStreamPtr i, content->streams ()) {
- _streams[i] = shared_ptr<AudioDecoderStream> (new AudioDecoderStream (content, i, parent, this, log));
+ _positions[i] = 0;
}
}
return;
}
- if (_streams.find (stream) == _streams.end ()) {
-
- /* This method can be called with an unknown stream during the following sequence:
- - Add KDM to some DCP content.
- - Content gets re-examined.
- - SingleStreamAudioContent::take_from_audio_examiner creates a new stream.
- - Some content property change signal is delivered so Player::Changed is emitted.
- - Film viewer to re-gets the frame.
- - Player calls DCPDecoder pass which calls this method on the new stream.
-
- At this point the AudioDecoder does not know about the new stream.
-
- Then
- - Some other property change signal is delivered which marks the player's pieces invalid.
- - Film viewer re-gets again.
- - Everything is OK.
-
- In this situation it is fine for us to silently drop the audio.
- */
-
- return;
+ if (_positions[stream] == 0) {
+ _positions[stream] = time.frames_round (stream->frame_rate ());
}
- _streams[stream]->audio (data, time);
- _positions[stream] = time;
+ Data (stream, ContentAudio (data, _positions[stream]));
+ _positions[stream] += data->frames();
}
-void
-AudioDecoder::flush ()
+ContentTime
+AudioDecoder::position () const
{
- for (StreamMap::const_iterator i = _streams.begin(); i != _streams.end(); ++i) {
- i->second->flush ();
+ 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 ());
+ if (!p || ct < *p) {
+ p = ct;
+ }
}
-}
-void
-AudioDecoder::set_fast ()
-{
- for (StreamMap::const_iterator i = _streams.begin(); i != _streams.end(); ++i) {
- i->second->set_fast ();
- }
+ return p.get_value_or(ContentTime());
}
-optional<ContentTime>
-AudioDecoder::position () const
+void
+AudioDecoder::seek ()
{
- optional<ContentTime> p;
- for (map<AudioStreamPtr, ContentTime>::const_iterator i = _positions.begin(); i != _positions.end(); ++i) {
- if (!p || i->second < *p) {
- p = i->second;
- }
+ for (map<AudioStreamPtr, Frame>::iterator i = _positions.begin(); i != _positions.end(); ++i) {
+ i->second = 0;
}
-
- return p;
}
class AudioDecoder : public boost::enable_shared_from_this<AudioDecoder>, public DecoderPart
{
public:
- AudioDecoder (Decoder* parent, boost::shared_ptr<const AudioContent>, boost::shared_ptr<Log> log);
-
- boost::optional<ContentTime> position () const;
-
- void set_fast ();
- void flush ();
+ AudioDecoder (Decoder* parent, boost::shared_ptr<AudioContent> content, boost::shared_ptr<Log> log);
+ ContentTime position () const;
void emit (AudioStreamPtr stream, boost::shared_ptr<const AudioBuffers>, ContentTime);
+ void seek ();
boost::signals2::signal<void (AudioStreamPtr, ContentAudio)> Data;
private:
- /** An AudioDecoderStream object to manage each stream in _audio_content */
- typedef std::map<AudioStreamPtr, boost::shared_ptr<AudioDecoderStream> > StreamMap;
- StreamMap _streams;
- std::map<AudioStreamPtr, ContentTime> _positions;
+ std::map<AudioStreamPtr, Frame> _positions;
};
#endif
+++ /dev/null
-/*
- Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
-
- This file is part of DCP-o-matic.
-
- DCP-o-matic 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.
-
- DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-#include "audio_decoder_stream.h"
-#include "audio_buffers.h"
-#include "audio_processor.h"
-#include "audio_decoder.h"
-#include "resampler.h"
-#include "util.h"
-#include "film.h"
-#include "log.h"
-#include "audio_content.h"
-#include "compose.hpp"
-#include <iostream>
-
-#include "i18n.h"
-
-using std::list;
-using std::pair;
-using std::cout;
-using std::min;
-using std::max;
-using boost::optional;
-using boost::shared_ptr;
-
-AudioDecoderStream::AudioDecoderStream (
- shared_ptr<const AudioContent> content, AudioStreamPtr stream, Decoder* decoder, AudioDecoder* audio_decoder, shared_ptr<Log> log
- )
- : _content (content)
- , _stream (stream)
- , _decoder (decoder)
- , _audio_decoder (audio_decoder)
- , _log (log)
- /* We effectively start having done a seek to zero; this allows silence-padding of the first
- data that comes out of our decoder.
- */
- , _seek_reference (ContentTime ())
-{
- if (content->resampled_frame_rate() != _stream->frame_rate() && _stream->channels() > 0) {
- _resampler.reset (new Resampler (_stream->frame_rate(), content->resampled_frame_rate(), _stream->channels ()));
- }
-
- reset_decoded ();
-}
-
-void
-AudioDecoderStream::reset_decoded ()
-{
- _decoded = ContentAudio (shared_ptr<AudioBuffers> (new AudioBuffers (_stream->channels(), 0)), 0);
-}
-
-/** Audio timestamping is made hard by many factors, but perhaps the most entertaining is resampling.
- * We have to assume that we are feeding continuous data into the resampler, and so we get continuous
- * data out. Hence we do the timestamping here, post-resampler, just by counting samples.
- *
- * The time is passed in here so that after a seek we can set up our _position. The
- * time is ignored once this has been done.
- */
-void
-AudioDecoderStream::audio (shared_ptr<const AudioBuffers> data, ContentTime time)
-{
- _log->log (String::compose ("ADS receives %1 %2", to_string(time), data->frames ()), LogEntry::TYPE_DEBUG_DECODE);
-
- if (_resampler) {
- data = _resampler->run (data);
- }
-
- Frame const frame_rate = _content->resampled_frame_rate ();
-
- if (_seek_reference) {
- /* We've had an accurate seek and now we're seeing some data */
- ContentTime const delta = time - _seek_reference.get ();
- Frame const delta_frames = delta.frames_round (frame_rate);
- if (delta_frames > 0) {
- /* This data comes after the seek time. Pad the data with some silence. */
- shared_ptr<AudioBuffers> padded (new AudioBuffers (data->channels(), data->frames() + delta_frames));
- padded->make_silent ();
- padded->copy_from (data.get(), data->frames(), 0, delta_frames);
- data = padded;
- time -= delta;
- }
- _seek_reference = optional<ContentTime> ();
- }
-
- if (!_position) {
- _position = time.frames_round (frame_rate);
- }
-
- DCPOMATIC_ASSERT (_position.get() >= (_decoded.frame + _decoded.audio->frames()));
-
- add (data);
-}
-
-void
-AudioDecoderStream::add (shared_ptr<const AudioBuffers> data)
-{
- if (!_position) {
- /* This should only happen when there is a seek followed by a flush, but
- we need to cope with it.
- */
- return;
- }
-
- /* Resize _decoded to fit the new data */
- int new_size = 0;
- if (_decoded.audio->frames() == 0) {
- /* There's nothing in there, so just store the new data */
- new_size = data->frames ();
- _decoded.frame = _position.get ();
- } else {
- /* Otherwise we need to extend _decoded to include the new stuff */
- new_size = _position.get() + data->frames() - _decoded.frame;
- }
-
- _decoded.audio->ensure_size (new_size);
- _decoded.audio->set_frames (new_size);
-
- /* Copy new data in */
- _decoded.audio->copy_from (data.get(), data->frames(), 0, _position.get() - _decoded.frame);
- _position = _position.get() + data->frames ();
-
- /* Limit the amount of data we keep in case nobody is asking for it */
- int const max_frames = _content->resampled_frame_rate () * 10;
- if (_decoded.audio->frames() > max_frames) {
- int const to_remove = _decoded.audio->frames() - max_frames;
- _decoded.frame += to_remove;
- _decoded.audio->move (to_remove, 0, max_frames);
- _decoded.audio->set_frames (max_frames);
- }
-}
-
-void
-AudioDecoderStream::flush ()
-{
- if (!_resampler) {
- return;
- }
-
- shared_ptr<const AudioBuffers> b = _resampler->flush ();
- if (b) {
- add (b);
- }
-}
-
-void
-AudioDecoderStream::set_fast ()
-{
- if (_resampler) {
- _resampler->set_fast ();
- }
-}
-
-optional<ContentTime>
-AudioDecoderStream::position () const
-{
- if (!_position) {
- return optional<ContentTime> ();
- }
-
- return ContentTime::from_frames (_position.get(), _content->resampled_frame_rate());
-}
+++ /dev/null
-/*
- Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
-
- This file is part of DCP-o-matic.
-
- DCP-o-matic 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.
-
- DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-#ifndef DCPOMATIC_AUDIO_DECODER_STREAM_H
-#define DCPOMATIC_AUDIO_DECODER_STREAM_H
-
-#include "audio_stream.h"
-#include "content_audio.h"
-#include "dcpomatic_time.h"
-#include <boost/shared_ptr.hpp>
-
-class AudioContent;
-class AudioDecoder;
-class Resampler;
-class Log;
-class Decoder;
-
-class AudioDecoderStream
-{
-public:
- AudioDecoderStream (boost::shared_ptr<const AudioContent>, AudioStreamPtr, Decoder* decoder, AudioDecoder* audio_decoder, boost::shared_ptr<Log> log);
-
- void audio (boost::shared_ptr<const AudioBuffers>, ContentTime);
- void flush ();
- void set_fast ();
-
- boost::optional<ContentTime> position () const;
-
-private:
-
- void reset_decoded ();
- void add (boost::shared_ptr<const AudioBuffers>);
-
- boost::shared_ptr<const AudioContent> _content;
- AudioStreamPtr _stream;
- Decoder* _decoder;
- AudioDecoder* _audio_decoder;
- boost::shared_ptr<Log> _log;
- boost::shared_ptr<Resampler> _resampler;
- boost::optional<Frame> _position;
- /** Currently-available decoded audio data */
- ContentAudio _decoded;
- /** The time of an accurate seek after which we have not yet received any actual
- data at the seek time.
- */
- boost::optional<ContentTime> _seek_reference;
-};
-
-#endif
#include "audio_merger.h"
#include "dcpomatic_time.h"
+#include <iostream>
using std::pair;
using std::min;
*/
std::pair<boost::shared_ptr<AudioBuffers>, DCPTime> pull (DCPTime time);
void push (boost::shared_ptr<const AudioBuffers> audio, DCPTime time);
+ DCPTime last_pull () const {
+ return _last_pull;
+ }
private:
boost::shared_ptr<AudioBuffers> _buffers;
, frame (0)
{}
- ContentAudio (boost::shared_ptr<AudioBuffers> a, Frame f)
+ ContentAudio (boost::shared_ptr<const AudioBuffers> a, Frame f)
: audio (a)
, frame (f)
{}
- boost::shared_ptr<AudioBuffers> audio;
+ boost::shared_ptr<const AudioBuffers> audio;
Frame frame;
};
}
void
-DCPDecoder::seek (ContentTime t, bool)
+DCPDecoder::seek (ContentTime t, bool accurate)
{
+ Decoder::seek (t, accurate);
+
_reel = _reels.begin ();
_offset = 0;
get_readers ();
}
void
-DCPSubtitleDecoder::seek (ContentTime time, bool)
+DCPSubtitleDecoder::seek (ContentTime time, bool accurate)
{
+ Decoder::seek (time, accurate);
+
_next = _subtitles.begin ();
list<dcp::SubtitleString>::const_iterator i = _subtitles.begin ();
while (i != _subtitles.end() && ContentTime::from_seconds (_next->in().as_seconds()) < time) {
#include "video_decoder.h"
#include "audio_decoder.h"
#include "subtitle_decoder.h"
+#include <boost/optional.hpp>
+#include <iostream>
+
+using std::cout;
+using boost::optional;
ContentTime
Decoder::position () const
{
- ContentTime pos;
+ optional<ContentTime> pos;
- if (video && video->position()) {
- pos = min (pos, video->position().get());
+ if (video && (!pos || video->position() < *pos)) {
+ pos = video->position();
}
- if (audio && audio->position()) {
- pos = min (pos, audio->position().get());
+ if (audio && (!pos || audio->position() < *pos)) {
+ pos = audio->position();
}
- if (subtitle && subtitle->position()) {
- pos = min (pos, subtitle->position().get());
+ if (subtitle && (!pos || subtitle->position() < *pos)) {
+ pos = subtitle->position();
}
- return pos;
+ return pos.get_value_or(ContentTime());
+}
+
+void
+Decoder::seek (ContentTime time, bool accurate)
+{
+ if (audio) {
+ audio->seek ();
+ }
}
boost::shared_ptr<AudioDecoder> audio;
boost::shared_ptr<SubtitleDecoder> subtitle;
- /** @return true if there is no more data to come from this decoder */
+ /** 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;
- virtual void seek (ContentTime time, bool accurate) = 0;
+ virtual void seek (ContentTime time, bool accurate);
ContentTime position () const;
};
DecoderPart (Decoder* parent, boost::shared_ptr<Log> log);
virtual ~DecoderPart () {}
- virtual boost::optional<ContentTime> position () const = 0;
+ virtual ContentTime position () const = 0;
void set_ignore () {
_ignore = true;
if (audio) {
decode_audio_packet ();
- audio->flush ();
}
}
void
FFmpegDecoder::seek (ContentTime time, bool accurate)
{
+ Decoder::seek (time, accurate);
+
/* If we are doing an `accurate' seek, we need to use pre-roll, as
we don't really know what the seek will give us.
*/
}
void
-ImageDecoder::seek (ContentTime time, bool)
+ImageDecoder::seek (ContentTime time, bool accurate)
{
+ Decoder::seek (time, accurate);
_frame_video_position = time.frames_round (_image_content->active_video_frame_rate ());
}
: content (c)
, decoder (d)
, frc (f)
+ , done (false)
{}
boost::shared_ptr<Content> content;
boost::shared_ptr<Decoder> decoder;
FrameRateChange frc;
+ bool done;
};
#endif
#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>
#include <dcp/reel_subtitle_asset.h>
decoder->audio->set_ignore ();
}
- if (decoder->audio && _fast) {
- decoder->audio->set_fast ();
- }
-
shared_ptr<DCPDecoder> dcp = dynamic_pointer_cast<DCPDecoder> (decoder);
if (dcp && _play_referenced) {
dcp->set_decode_referenced ();
}
shared_ptr<Piece> earliest;
- DCPTime earliest_position;
+ DCPTime earliest_content;
+
BOOST_FOREACH (shared_ptr<Piece> i, _pieces) {
- DCPTime const t = i->content->position() + DCPTime (i->decoder->position(), i->frc);
- if (!earliest || t < earliest_position) {
- earliest_position = t;
- earliest = i;
+ if (!i->done) {
+ DCPTime const t = i->content->position() + DCPTime (i->decoder->position(), i->frc);
+ if (!earliest || t < earliest_content) {
+ earliest_content = t;
+ earliest = i;
+ }
}
}
return true;
}
- earliest->decoder->pass ();
+ earliest->done = earliest->decoder->pass ();
/* Emit any audio that is ready */
- pair<shared_ptr<AudioBuffers>, DCPTime> audio = _audio_merger.pull (earliest_position);
+ optional<DCPTime> earliest_audio;
+ BOOST_FOREACH (shared_ptr<Piece> i, _pieces) {
+ if (i->decoder->audio) {
+ DCPTime const t = i->content->position() + DCPTime (i->decoder->audio->position(), i->frc);
+ if (!earliest_audio || t < *earliest_audio) {
+ earliest_audio = t;
+ }
+ }
+ }
+
+ pair<shared_ptr<AudioBuffers>, DCPTime> audio = _audio_merger.pull (earliest_audio.get_value_or(DCPTime()));
if (audio.first->frames() > 0) {
DCPOMATIC_ASSERT (audio.second >= _last_audio_time);
DCPTime t = _last_audio_time;
DCPTime const time = content_video_to_dcp (piece, video.frame.index());
DCPTimePeriod const period (time, time + DCPTime::from_frames (1, _film->video_frame_rate()));
+ /* Discard if it's outside the content's period */
+ if (time < piece->content->position() || time >= piece->content->end()) {
+ return;
+ }
+
/* Get any subtitles */
optional<PositionImage> subtitles;
shared_ptr<AudioContent> content = piece->content->audio;
DCPOMATIC_ASSERT (content);
- shared_ptr<AudioBuffers> audio = content_audio.audio;
-
/* Gain */
if (content->gain() != 0) {
- shared_ptr<AudioBuffers> gain (new AudioBuffers (audio));
+ shared_ptr<AudioBuffers> gain (new AudioBuffers (content_audio.audio));
gain->apply_gain (content->gain ());
- audio = gain;
+ content_audio.audio = gain;
+ }
+
+ /* 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);
+ content_audio.audio = ro.first;
+ content_audio.frame = ro.second;
}
/* XXX: end-trimming used to be checked here */
/* Compute time in the DCP */
- DCPTime const time = resampled_audio_to_dcp (piece, content_audio.frame) + DCPTime::from_seconds (content->delay() / 1000);
+ DCPTime time = resampled_audio_to_dcp (piece, content_audio.frame) + DCPTime::from_seconds (content->delay() / 1000);
/* Remap channels */
- shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), audio->frames()));
+ shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), content_audio.audio->frames()));
dcp_mapped->make_silent ();
AudioMapping map = stream->mapping ();
for (int j = 0; j < dcp_mapped->channels(); ++j) {
if (map.get (i, static_cast<dcp::Channel> (j)) > 0) {
dcp_mapped->accumulate_channel (
- audio.get(),
+ content_audio.audio.get(),
i,
static_cast<dcp::Channel> (j),
map.get (i, static_cast<dcp::Channel> (j))
}
}
- audio = dcp_mapped;
+ content_audio.audio = dcp_mapped;
if (_audio_processor) {
- audio = _audio_processor->run (audio, _film->audio_channels ());
+ content_audio.audio = _audio_processor->run (content_audio.audio, _film->audio_channels ());
}
- _audio_merger.push (audio, time);
+ /* XXX: this may be nonsense */
+ if (time < _audio_merger.last_pull()) {
+ DCPTime const discard_time = _audio_merger.last_pull() - time;
+ Frame discard_frames = discard_time.frames_round(_film->audio_frame_rate());
+ content_audio.audio.reset (new AudioBuffers (_film->audio_channels(), content_audio.audio->frames() - discard_frames));
+ time += discard_time;
+ }
+
+ if (content_audio.audio->frames() > 0) {
+ _audio_merger.push (content_audio.audio, time);
+ }
}
void
BOOST_FOREACH (shared_ptr<Piece> i, _pieces) {
if (i->content->position() <= time && time < i->content->end()) {
i->decoder->seek (dcp_to_content_time (i, time), accurate);
+ i->done = false;
}
}
_last_time = optional<DCPTime> ();
}
}
+
+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;
+}
class Font;
class AudioBuffers;
class ReferencedReelAsset;
+class Resampler;
/** @class Player
* @brief A class which can `play' a Playlist.
void audio (boost::weak_ptr<Piece>, AudioStreamPtr, ContentAudio);
void image_subtitle (boost::weak_ptr<Piece>, ContentImageSubtitle);
void text_subtitle (boost::weak_ptr<Piece>, ContentTextSubtitle);
+ boost::shared_ptr<Resampler> resampler (boost::shared_ptr<const AudioContent> content, AudioStreamPtr stream, bool create);
boost::shared_ptr<const Film> _film;
boost::shared_ptr<const Playlist> _playlist;
std::list<std::pair<PlayerSubtitles, DCPTimePeriod> > _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;
}
}
-shared_ptr<const AudioBuffers>
-Resampler::run (shared_ptr<const AudioBuffers> in)
+pair<shared_ptr<const AudioBuffers>, Frame>
+Resampler::run (shared_ptr<const AudioBuffers> in, Frame frame)
{
+ 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;
}
- return resampled;
+ Frame out_frame = _next_out.get ();
+
+ /* Expected next output frame */
+ _next_out = _next_out.get() + resampled->frames();
+
+ return make_pair (resampled, out_frame);
}
shared_ptr<const AudioBuffers>
Resampler (int, int, int);
~Resampler ();
- boost::shared_ptr<const AudioBuffers> run (boost::shared_ptr<const AudioBuffers>);
+ std::pair<boost::shared_ptr<const AudioBuffers>, Frame> run (boost::shared_ptr<const AudioBuffers>, Frame);
boost::shared_ptr<const AudioBuffers> flush ();
void set_fast ();
int _in_rate;
int _out_rate;
int _channels;
+ boost::optional<Frame> _next_in;
+ boost::optional<Frame> _next_out;
};
boost::shared_ptr<Log> log
);
- boost::optional<ContentTime> position () const {
+ ContentTime position () const {
return _position;
}
private:
boost::shared_ptr<const SubtitleContent> _content;
- boost::optional<ContentTime> _position;
+ ContentTime _position;
};
#endif
}
void
-TextSubtitleDecoder::seek (ContentTime time, bool)
+TextSubtitleDecoder::seek (ContentTime time, bool accurate)
{
+ Decoder::seek (time, accurate);
+
_next = 0;
while (_next < _subtitles.size() && ContentTime::from_seconds (_subtitles[_next].from.all_as_seconds ()) < time) {
++_next;
friend struct ffmpeg_pts_offset_test;
friend void ffmpeg_decoder_sequential_test_one (boost::filesystem::path file, float fps, int gaps, int video_length);
- boost::optional<ContentTime> position () const {
+ ContentTime position () const {
return _position;
}
private:
boost::shared_ptr<const Content> _content;
boost::optional<Frame> _last_emitted;
- boost::optional<ContentTime> _position;
+ ContentTime _position;
};
#endif
}
void
-VideoMXFDecoder::seek (ContentTime t, bool)
+VideoMXFDecoder::seek (ContentTime t, bool accurate)
{
+ Decoder::seek (t, accurate);
_next = t;
}
audio_buffers.cc
audio_content.cc
audio_decoder.cc
- audio_decoder_stream.cc
audio_delay.cc
audio_filter.cc
audio_filter_graph.cc
for (int64_t i = 0; i < N; i += 1000) {
shared_ptr<AudioBuffers> a (new AudioBuffers (1, 1000));
a->make_silent ();
- shared_ptr<const AudioBuffers> r = resamp.run (a);
+ pair<shared_ptr<const AudioBuffers>, Frame> r = resamp.run (a, 0);
}
}