diff options
| author | Carl Hetherington <cth@carlh.net> | 2012-11-17 22:06:12 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2012-11-17 22:06:12 +0000 |
| commit | cafa76a2b52449ce3c9eecfd0ea53b7318814951 (patch) | |
| tree | 81fe66f74256a54eb50f398790f2eea010bb3113 /src | |
| parent | 40532d61ea4909b3f8b12dd7024de217dbdfec6d (diff) | |
Another attempt to do external audio moderately nicely.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/ab_transcoder.cc | 6 | ||||
| -rw-r--r-- | src/lib/audio_decoder.cc | 2 | ||||
| -rw-r--r-- | src/lib/audio_decoder.h | 10 | ||||
| -rw-r--r-- | src/lib/decoder_factory.cc | 3 | ||||
| -rw-r--r-- | src/lib/external_audio_decoder.cc | 92 | ||||
| -rw-r--r-- | src/lib/external_audio_decoder.h | 25 | ||||
| -rw-r--r-- | src/lib/ffmpeg_decoder.cc | 100 | ||||
| -rw-r--r-- | src/lib/ffmpeg_decoder.h | 34 | ||||
| -rw-r--r-- | src/lib/film.cc | 154 | ||||
| -rw-r--r-- | src/lib/film.h | 55 | ||||
| -rw-r--r-- | src/lib/j2k_wav_encoder.cc | 23 | ||||
| -rw-r--r-- | src/lib/stream.cc | 61 | ||||
| -rw-r--r-- | src/lib/stream.h | 70 | ||||
| -rw-r--r-- | src/lib/transcoder.cc | 6 | ||||
| -rw-r--r-- | src/lib/util.cc | 2 | ||||
| -rw-r--r-- | src/lib/video_decoder.cc | 2 | ||||
| -rw-r--r-- | src/lib/video_decoder.h | 10 | ||||
| -rw-r--r-- | src/wx/film_editor.cc | 74 |
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 |
