summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2012-11-17 22:06:12 +0000
committerCarl Hetherington <cth@carlh.net>2012-11-17 22:06:12 +0000
commitcafa76a2b52449ce3c9eecfd0ea53b7318814951 (patch)
tree81fe66f74256a54eb50f398790f2eea010bb3113 /src
parent40532d61ea4909b3f8b12dd7024de217dbdfec6d (diff)
Another attempt to do external audio moderately nicely.
Diffstat (limited to 'src')
-rw-r--r--src/lib/ab_transcoder.cc6
-rw-r--r--src/lib/audio_decoder.cc2
-rw-r--r--src/lib/audio_decoder.h10
-rw-r--r--src/lib/decoder_factory.cc3
-rw-r--r--src/lib/external_audio_decoder.cc92
-rw-r--r--src/lib/external_audio_decoder.h25
-rw-r--r--src/lib/ffmpeg_decoder.cc100
-rw-r--r--src/lib/ffmpeg_decoder.h34
-rw-r--r--src/lib/film.cc154
-rw-r--r--src/lib/film.h55
-rw-r--r--src/lib/j2k_wav_encoder.cc23
-rw-r--r--src/lib/stream.cc61
-rw-r--r--src/lib/stream.h70
-rw-r--r--src/lib/transcoder.cc6
-rw-r--r--src/lib/util.cc2
-rw-r--r--src/lib/video_decoder.cc2
-rw-r--r--src/lib/video_decoder.h10
-rw-r--r--src/wx/film_editor.cc74
18 files changed, 481 insertions, 248 deletions
diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc
index e9277a96f..f280ab48c 100644
--- a/src/lib/ab_transcoder.cc
+++ b/src/lib/ab_transcoder.cc
@@ -60,9 +60,9 @@ ABTranscoder::ABTranscoder (
_db = decoder_factory (_film_b, o, j);
if (_film_a->audio_stream()) {
- AudioStream st = _film_a->audio_stream().get();
- _matcher.reset (new Matcher (_film_a->log(), st.sample_rate(), _film_a->frames_per_second()));
- _delay_line.reset (new DelayLine (_film_a->log(), st.channels(), _film_a->audio_delay() * st.sample_rate() / 1000));
+ shared_ptr<AudioStream> st = _film_a->audio_stream();
+ _matcher.reset (new Matcher (_film_a->log(), st->sample_rate(), _film_a->frames_per_second()));
+ _delay_line.reset (new DelayLine (_film_a->log(), st->channels(), _film_a->audio_delay() * st->sample_rate() / 1000));
_gain.reset (new Gain (_film_a->log(), _film_a->audio_gain()));
}
diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc
index da39ef2ec..70f0effd9 100644
--- a/src/lib/audio_decoder.cc
+++ b/src/lib/audio_decoder.cc
@@ -30,7 +30,7 @@ AudioDecoder::AudioDecoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job
}
void
-AudioDecoder::set_audio_stream (optional<AudioStream> s)
+AudioDecoder::set_audio_stream (shared_ptr<AudioStream> s)
{
_audio_stream = s;
}
diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h
index 6e89f6144..e9fbd6f62 100644
--- a/src/lib/audio_decoder.h
+++ b/src/lib/audio_decoder.h
@@ -29,19 +29,19 @@ class AudioDecoder : public AudioSource, public virtual Decoder
public:
AudioDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *);
- virtual void set_audio_stream (boost::optional<AudioStream>);
+ virtual void set_audio_stream (boost::shared_ptr<AudioStream>);
- boost::optional<AudioStream> audio_stream () const {
+ boost::shared_ptr<AudioStream> audio_stream () const {
return _audio_stream;
}
- std::vector<AudioStream> audio_streams () const {
+ std::vector<boost::shared_ptr<AudioStream> > audio_streams () const {
return _audio_streams;
}
protected:
- boost::optional<AudioStream> _audio_stream;
- std::vector<AudioStream> _audio_streams;
+ boost::shared_ptr<AudioStream> _audio_stream;
+ std::vector<boost::shared_ptr<AudioStream> > _audio_streams;
};
#endif
diff --git a/src/lib/decoder_factory.cc b/src/lib/decoder_factory.cc
index e9b5bfa9e..b2118ef74 100644
--- a/src/lib/decoder_factory.cc
+++ b/src/lib/decoder_factory.cc
@@ -31,6 +31,7 @@ using std::string;
using std::pair;
using std::make_pair;
using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
pair<shared_ptr<VideoDecoder>, shared_ptr<AudioDecoder> >
decoder_factory (
@@ -49,6 +50,6 @@ decoder_factory (
if (f->use_content_audio()) {
return make_pair (fd, fd);
}
-
+
return make_pair (fd, shared_ptr<AudioDecoder> (new ExternalAudioDecoder (f, o, j)));
}
diff --git a/src/lib/external_audio_decoder.cc b/src/lib/external_audio_decoder.cc
index 2297ac4da..29668d922 100644
--- a/src/lib/external_audio_decoder.cc
+++ b/src/lib/external_audio_decoder.cc
@@ -24,19 +24,23 @@
using std::vector;
using std::string;
+using std::stringstream;
using std::min;
using std::cout;
using boost::shared_ptr;
+using boost::optional;
ExternalAudioDecoder::ExternalAudioDecoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j)
: Decoder (f, o, j)
, AudioDecoder (f, o, j)
{
-
+ sf_count_t frames;
+ vector<SNDFILE*> sf = open_files (frames);
+ close_files (sf);
}
-bool
-ExternalAudioDecoder::pass ()
+vector<SNDFILE*>
+ExternalAudioDecoder::open_files (sf_count_t & frames)
{
vector<string> const files = _film->external_audio ();
@@ -48,11 +52,11 @@ ExternalAudioDecoder::pass ()
}
if (N == 0) {
- return true;
+ return vector<SNDFILE*> ();
}
bool first = true;
- sf_count_t frames = 0;
+ frames = 0;
vector<SNDFILE*> sndfiles;
for (size_t i = 0; i < (size_t) N; ++i) {
@@ -72,8 +76,12 @@ ExternalAudioDecoder::pass ()
sndfiles.push_back (s);
if (first) {
- /* XXX: nasty magic value */
- AudioStream st ("DVDOMATIC-EXTERNAL", -1, info.samplerate, av_get_default_channel_layout (N));
+ shared_ptr<ExternalAudioStream> st (
+ new ExternalAudioStream (
+ info.samplerate, av_get_default_channel_layout (N)
+ )
+ );
+
_audio_streams.push_back (st);
_audio_stream = st;
frames = info.frames;
@@ -86,9 +94,23 @@ ExternalAudioDecoder::pass ()
}
}
+ return sndfiles;
+}
+
+bool
+ExternalAudioDecoder::pass ()
+{
+ sf_count_t frames;
+ vector<SNDFILE*> sndfiles = open_files (frames);
+ if (sndfiles.empty()) {
+ return true;
+ }
+
sf_count_t const block = 65536;
- shared_ptr<AudioBuffers> audio (new AudioBuffers (_audio_stream.get().channels(), block));
+ cout << frames << " audio frames.\n";
+
+ shared_ptr<AudioBuffers> audio (new AudioBuffers (_audio_stream->channels(), block));
while (frames > 0) {
sf_count_t const this_time = min (block, frames);
for (size_t i = 0; i < sndfiles.size(); ++i) {
@@ -103,9 +125,59 @@ ExternalAudioDecoder::pass ()
frames -= this_time;
}
+ close_files (sndfiles);
+
+ return true;
+}
+
+void
+ExternalAudioDecoder::close_files (vector<SNDFILE*> const & sndfiles)
+{
for (size_t i = 0; i < sndfiles.size(); ++i) {
sf_close (sndfiles[i]);
}
-
- return true;
+}
+
+shared_ptr<ExternalAudioStream>
+ExternalAudioStream::create ()
+{
+ return shared_ptr<ExternalAudioStream> (new ExternalAudioStream);
+}
+
+shared_ptr<ExternalAudioStream>
+ExternalAudioStream::create (string t, optional<int> v)
+{
+ if (!v) {
+ /* version < 1; no type in the string, and there's only FFmpeg streams anyway */
+ return shared_ptr<ExternalAudioStream> ();
+ }
+
+ stringstream s (t);
+ string type;
+ s >> type;
+ if (type != "external") {
+ return shared_ptr<ExternalAudioStream> ();
+ }
+
+ return shared_ptr<ExternalAudioStream> (new ExternalAudioStream (t, v));
+}
+
+ExternalAudioStream::ExternalAudioStream (string t, optional<int> v)
+{
+ assert (v);
+
+ stringstream s (t);
+ string type;
+ s >> type >> _sample_rate >> _channel_layout;
+}
+
+ExternalAudioStream::ExternalAudioStream ()
+{
+
+}
+
+string
+ExternalAudioStream::to_string () const
+{
+ return String::compose ("external %1 %2", _sample_rate, _channel_layout);
}
diff --git a/src/lib/external_audio_decoder.h b/src/lib/external_audio_decoder.h
index 79820936e..45a2a809c 100644
--- a/src/lib/external_audio_decoder.h
+++ b/src/lib/external_audio_decoder.h
@@ -17,8 +17,29 @@
*/
+#include <sndfile.h>
#include "decoder.h"
#include "audio_decoder.h"
+#include "stream.h"
+
+class ExternalAudioStream : public AudioStream
+{
+public:
+ ExternalAudioStream (int sample_rate, int64_t layout)
+ : AudioStream (sample_rate, layout)
+ {}
+
+ std::string to_string () const;
+
+ static boost::shared_ptr<ExternalAudioStream> create ();
+ static boost::shared_ptr<ExternalAudioStream> create (std::string t, boost::optional<int> v);
+
+private:
+ friend class stream_test;
+
+ ExternalAudioStream ();
+ ExternalAudioStream (std::string t, boost::optional<int> v);
+};
class ExternalAudioDecoder : public AudioDecoder
{
@@ -26,4 +47,8 @@ public:
ExternalAudioDecoder (boost::shared_ptr<Film>, boost::shared_ptr<const Options>, Job *);
bool pass ();
+
+private:
+ std::vector<SNDFILE*> open_files (sf_count_t &);
+ void close_files (std::vector<SNDFILE*> const &);
};
diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc
index 60f192c85..4a6e236c3 100644
--- a/src/lib/ffmpeg_decoder.cc
+++ b/src/lib/ffmpeg_decoder.cc
@@ -57,6 +57,7 @@ using std::stringstream;
using std::list;
using boost::shared_ptr;
using boost::optional;
+using boost::dynamic_pointer_cast;
FFmpegDecoder::FFmpegDecoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j)
: Decoder (f, o, j)
@@ -119,9 +120,17 @@ FFmpegDecoder::setup_general ()
if (s->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
_video_stream = i;
} else if (s->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
- _audio_streams.push_back (AudioStream (stream_name (s), i, s->codec->sample_rate, s->codec->channel_layout));
+ _audio_streams.push_back (
+ shared_ptr<AudioStream> (
+ new FFmpegAudioStream (stream_name (s), i, s->codec->sample_rate, s->codec->channel_layout)
+ )
+ );
} else if (s->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
- _subtitle_streams.push_back (SubtitleStream (stream_name (s), i));
+ _subtitle_streams.push_back (
+ shared_ptr<SubtitleStream> (
+ new SubtitleStream (stream_name (s), i)
+ )
+ );
}
}
@@ -163,8 +172,11 @@ FFmpegDecoder::setup_audio ()
if (!_audio_stream) {
return;
}
+
+ shared_ptr<FFmpegAudioStream> ffa = dynamic_pointer_cast<FFmpegAudioStream> (_audio_stream);
+ assert (ffa);
- _audio_codec_context = _format_context->streams[_audio_stream.get().id()]->codec;
+ _audio_codec_context = _format_context->streams[ffa->id()]->codec;
_audio_codec = avcodec_find_decoder (_audio_codec_context->codec_id);
if (_audio_codec == 0) {
@@ -180,7 +192,7 @@ FFmpegDecoder::setup_audio ()
*/
if (_audio_codec_context->channel_layout == 0) {
- _audio_codec_context->channel_layout = av_get_default_channel_layout (_audio_stream.get().channels());
+ _audio_codec_context->channel_layout = av_get_default_channel_layout (ffa->channels());
}
}
@@ -191,7 +203,7 @@ FFmpegDecoder::setup_subtitle ()
return;
}
- _subtitle_codec_context = _format_context->streams[_subtitle_stream.get().id()]->codec;
+ _subtitle_codec_context = _format_context->streams[_subtitle_stream->id()]->codec;
_subtitle_codec = avcodec_find_decoder (_subtitle_codec_context->codec_id);
if (_subtitle_codec == 0) {
@@ -230,7 +242,7 @@ FFmpegDecoder::pass ()
filter_and_emit_video (_frame);
}
- if (_audio_stream && _opt->decode_audio && _film->use_content_audio()) {
+ if (_audio_stream && _opt->decode_audio) {
while (avcodec_decode_audio4 (_audio_codec_context, _frame, &frame_finished, &_packet) >= 0 && frame_finished) {
int const data_size = av_samples_get_buffer_size (
0, _audio_codec_context->channels, _frame->nb_samples, audio_sample_format (), 1
@@ -245,6 +257,8 @@ FFmpegDecoder::pass ()
}
avcodec_get_frame_defaults (_frame);
+
+ shared_ptr<FFmpegAudioStream> ffa = dynamic_pointer_cast<FFmpegAudioStream> (_audio_stream);
if (_packet.stream_index == _video_stream) {
@@ -294,7 +308,7 @@ FFmpegDecoder::pass ()
}
}
- } else if (_audio_stream && _packet.stream_index == _audio_stream.get().id() && _opt->decode_audio && _film->use_content_audio()) {
+ } else if (ffa && _packet.stream_index == ffa->id() && _opt->decode_audio) {
int frame_finished;
if (avcodec_decode_audio4 (_audio_codec_context, _frame, &frame_finished, &_packet) >= 0 && frame_finished) {
@@ -318,17 +332,17 @@ FFmpegDecoder::pass ()
*/
/* frames of silence that we must push */
- int const s = rint ((_first_audio.get() - _first_video.get()) * _audio_stream.get().sample_rate ());
+ int const s = rint ((_first_audio.get() - _first_video.get()) * ffa->sample_rate ());
_film->log()->log (
String::compose (
"First video at %1, first audio at %2, pushing %3 frames of silence for %4 channels (%5 bytes per sample)",
- _first_video.get(), _first_audio.get(), s, _audio_stream.get().channels(), bytes_per_audio_sample()
+ _first_video.get(), _first_audio.get(), s, ffa->channels(), bytes_per_audio_sample()
)
);
if (s) {
- shared_ptr<AudioBuffers> audio (new AudioBuffers (_audio_stream.get().channels(), s));
+ shared_ptr<AudioBuffers> audio (new AudioBuffers (ffa->channels(), s));
audio->make_silent ();
Audio (audio);
}
@@ -343,7 +357,7 @@ FFmpegDecoder::pass ()
}
}
- } else if (_subtitle_stream && _packet.stream_index == _subtitle_stream.get().id() && _opt->decode_subtitles && _first_video) {
+ } else if (_subtitle_stream && _packet.stream_index == _subtitle_stream->id() && _opt->decode_subtitles && _first_video) {
int got_subtitle;
AVSubtitle sub;
@@ -369,14 +383,17 @@ FFmpegDecoder::deinterleave_audio (uint8_t* data, int size)
{
assert (_film->audio_channels());
assert (bytes_per_audio_sample());
+
+ shared_ptr<FFmpegAudioStream> ffa = dynamic_pointer_cast<FFmpegAudioStream> (_audio_stream);
+ assert (ffa);
/* Deinterleave and convert to float */
- assert ((size % (bytes_per_audio_sample() * _audio_stream.get().channels())) == 0);
+ assert ((size % (bytes_per_audio_sample() * ffa->channels())) == 0);
int const total_samples = size / bytes_per_audio_sample();
int const frames = total_samples / _film->audio_channels();
- shared_ptr<AudioBuffers> audio (new AudioBuffers (_audio_stream.get().channels(), frames));
+ shared_ptr<AudioBuffers> audio (new AudioBuffers (ffa->channels(), frames));
switch (audio_sample_format()) {
case AV_SAMPLE_FMT_S16:
@@ -519,14 +536,14 @@ FFmpegDecoder::bytes_per_audio_sample () const
}
void
-FFmpegDecoder::set_audio_stream (optional<AudioStream> s)
+FFmpegDecoder::set_audio_stream (shared_ptr<AudioStream> s)
{
AudioDecoder::set_audio_stream (s);
setup_audio ();
}
void
-FFmpegDecoder::set_subtitle_stream (optional<SubtitleStream> s)
+FFmpegDecoder::set_subtitle_stream (shared_ptr<SubtitleStream> s)
{
VideoDecoder::set_subtitle_stream (s);
setup_subtitle ();
@@ -556,3 +573,56 @@ FFmpegDecoder::filter_and_emit_video (AVFrame* frame)
emit_video (*i);
}
}
+
+shared_ptr<FFmpegAudioStream>
+FFmpegAudioStream::create (string t, optional<int> v)
+{
+ if (!v) {
+ /* version < 1; no type in the string, and there's only FFmpeg streams anyway */
+ return shared_ptr<FFmpegAudioStream> (new FFmpegAudioStream (t, v));
+ }
+
+ stringstream s (t);
+ string type;
+ s >> type;
+ if (type != "ffmpeg") {
+ return shared_ptr<FFmpegAudioStream> ();
+ }
+
+ return shared_ptr<FFmpegAudioStream> (new FFmpegAudioStream (t, v));
+}
+
+FFmpegAudioStream::FFmpegAudioStream (string t, optional<int> version)
+{
+ stringstream n (t);
+
+ int name_index = 4;
+ if (!version) {
+ name_index = 2;
+ int channels;
+ n >> _id >> channels;
+ _channel_layout = av_get_default_channel_layout (channels);
+ _sample_rate = 0;
+ } else {
+ string type;
+ /* Current (marked version 1) */
+ n >> type >> _id >> _sample_rate >> _channel_layout;
+ assert (type == "ffmpeg");
+ }
+
+ for (int i = 0; i < name_index; ++i) {
+ size_t const s = t.find (' ');
+ if (s != string::npos) {
+ t = t.substr (s + 1);
+ }
+ }
+
+ _name = t;
+}
+
+string
+FFmpegAudioStream::to_string () const
+{
+ return String::compose ("ffmpeg %1 %2 %3 %4", _id, _sample_rate, _channel_layout, _name);
+}
+
diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h
index a4a9246f0..87eebe1ec 100644
--- a/src/lib/ffmpeg_decoder.h
+++ b/src/lib/ffmpeg_decoder.h
@@ -48,6 +48,36 @@ class Options;
class Image;
class Log;
+class FFmpegAudioStream : public AudioStream
+{
+public:
+ FFmpegAudioStream (std::string n, int i, int s, int64_t c)
+ : AudioStream (s, c)
+ , _name (n)
+ , _id (i)
+ {}
+
+ std::string to_string () const;
+
+ std::string name () const {
+ return _name;
+ }
+
+ int id () const {
+ return _id;
+ }
+
+ static boost::shared_ptr<FFmpegAudioStream> create (std::string t, boost::optional<int> v);
+
+private:
+ friend class stream_test;
+
+ FFmpegAudioStream (std::string t, boost::optional<int> v);
+
+ std::string _name;
+ int _id;
+};
+
/** @class FFmpegDecoder
* @brief A decoder using FFmpeg to decode content.
*/
@@ -64,8 +94,8 @@ public:
int sample_aspect_ratio_numerator () const;
int sample_aspect_ratio_denominator () const;
- void set_audio_stream (boost::optional<AudioStream>);
- void set_subtitle_stream (boost::optional<SubtitleStream>);
+ void set_audio_stream (boost::shared_ptr<AudioStream>);
+ void set_subtitle_stream (boost::shared_ptr<SubtitleStream>);
private:
diff --git a/src/lib/film.cc b/src/lib/film.cc
index 2330e3c73..ce551041b 100644
--- a/src/lib/film.cc
+++ b/src/lib/film.cc
@@ -54,6 +54,7 @@
#include "ui_signaller.h"
#include "video_decoder.h"
#include "audio_decoder.h"
+#include "external_audio_decoder.h"
using std::string;
using std::stringstream;
@@ -66,6 +67,7 @@ using std::ofstream;
using std::setfill;
using std::min;
using std::make_pair;
+using std::cout;
using boost::shared_ptr;
using boost::lexical_cast;
using boost::to_upper_copy;
@@ -129,6 +131,8 @@ Film::Film (string d, bool must_exist)
}
}
+ _external_audio_stream = ExternalAudioStream::create ();
+
read_metadata ();
_log = new FileLog (file ("log"));
@@ -149,9 +153,9 @@ Film::Film (Film const & o)
, _dcp_trim_start (o._dcp_trim_start)
, _dcp_trim_end (o._dcp_trim_end)
, _dcp_ab (o._dcp_ab)
- , _use_content_audio (o._use_content_audio)
- , _audio_stream (o._audio_stream)
+ , _content_audio_stream (o._content_audio_stream)
, _external_audio (o._external_audio)
+ , _use_content_audio (o._use_content_audio)
, _audio_gain (o._audio_gain)
, _audio_delay (o._audio_delay)
, _still_duration (o._still_duration)
@@ -170,7 +174,8 @@ Film::Film (Film const & o)
, _size (o._size)
, _length (o._length)
, _content_digest (o._content_digest)
- , _audio_streams (o._audio_streams)
+ , _content_audio_streams (o._content_audio_streams)
+ , _external_audio_stream (o._external_audio_stream)
, _subtitle_streams (o._subtitle_streams)
, _frames_per_second (o._frames_per_second)
, _dirty (o._dirty)
@@ -264,8 +269,8 @@ Film::make_dcp (bool transcode)
o->video_decode_range = make_pair (dcp_trim_start(), dcp_trim_start() + dcp_length().get());
if (audio_stream()) {
o->audio_decode_range = make_pair (
- video_frames_to_audio_frames (o->video_decode_range.get().first, audio_stream().get().sample_rate(), frames_per_second()),
- video_frames_to_audio_frames (o->video_decode_range.get().second, audio_stream().get().sample_rate(), frames_per_second())
+ video_frames_to_audio_frames (o->video_decode_range.get().first, audio_stream()->sample_rate(), frames_per_second()),
+ video_frames_to_audio_frames (o->video_decode_range.get().second, audio_stream()->sample_rate(), frames_per_second())
);
}
@@ -424,18 +429,18 @@ Film::write_metadata () const
f << "dcp_trim_start " << _dcp_trim_start << "\n";
f << "dcp_trim_end " << _dcp_trim_end << "\n";
f << "dcp_ab " << (_dcp_ab ? "1" : "0") << "\n";
- f << "use_content_audio " << (_use_content_audio ? "1" : "0") << "\n";
- if (_audio_stream) {
- f << "selected_audio_stream " << _audio_stream.get().to_string() << "\n";
+ if (_content_audio_stream) {
+ f << "selected_content_audio_stream " << _content_audio_stream->to_string() << "\n";
}
for (vector<string>::const_iterator i = _external_audio.begin(); i != _external_audio.end(); ++i) {
f << "external_audio " << *i << "\n";
}
+ f << "use_content_audio " << (_use_content_audio ? "1" : "0") << "\n";
f << "audio_gain " << _audio_gain << "\n";
f << "audio_delay " << _audio_delay << "\n";
f << "still_duration " << _still_duration << "\n";
if (_subtitle_stream) {
- f << "selected_subtitle_stream " << _subtitle_stream.get().to_string() << "\n";
+ f << "selected_subtitle_stream " << _subtitle_stream->to_string() << "\n";
}
f << "with_subtitles " << _with_subtitles << "\n";
f << "subtitle_offset " << _subtitle_offset << "\n";
@@ -459,12 +464,14 @@ Film::write_metadata () const
f << "length " << _length.get_value_or(0) << "\n";
f << "content_digest " << _content_digest << "\n";
- for (vector<AudioStream>::const_iterator i = _audio_streams.begin(); i != _audio_streams.end(); ++i) {
- f << "audio_stream " << i->to_string () << "\n";
+ for (vector<shared_ptr<AudioStream> >::const_iterator i = _content_audio_streams.begin(); i != _content_audio_streams.end(); ++i) {
+ f << "content_audio_stream " << (*i)->to_string () << "\n";
}
- for (vector<SubtitleStream>::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) {
- f << "subtitle_stream " << i->to_string () << "\n";
+ f << "external_audio_stream " << _external_audio_stream->to_string() << "\n";
+
+ for (vector<shared_ptr<SubtitleStream> >::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) {
+ f << "subtitle_stream " << (*i)->to_string () << "\n";
}
f << "frames_per_second " << _frames_per_second << "\n";
@@ -480,7 +487,7 @@ Film::read_metadata ()
_external_audio.clear ();
_thumbs.clear ();
- _audio_streams.clear ();
+ _content_audio_streams.clear ();
_subtitle_streams.clear ();
boost::optional<int> version;
@@ -492,13 +499,18 @@ Film::read_metadata ()
ifstream f (file ("metadata").c_str());
multimap<string, string> kv = read_key_value (f);
+
+ /* We need version before anything else */
+ multimap<string, string>::iterator v = kv.find ("version");
+ if (v != kv.end ()) {
+ version = atoi (v->second.c_str());
+ }
+
for (multimap<string, string>::const_iterator i = kv.begin(); i != kv.end(); ++i) {
string const k = i->first;
string const v = i->second;
- if (k == "version") {
- version = atoi (v.c_str());
- } else if (k == "audio_sample_rate") {
+ if (k == "audio_sample_rate") {
audio_sample_rate = atoi (v.c_str());
}
@@ -531,16 +543,16 @@ Film::read_metadata ()
_dcp_trim_end = atoi (v.c_str ());
} else if (k == "dcp_ab") {
_dcp_ab = (v == "1");
- } else if (k == "use_content_audio") {
- _use_content_audio = (v == "1");
- } else if (k == "selected_audio_stream") {
+ } else if (k == "selected_content_audio_stream" || (!version && k == "content_audio_stream")) {
if (!version) {
audio_stream_index = atoi (v.c_str ());
} else {
- _audio_stream = AudioStream (v, version);
+ _content_audio_stream = audio_stream_factory (v, version);
}
} else if (k == "external_audio") {
_external_audio.push_back (v);
+ } else if (k == "use_content_audio") {
+ _use_content_audio = (v == "1");
} else if (k == "audio_gain") {
_audio_gain = atof (v.c_str ());
} else if (k == "audio_delay") {
@@ -551,7 +563,7 @@ Film::read_metadata ()
if (!version) {
subtitle_stream_index = atoi (v.c_str ());
} else {
- _subtitle_stream = SubtitleStream (v);
+ _subtitle_stream = subtitle_stream_factory (v, version);
}
} else if (k == "with_subtitles") {
_with_subtitles = (v == "1");
@@ -593,10 +605,12 @@ Film::read_metadata ()
}
} else if (k == "content_digest") {
_content_digest = v;
- } else if (k == "audio_stream") {
- _audio_streams.push_back (AudioStream (v, version));
+ } else if (k == "content_audio_stream" || (!version && k == "audio_stream")) {
+ _content_audio_streams.push_back (audio_stream_factory (v, version));
+ } else if (k == "external_audio_stream") {
+ _external_audio_stream = audio_stream_factory (v, version);
} else if (k == "subtitle_stream") {
- _subtitle_streams.push_back (SubtitleStream (v));
+ _subtitle_streams.push_back (subtitle_stream_factory (v, version));
} else if (k == "frames_per_second") {
_frames_per_second = atof (v.c_str ());
}
@@ -605,14 +619,14 @@ Film::read_metadata ()
if (!version) {
if (audio_sample_rate) {
/* version < 1 didn't specify sample rate in the audio streams, so fill it in here */
- for (vector<AudioStream>::iterator i = _audio_streams.begin(); i != _audio_streams.end(); ++i) {
- i->set_sample_rate (audio_sample_rate.get());
+ for (vector<shared_ptr<AudioStream> >::iterator i = _content_audio_streams.begin(); i != _content_audio_streams.end(); ++i) {
+ (*i)->set_sample_rate (audio_sample_rate.get());
}
}
/* also the selected stream was specified as an index */
- if (audio_stream_index && audio_stream_index.get() >= 0 && audio_stream_index.get() < (int) _audio_streams.size()) {
- _audio_stream = _audio_streams[audio_stream_index.get()];
+ if (audio_stream_index && audio_stream_index.get() >= 0 && audio_stream_index.get() < (int) _content_audio_streams.size()) {
+ _content_audio_stream = _content_audio_streams[audio_stream_index.get()];
}
/* similarly the subtitle */
@@ -748,8 +762,12 @@ Film::content_type () const
int
Film::target_audio_sample_rate () const
{
+ if (!audio_stream()) {
+ return 0;
+ }
+
/* Resample to a DCI-approved sample rate */
- double t = dcp_audio_sample_rate (audio_stream().get().sample_rate());
+ double t = dcp_audio_sample_rate (audio_stream()->sample_rate());
DCPFrameRate dfr = dcp_frame_rate (frames_per_second ());
@@ -930,8 +948,8 @@ Film::set_content (string c)
_content = c;
}
- _audio_stream = optional<AudioStream> ();
- _subtitle_stream = optional<SubtitleStream> ();
+ _content_audio_stream = shared_ptr<AudioStream> ();
+ _subtitle_stream = shared_ptr<SubtitleStream> ();
/* Create a temporary decoder so that we can get information
about the content.
@@ -946,11 +964,11 @@ Film::set_content (string c)
set_size (d.first->native_size ());
set_frames_per_second (d.first->frames_per_second ());
set_subtitle_streams (d.first->subtitle_streams ());
- set_audio_streams (d.second->audio_streams ());
+ set_content_audio_streams (d.second->audio_streams ());
/* Start off with the first audio and subtitle streams */
if (!d.second->audio_streams().empty()) {
- set_audio_stream (d.second->audio_streams().front());
+ set_content_audio_stream (d.second->audio_streams().front());
}
if (!d.first->subtitle_streams().empty()) {
@@ -1115,33 +1133,42 @@ Film::set_dcp_ab (bool a)
}
void
-Film::set_use_content_audio (bool s)
+Film::set_content_audio_stream (shared_ptr<AudioStream> s)
{
{
boost::mutex::scoped_lock lm (_state_mutex);
- _use_content_audio = s;
+ _content_audio_stream = s;
}
- signal_changed (USE_CONTENT_AUDIO);
+ signal_changed (CONTENT_AUDIO_STREAM);
}
void
-Film::set_audio_stream (optional<AudioStream> s)
+Film::set_external_audio (vector<string> a)
{
{
boost::mutex::scoped_lock lm (_state_mutex);
- _audio_stream = s;
+ _external_audio = a;
+ }
+
+ shared_ptr<Options> o (new Options ("", "", ""));
+ o->decode_audio = true;
+ shared_ptr<ExternalAudioDecoder> decoder (new ExternalAudioDecoder (shared_from_this(), o, 0));
+ if (decoder->audio_stream()) {
+ _external_audio_stream = decoder->audio_stream ();
}
- signal_changed (AUDIO_STREAM);
+
+ signal_changed (EXTERNAL_AUDIO);
}
void
-Film::set_external_audio (vector<string> a)
+Film::set_use_content_audio (bool e)
{
{
boost::mutex::scoped_lock lm (_state_mutex);
- _external_audio = a;
+ _use_content_audio = e;
}
- signal_changed (EXTERNAL_AUDIO);
+
+ signal_changed (USE_CONTENT_AUDIO);
}
void
@@ -1175,7 +1202,7 @@ Film::set_still_duration (int d)
}
void
-Film::set_subtitle_stream (optional<SubtitleStream> s)
+Film::set_subtitle_stream (shared_ptr<SubtitleStream> s)
{
{
boost::mutex::scoped_lock lm (_state_mutex);
@@ -1335,23 +1362,23 @@ Film::set_content_digest (string d)
}
void
-Film::set_audio_streams (vector<AudioStream> s)
+Film::set_content_audio_streams (vector<shared_ptr<AudioStream> > s)
{
{
boost::mutex::scoped_lock lm (_state_mutex);
- _audio_streams = s;
+ _content_audio_streams = s;
}
- _dirty = true;
+ signal_changed (CONTENT_AUDIO_STREAMS);
}
void
-Film::set_subtitle_streams (vector<SubtitleStream> s)
+Film::set_subtitle_streams (vector<shared_ptr<SubtitleStream> > s)
{
{
boost::mutex::scoped_lock lm (_state_mutex);
_subtitle_streams = s;
}
- _dirty = true;
+ signal_changed (SUBTITLE_STREAMS);
}
void
@@ -1380,24 +1407,12 @@ Film::signal_changed (Property p)
int
Film::audio_channels () const
{
- boost::mutex::scoped_lock lm (_state_mutex);
-
- if (_use_content_audio) {
- if (_audio_stream) {
- return _audio_stream.get().channels ();
- }
- } else {
- int last_filled = -1;
- for (size_t i = 0; i < _external_audio.size(); ++i) {
- if (!_external_audio[i].empty()) {
- last_filled = i;
- }
- }
-
- return last_filled + 1;
+ shared_ptr<AudioStream> s = audio_stream ();
+ if (!s) {
+ return 0;
}
- return 0;
+ return s->channels ();
}
void
@@ -1406,3 +1421,12 @@ Film::set_dci_date_today ()
_dci_date = boost::gregorian::day_clock::local_day ();
}
+boost::shared_ptr<AudioStream>
+Film::audio_stream () const
+{
+ if (use_content_audio()) {
+ return _content_audio_stream;
+ }
+
+ return _external_audio_stream;
+}
diff --git a/src/lib/film.h b/src/lib/film.h
index 37eb13d25..99957a00f 100644
--- a/src/lib/film.h
+++ b/src/lib/film.h
@@ -44,6 +44,7 @@ class Job;
class Filter;
class Log;
class ExamineContentJob;
+class ExternalAudioStream;
/** @class Film
* @brief A representation of a video with sound.
@@ -120,9 +121,9 @@ public:
DCP_TRIM_START,
DCP_TRIM_END,
DCP_AB,
- USE_CONTENT_AUDIO,
- AUDIO_STREAM,
+ CONTENT_AUDIO_STREAM,
EXTERNAL_AUDIO,
+ USE_CONTENT_AUDIO,
AUDIO_GAIN,
AUDIO_DELAY,
STILL_DURATION,
@@ -134,7 +135,7 @@ public:
THUMBS,
SIZE,
LENGTH,
- AUDIO_STREAMS,
+ CONTENT_AUDIO_STREAMS,
SUBTITLE_STREAMS,
FRAMES_PER_SECOND,
};
@@ -202,19 +203,19 @@ public:
return _dcp_ab;
}
- bool use_content_audio () const {
+ boost::shared_ptr<AudioStream> content_audio_stream () const {
boost::mutex::scoped_lock lm (_state_mutex);
- return _use_content_audio;
+ return _content_audio_stream;
}
- boost::optional<AudioStream> audio_stream () const {
+ std::vector<std::string> external_audio () const {
boost::mutex::scoped_lock lm (_state_mutex);
- return _audio_stream;
+ return _external_audio;
}
- std::vector<std::string> external_audio () const {
+ bool use_content_audio () const {
boost::mutex::scoped_lock lm (_state_mutex);
- return _external_audio;
+ return _use_content_audio;
}
float audio_gain () const {
@@ -232,7 +233,7 @@ public:
return _still_duration;
}
- boost::optional<SubtitleStream> subtitle_stream () const {
+ boost::shared_ptr<SubtitleStream> subtitle_stream () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _subtitle_stream;
}
@@ -307,12 +308,12 @@ public:
return _content_digest;
}
- std::vector<AudioStream> audio_streams () const {
+ std::vector<boost::shared_ptr<AudioStream> > content_audio_streams () const {
boost::mutex::scoped_lock lm (_state_mutex);
- return _audio_streams;
+ return _content_audio_streams;
}
- std::vector<SubtitleStream> subtitle_streams () const {
+ std::vector<boost::shared_ptr<SubtitleStream> > subtitle_streams () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _subtitle_streams;
}
@@ -322,7 +323,9 @@ public:
return _frames_per_second;
}
+ boost::shared_ptr<AudioStream> audio_stream () const;
+
/* SET */
void set_directory (std::string);
@@ -341,13 +344,13 @@ public:
void set_dcp_trim_start (int);
void set_dcp_trim_end (int);
void set_dcp_ab (bool);
- void set_use_content_audio (bool);
- void set_audio_stream (boost::optional<AudioStream>);
+ void set_content_audio_stream (boost::shared_ptr<AudioStream>);
void set_external_audio (std::vector<std::string>);
+ void set_use_content_audio (bool);
void set_audio_gain (float);
void set_audio_delay (int);
void set_still_duration (int);
- void set_subtitle_stream (boost::optional<SubtitleStream>);
+ void set_subtitle_stream (boost::shared_ptr<SubtitleStream>);
void set_with_subtitles (bool);
void set_subtitle_offset (int);
void set_subtitle_scale (float);
@@ -363,8 +366,8 @@ public:
void set_length (SourceFrame);
void unset_length ();
void set_content_digest (std::string);
- void set_audio_streams (std::vector<AudioStream>);
- void set_subtitle_streams (std::vector<SubtitleStream>);
+ void set_content_audio_streams (std::vector<boost::shared_ptr<AudioStream> >);
+ void set_subtitle_streams (std::vector<boost::shared_ptr<SubtitleStream> >);
void set_frames_per_second (float);
/** Emitted when some property has changed */
@@ -422,17 +425,16 @@ private:
has the specified filters and post-processing.
*/
bool _dcp_ab;
- /** true to use the audio from the content file, false to use external audio */
- bool _use_content_audio;
- boost::optional<AudioStream> _audio_stream;
+ boost::shared_ptr<AudioStream> _content_audio_stream;
std::vector<std::string> _external_audio;
+ bool _use_content_audio;
/** Gain to apply to audio in dB */
float _audio_gain;
/** Delay to apply to audio (positive moves audio later) in milliseconds */
int _audio_delay;
/** Duration to make still-sourced films (in seconds) */
int _still_duration;
- boost::optional<SubtitleStream> _subtitle_stream;
+ boost::shared_ptr<SubtitleStream> _subtitle_stream;
/** True if subtitles should be shown for this film */
bool _with_subtitles;
/** y offset for placing subtitles, in source pixels; +ve is further down
@@ -461,10 +463,11 @@ private:
boost::optional<SourceFrame> _length;
/** MD5 digest of our content file */
std::string _content_digest;
- /** the audio streams that the source has */
- std::vector<AudioStream> _audio_streams;
- /** the subtitle streams that the source has */
- std::vector<SubtitleStream> _subtitle_streams;
+ /** the audio streams in our content */
+ std::vector<boost::shared_ptr<AudioStream> > _content_audio_streams;
+ boost::shared_ptr<AudioStream> _external_audio_stream;
+ /** the subtitle streams that we can use */
+ std::vector<boost::shared_ptr<SubtitleStream> > _subtitle_streams;
/** Frames per second of the source */
float _frames_per_second;
diff --git a/src/lib/j2k_wav_encoder.cc b/src/lib/j2k_wav_encoder.cc
index 847ee9486..be1f96fd4 100644
--- a/src/lib/j2k_wav_encoder.cc
+++ b/src/lib/j2k_wav_encoder.cc
@@ -46,6 +46,7 @@ using std::stringstream;
using std::list;
using std::vector;
using std::pair;
+using std::cout;
using boost::shared_ptr;
using boost::thread;
using boost::lexical_cast;
@@ -64,7 +65,7 @@ J2KWAVEncoder::J2KWAVEncoder (shared_ptr<const Film> f, shared_ptr<const Options
*/
for (int i = 0; i < _film->audio_channels(); ++i) {
SF_INFO sf_info;
- sf_info.samplerate = dcp_audio_sample_rate (_film->audio_stream().get().sample_rate());
+ sf_info.samplerate = dcp_audio_sample_rate (_film->audio_stream()->sample_rate());
/* We write mono files */
sf_info.channels = 1;
sf_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_24;
@@ -229,22 +230,22 @@ J2KWAVEncoder::encoder_thread (ServerDescription* server)
void
J2KWAVEncoder::process_begin ()
{
- if (_film->audio_stream() && _film->audio_stream().get().sample_rate() != _film->target_audio_sample_rate()) {
+ if (_film->audio_stream() && _film->audio_stream()->sample_rate() != _film->target_audio_sample_rate()) {
#ifdef HAVE_SWRESAMPLE
stringstream s;
- s << "Will resample audio from " << _film->audio_stream().get().sample_rate() << " to " << _film->target_audio_sample_rate();
+ s << "Will resample audio from " << _film->audio_stream()->sample_rate() << " to " << _film->target_audio_sample_rate();
_film->log()->log (s.str ());
/* We will be using planar float data when we call the resampler */
_swr_context = swr_alloc_set_opts (
0,
- _film->audio_stream().get().channel_layout(),
+ _film->audio_stream()->channel_layout(),
AV_SAMPLE_FMT_FLTP,
_film->target_audio_sample_rate(),
- _film->audio_stream().get().channel_layout(),
+ _film->audio_stream()->channel_layout(),
AV_SAMPLE_FMT_FLTP,
- _film->audio_stream().get().sample_rate(),
+ _film->audio_stream()->sample_rate(),
0, 0
);
@@ -314,7 +315,7 @@ J2KWAVEncoder::process_end ()
#if HAVE_SWRESAMPLE
if (_film->audio_stream() && _swr_context) {
- shared_ptr<AudioBuffers> out (new AudioBuffers (_film->audio_stream().get().channels(), 256));
+ shared_ptr<AudioBuffers> out (new AudioBuffers (_film->audio_stream()->channels(), 256));
while (1) {
int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0);
@@ -336,9 +337,9 @@ J2KWAVEncoder::process_end ()
#endif
if (_film->audio_stream()) {
- int const dcp_sr = dcp_audio_sample_rate (_film->audio_stream().get().sample_rate ());
+ int const dcp_sr = dcp_audio_sample_rate (_film->audio_stream()->sample_rate ());
int64_t const extra_audio_frames = dcp_sr - (_audio_frames_written % dcp_sr);
- shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_stream().get().channels(), extra_audio_frames));
+ shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_stream()->channels(), extra_audio_frames));
silence->make_silent ();
write_audio (silence);
@@ -364,9 +365,9 @@ J2KWAVEncoder::do_process_audio (shared_ptr<AudioBuffers> audio)
if (_swr_context) {
/* Compute the resampled frames count and add 32 for luck */
- int const max_resampled_frames = ceil (audio->frames() * _film->target_audio_sample_rate() / _film->audio_stream().get().sample_rate()) + 32;
+ int const max_resampled_frames = ceil ((int64_t) audio->frames() * _film->target_audio_sample_rate() / _film->audio_stream()->sample_rate()) + 32;
- resampled.reset (new AudioBuffers (_film->audio_stream().get().channels(), max_resampled_frames));
+ resampled.reset (new AudioBuffers (_film->audio_stream()->channels(), max_resampled_frames));
/* Resample audio */
int const resampled_frames = swr_convert (
diff --git a/src/lib/stream.cc b/src/lib/stream.cc
index 5bc184eb9..372077cd8 100644
--- a/src/lib/stream.cc
+++ b/src/lib/stream.cc
@@ -20,55 +20,52 @@
#include <sstream>
#include "compose.hpp"
#include "stream.h"
+#include "ffmpeg_decoder.h"
+#include "external_audio_decoder.h"
-using namespace std;
+using std::string;
+using std::stringstream;
+using boost::shared_ptr;
using boost::optional;
-AudioStream::AudioStream (string t, optional<int> version)
+SubtitleStream::SubtitleStream (string t, boost::optional<int>)
{
stringstream n (t);
-
- int name_index = 3;
- if (!version) {
- name_index = 2;
- int channels;
- n >> _id >> channels;
- _channel_layout = av_get_default_channel_layout (channels);
- _sample_rate = 0;
- } else {
- /* Current (marked version 1) */
- n >> _id >> _sample_rate >> _channel_layout;
- }
+ n >> _id;
- for (int i = 0; i < name_index; ++i) {
- size_t const s = t.find (' ');
- if (s != string::npos) {
- t = t.substr (s + 1);
- }
+ size_t const s = t.find (' ');
+ if (s != string::npos) {
+ _name = t.substr (s + 1);
}
-
- _name = t;
}
string
-AudioStream::to_string () const
+SubtitleStream::to_string () const
{
- return String::compose ("%1 %2 %3 %4", _id, _sample_rate, _channel_layout, _name);
+ return String::compose ("%1 %2", _id, _name);
}
-SubtitleStream::SubtitleStream (string t)
+shared_ptr<SubtitleStream>
+SubtitleStream::create (string t, optional<int> v)
{
- stringstream n (t);
- n >> _id;
+ return shared_ptr<SubtitleStream> (new SubtitleStream (t, v));
+}
- size_t const s = t.find (' ');
- if (s != string::npos) {
- _name = t.substr (s + 1);
+shared_ptr<AudioStream>
+audio_stream_factory (string t, optional<int> v)
+{
+ shared_ptr<AudioStream> s;
+
+ s = FFmpegAudioStream::create (t, v);
+ if (!s) {
+ s = ExternalAudioStream::create (t, v);
}
+
+ return s;
}
-string
-SubtitleStream::to_string () const
+shared_ptr<SubtitleStream>
+subtitle_stream_factory (string t, optional<int> v)
{
- return String::compose ("%1 %2", _id, _name);
+ return SubtitleStream::create (t, v);
}
diff --git a/src/lib/stream.h b/src/lib/stream.h
index 760befa02..5dd91f5f4 100644
--- a/src/lib/stream.h
+++ b/src/lib/stream.h
@@ -21,6 +21,7 @@
#define DVDOMATIC_STREAM_H
#include <stdint.h>
+#include <boost/shared_ptr.hpp>
#include <boost/optional.hpp>
extern "C" {
#include <libavutil/audioconvert.h>
@@ -29,48 +30,22 @@ extern "C" {
class Stream
{
public:
- Stream ()
- : _id (-1)
- {}
-
- Stream (std::string n, int i)
- : _name (n)
- , _id (i)
- {}
-
virtual std::string to_string () const = 0;
-
- std::string name () const {
- return _name;
- }
-
- int id () const {
- return _id;
- }
-
-protected:
- std::string _name;
- int _id;
};
struct AudioStream : public Stream
{
public:
- AudioStream (std::string t, boost::optional<int> v);
-
- AudioStream (std::string n, int id, int r, int64_t l)
- : Stream (n, id)
- , _sample_rate (r)
+ AudioStream (int r, int64_t l)
+ : _sample_rate (r)
, _channel_layout (l)
{}
- /** Only used for state file version < 1 compatibility */
- void set_sample_rate (int r) {
- _sample_rate = r;
+ /* Only used for backwards compatibility for state file version < 1 */
+ void set_sample_rate (int s) {
+ _sample_rate = s;
}
- std::string to_string () const;
-
int channels () const {
return av_get_channel_layout_nb_channels (_channel_layout);
}
@@ -83,7 +58,12 @@ public:
return _channel_layout;
}
-private:
+protected:
+ AudioStream ()
+ : _sample_rate (0)
+ , _channel_layout (0)
+ {}
+
int _sample_rate;
int64_t _channel_layout;
};
@@ -91,13 +71,33 @@ private:
class SubtitleStream : public Stream
{
public:
- SubtitleStream (std::string t);
-
SubtitleStream (std::string n, int i)
- : Stream (n, i)
+ : _name (n)
+ , _id (i)
{}
std::string to_string () const;
+
+ std::string name () const {
+ return _name;
+ }
+
+ int id () const {
+ return _id;
+ }
+
+ static boost::shared_ptr<SubtitleStream> create (std::string t, boost::optional<int> v);
+
+private:
+ friend class stream_test;
+
+ SubtitleStream (std::string t, boost::optional<int> v);
+
+ std::string _name;
+ int _id;
};
+boost::shared_ptr<AudioStream> audio_stream_factory (std::string t, boost::optional<int> version);
+boost::shared_ptr<SubtitleStream> subtitle_stream_factory (std::string t, boost::optional<int> version);
+
#endif
diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc
index 2ee96790a..cad76af6e 100644
--- a/src/lib/transcoder.cc
+++ b/src/lib/transcoder.cc
@@ -56,9 +56,9 @@ Transcoder::Transcoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j,
assert (_encoder);
if (f->audio_stream()) {
- AudioStream st = f->audio_stream().get();
- _matcher.reset (new Matcher (f->log(), st.sample_rate(), f->frames_per_second()));
- _delay_line.reset (new DelayLine (f->log(), st.channels(), f->audio_delay() * st.sample_rate() / 1000));
+ shared_ptr<AudioStream> st = f->audio_stream();
+ _matcher.reset (new Matcher (f->log(), st->sample_rate(), f->frames_per_second()));
+ _delay_line.reset (new DelayLine (f->log(), st->channels(), f->audio_delay() * st->sample_rate() / 1000));
_gain.reset (new Gain (f->log(), f->audio_gain()));
}
diff --git a/src/lib/util.cc b/src/lib/util.cc
index ed9594692..aeb529702 100644
--- a/src/lib/util.cc
+++ b/src/lib/util.cc
@@ -650,7 +650,7 @@ read_key_value (istream &s)
if (line.empty ()) {
continue;
}
-
+
if (line[0] == '#') {
continue;
}
diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc
index 38a0e0e34..23a69f958 100644
--- a/src/lib/video_decoder.cc
+++ b/src/lib/video_decoder.cc
@@ -84,7 +84,7 @@ VideoDecoder::emit_subtitle (shared_ptr<TimedSubtitle> s)
}
void
-VideoDecoder::set_subtitle_stream (optional<SubtitleStream> s)
+VideoDecoder::set_subtitle_stream (shared_ptr<SubtitleStream> s)
{
_subtitle_stream = s;
}
diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h
index fb782cd7e..5acce7c8d 100644
--- a/src/lib/video_decoder.h
+++ b/src/lib/video_decoder.h
@@ -39,7 +39,7 @@ public:
virtual int sample_aspect_ratio_numerator () const = 0;
virtual int sample_aspect_ratio_denominator () const = 0;
- virtual void set_subtitle_stream (boost::optional<SubtitleStream>);
+ virtual void set_subtitle_stream (boost::shared_ptr<SubtitleStream>);
void set_progress () const;
@@ -47,11 +47,11 @@ public:
return _video_frame;
}
- boost::optional<SubtitleStream> subtitle_stream () const {
+ boost::shared_ptr<SubtitleStream> subtitle_stream () const {
return _subtitle_stream;
}
- std::vector<SubtitleStream> subtitle_streams () const {
+ std::vector<boost::shared_ptr<SubtitleStream> > subtitle_streams () const {
return _subtitle_streams;
}
@@ -63,8 +63,8 @@ protected:
void emit_subtitle (boost::shared_ptr<TimedSubtitle>);
void repeat_last_video ();
- boost::optional<SubtitleStream> _subtitle_stream;
- std::vector<SubtitleStream> _subtitle_streams;
+ boost::shared_ptr<SubtitleStream> _subtitle_stream;
+ std::vector<boost::shared_ptr<SubtitleStream> > _subtitle_streams;
private:
void signal_video (boost::shared_ptr<Image>, boost::shared_ptr<Subtitle>);
diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc
index 6602435c4..f2831d75a 100644
--- a/src/wx/film_editor.cc
+++ b/src/wx/film_editor.cc
@@ -37,6 +37,8 @@
#include "lib/filter.h"
#include "lib/screen.h"
#include "lib/config.h"
+#include "lib/ffmpeg_decoder.h"
+#include "lib/external_audio_decoder.h"
#include "filter_dialog.h"
#include "wx_util.h"
#include "film_editor.h"
@@ -54,6 +56,7 @@ using std::setprecision;
using std::list;
using std::vector;
using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
/** @param f Film to edit */
FilmEditor::FilmEditor (shared_ptr<Film> f, wxWindow* parent)
@@ -485,11 +488,13 @@ FilmEditor::film_changed (Film::Property p)
setup_subtitle_control_sensitivity ();
setup_streams ();
break;
- case Film::AUDIO_STREAMS:
case Film::SUBTITLE_STREAMS:
setup_subtitle_control_sensitivity ();
setup_streams ();
break;
+ case Film::CONTENT_AUDIO_STREAMS:
+ setup_streams ();
+ break;
case Film::FORMAT:
{
int n = 0;
@@ -600,31 +605,33 @@ FilmEditor::film_changed (Film::Property p)
case Film::DCI_METADATA:
_dcp_name->SetLabel (std_to_wx (_film->dcp_name ()));
break;
- case Film::AUDIO_STREAM:
- if (_film->audio_stream()) {
- checked_set (_audio_stream, _film->audio_stream().get().to_string());
- } else {
- checked_set (_audio_stream, wxNOT_FOUND);
+ case Film::CONTENT_AUDIO_STREAM:
+ if (_film->content_audio_stream()) {
+ checked_set (_audio_stream, _film->content_audio_stream()->to_string());
}
_dcp_name->SetLabel (std_to_wx (_film->dcp_name ()));
setup_audio_details ();
+ setup_audio_control_sensitivity ();
+ break;
+ case Film::USE_CONTENT_AUDIO:
+ checked_set (_use_content_audio, _film->use_content_audio());
+ checked_set (_use_external_audio, !_film->use_content_audio());
+ _dcp_name->SetLabel (std_to_wx (_film->dcp_name ()));
+ setup_audio_details ();
+ setup_audio_control_sensitivity ();
break;
case Film::SUBTITLE_STREAM:
if (_film->subtitle_stream()) {
- checked_set (_subtitle_stream, _film->subtitle_stream().get().to_string());
+ checked_set (_subtitle_stream, _film->subtitle_stream()->to_string());
}
break;
- case Film::USE_CONTENT_AUDIO:
- checked_set (_use_content_audio, _film->use_content_audio ());
- checked_set (_use_external_audio, !_film->use_content_audio ());
- setup_audio_control_sensitivity ();
- break;
case Film::EXTERNAL_AUDIO:
{
vector<string> a = _film->external_audio ();
for (size_t i = 0; i < a.size() && i < MAX_AUDIO_CHANNELS; ++i) {
checked_set (_external_audio[i], a[i]);
}
+ setup_audio_details ();
break;
}
}
@@ -688,9 +695,9 @@ FilmEditor::set_film (shared_ptr<Film> f)
film_changed (Film::DCP_TRIM_START);
film_changed (Film::DCP_TRIM_END);
film_changed (Film::DCP_AB);
- film_changed (Film::USE_CONTENT_AUDIO);
- film_changed (Film::AUDIO_STREAM);
+ film_changed (Film::CONTENT_AUDIO_STREAM);
film_changed (Film::EXTERNAL_AUDIO);
+ film_changed (Film::USE_CONTENT_AUDIO);
film_changed (Film::AUDIO_GAIN);
film_changed (Film::AUDIO_DELAY);
film_changed (Film::WITH_SUBTITLES);
@@ -699,7 +706,7 @@ FilmEditor::set_film (shared_ptr<Film> f)
film_changed (Film::DCI_METADATA);
film_changed (Film::SIZE);
film_changed (Film::LENGTH);
- film_changed (Film::AUDIO_STREAMS);
+ film_changed (Film::CONTENT_AUDIO_STREAMS);
film_changed (Film::SUBTITLE_STREAMS);
film_changed (Film::FRAMES_PER_SECOND);
}
@@ -965,24 +972,23 @@ void
FilmEditor::setup_streams ()
{
_audio_stream->Clear ();
- vector<AudioStream> a = _film->audio_streams ();
- for (vector<AudioStream>::iterator i = a.begin(); i != a.end(); ++i) {
- _audio_stream->Append (std_to_wx (i->name()), new wxStringClientData (std_to_wx (i->to_string ())));
+ vector<shared_ptr<AudioStream> > a = _film->content_audio_streams ();
+ for (vector<shared_ptr<AudioStream> >::iterator i = a.begin(); i != a.end(); ++i) {
+ shared_ptr<FFmpegAudioStream> ffa = dynamic_pointer_cast<FFmpegAudioStream> (*i);
+ _audio_stream->Append (std_to_wx (ffa->name()), new wxStringClientData (std_to_wx (ffa->to_string ())));
}
- if (_film->audio_stream()) {
- checked_set (_audio_stream, _film->audio_stream().get().to_string());
- } else {
- _audio_stream->SetValue (wxT (""));
+ if (_film->use_content_audio() && _film->audio_stream()) {
+ checked_set (_audio_stream, _film->audio_stream()->to_string());
}
_subtitle_stream->Clear ();
- vector<SubtitleStream> s = _film->subtitle_streams ();
- for (vector<SubtitleStream>::iterator i = s.begin(); i != s.end(); ++i) {
- _subtitle_stream->Append (std_to_wx (i->name()), new wxStringClientData (std_to_wx (i->to_string ())));
+ vector<shared_ptr<SubtitleStream> > s = _film->subtitle_streams ();
+ for (vector<shared_ptr<SubtitleStream> >::iterator i = s.begin(); i != s.end(); ++i) {
+ _subtitle_stream->Append (std_to_wx ((*i)->name()), new wxStringClientData (std_to_wx ((*i)->to_string ())));
}
if (_film->subtitle_stream()) {
- checked_set (_subtitle_stream, _film->subtitle_stream().get().to_string());
+ checked_set (_subtitle_stream, _film->subtitle_stream()->to_string());
} else {
_subtitle_stream->SetValue (wxT (""));
}
@@ -995,8 +1001,8 @@ FilmEditor::audio_stream_changed (wxCommandEvent &)
return;
}
- _film->set_audio_stream (
- AudioStream (
+ _film->set_content_audio_stream (
+ audio_stream_factory (
string_client_data (_audio_stream->GetClientObject (_audio_stream->GetSelection ())),
Film::state_version
)
@@ -1010,7 +1016,12 @@ FilmEditor::subtitle_stream_changed (wxCommandEvent &)
return;
}
- _film->set_subtitle_stream (SubtitleStream (string_client_data (_subtitle_stream->GetClientObject (_subtitle_stream->GetSelection ()))));
+ _film->set_subtitle_stream (
+ subtitle_stream_factory (
+ string_client_data (_subtitle_stream->GetClientObject (_subtitle_stream->GetSelection ())),
+ Film::state_version
+ )
+ );
}
void
@@ -1020,7 +1031,7 @@ FilmEditor::setup_audio_details ()
_audio->SetLabel (wxT (""));
} else {
stringstream s;
- s << _film->audio_stream().get().channels () << " channels, " << _film->audio_stream().get().sample_rate() << "Hz";
+ s << _film->audio_stream()->channels () << " channels, " << _film->audio_stream()->sample_rate() << "Hz";
_audio->SetLabel (std_to_wx (s.str ()));
}
}
@@ -1034,8 +1045,7 @@ FilmEditor::active_jobs_changed (bool a)
void
FilmEditor::use_audio_changed (wxCommandEvent &)
{
- _film->set_use_content_audio (_use_content_audio->GetValue ());
- setup_audio_control_sensitivity ();
+ _film->set_use_content_audio (_use_content_audio->GetValue());
}
void