summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/ab_transcoder.cc2
-rw-r--r--src/lib/decoder.cc105
-rw-r--r--src/lib/decoder.h39
-rw-r--r--src/lib/encoder.h4
-rw-r--r--src/lib/examine_content_job.cc6
-rw-r--r--src/lib/ffmpeg_decoder.cc189
-rw-r--r--src/lib/ffmpeg_decoder.h17
-rw-r--r--src/lib/film.cc201
-rw-r--r--src/lib/film.h54
-rw-r--r--src/lib/imagemagick_decoder.h4
-rw-r--r--src/lib/imagemagick_encoder.h3
-rw-r--r--src/lib/j2k_still_encoder.h3
-rw-r--r--src/lib/j2k_wav_encoder.cc76
-rw-r--r--src/lib/j2k_wav_encoder.h2
-rw-r--r--src/lib/stream.cc4
-rw-r--r--src/lib/stream.h25
-rw-r--r--src/lib/tiff_decoder.cc7
-rw-r--r--src/lib/tiff_decoder.h1
-rw-r--r--src/lib/transcoder.cc7
-rw-r--r--src/lib/util.h2
-rw-r--r--src/wx/film_editor.cc504
-rw-r--r--src/wx/film_editor.h27
-rw-r--r--src/wx/wx_util.cc28
-rw-r--r--src/wx/wx_util.h4
24 files changed, 739 insertions, 575 deletions
diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc
index c40c0916e..4183749c8 100644
--- a/src/lib/ab_transcoder.cc
+++ b/src/lib/ab_transcoder.cc
@@ -100,7 +100,7 @@ ABTranscoder::process_video (shared_ptr<Image> yuv, SourceFrame frame, shared_pt
void
ABTranscoder::go ()
{
- _encoder->process_begin (_da->audio_channel_layout());
+ _encoder->process_begin ();
_da->process_begin ();
_db->process_begin ();
diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc
index c9d8f063a..2f66aff68 100644
--- a/src/lib/decoder.cc
+++ b/src/lib/decoder.cc
@@ -43,6 +43,7 @@ using std::min;
using std::pair;
using std::list;
using boost::shared_ptr;
+using boost::optional;
/** @param f Film.
* @param o Options.
@@ -73,31 +74,33 @@ Decoder::~Decoder ()
void
Decoder::process_begin ()
{
- _delay_in_frames = _film->audio_delay() * audio_sample_rate() / 1000;
- _delay_line = new DelayLine (audio_channels(), _delay_in_frames);
+ if (_audio_stream) {
+ _delay_in_frames = _film->audio_delay() * _audio_stream.get().sample_rate() / 1000;
+ _delay_line = new DelayLine (_audio_stream.get().channels(), _delay_in_frames);
+ }
}
/** Finish off a decode processing run */
void
Decoder::process_end ()
{
- if (_delay_in_frames < 0 && _opt->decode_audio && audio_channels()) {
- shared_ptr<AudioBuffers> b (new AudioBuffers (audio_channels(), -_delay_in_frames));
+ if (_delay_in_frames < 0 && _opt->decode_audio && _audio_stream) {
+ shared_ptr<AudioBuffers> b (new AudioBuffers (_audio_stream.get().channels(), -_delay_in_frames));
b->make_silent ();
emit_audio (b);
}
- if (_opt->decode_audio && audio_channels()) {
+ if (_opt->decode_audio && _audio_stream) {
/* Ensure that our video and audio emissions are the same length */
- int64_t audio_short_by_frames = video_frames_to_audio_frames (_video_frame, audio_sample_rate(), frames_per_second()) - _audio_frame;
+ int64_t audio_short_by_frames = video_frames_to_audio_frames (_video_frame, _audio_stream.get().sample_rate(), frames_per_second()) - _audio_frame;
_film->log()->log (
String::compose (
"Decoder has emitted %1 video frames (which equals %2 audio frames) and %3 audio frames",
_video_frame,
- video_frames_to_audio_frames (_video_frame, audio_sample_rate(), frames_per_second()),
+ video_frames_to_audio_frames (_video_frame, _audio_stream.get().sample_rate(), frames_per_second()),
_audio_frame
)
);
@@ -107,7 +110,7 @@ Decoder::process_end ()
_film->log()->log (String::compose ("Emitted %1 too many audio frames", -audio_short_by_frames));
/* We have emitted more audio than video. Emit enough black video frames so that we reverse this */
- int const black_video_frames = ceil (-audio_short_by_frames * frames_per_second() / audio_sample_rate());
+ int const black_video_frames = ceil (-audio_short_by_frames * frames_per_second() / _audio_stream.get().sample_rate());
_film->log()->log (String::compose ("Emitting %1 frames of black video", black_video_frames));
@@ -118,12 +121,12 @@ Decoder::process_end ()
}
/* Now recompute our check value */
- audio_short_by_frames = video_frames_to_audio_frames (_video_frame, audio_sample_rate(), frames_per_second()) - _audio_frame;
+ audio_short_by_frames = video_frames_to_audio_frames (_video_frame, _audio_stream.get().sample_rate(), frames_per_second()) - _audio_frame;
}
if (audio_short_by_frames > 0) {
_film->log()->log (String::compose ("Emitted %1 too few audio frames", audio_short_by_frames));
- shared_ptr<AudioBuffers> b (new AudioBuffers (audio_channels(), audio_short_by_frames));
+ shared_ptr<AudioBuffers> b (new AudioBuffers (_audio_stream.get().channels(), audio_short_by_frames));
b->make_silent ();
emit_audio (b);
}
@@ -154,77 +157,13 @@ Decoder::go ()
* @param size Number of bytes of data.
*/
void
-Decoder::process_audio (uint8_t* data, int size)
+Decoder::process_audio (shared_ptr<AudioBuffers> audio)
{
- /* XXX: could this be removed? */
- if (size == 0) {
- return;
- }
-
- assert (_film->audio_channels());
- assert (bytes_per_audio_sample());
-
- /* Deinterleave and convert to float */
-
- assert ((size % (bytes_per_audio_sample() * audio_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_channels(), frames));
-
- switch (audio_sample_format()) {
- case AV_SAMPLE_FMT_S16:
- {
- int16_t* p = (int16_t *) data;
- int sample = 0;
- int channel = 0;
- for (int i = 0; i < total_samples; ++i) {
- audio->data(channel)[sample] = float(*p++) / (1 << 15);
-
- ++channel;
- if (channel == _film->audio_channels()) {
- channel = 0;
- ++sample;
- }
- }
- }
- break;
-
- case AV_SAMPLE_FMT_S32:
- {
- int32_t* p = (int32_t *) data;
- int sample = 0;
- int channel = 0;
- for (int i = 0; i < total_samples; ++i) {
- audio->data(channel)[sample] = float(*p++) / (1 << 31);
-
- ++channel;
- if (channel == _film->audio_channels()) {
- channel = 0;
- ++sample;
- }
- }
- }
-
- case AV_SAMPLE_FMT_FLTP:
- {
- float* p = reinterpret_cast<float*> (data);
- for (int i = 0; i < _film->audio_channels(); ++i) {
- memcpy (audio->data(i), p, frames * sizeof(float));
- p += frames;
- }
- }
- break;
-
- default:
- assert (false);
- }
-
/* Maybe apply gain */
if (_film->audio_gain() != 0) {
float const linear_gain = pow (10, _film->audio_gain() / 20);
- for (int i = 0; i < _film->audio_channels(); ++i) {
- for (int j = 0; j < frames; ++j) {
+ for (int i = 0; i < audio->channels(); ++i) {
+ for (int j = 0; j < audio->frames(); ++j) {
audio->data(i)[j] *= linear_gain;
}
}
@@ -308,8 +247,14 @@ Decoder::process_subtitle (shared_ptr<TimedSubtitle> s)
}
}
-int
-Decoder::bytes_per_audio_sample () const
+void
+Decoder::set_audio_stream (optional<AudioStream> s)
+{
+ _audio_stream = s;
+}
+
+void
+Decoder::set_subtitle_stream (optional<SubtitleStream> s)
{
- return av_get_bytes_per_sample (audio_sample_format ());
+ _subtitle_stream = s;
}
diff --git a/src/lib/decoder.h b/src/lib/decoder.h
index 9f47bf425..d0e20b03a 100644
--- a/src/lib/decoder.h
+++ b/src/lib/decoder.h
@@ -61,14 +61,6 @@ public:
virtual float frames_per_second () const = 0;
/** @return native size in pixels */
virtual Size native_size () const = 0;
- /** @return number of audio channels */
- virtual int audio_channels () const = 0;
- /** @return audio sampling rate in Hz */
- virtual int audio_sample_rate () const = 0;
- /** @return format of audio samples */
- virtual AVSampleFormat audio_sample_format () const = 0;
- virtual int64_t audio_channel_layout () const = 0;
- virtual bool has_subtitles () const = 0;
virtual int time_base_numerator () const = 0;
virtual int time_base_denominator () const = 0;
@@ -84,12 +76,23 @@ public:
return _video_frame;
}
- virtual std::vector<AudioStream> audio_streams () const {
- return std::vector<AudioStream> ();
+ virtual void set_audio_stream (boost::optional<AudioStream>);
+ virtual void set_subtitle_stream (boost::optional<SubtitleStream>);
+
+ boost::optional<AudioStream> audio_stream () const {
+ return _audio_stream;
+ }
+
+ boost::optional<SubtitleStream> subtitle_stream () const {
+ return _subtitle_stream;
+ }
+
+ std::vector<AudioStream> audio_streams () const {
+ return _audio_streams;
}
- virtual std::vector<SubtitleStream> subtitle_streams () const {
- return std::vector<SubtitleStream> ();
+ std::vector<SubtitleStream> subtitle_streams () const {
+ return _subtitle_streams;
}
/** Emitted when a video frame is ready.
@@ -107,12 +110,10 @@ protected:
virtual PixelFormat pixel_format () const = 0;
void process_video (AVFrame *);
- void process_audio (uint8_t *, int);
+ void process_audio (boost::shared_ptr<AudioBuffers>);
void process_subtitle (boost::shared_ptr<TimedSubtitle>);
void repeat_last_video ();
- int bytes_per_audio_sample () const;
-
/** our Film */
boost::shared_ptr<Film> _film;
/** our options */
@@ -120,13 +121,19 @@ protected:
/** associated Job, or 0 */
Job* _job;
+ boost::optional<AudioStream> _audio_stream;
+ boost::optional<SubtitleStream> _subtitle_stream;
+
+ std::vector<AudioStream> _audio_streams;
+ std::vector<SubtitleStream> _subtitle_streams;
+
private:
void emit_video (boost::shared_ptr<Image>, boost::shared_ptr<Subtitle>);
void emit_audio (boost::shared_ptr<AudioBuffers>);
SourceFrame _video_frame;
int64_t _audio_frame;
-
+
std::list<boost::shared_ptr<FilterGraph> > _filter_graphs;
DelayLine* _delay_line;
diff --git a/src/lib/encoder.h b/src/lib/encoder.h
index 2d9780b52..e04397f78 100644
--- a/src/lib/encoder.h
+++ b/src/lib/encoder.h
@@ -55,7 +55,7 @@ public:
Encoder (boost::shared_ptr<const Film> f, boost::shared_ptr<const Options> o);
/** Called to indicate that a processing run is about to begin */
- virtual void process_begin (int64_t audio_channel_layout) = 0;
+ virtual void process_begin () {}
/** Call with a frame of video.
* @param i Video frame image.
@@ -68,7 +68,7 @@ public:
void process_audio (boost::shared_ptr<const AudioBuffers>, int64_t);
/** Called when a processing run has finished */
- virtual void process_end () = 0;
+ virtual void process_end () {}
float current_frames_per_second () const;
bool skipping () const;
diff --git a/src/lib/examine_content_job.cc b/src/lib/examine_content_job.cc
index 4646fe8fc..b13e9d9d5 100644
--- a/src/lib/examine_content_job.cc
+++ b/src/lib/examine_content_job.cc
@@ -59,10 +59,16 @@ void
ExamineContentJob::run ()
{
/* Decode the content to get an accurate length */
+
+ /* We don't want to use any existing length here, as progress
+ will be messed up.
+ */
+ _film->unset_length ();
shared_ptr<Options> o (new Options ("", "", ""));
o->out_size = Size (512, 512);
o->apply_crop = false;
+ o->decode_audio = false;
descend (0.5);
diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc
index a2ca739e2..1cac25ca1 100644
--- a/src/lib/ffmpeg_decoder.cc
+++ b/src/lib/ffmpeg_decoder.cc
@@ -54,13 +54,12 @@ using std::string;
using std::vector;
using std::stringstream;
using boost::shared_ptr;
+using boost::optional;
FFmpegDecoder::FFmpegDecoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j)
: Decoder (f, o, j)
, _format_context (0)
, _video_stream (-1)
- , _audio_stream (-1)
- , _subtitle_stream (-1)
, _frame (0)
, _video_codec_context (0)
, _video_codec (0)
@@ -116,28 +115,12 @@ FFmpegDecoder::setup_general ()
if (s->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
_video_stream = i;
} else if (s->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
- if (_audio_stream == -1) {
- _audio_stream = i;
- }
- _audio_streams.push_back (AudioStream (stream_name (s), i, s->codec->channels));
+ _audio_streams.push_back (AudioStream (stream_name (s), i, s->codec->sample_rate, s->codec->channel_layout));
} else if (s->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) {
- if (_subtitle_stream == -1) {
- _subtitle_stream = i;
- }
_subtitle_streams.push_back (SubtitleStream (stream_name (s), i));
}
}
- /* Now override audio and subtitle streams with those from the Film, if it has any */
-
- if (_film->audio_stream_index() != -1) {
- _audio_stream = _film->audio_stream().id();
- }
-
- if (_film->subtitle_stream_index() != -1) {
- _subtitle_stream = _film->subtitle_stream().id ();
- }
-
if (_video_stream < 0) {
throw DecodeError ("could not find video stream");
}
@@ -173,11 +156,11 @@ FFmpegDecoder::setup_video ()
void
FFmpegDecoder::setup_audio ()
{
- if (_audio_stream < 0) {
+ if (!_audio_stream) {
return;
}
- _audio_codec_context = _format_context->streams[_audio_stream]->codec;
+ _audio_codec_context = _format_context->streams[_audio_stream.get().id()]->codec;
_audio_codec = avcodec_find_decoder (_audio_codec_context->codec_id);
if (_audio_codec == 0) {
@@ -193,18 +176,18 @@ FFmpegDecoder::setup_audio ()
*/
if (_audio_codec_context->channel_layout == 0) {
- _audio_codec_context->channel_layout = av_get_default_channel_layout (audio_channels ());
+ _audio_codec_context->channel_layout = av_get_default_channel_layout (_audio_stream.get().channels());
}
}
void
FFmpegDecoder::setup_subtitle ()
{
- if (_subtitle_stream < 0) {
+ if (!_subtitle_stream) {
return;
}
- _subtitle_codec_context = _format_context->streams[_subtitle_stream]->codec;
+ _subtitle_codec_context = _format_context->streams[_subtitle_stream.get().id()]->codec;
_subtitle_codec = avcodec_find_decoder (_subtitle_codec_context->codec_id);
if (_subtitle_codec == 0) {
@@ -243,14 +226,14 @@ FFmpegDecoder::pass ()
process_video (_frame);
}
- if (_audio_stream >= 0 && _opt->decode_audio) {
+ if (_audio_stream && _opt->decode_audio && _film->use_source_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
);
assert (_audio_codec_context->channels == _film->audio_channels());
- process_audio (_frame->data[0], data_size);
+ process_audio (deinterleave_audio (_frame->data[0], data_size));
}
}
@@ -307,7 +290,7 @@ FFmpegDecoder::pass ()
}
}
- } else if (_audio_stream >= 0 && _packet.stream_index == _audio_stream && _opt->decode_audio) {
+ } else if (_audio_stream && _packet.stream_index == _audio_stream.get().id() && _opt->decode_audio && _film->use_source_audio()) {
int frame_finished;
if (avcodec_decode_audio4 (_audio_codec_context, _frame, &frame_finished, &_packet) >= 0 && frame_finished) {
@@ -331,25 +314,19 @@ FFmpegDecoder::pass ()
*/
/* frames of silence that we must push */
- int const s = rint ((_first_audio.get() - _first_video.get()) * audio_sample_rate ());
+ int const s = rint ((_first_audio.get() - _first_video.get()) * _audio_stream.get().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_channels(), bytes_per_audio_sample()
+ _first_video.get(), _first_audio.get(), s, _audio_stream.get().channels(), bytes_per_audio_sample()
)
);
if (s) {
- /* hence bytes */
- int const b = s * audio_channels() * bytes_per_audio_sample();
-
- /* XXX: this assumes that it won't be too much, and there are shaky assumptions
- that all sound representations are silent with memset()ed zero data.
- */
- uint8_t silence[b];
- memset (silence, 0, b);
- process_audio (silence, b);
+ shared_ptr<AudioBuffers> audio (new AudioBuffers (_audio_stream.get().channels(), s));
+ audio->make_silent ();
+ process_audio (audio);
}
}
@@ -358,11 +335,11 @@ FFmpegDecoder::pass ()
);
assert (_audio_codec_context->channels == _film->audio_channels());
- process_audio (_frame->data[0], data_size);
+ process_audio (deinterleave_audio (_frame->data[0], data_size));
}
}
- } else if (_subtitle_stream >= 0 && _packet.stream_index == _subtitle_stream && _opt->decode_subtitles && _first_video) {
+ } else if (_subtitle_stream && _packet.stream_index == _subtitle_stream.get().id() && _opt->decode_subtitles && _first_video) {
int got_subtitle;
AVSubtitle sub;
@@ -383,36 +360,81 @@ FFmpegDecoder::pass ()
return false;
}
-float
-FFmpegDecoder::frames_per_second () const
+shared_ptr<AudioBuffers>
+FFmpegDecoder::deinterleave_audio (uint8_t* data, int size)
{
- AVStream* s = _format_context->streams[_video_stream];
-
- if (s->avg_frame_rate.num && s->avg_frame_rate.den) {
- return av_q2d (s->avg_frame_rate);
+ assert (_film->audio_channels());
+ assert (bytes_per_audio_sample());
+
+ /* Deinterleave and convert to float */
+
+ assert ((size % (bytes_per_audio_sample() * _audio_stream.get().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));
+
+ switch (audio_sample_format()) {
+ case AV_SAMPLE_FMT_S16:
+ {
+ int16_t* p = (int16_t *) data;
+ int sample = 0;
+ int channel = 0;
+ for (int i = 0; i < total_samples; ++i) {
+ audio->data(channel)[sample] = float(*p++) / (1 << 15);
+
+ ++channel;
+ if (channel == _film->audio_channels()) {
+ channel = 0;
+ ++sample;
+ }
+ }
+ }
+ break;
+
+ case AV_SAMPLE_FMT_S32:
+ {
+ int32_t* p = (int32_t *) data;
+ int sample = 0;
+ int channel = 0;
+ for (int i = 0; i < total_samples; ++i) {
+ audio->data(channel)[sample] = float(*p++) / (1 << 31);
+
+ ++channel;
+ if (channel == _film->audio_channels()) {
+ channel = 0;
+ ++sample;
+ }
+ }
}
- return av_q2d (s->r_frame_rate);
-}
+ case AV_SAMPLE_FMT_FLTP:
+ {
+ float* p = reinterpret_cast<float*> (data);
+ for (int i = 0; i < _film->audio_channels(); ++i) {
+ memcpy (audio->data(i), p, frames * sizeof(float));
+ p += frames;
+ }
+ }
+ break;
-int
-FFmpegDecoder::audio_channels () const
-{
- if (_audio_codec_context == 0) {
- return 0;
+ default:
+ assert (false);
}
- return _audio_codec_context->channels;
+ return audio;
}
-int
-FFmpegDecoder::audio_sample_rate () const
+float
+FFmpegDecoder::frames_per_second () const
{
- if (_audio_codec_context == 0) {
- return 0;
+ AVStream* s = _format_context->streams[_video_stream];
+
+ if (s->avg_frame_rate.num && s->avg_frame_rate.den) {
+ return av_q2d (s->avg_frame_rate);
}
-
- return _audio_codec_context->sample_rate;
+
+ return av_q2d (s->r_frame_rate);
}
AVSampleFormat
@@ -425,16 +447,6 @@ FFmpegDecoder::audio_sample_format () const
return _audio_codec_context->sample_fmt;
}
-int64_t
-FFmpegDecoder::audio_channel_layout () const
-{
- if (_audio_codec_context == 0) {
- return 0;
- }
-
- return _audio_codec_context->channel_layout;
-}
-
Size
FFmpegDecoder::native_size () const
{
@@ -471,24 +483,6 @@ FFmpegDecoder::sample_aspect_ratio_denominator () const
return _video_codec_context->sample_aspect_ratio.den;
}
-bool
-FFmpegDecoder::has_subtitles () const
-{
- return (_subtitle_stream != -1);
-}
-
-vector<AudioStream>
-FFmpegDecoder::audio_streams () const
-{
- return _audio_streams;
-}
-
-vector<SubtitleStream>
-FFmpegDecoder::subtitle_streams () const
-{
- return _subtitle_streams;
-}
-
string
FFmpegDecoder::stream_name (AVStream* s) const
{
@@ -514,3 +508,22 @@ FFmpegDecoder::stream_name (AVStream* s) const
return n.str ();
}
+int
+FFmpegDecoder::bytes_per_audio_sample () const
+{
+ return av_get_bytes_per_sample (audio_sample_format ());
+}
+
+void
+FFmpegDecoder::set_audio_stream (optional<AudioStream> s)
+{
+ Decoder::set_audio_stream (s);
+ setup_audio ();
+}
+
+void
+FFmpegDecoder::set_subtitle_stream (optional<SubtitleStream> s)
+{
+ Decoder::set_subtitle_stream (s);
+ setup_subtitle ();
+}
diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h
index 0265f7478..856ac0801 100644
--- a/src/lib/ffmpeg_decoder.h
+++ b/src/lib/ffmpeg_decoder.h
@@ -58,14 +58,9 @@ public:
/* Methods to query our input video */
float frames_per_second () const;
Size native_size () const;
- int audio_channels () const;
- int audio_sample_rate () const;
- AVSampleFormat audio_sample_format () const;
- int64_t audio_channel_layout () const;
- bool has_subtitles () const;
- std::vector<AudioStream> audio_streams () const;
- std::vector<SubtitleStream> subtitle_streams () const;
+ void set_audio_stream (boost::optional<AudioStream>);
+ void set_subtitle_stream (boost::optional<SubtitleStream>);
private:
@@ -75,6 +70,8 @@ private:
int time_base_denominator () const;
int sample_aspect_ratio_numerator () const;
int sample_aspect_ratio_denominator () const;
+ AVSampleFormat audio_sample_format () const;
+ int bytes_per_audio_sample () const;
void setup_general ();
void setup_video ();
@@ -82,19 +79,15 @@ private:
void setup_subtitle ();
void maybe_add_subtitle ();
+ boost::shared_ptr<AudioBuffers> deinterleave_audio (uint8_t* data, int size);
std::string stream_name (AVStream* s) const;
AVFormatContext* _format_context;
int _video_stream;
- int _audio_stream; ///< may be < 0 if there is no audio
- int _subtitle_stream; ///< may be < 0 if there is no subtitle
AVFrame* _frame;
- std::vector<AudioStream> _audio_streams;
- std::vector<SubtitleStream> _subtitle_streams;
-
AVCodecContext* _video_codec_context;
AVCodec* _video_codec;
AVCodecContext* _audio_codec_context; ///< may be 0 if there is no audio
diff --git a/src/lib/film.cc b/src/lib/film.cc
index d5bf79d09..3ce3a8df3 100644
--- a/src/lib/film.cc
+++ b/src/lib/film.cc
@@ -69,6 +69,7 @@ using boost::lexical_cast;
using boost::to_upper_copy;
using boost::ends_with;
using boost::starts_with;
+using boost::optional;
/** Construct a Film object in a given directory, reading any metadata
* file that exists in that directory. An exception will be thrown if
@@ -86,16 +87,13 @@ Film::Film (string d, bool must_exist)
, _dcp_trim_start (0)
, _dcp_trim_end (0)
, _dcp_ab (false)
- , _audio_stream (-1)
+ , _use_source_audio (true)
, _audio_gain (0)
, _audio_delay (0)
, _still_duration (10)
- , _subtitle_stream (-1)
, _with_subtitles (false)
, _subtitle_offset (0)
, _subtitle_scale (1)
- , _audio_sample_rate (0)
- , _has_subtitles (false)
, _frames_per_second (0)
, _dirty (false)
{
@@ -147,7 +145,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_source_audio (o._use_source_audio)
, _audio_stream (o._audio_stream)
+ , _external_audio (o._external_audio)
, _audio_gain (o._audio_gain)
, _audio_delay (o._audio_delay)
, _still_duration (o._still_duration)
@@ -165,9 +165,7 @@ Film::Film (Film const & o)
, _thumbs (o._thumbs)
, _size (o._size)
, _length (o._length)
- , _audio_sample_rate (o._audio_sample_rate)
, _content_digest (o._content_digest)
- , _has_subtitles (o._has_subtitles)
, _audio_streams (o._audio_streams)
, _subtitle_streams (o._subtitle_streams)
, _frames_per_second (o._frames_per_second)
@@ -260,10 +258,12 @@ Film::make_dcp (bool transcode)
o->ratio = format()->ratio_as_float (shared_from_this ());
if (dcp_length ()) {
o->video_decode_range = make_pair (dcp_trim_start(), dcp_trim_start() + dcp_length().get());
- o->audio_decode_range = make_pair (
- video_frames_to_audio_frames (o->video_decode_range.get().first, audio_sample_rate(), frames_per_second()),
- video_frames_to_audio_frames (o->video_decode_range.get().second, audio_sample_rate(), frames_per_second())
- );
+ 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())
+ );
+ }
}
o->decode_subtitles = with_subtitles ();
@@ -418,11 +418,19 @@ 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 << "selected_audio_stream " << _audio_stream << "\n";
+ f << "use_source_audio " << (_use_source_audio ? "1" : "0") << "\n";
+ if (_audio_stream) {
+ f << "selected_audio_stream " << _audio_stream.get().to_string() << "\n";
+ }
+ for (vector<string>::const_iterator i = _external_audio.begin(); i != _external_audio.end(); ++i) {
+ f << "external_audio " << *i << "\n";
+ }
f << "audio_gain " << _audio_gain << "\n";
f << "audio_delay " << _audio_delay << "\n";
f << "still_duration " << _still_duration << "\n";
- f << "selected_subtitle_stream " << _subtitle_stream << "\n";
+ if (_subtitle_stream) {
+ f << "selected_subtitle_stream " << _subtitle_stream.get().to_string() << "\n";
+ }
f << "with_subtitles " << _with_subtitles << "\n";
f << "subtitle_offset " << _subtitle_offset << "\n";
f << "subtitle_scale " << _subtitle_scale << "\n";
@@ -443,9 +451,7 @@ Film::write_metadata () const
f << "width " << _size.width << "\n";
f << "height " << _size.height << "\n";
f << "length " << _length.get_value_or(0) << "\n";
- f << "audio_sample_rate " << _audio_sample_rate << "\n";
f << "content_digest " << _content_digest << "\n";
- f << "has_subtitles " << _has_subtitles << "\n";
for (vector<AudioStream>::const_iterator i = _audio_streams.begin(); i != _audio_streams.end(); ++i) {
f << "audio_stream " << i->to_string () << "\n";
@@ -465,6 +471,11 @@ void
Film::read_metadata ()
{
boost::mutex::scoped_lock lm (_state_mutex);
+
+ _external_audio.clear ();
+ _thumbs.clear ();
+ _audio_streams.clear ();
+ _subtitle_streams.clear ();
ifstream f (file ("metadata").c_str());
multimap<string, string> kv = read_key_value (f);
@@ -501,8 +512,12 @@ Film::read_metadata ()
_dcp_trim_end = atoi (v.c_str ());
} else if (k == "dcp_ab") {
_dcp_ab = (v == "1");
+ } else if (k == "use_source_audio") {
+ _use_source_audio = (v == "1");
} else if (k == "selected_audio_stream") {
- _audio_stream = atoi (v.c_str ());
+ _audio_stream = AudioStream (v);
+ } else if (k == "external_audio") {
+ _external_audio.push_back (v);
} else if (k == "audio_gain") {
_audio_gain = atof (v.c_str ());
} else if (k == "audio_delay") {
@@ -510,7 +525,7 @@ Film::read_metadata ()
} else if (k == "still_duration") {
_still_duration = atoi (v.c_str ());
} else if (k == "selected_subtitle_stream") {
- _subtitle_stream = atoi (v.c_str ());
+ _subtitle_stream = SubtitleStream (v);
} else if (k == "with_subtitles") {
_with_subtitles = (v == "1");
} else if (k == "subtitle_offset") {
@@ -549,12 +564,8 @@ Film::read_metadata ()
if (vv) {
_length = vv;
}
- } else if (k == "audio_sample_rate") {
- _audio_sample_rate = atoi (v.c_str ());
} else if (k == "content_digest") {
_content_digest = v;
- } else if (k == "has_subtitles") {
- _has_subtitles = (v == "1");
} else if (k == "audio_stream") {
_audio_streams.push_back (AudioStream (v));
} else if (k == "subtitle_stream") {
@@ -695,7 +706,7 @@ int
Film::target_audio_sample_rate () const
{
/* Resample to a DCI-approved sample rate */
- double t = dcp_audio_sample_rate (audio_sample_rate());
+ double t = dcp_audio_sample_rate (audio_stream().get().sample_rate());
DCPFrameRate dfr = dcp_frame_rate (frames_per_second ());
@@ -723,11 +734,9 @@ Film::dcp_length () const
string
Film::dci_name () const
{
- boost::mutex::scoped_lock lm (_state_mutex);
-
stringstream d;
- string fixed_name = to_upper_copy (_name);
+ string fixed_name = to_upper_copy (name());
for (size_t i = 0; i < fixed_name.length(); ++i) {
if (fixed_name[i] == ' ') {
fixed_name[i] = '-';
@@ -741,18 +750,18 @@ Film::dci_name () const
d << fixed_name << "_";
- if (_dcp_content_type) {
- d << _dcp_content_type->dci_name() << "_";
+ if (dcp_content_type()) {
+ d << dcp_content_type()->dci_name() << "_";
}
- if (_format) {
- d << _format->dci_name() << "_";
+ if (format()) {
+ d << format()->dci_name() << "_";
}
- if (!_audio_language.empty ()) {
- d << _audio_language;
- if (!_subtitle_language.empty() && _with_subtitles) {
- d << "-" << _subtitle_language;
+ if (!audio_language().empty ()) {
+ d << audio_language();
+ if (!subtitle_language().empty() && with_subtitles()) {
+ d << "-" << subtitle_language();
} else {
d << "-XX";
}
@@ -760,45 +769,43 @@ Film::dci_name () const
d << "_";
}
- if (!_territory.empty ()) {
- d << _territory;
- if (!_rating.empty ()) {
- d << "-" << _rating;
+ if (!territory().empty ()) {
+ d << territory();
+ if (!rating().empty ()) {
+ d << "-" << rating();
}
d << "_";
}
- if (_audio_stream != -1) {
- switch (_audio_streams[_audio_stream].channels()) {
- case 1:
- d << "10_";
- break;
- case 2:
- d << "20_";
- break;
- case 6:
- d << "51_";
- break;
- case 8:
- d << "71_";
- break;
- }
+ switch (audio_channels()) {
+ case 1:
+ d << "10_";
+ break;
+ case 2:
+ d << "20_";
+ break;
+ case 6:
+ d << "51_";
+ break;
+ case 8:
+ d << "71_";
+ break;
}
d << "2K_";
- if (!_studio.empty ()) {
- d << _studio << "_";
+ if (!studio().empty ()) {
+ d << studio() << "_";
}
d << boost::gregorian::to_iso_string (_dci_date) << "_";
- if (!_facility.empty ()) {
- d << _facility << "_";
+ if (!facility().empty ()) {
+ d << facility() << "_";
}
- if (!_package_type.empty ()) {
- d << _package_type;
+ if (!package_type().empty ()) {
+ d << package_type();
}
return d.str ();
@@ -880,6 +887,9 @@ Film::set_content (string c)
_content = c;
}
+ _audio_stream = optional<AudioStream> ();
+ _subtitle_stream = optional<SubtitleStream> ();
+
/* Create a temporary decoder so that we can get information
about the content.
*/
@@ -892,12 +902,17 @@ Film::set_content (string c)
set_size (d->native_size ());
set_frames_per_second (d->frames_per_second ());
- set_audio_sample_rate (d->audio_sample_rate ());
- set_has_subtitles (d->has_subtitles ());
set_audio_streams (d->audio_streams ());
set_subtitle_streams (d->subtitle_streams ());
- set_audio_stream (audio_streams().empty() ? -1 : 0);
- set_subtitle_stream (subtitle_streams().empty() ? -1 : 0);
+
+ /* Start off with the first audio and subtitle streams */
+ if (!d->audio_streams().empty()) {
+ set_audio_stream (d->audio_streams().front());
+ }
+
+ if (!d->subtitle_streams().empty()) {
+ set_subtitle_stream (d->subtitle_streams().front());
+ }
{
boost::mutex::scoped_lock lm (_state_mutex);
@@ -1057,7 +1072,17 @@ Film::set_dcp_ab (bool a)
}
void
-Film::set_audio_stream (int s)
+Film::set_use_source_audio (bool s)
+{
+ {
+ boost::mutex::scoped_lock lm (_state_mutex);
+ _use_source_audio = s;
+ }
+ signal_changed (USE_SOURCE_AUDIO);
+}
+
+void
+Film::set_audio_stream (optional<AudioStream> s)
{
{
boost::mutex::scoped_lock lm (_state_mutex);
@@ -1067,6 +1092,16 @@ Film::set_audio_stream (int s)
}
void
+Film::set_external_audio (vector<string> a)
+{
+ {
+ boost::mutex::scoped_lock lm (_state_mutex);
+ _external_audio = a;
+ }
+ signal_changed (EXTERNAL_AUDIO);
+}
+
+void
Film::set_audio_gain (float g)
{
{
@@ -1097,7 +1132,7 @@ Film::set_still_duration (int d)
}
void
-Film::set_subtitle_stream (int s)
+Film::set_subtitle_stream (optional<SubtitleStream> s)
{
{
boost::mutex::scoped_lock lm (_state_mutex);
@@ -1247,16 +1282,6 @@ Film::unset_length ()
}
void
-Film::set_audio_sample_rate (int r)
-{
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _audio_sample_rate = r;
- }
- signal_changed (AUDIO_SAMPLE_RATE);
-}
-
-void
Film::set_content_digest (string d)
{
{
@@ -1267,16 +1292,6 @@ Film::set_content_digest (string d)
}
void
-Film::set_has_subtitles (bool s)
-{
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _has_subtitles = s;
- }
- signal_changed (HAS_SUBTITLES);
-}
-
-void
Film::set_audio_streams (vector<AudioStream> s)
{
{
@@ -1323,11 +1338,23 @@ int
Film::audio_channels () const
{
boost::mutex::scoped_lock lm (_state_mutex);
- if (_audio_stream == -1) {
- return 0;
- }
- return _audio_streams[_audio_stream].channels ();
+ if (_use_source_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;
+ }
+
+ return 0;
}
void
diff --git a/src/lib/film.h b/src/lib/film.h
index 049af45e2..af1f49e2e 100644
--- a/src/lib/film.h
+++ b/src/lib/film.h
@@ -120,7 +120,9 @@ public:
DCP_TRIM_START,
DCP_TRIM_END,
DCP_AB,
+ USE_SOURCE_AUDIO,
AUDIO_STREAM,
+ EXTERNAL_AUDIO,
AUDIO_GAIN,
AUDIO_DELAY,
STILL_DURATION,
@@ -132,8 +134,6 @@ public:
THUMBS,
SIZE,
LENGTH,
- AUDIO_SAMPLE_RATE,
- HAS_SUBTITLES,
AUDIO_STREAMS,
SUBTITLE_STREAMS,
FRAMES_PER_SECOND,
@@ -202,15 +202,19 @@ public:
return _dcp_ab;
}
- int audio_stream_index () const {
+ bool use_source_audio () const {
+ boost::mutex::scoped_lock lm (_state_mutex);
+ return _use_source_audio;
+ }
+
+ boost::optional<AudioStream> audio_stream () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _audio_stream;
}
- AudioStream audio_stream () const {
+ std::vector<std::string> external_audio () const {
boost::mutex::scoped_lock lm (_state_mutex);
- assert (_audio_stream < int (_audio_streams.size()));
- return _audio_streams[_audio_stream];
+ return _external_audio;
}
float audio_gain () const {
@@ -228,17 +232,11 @@ public:
return _still_duration;
}
- int subtitle_stream_index () const {
+ boost::optional<SubtitleStream> subtitle_stream () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _subtitle_stream;
}
- SubtitleStream subtitle_stream () const {
- boost::mutex::scoped_lock lm (_state_mutex);
- assert (_subtitle_stream < int (_subtitle_streams.size()));
- return _subtitle_streams[_subtitle_stream];
- }
-
bool with_subtitles () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _with_subtitles;
@@ -304,21 +302,11 @@ public:
return _length;
}
- int audio_sample_rate () const {
- boost::mutex::scoped_lock lm (_state_mutex);
- return _audio_sample_rate;
- }
-
std::string content_digest () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _content_digest;
}
- bool has_subtitles () const {
- boost::mutex::scoped_lock lm (_state_mutex);
- return _has_subtitles;
- }
-
std::vector<AudioStream> audio_streams () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _audio_streams;
@@ -353,11 +341,13 @@ public:
void set_dcp_trim_start (int);
void set_dcp_trim_end (int);
void set_dcp_ab (bool);
- void set_audio_stream (int);
+ void set_use_source_audio (bool);
+ void set_audio_stream (boost::optional<AudioStream>);
+ void set_external_audio (std::vector<std::string>);
void set_audio_gain (float);
void set_audio_delay (int);
void set_still_duration (int);
- void set_subtitle_stream (int);
+ void set_subtitle_stream (boost::optional<SubtitleStream>);
void set_with_subtitles (bool);
void set_subtitle_offset (int);
void set_subtitle_scale (float);
@@ -372,9 +362,7 @@ public:
void set_size (Size);
void set_length (SourceFrame);
void unset_length ();
- void set_audio_sample_rate (int);
void set_content_digest (std::string);
- void set_has_subtitles (bool);
void set_audio_streams (std::vector<AudioStream>);
void set_subtitle_streams (std::vector<SubtitleStream>);
void set_frames_per_second (float);
@@ -432,16 +420,16 @@ private:
has the specified filters and post-processing.
*/
bool _dcp_ab;
- /** An index into our _audio_streams vector for the stream to use for audio, or -1 if there is none */
- int _audio_stream;
+ bool _use_source_audio;
+ boost::optional<AudioStream> _audio_stream;
+ std::vector<std::string> _external_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;
- /** An index into our _subtitle_streams vector for the stream to use for subtitles, or -1 if there is none */
- int _subtitle_stream;
+ boost::optional<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
@@ -468,12 +456,8 @@ private:
Size _size;
/** Actual length of the source (in video frames) from examining it */
boost::optional<SourceFrame> _length;
- /** Sample rate of the source audio, in Hz */
- int _audio_sample_rate;
/** MD5 digest of our content file */
std::string _content_digest;
- /** true if the source has subtitles */
- bool _has_subtitles;
/** the audio streams that the source has */
std::vector<AudioStream> _audio_streams;
/** the subtitle streams that the source has */
diff --git a/src/lib/imagemagick_decoder.h b/src/lib/imagemagick_decoder.h
index b7ab9af18..1bf50378b 100644
--- a/src/lib/imagemagick_decoder.h
+++ b/src/lib/imagemagick_decoder.h
@@ -42,10 +42,6 @@ public:
return 0;
}
- AVSampleFormat audio_sample_format () const {
- return AV_SAMPLE_FMT_NONE;
- }
-
int64_t audio_channel_layout () const {
return 0;
}
diff --git a/src/lib/imagemagick_encoder.h b/src/lib/imagemagick_encoder.h
index 9adfbf56b..02458fc5b 100644
--- a/src/lib/imagemagick_encoder.h
+++ b/src/lib/imagemagick_encoder.h
@@ -36,9 +36,6 @@ class ImageMagickEncoder : public Encoder
public:
ImageMagickEncoder (boost::shared_ptr<const Film> f, boost::shared_ptr<const Options> o);
- void process_begin (int64_t audio_channel_layout) {}
- void process_end () {}
-
private:
void do_process_video (boost::shared_ptr<const Image>, SourceFrame, boost::shared_ptr<Subtitle>);
void do_process_audio (boost::shared_ptr<const AudioBuffers>) {}
diff --git a/src/lib/j2k_still_encoder.h b/src/lib/j2k_still_encoder.h
index bc324e967..65cfa7cac 100644
--- a/src/lib/j2k_still_encoder.h
+++ b/src/lib/j2k_still_encoder.h
@@ -36,9 +36,6 @@ class J2KStillEncoder : public Encoder
public:
J2KStillEncoder (boost::shared_ptr<const Film>, boost::shared_ptr<const Options>);
- void process_begin (int64_t audio_channel_layout) {}
- void process_end () {}
-
private:
void do_process_video (boost::shared_ptr<const Image>, SourceFrame, boost::shared_ptr<Subtitle>);
void do_process_audio (boost::shared_ptr<const AudioBuffers>) {}
diff --git a/src/lib/j2k_wav_encoder.cc b/src/lib/j2k_wav_encoder.cc
index 6d777babb..108320d32 100644
--- a/src/lib/j2k_wav_encoder.cc
+++ b/src/lib/j2k_wav_encoder.cc
@@ -58,20 +58,22 @@ J2KWAVEncoder::J2KWAVEncoder (shared_ptr<const Film> f, shared_ptr<const Options
, _audio_frames_written (0)
, _process_end (false)
{
- /* Create sound output files with .tmp suffixes; we will rename
- them if and when we complete.
- */
- for (int i = 0; i < _film->audio_channels(); ++i) {
- SF_INFO sf_info;
- sf_info.samplerate = dcp_audio_sample_rate (_film->audio_sample_rate());
- /* We write mono files */
- sf_info.channels = 1;
- sf_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_24;
- SNDFILE* f = sf_open (_opt->multichannel_audio_out_path (i, true).c_str (), SFM_WRITE, &sf_info);
- if (f == 0) {
- throw CreateFileError (_opt->multichannel_audio_out_path (i, true));
+ if (_film->audio_stream()) {
+ /* Create sound output files with .tmp suffixes; we will rename
+ them if and when we complete.
+ */
+ 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());
+ /* We write mono files */
+ sf_info.channels = 1;
+ sf_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_24;
+ SNDFILE* f = sf_open (_opt->multichannel_audio_out_path (i, true).c_str (), SFM_WRITE, &sf_info);
+ if (f == 0) {
+ throw CreateFileError (_opt->multichannel_audio_out_path (i, true));
+ }
+ _sound_files.push_back (f);
}
- _sound_files.push_back (f);
}
}
@@ -225,24 +227,24 @@ J2KWAVEncoder::encoder_thread (ServerDescription* server)
}
void
-J2KWAVEncoder::process_begin (int64_t audio_channel_layout)
+J2KWAVEncoder::process_begin ()
{
- if (_film->audio_sample_rate() != _film->target_audio_sample_rate()) {
+ if (_film->audio_stream() && _film->audio_stream().get().sample_rate() != _film->target_audio_sample_rate()) {
#ifdef HAVE_SWRESAMPLE
stringstream s;
- s << "Will resample audio from " << _film->audio_sample_rate() << " to " << _film->target_audio_sample_rate();
+ s << "Will resample audio from " << _film->audio_stream().get().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,
- audio_channel_layout,
+ _film->audio_stream().get().channel_layout(),
AV_SAMPLE_FMT_FLTP,
_film->target_audio_sample_rate(),
- audio_channel_layout,
+ _film->audio_stream().get().channel_layout(),
AV_SAMPLE_FMT_FLTP,
- _film->audio_sample_rate(),
+ _film->audio_stream().get().sample_rate(),
0, 0
);
@@ -310,9 +312,9 @@ J2KWAVEncoder::process_end ()
}
#if HAVE_SWRESAMPLE
- if (_swr_context) {
+ if (_film->audio_stream() && _swr_context) {
- shared_ptr<AudioBuffers> out (new AudioBuffers (_film->audio_channels(), 256));
+ shared_ptr<AudioBuffers> out (new AudioBuffers (_film->audio_stream().get().channels(), 256));
while (1) {
int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0);
@@ -333,20 +335,22 @@ J2KWAVEncoder::process_end ()
}
#endif
- int const dcp_sr = dcp_audio_sample_rate (_film->audio_sample_rate ());
- int64_t const extra_audio_frames = dcp_sr - (_audio_frames_written % dcp_sr);
- shared_ptr<AudioBuffers> silence (new AudioBuffers (_film->audio_channels(), extra_audio_frames));
- silence->make_silent ();
- write_audio (silence);
-
- close_sound_files ();
-
- /* Rename .wav.tmp files to .wav */
- for (int i = 0; i < _film->audio_channels(); ++i) {
- if (boost::filesystem::exists (_opt->multichannel_audio_out_path (i, false))) {
- boost::filesystem::remove (_opt->multichannel_audio_out_path (i, false));
+ if (_film->audio_stream()) {
+ int const dcp_sr = dcp_audio_sample_rate (_film->audio_stream().get().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));
+ silence->make_silent ();
+ write_audio (silence);
+
+ close_sound_files ();
+
+ /* Rename .wav.tmp files to .wav */
+ for (int i = 0; i < _film->audio_channels(); ++i) {
+ if (boost::filesystem::exists (_opt->multichannel_audio_out_path (i, false))) {
+ boost::filesystem::remove (_opt->multichannel_audio_out_path (i, false));
+ }
+ boost::filesystem::rename (_opt->multichannel_audio_out_path (i, true), _opt->multichannel_audio_out_path (i, false));
}
- boost::filesystem::rename (_opt->multichannel_audio_out_path (i, true), _opt->multichannel_audio_out_path (i, false));
}
}
@@ -360,9 +364,9 @@ J2KWAVEncoder::do_process_audio (shared_ptr<const 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_sample_rate()) + 32;
+ int const max_resampled_frames = ceil (audio->frames() * _film->target_audio_sample_rate() / _film->audio_stream().get().sample_rate()) + 32;
- resampled.reset (new AudioBuffers (_film->audio_channels(), max_resampled_frames));
+ resampled.reset (new AudioBuffers (_film->audio_stream().get().channels(), max_resampled_frames));
/* Resample audio */
int const resampled_frames = swr_convert (
diff --git a/src/lib/j2k_wav_encoder.h b/src/lib/j2k_wav_encoder.h
index b494be8e5..5cf508cff 100644
--- a/src/lib/j2k_wav_encoder.h
+++ b/src/lib/j2k_wav_encoder.h
@@ -50,7 +50,7 @@ public:
J2KWAVEncoder (boost::shared_ptr<const Film>, boost::shared_ptr<const Options>);
~J2KWAVEncoder ();
- void process_begin (int64_t audio_channel_layout);
+ void process_begin ();
void process_end ();
private:
diff --git a/src/lib/stream.cc b/src/lib/stream.cc
index d1c2b5a9e..9d10813f7 100644
--- a/src/lib/stream.cc
+++ b/src/lib/stream.cc
@@ -26,7 +26,7 @@ using namespace std;
AudioStream::AudioStream (string t)
{
stringstream n (t);
- n >> _id >> _channels;
+ n >> _id >> _sample_rate >> _channel_layout;
for (int i = 0; i < 2; ++i) {
size_t const s = t.find (' ');
@@ -41,7 +41,7 @@ AudioStream::AudioStream (string t)
string
AudioStream::to_string () const
{
- return String::compose ("%1 %2 %3", _id, _channels, _name);
+ return String::compose ("%1 %2 %3 %4", _id, _sample_rate, _channel_layout, _name);
}
SubtitleStream::SubtitleStream (string t)
diff --git a/src/lib/stream.h b/src/lib/stream.h
index 2db63c620..d6c4ca382 100644
--- a/src/lib/stream.h
+++ b/src/lib/stream.h
@@ -20,6 +20,11 @@
#ifndef DVDOMATIC_STREAM_H
#define DVDOMATIC_STREAM_H
+#include <stdint.h>
+extern "C" {
+#include <libavutil/audioconvert.h>
+}
+
class Stream
{
public:
@@ -52,19 +57,29 @@ struct AudioStream : public Stream
public:
AudioStream (std::string t);
- AudioStream (std::string n, int i, int c)
- : Stream (n, i)
- , _channels (c)
+ AudioStream (std::string n, int id, int r, int64_t l)
+ : Stream (n, id)
+ , _sample_rate (r)
+ , _channel_layout (l)
{}
std::string to_string () const;
int channels () const {
- return _channels;
+ return av_get_channel_layout_nb_channels (_channel_layout);
+ }
+
+ int sample_rate () const {
+ return _sample_rate;
+ }
+
+ int64_t channel_layout () const {
+ return _channel_layout;
}
private:
- int _channels;
+ int _sample_rate;
+ int64_t _channel_layout;
};
class SubtitleStream : public Stream
diff --git a/src/lib/tiff_decoder.cc b/src/lib/tiff_decoder.cc
index 7cca511dd..c92e080d7 100644
--- a/src/lib/tiff_decoder.cc
+++ b/src/lib/tiff_decoder.cc
@@ -114,13 +114,6 @@ TIFFDecoder::audio_sample_rate () const
return 0;
}
-AVSampleFormat
-TIFFDecoder::audio_sample_format () const
-{
- return AV_SAMPLE_FMT_NONE;
-}
-
-
int64_t
TIFFDecoder::audio_channel_layout () const
{
diff --git a/src/lib/tiff_decoder.h b/src/lib/tiff_decoder.h
index 1c33443cf..e6821eec6 100644
--- a/src/lib/tiff_decoder.h
+++ b/src/lib/tiff_decoder.h
@@ -49,7 +49,6 @@ public:
Size native_size () const;
int audio_channels () const;
int audio_sample_rate () const;
- AVSampleFormat audio_sample_format () const;
int64_t audio_channel_layout () const;
bool has_subtitles () const {
return false;
diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc
index 66d5606af..ac908768e 100644
--- a/src/lib/transcoder.cc
+++ b/src/lib/transcoder.cc
@@ -29,6 +29,7 @@
#include "transcoder.h"
#include "encoder.h"
#include "decoder_factory.h"
+#include "film.h"
using std::string;
using boost::shared_ptr;
@@ -45,6 +46,10 @@ Transcoder::Transcoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j,
, _decoder (decoder_factory (f, o, j))
{
assert (_encoder);
+
+ /* Set up the decoder to use the film's set streams */
+ _decoder->set_audio_stream (f->audio_stream ());
+ _decoder->set_subtitle_stream (f->subtitle_stream ());
_decoder->Video.connect (bind (&Encoder::process_video, e, _1, _2, _3));
_decoder->Audio.connect (bind (&Encoder::process_audio, e, _1, _2));
@@ -56,7 +61,7 @@ Transcoder::Transcoder (shared_ptr<Film> f, shared_ptr<const Options> o, Job* j,
void
Transcoder::go ()
{
- _encoder->process_begin (_decoder->audio_channel_layout());
+ _encoder->process_begin ();
try {
_decoder->go ();
} catch (...) {
diff --git a/src/lib/util.h b/src/lib/util.h
index 7aa9f25e1..577b9ba1b 100644
--- a/src/lib/util.h
+++ b/src/lib/util.h
@@ -41,6 +41,8 @@ extern "C" {
#define TIMING(...)
#endif
+#define MAX_AUDIO_CHANNELS 6
+
class Scaler;
extern std::string seconds_to_hms (int);
diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc
index 703059780..e49bf6272 100644
--- a/src/wx/film_editor.cc
+++ b/src/wx/film_editor.cc
@@ -24,6 +24,7 @@
#include <iostream>
#include <iomanip>
#include <wx/wx.h>
+#include <wx/notebook.h>
#include <boost/thread.hpp>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
@@ -45,6 +46,7 @@
#include "scaler.h"
using std::string;
+using std::cout;
using std::stringstream;
using std::pair;
using std::fixed;
@@ -59,225 +61,300 @@ FilmEditor::FilmEditor (shared_ptr<Film> f, wxWindow* parent)
, _film (f)
, _generally_sensitive (true)
{
- _sizer = new wxFlexGridSizer (2, 4, 4);
- SetSizer (_sizer);
+ wxSizer* s = new wxBoxSizer (wxVERTICAL);
+ SetSizer (s);
+ _notebook = new wxNotebook (this, wxID_ANY);
+ s->Add (_notebook, 1);
+
+ make_film_panel ();
+ _notebook->AddPage (_film_panel, _("Film"), true);
+ make_video_panel ();
+ _notebook->AddPage (_video_panel, _("Video"), false);
+ make_audio_panel ();
+ _notebook->AddPage (_audio_panel, _("Audio"), false);
+ make_subtitle_panel ();
+ _notebook->AddPage (_subtitle_panel, _("Subtitles"), false);
+
+ set_film (_film);
+ connect_to_widgets ();
+
+ JobManager::instance()->ActiveJobsChanged.connect (
+ bind (&FilmEditor::active_jobs_changed, this, _1)
+ );
+
+ setup_visibility ();
+ setup_formats ();
+}
+
+void
+FilmEditor::make_film_panel ()
+{
+ _film_panel = new wxPanel (_notebook);
+ _film_sizer = new wxFlexGridSizer (2, 4, 4);
+ _film_panel->SetSizer (_film_sizer);
+
+ add_label_to_sizer (_film_sizer, _film_panel, "Name");
+ _name = new wxTextCtrl (_film_panel, wxID_ANY);
+ _film_sizer->Add (_name, 1, wxEXPAND);
+
+ add_label_to_sizer (_film_sizer, _film_panel, "DCP Name");
+ _dcp_name = new wxStaticText (_film_panel, wxID_ANY, wxT (""));
+ _film_sizer->Add (_dcp_name, 0, wxALIGN_CENTER_VERTICAL | wxSHRINK);
+
+ _use_dci_name = new wxCheckBox (_film_panel, wxID_ANY, wxT ("Use DCI name"));
+ _film_sizer->Add (_use_dci_name, 1, wxEXPAND);
+ _edit_dci_button = new wxButton (_film_panel, wxID_ANY, wxT ("Details..."));
+ _film_sizer->Add (_edit_dci_button, 0);
+
+ add_label_to_sizer (_film_sizer, _film_panel, "Content");
+ _content = new wxFilePickerCtrl (_film_panel, wxID_ANY, wxT (""), wxT ("Select Content File"), wxT("*.*"));
+ _film_sizer->Add (_content, 1, wxEXPAND);
+
+ add_label_to_sizer (_film_sizer, _film_panel, "Content Type");
+ _dcp_content_type = new wxComboBox (_film_panel, wxID_ANY);
+ _film_sizer->Add (_dcp_content_type);
+
+ video_control (add_label_to_sizer (_film_sizer, _film_panel, "Frames Per Second"));
+ _frames_per_second = new wxStaticText (_film_panel, wxID_ANY, wxT (""));
+ _film_sizer->Add (video_control (_frames_per_second), 1, wxALIGN_CENTER_VERTICAL);
+
+ video_control (add_label_to_sizer (_film_sizer, _film_panel, "Original Size"));
+ _original_size = new wxStaticText (_film_panel, wxID_ANY, wxT (""));
+ _film_sizer->Add (video_control (_original_size), 1, wxALIGN_CENTER_VERTICAL);
+
+ video_control (add_label_to_sizer (_film_sizer, _film_panel, "Length"));
+ _length = new wxStaticText (_film_panel, wxID_ANY, wxT (""));
+ _film_sizer->Add (video_control (_length), 1, wxALIGN_CENTER_VERTICAL);
- add_label_to_sizer (_sizer, this, "Name");
- _name = new wxTextCtrl (this, wxID_ANY);
- _sizer->Add (_name, 1, wxEXPAND);
- add_label_to_sizer (_sizer, this, "DCP Name");
- _dcp_name = new wxStaticText (this, wxID_ANY, wxT (""));
- _sizer->Add (_dcp_name, 0, wxALIGN_CENTER_VERTICAL | wxSHRINK);
+ {
+ video_control (add_label_to_sizer (_film_sizer, _film_panel, "Trim frames"));
+ wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+ add_label_to_sizer (s, _film_panel, "Start");
+ _dcp_trim_start = new wxSpinCtrl (_film_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
+ s->Add (_dcp_trim_start);
+ add_label_to_sizer (s, _film_panel, "End");
+ _dcp_trim_end = new wxSpinCtrl (_film_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
+ s->Add (_dcp_trim_end);
- _use_dci_name = new wxCheckBox (this, wxID_ANY, wxT ("Use DCI name"));
- _sizer->Add (_use_dci_name, 1, wxEXPAND);
- _edit_dci_button = new wxButton (this, wxID_ANY, wxT ("Details..."));
- _sizer->Add (_edit_dci_button, 0);
+ _film_sizer->Add (s);
+ }
- add_label_to_sizer (_sizer, this, "Content");
- _content = new wxFilePickerCtrl (this, wxID_ANY, wxT (""), wxT ("Select Content File"), wxT("*.*"));
- _sizer->Add (_content, 1, wxEXPAND);
+ _dcp_ab = new wxCheckBox (_film_panel, wxID_ANY, wxT ("A/B"));
+ video_control (_dcp_ab);
+ _film_sizer->Add (_dcp_ab, 1);
+ _film_sizer->AddSpacer (0);
+
+ /* STILL-only stuff */
+ {
+ still_control (add_label_to_sizer (_film_sizer, _film_panel, "Duration"));
+ wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+ _still_duration = new wxSpinCtrl (_film_panel);
+ still_control (_still_duration);
+ s->Add (_still_duration, 1, wxEXPAND);
+ still_control (add_label_to_sizer (s, _film_panel, "s"));
+ _film_sizer->Add (s);
+ }
+
+ vector<DCPContentType const *> const ct = DCPContentType::all ();
+ for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) {
+ _dcp_content_type->Append (std_to_wx ((*i)->pretty_name ()));
+ }
+}
+
+void
+FilmEditor::connect_to_widgets ()
+{
+ _name->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (FilmEditor::name_changed), 0, this);
+ _use_dci_name->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::use_dci_name_toggled), 0, this);
+ _edit_dci_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::edit_dci_button_clicked), 0, this);
+ _format->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::format_changed), 0, this);
+ _content->Connect (wxID_ANY, wxEVT_COMMAND_FILEPICKER_CHANGED, wxCommandEventHandler (FilmEditor::content_changed), 0, this);
+ _left_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::left_crop_changed), 0, this);
+ _right_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::right_crop_changed), 0, this);
+ _top_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::top_crop_changed), 0, this);
+ _bottom_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::bottom_crop_changed), 0, this);
+ _filters_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::edit_filters_clicked), 0, this);
+ _scaler->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::scaler_changed), 0, this);
+ _dcp_content_type->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::dcp_content_type_changed), 0, this);
+ _dcp_ab->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::dcp_ab_toggled), 0, this);
+ _still_duration->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::still_duration_changed), 0, this);
+ _dcp_trim_start->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::dcp_trim_start_changed), 0, this);
+ _dcp_trim_end->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::dcp_trim_end_changed), 0, this);
+ _with_subtitles->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::with_subtitles_toggled), 0, this);
+ _subtitle_offset->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_offset_changed), 0, this);
+ _subtitle_scale->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_scale_changed), 0, this);
+ _subtitle_stream->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::subtitle_stream_changed), 0, this);
+ _audio_stream->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::audio_stream_changed), 0, this);
+ _audio_gain->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::audio_gain_changed), 0, this);
+ _audio_gain_calculate_button->Connect (
+ wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::audio_gain_calculate_button_clicked), 0, this
+ );
+ _audio_delay->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::audio_delay_changed), 0, this);
+ _use_source_audio->Connect (wxID_ANY, wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler (FilmEditor::use_audio_changed), 0, this);
+ _use_external_audio->Connect (wxID_ANY, wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler (FilmEditor::use_audio_changed), 0, this);
+ for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) {
+ _external_audio[i]->Connect (
+ wxID_ANY, wxEVT_COMMAND_FILEPICKER_CHANGED, wxCommandEventHandler (FilmEditor::external_audio_changed), 0, this
+ );
+ }
+}
- add_label_to_sizer (_sizer, this, "Content Type");
- _dcp_content_type = new wxComboBox (this, wxID_ANY);
- _sizer->Add (_dcp_content_type);
+void
+FilmEditor::make_video_panel ()
+{
+ _video_panel = new wxPanel (_notebook);
+ _video_sizer = new wxFlexGridSizer (2, 4, 4);
+ _video_panel->SetSizer (_video_sizer);
- add_label_to_sizer (_sizer, this, "Format");
- _format = new wxComboBox (this, wxID_ANY);
- _sizer->Add (_format);
+ add_label_to_sizer (_video_sizer, _video_panel, "Format");
+ _format = new wxComboBox (_video_panel, wxID_ANY);
+ _video_sizer->Add (_format);
{
- add_label_to_sizer (_sizer, this, "Crop");
+ add_label_to_sizer (_video_sizer, _video_panel, "Crop");
wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- add_label_to_sizer (s, this, "L");
- _left_crop = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
+ add_label_to_sizer (s, _video_panel, "L");
+ _left_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
s->Add (_left_crop, 0);
- add_label_to_sizer (s, this, "R");
- _right_crop = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
+ add_label_to_sizer (s, _video_panel, "R");
+ _right_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
s->Add (_right_crop, 0);
- add_label_to_sizer (s, this, "T");
- _top_crop = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
+ add_label_to_sizer (s, _video_panel, "T");
+ _top_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
s->Add (_top_crop, 0);
- add_label_to_sizer (s, this, "B");
- _bottom_crop = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
+ add_label_to_sizer (s, _video_panel, "B");
+ _bottom_crop = new wxSpinCtrl (_video_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
s->Add (_bottom_crop, 0);
- _sizer->Add (s);
+ _video_sizer->Add (s);
}
/* VIDEO-only stuff */
{
- video_control (add_label_to_sizer (_sizer, this, "Filters"));
+ video_control (add_label_to_sizer (_video_sizer, _video_panel, "Filters"));
wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _filters = new wxStaticText (this, wxID_ANY, wxT ("None"));
+ _filters = new wxStaticText (_video_panel, wxID_ANY, wxT ("None"));
video_control (_filters);
s->Add (_filters, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM | wxRIGHT, 6);
- _filters_button = new wxButton (this, wxID_ANY, wxT ("Edit..."));
+ _filters_button = new wxButton (_video_panel, wxID_ANY, wxT ("Edit..."));
video_control (_filters_button);
s->Add (_filters_button, 0);
- _sizer->Add (s, 1);
+ _video_sizer->Add (s, 1);
}
- video_control (add_label_to_sizer (_sizer, this, "Scaler"));
- _scaler = new wxComboBox (this, wxID_ANY);
- _sizer->Add (video_control (_scaler), 1);
+ video_control (add_label_to_sizer (_video_sizer, _video_panel, "Scaler"));
+ _scaler = new wxComboBox (_video_panel, wxID_ANY);
+ _video_sizer->Add (video_control (_scaler), 1);
- {
- video_control (add_label_to_sizer (_sizer, this, "Audio Stream"));
- wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _audio_stream = new wxComboBox (this, wxID_ANY);
- s->Add (video_control (_audio_stream), 1);
- _audio = new wxStaticText (this, wxID_ANY, wxT (""));
- s->Add (video_control (_audio), 1, wxALIGN_CENTER_VERTICAL | wxLEFT, 8);
- _sizer->Add (s, 1, wxEXPAND);
+ vector<Scaler const *> const sc = Scaler::all ();
+ for (vector<Scaler const *>::const_iterator i = sc.begin(); i != sc.end(); ++i) {
+ _scaler->Append (std_to_wx ((*i)->name()));
}
+ _left_crop->SetRange (0, 1024);
+ _top_crop->SetRange (0, 1024);
+ _right_crop->SetRange (0, 1024);
+ _bottom_crop->SetRange (0, 1024);
+ _still_duration->SetRange (0, 60 * 60);
+ _dcp_trim_start->SetRange (0, 100);
+ _dcp_trim_end->SetRange (0, 100);
+}
+
+void
+FilmEditor::make_audio_panel ()
+{
+ _audio_panel = new wxPanel (_notebook);
+ _audio_sizer = new wxFlexGridSizer (2, 4, 4);
+ _audio_panel->SetSizer (_audio_sizer);
+
{
- video_control (add_label_to_sizer (_sizer, this, "Audio Gain"));
+ video_control (add_label_to_sizer (_audio_sizer, _audio_panel, "Audio Gain"));
wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _audio_gain = new wxSpinCtrl (this);
+ _audio_gain = new wxSpinCtrl (_audio_panel);
s->Add (video_control (_audio_gain), 1);
- video_control (add_label_to_sizer (s, this, "dB"));
- _audio_gain_calculate_button = new wxButton (this, wxID_ANY, _("Calculate..."));
+ video_control (add_label_to_sizer (s, _audio_panel, "dB"));
+ _audio_gain_calculate_button = new wxButton (_audio_panel, wxID_ANY, _("Calculate..."));
video_control (_audio_gain_calculate_button);
s->Add (_audio_gain_calculate_button, 1, wxEXPAND);
- _sizer->Add (s);
+ _audio_sizer->Add (s);
}
{
- video_control (add_label_to_sizer (_sizer, this, "Audio Delay"));
+ video_control (add_label_to_sizer (_audio_sizer, _audio_panel, "Audio Delay"));
wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _audio_delay = new wxSpinCtrl (this);
+ _audio_delay = new wxSpinCtrl (_audio_panel);
s->Add (video_control (_audio_delay), 1);
- video_control (add_label_to_sizer (s, this, "ms"));
- _sizer->Add (s);
+ video_control (add_label_to_sizer (s, _audio_panel, "ms"));
+ _audio_sizer->Add (s);
}
- _with_subtitles = new wxCheckBox (this, wxID_ANY, wxT("With Subtitles"));
- video_control (_with_subtitles);
- _sizer->Add (_with_subtitles, 1);
-
- _subtitle_stream = new wxComboBox (this, wxID_ANY);
- _sizer->Add (_subtitle_stream);
-
- video_control (add_label_to_sizer (_sizer, this, "Subtitle Offset"));
- _subtitle_offset = new wxSpinCtrl (this);
- _sizer->Add (video_control (_subtitle_offset), 1);
-
{
- video_control (add_label_to_sizer (_sizer, this, "Subtitle Scale"));
+ _use_source_audio = new wxRadioButton (_audio_panel, wxID_ANY, _("Use source audio"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
+ _audio_sizer->Add (video_control (_use_source_audio));
wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _subtitle_scale = new wxSpinCtrl (this);
- s->Add (video_control (_subtitle_scale));
- video_control (add_label_to_sizer (s, this, "%"));
- _sizer->Add (s);
- }
-
- video_control (add_label_to_sizer (_sizer, this, "Frames Per Second"));
- _frames_per_second = new wxStaticText (this, wxID_ANY, wxT (""));
- _sizer->Add (video_control (_frames_per_second), 1, wxALIGN_CENTER_VERTICAL);
-
- video_control (add_label_to_sizer (_sizer, this, "Original Size"));
- _original_size = new wxStaticText (this, wxID_ANY, wxT (""));
- _sizer->Add (video_control (_original_size), 1, wxALIGN_CENTER_VERTICAL);
-
- video_control (add_label_to_sizer (_sizer, this, "Length"));
- _length = new wxStaticText (this, wxID_ANY, wxT (""));
- _sizer->Add (video_control (_length), 1, wxALIGN_CENTER_VERTICAL);
-
-
- {
- video_control (add_label_to_sizer (_sizer, this, "Trim frames"));
- wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- add_label_to_sizer (s, this, "Start");
- _dcp_trim_start = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
- s->Add (_dcp_trim_start);
- add_label_to_sizer (s, this, "End");
- _dcp_trim_end = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
- s->Add (_dcp_trim_end);
-
- _sizer->Add (s);
+ _audio_stream = new wxComboBox (_audio_panel, wxID_ANY);
+ s->Add (video_control (_audio_stream), 1);
+ _audio = new wxStaticText (_audio_panel, wxID_ANY, wxT (""));
+ s->Add (video_control (_audio), 1, wxALIGN_CENTER_VERTICAL | wxLEFT, 8);
+ _audio_sizer->Add (s, 1, wxEXPAND);
}
- _dcp_ab = new wxCheckBox (this, wxID_ANY, wxT ("A/B"));
- video_control (_dcp_ab);
- _sizer->Add (_dcp_ab, 1);
- _sizer->AddSpacer (0);
-
- /* STILL-only stuff */
- {
- still_control (add_label_to_sizer (_sizer, this, "Duration"));
- wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _still_duration = new wxSpinCtrl (this);
- still_control (_still_duration);
- s->Add (_still_duration, 1, wxEXPAND);
- still_control (add_label_to_sizer (s, this, "s"));
- _sizer->Add (s);
+ _use_external_audio = new wxRadioButton (_audio_panel, wxID_ANY, _("Use external audio"));
+ _audio_sizer->Add (video_control (_use_external_audio));
+ _audio_sizer->AddSpacer (0);
+
+ assert (MAX_AUDIO_CHANNELS == 6);
+
+ char const * channels[] = {
+ "L",
+ "R",
+ "C",
+ "Lfe",
+ "Ls",
+ "Rs"
+ };
+
+ for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) {
+ add_label_to_sizer (_audio_sizer, _audio_panel, channels[i]);
+ _external_audio[i] = new wxFilePickerCtrl (_audio_panel, wxID_ANY, wxT (""), wxT ("Select Audio File"), wxT ("*.wav"));
+ _audio_sizer->Add (video_control (_external_audio[i]), 1, wxEXPAND);
}
- /* Set up our editing widgets */
-
- _left_crop->SetRange (0, 1024);
- _top_crop->SetRange (0, 1024);
- _right_crop->SetRange (0, 1024);
- _bottom_crop->SetRange (0, 1024);
_audio_gain->SetRange (-60, 60);
_audio_delay->SetRange (-1000, 1000);
- _still_duration->SetRange (0, 60 * 60);
- _subtitle_offset->SetRange (-1024, 1024);
- _subtitle_scale->SetRange (1, 1000);
- _dcp_trim_start->SetRange (0, 100);
- _dcp_trim_end->SetRange (0, 100);
+}
- vector<DCPContentType const *> const ct = DCPContentType::all ();
- for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) {
- _dcp_content_type->Append (std_to_wx ((*i)->pretty_name ()));
- }
+void
+FilmEditor::make_subtitle_panel ()
+{
+ _subtitle_panel = new wxPanel (_notebook);
+ _subtitle_sizer = new wxFlexGridSizer (2, 4, 4);
+ _subtitle_panel->SetSizer (_subtitle_sizer);
- vector<Scaler const *> const sc = Scaler::all ();
- for (vector<Scaler const *>::const_iterator i = sc.begin(); i != sc.end(); ++i) {
- _scaler->Append (std_to_wx ((*i)->name()));
- }
+ _with_subtitles = new wxCheckBox (_subtitle_panel, wxID_ANY, wxT("With Subtitles"));
+ video_control (_with_subtitles);
+ _subtitle_sizer->Add (_with_subtitles, 1);
+
+ _subtitle_stream = new wxComboBox (_subtitle_panel, wxID_ANY);
+ _subtitle_sizer->Add (_subtitle_stream);
- JobManager::instance()->ActiveJobsChanged.connect (
- bind (&FilmEditor::active_jobs_changed, this, _1)
- );
+ video_control (add_label_to_sizer (_subtitle_sizer, _subtitle_panel, "Subtitle Offset"));
+ _subtitle_offset = new wxSpinCtrl (_subtitle_panel);
+ _subtitle_sizer->Add (video_control (_subtitle_offset), 1);
- /* And set their values from the Film */
- set_film (f);
-
- /* Now connect to them, since initial values are safely set */
- _name->Connect (wxID_ANY, wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler (FilmEditor::name_changed), 0, this);
- _use_dci_name->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::use_dci_name_toggled), 0, this);
- _edit_dci_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::edit_dci_button_clicked), 0, this);
- _format->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::format_changed), 0, this);
- _content->Connect (wxID_ANY, wxEVT_COMMAND_FILEPICKER_CHANGED, wxCommandEventHandler (FilmEditor::content_changed), 0, this);
- _left_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::left_crop_changed), 0, this);
- _right_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::right_crop_changed), 0, this);
- _top_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::top_crop_changed), 0, this);
- _bottom_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::bottom_crop_changed), 0, this);
- _filters_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::edit_filters_clicked), 0, this);
- _scaler->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::scaler_changed), 0, this);
- _dcp_content_type->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::dcp_content_type_changed), 0, this);
- _dcp_ab->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::dcp_ab_toggled), 0, this);
- _audio_gain->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::audio_gain_changed), 0, this);
- _audio_gain_calculate_button->Connect (
- wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::audio_gain_calculate_button_clicked), 0, this
- );
- _audio_delay->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::audio_delay_changed), 0, this);
- _still_duration->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::still_duration_changed), 0, this);
- _dcp_trim_start->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::dcp_trim_start_changed), 0, this);
- _dcp_trim_end->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::dcp_trim_end_changed), 0, this);
- _with_subtitles->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::with_subtitles_toggled), 0, this);
- _subtitle_offset->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_offset_changed), 0, this);
- _subtitle_scale->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_scale_changed), 0, this);
- _audio_stream->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::audio_stream_changed), 0, this);
- _subtitle_stream->Connect (wxID_ANY, wxEVT_COMMAND_COMBOBOX_SELECTED, wxCommandEventHandler (FilmEditor::subtitle_stream_changed), 0, this);
+ {
+ video_control (add_label_to_sizer (_subtitle_sizer, _subtitle_panel, "Subtitle Scale"));
+ wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+ _subtitle_scale = new wxSpinCtrl (_subtitle_panel);
+ s->Add (video_control (_subtitle_scale));
+ video_control (add_label_to_sizer (s, _subtitle_panel, "%"));
+ _subtitle_sizer->Add (s);
+ }
- setup_visibility ();
- setup_formats ();
+ _subtitle_offset->SetRange (-1024, 1024);
+ _subtitle_scale->SetRange (1, 1000);
}
/** Called when the left crop widget has been changed */
@@ -408,12 +485,9 @@ FilmEditor::film_changed (Film::Property p)
setup_subtitle_control_sensitivity ();
setup_streams ();
break;
- case Film::HAS_SUBTITLES:
- setup_subtitle_control_sensitivity ();
- setup_streams ();
- break;
case Film::AUDIO_STREAMS:
case Film::SUBTITLE_STREAMS:
+ setup_subtitle_control_sensitivity ();
setup_streams ();
break;
case Film::FORMAT:
@@ -443,7 +517,7 @@ FilmEditor::film_changed (Film::Property p)
string const b = p.first + " " + p.second;
_filters->SetLabel (std_to_wx (b));
}
- _sizer->Layout ();
+ _film_sizer->Layout ();
break;
}
case Film::NAME:
@@ -455,9 +529,6 @@ FilmEditor::film_changed (Film::Property p)
s << fixed << setprecision(2) << _film->frames_per_second();
_frames_per_second->SetLabel (std_to_wx (s.str ()));
break;
- case Film::AUDIO_SAMPLE_RATE:
- setup_audio_details ();
- break;
case Film::SIZE:
if (_film->size().width == 0 && _film->size().height == 0) {
_original_size->SetLabel (wxT (""));
@@ -526,14 +597,31 @@ FilmEditor::film_changed (Film::Property p)
_dcp_name->SetLabel (std_to_wx (_film->dcp_name ()));
break;
case Film::AUDIO_STREAM:
- checked_set (_audio_stream, _film->audio_stream_index ());
+ if (_film->audio_stream()) {
+ checked_set (_audio_stream, _film->audio_stream().get().to_string());
+ }
_dcp_name->SetLabel (std_to_wx (_film->dcp_name ()));
setup_audio_details ();
break;
case Film::SUBTITLE_STREAM:
- checked_set (_subtitle_stream, _film->subtitle_stream_index ());
+ if (_film->subtitle_stream()) {
+ checked_set (_subtitle_stream, _film->subtitle_stream().get().to_string());
+ }
+ break;
+ case Film::USE_SOURCE_AUDIO:
+ checked_set (_use_source_audio, _film->use_source_audio ());
+ checked_set (_use_external_audio, !_film->use_source_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]);
+ }
break;
}
+ }
}
/** Called when the format widget has been changed */
@@ -592,16 +680,17 @@ 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_SOURCE_AUDIO);
+ film_changed (Film::AUDIO_STREAM);
+ film_changed (Film::EXTERNAL_AUDIO);
film_changed (Film::SIZE);
film_changed (Film::LENGTH);
film_changed (Film::FRAMES_PER_SECOND);
- film_changed (Film::AUDIO_SAMPLE_RATE);
film_changed (Film::SCALER);
film_changed (Film::AUDIO_GAIN);
film_changed (Film::AUDIO_DELAY);
film_changed (Film::STILL_DURATION);
film_changed (Film::WITH_SUBTITLES);
- film_changed (Film::HAS_SUBTITLES);
film_changed (Film::SUBTITLE_OFFSET);
film_changed (Film::SUBTITLE_SCALE);
film_changed (Film::USE_DCI_NAME);
@@ -638,6 +727,7 @@ FilmEditor::set_things_sensitive (bool s)
_still_duration->Enable (s);
setup_subtitle_control_sensitivity ();
+ setup_audio_control_sensitivity ();
}
/** Called when the `Edit filters' button has been clicked */
@@ -715,7 +805,7 @@ FilmEditor::setup_visibility ()
(*i)->Show (c == STILL);
}
- _sizer->Layout ();
+ _film_sizer->Layout ();
}
void
@@ -800,7 +890,7 @@ FilmEditor::setup_formats ()
_format->Append (std_to_wx ((*i)->name ()));
}
- _sizer->Layout ();
+ _film_sizer->Layout ();
}
void
@@ -818,7 +908,7 @@ FilmEditor::setup_subtitle_control_sensitivity ()
{
bool h = false;
if (_generally_sensitive && _film) {
- h = _film->has_subtitles();
+ h = !_film->subtitle_streams().empty();
}
_with_subtitles->Enable (h);
@@ -828,6 +918,21 @@ FilmEditor::setup_subtitle_control_sensitivity ()
}
void
+FilmEditor::setup_audio_control_sensitivity ()
+{
+ _use_source_audio->Enable (_generally_sensitive);
+ _use_external_audio->Enable (_generally_sensitive);
+
+ bool const source = _generally_sensitive && _use_source_audio->GetValue();
+ bool const external = _generally_sensitive && _use_external_audio->GetValue();
+
+ _audio_stream->Enable (source);
+ for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) {
+ _external_audio[i]->Enable (external);
+ }
+}
+
+void
FilmEditor::use_dci_name_toggled (wxCommandEvent &)
{
if (!_film) {
@@ -855,16 +960,21 @@ 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()));
+ _audio_stream->Append (std_to_wx (i->name()), new wxStringClientData (std_to_wx (i->to_string ())));
+ }
+
+ if (_film->audio_stream()) {
+ checked_set (_audio_stream, _film->audio_stream().get().to_string());
}
- _audio_stream->SetSelection (_film->audio_stream_index ());
_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()));
+ _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());
}
- _subtitle_stream->SetSelection (_film->subtitle_stream_index ());
}
void
@@ -874,7 +984,7 @@ FilmEditor::audio_stream_changed (wxCommandEvent &)
return;
}
- _film->set_audio_stream (_audio_stream->GetSelection ());
+ _film->set_audio_stream (AudioStream (string_client_data (_audio_stream->GetClientObject (_audio_stream->GetSelection ()))));
}
void
@@ -884,17 +994,17 @@ FilmEditor::subtitle_stream_changed (wxCommandEvent &)
return;
}
- _film->set_subtitle_stream (_subtitle_stream->GetSelection ());
+ _film->set_subtitle_stream (SubtitleStream (string_client_data (_subtitle_stream->GetClientObject (_subtitle_stream->GetSelection ()))));
}
void
FilmEditor::setup_audio_details ()
{
- if (_film->audio_channels() == 0 && _film->audio_sample_rate() == 0) {
+ if (!_film->audio_stream()) {
_audio->SetLabel (wxT (""));
} else {
stringstream s;
- s << _film->audio_channels () << " channels, " << _film->audio_sample_rate() << "Hz";
+ s << _film->audio_stream().get().channels () << " channels, " << _film->audio_stream().get().sample_rate() << "Hz";
_audio->SetLabel (std_to_wx (s.str ()));
}
}
@@ -904,3 +1014,21 @@ FilmEditor::active_jobs_changed (bool a)
{
set_things_sensitive (!a);
}
+
+void
+FilmEditor::use_audio_changed (wxCommandEvent &)
+{
+ _film->set_use_source_audio (_use_source_audio->GetValue ());
+ setup_audio_control_sensitivity ();
+}
+
+void
+FilmEditor::external_audio_changed (wxCommandEvent &)
+{
+ vector<string> a;
+ for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) {
+ a.push_back (wx_to_std (_external_audio[i]->GetPath()));
+ }
+
+ _film->set_external_audio (a);
+}
diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h
index c5fe4b6cc..2890df244 100644
--- a/src/wx/film_editor.h
+++ b/src/wx/film_editor.h
@@ -28,6 +28,8 @@
#include <boost/signals2.hpp>
#include "lib/film.h"
+class wxNotebook;
+
class Film;
/** @class FilmEditor
@@ -44,6 +46,12 @@ public:
boost::signals2::signal<void (std::string)> FileChanged;
private:
+ void make_film_panel ();
+ void make_video_panel ();
+ void make_audio_panel ();
+ void make_subtitle_panel ();
+ void connect_to_widgets ();
+
/* Handle changes to the view */
void name_changed (wxCommandEvent &);
void use_dci_name_toggled (wxCommandEvent &);
@@ -68,17 +76,19 @@ private:
void still_duration_changed (wxCommandEvent &);
void audio_stream_changed (wxCommandEvent &);
void subtitle_stream_changed (wxCommandEvent &);
+ void use_audio_changed (wxCommandEvent &);
+ void external_audio_changed (wxCommandEvent &);
/* Handle changes to the model */
void film_changed (Film::Property);
/* Button clicks */
void edit_filters_clicked (wxCommandEvent &);
- void change_dcp_range_clicked (wxCommandEvent &);
void set_things_sensitive (bool);
void setup_formats ();
void setup_subtitle_control_sensitivity ();
+ void setup_audio_control_sensitivity ();
void setup_streams ();
void setup_audio_details ();
@@ -87,6 +97,16 @@ private:
void active_jobs_changed (bool);
+ wxNotebook* _notebook;
+ wxPanel* _film_panel;
+ wxSizer* _film_sizer;
+ wxPanel* _video_panel;
+ wxSizer* _video_sizer;
+ wxPanel* _audio_panel;
+ wxSizer* _audio_sizer;
+ wxPanel* _subtitle_panel;
+ wxSizer* _subtitle_sizer;
+
/** The film we are editing */
boost::shared_ptr<Film> _film;
/** The Film's name */
@@ -112,7 +132,10 @@ private:
wxButton* _filters_button;
/** The Film's scaler */
wxComboBox* _scaler;
+ wxRadioButton* _use_source_audio;
wxComboBox* _audio_stream;
+ wxRadioButton* _use_external_audio;
+ wxFilePickerCtrl* _external_audio[MAX_AUDIO_CHANNELS];
/** The Film's audio gain */
wxSpinCtrl* _audio_gain;
/** A button to open the gain calculation dialogue */
@@ -146,7 +169,5 @@ private:
std::vector<Format const *> _formats;
- wxSizer* _sizer;
-
bool _generally_sensitive;
};
diff --git a/src/wx/wx_util.cc b/src/wx/wx_util.cc
index a677fd9ac..4196dd632 100644
--- a/src/wx/wx_util.cc
+++ b/src/wx/wx_util.cc
@@ -109,6 +109,12 @@ ThreadedStaticText::thread_finished (wxCommandEvent& ev)
SetLabel (ev.GetString ());
}
+string
+string_client_data (wxClientData* o)
+{
+ return wx_to_std (dynamic_cast<wxStringClientData*>(o)->GetData());
+}
+
void
checked_set (wxFilePickerCtrl* widget, string value)
{
@@ -134,6 +140,20 @@ checked_set (wxComboBox* widget, int value)
}
void
+checked_set (wxComboBox* widget, string value)
+{
+ wxClientData* o = widget->GetClientObject (widget->GetSelection ());
+
+ if (!o || string_client_data(o) != value) {
+ for (unsigned int i = 0; i < widget->GetCount(); ++i) {
+ if (string_client_data (widget->GetClientObject (i)) == value) {
+ widget->SetSelection (i);
+ }
+ }
+ }
+}
+
+void
checked_set (wxTextCtrl* widget, string value)
{
if (widget->GetValue() != std_to_wx (value)) {
@@ -148,3 +168,11 @@ checked_set (wxCheckBox* widget, bool value)
widget->SetValue (value);
}
}
+
+void
+checked_set (wxRadioButton* widget, bool value)
+{
+ if (widget->GetValue() != value) {
+ widget->SetValue (value);
+ }
+}
diff --git a/src/wx/wx_util.h b/src/wx/wx_util.h
index c2c3b6dde..6cb7fd002 100644
--- a/src/wx/wx_util.h
+++ b/src/wx/wx_util.h
@@ -54,8 +54,12 @@ private:
static const int _update_event_id;
};
+extern std::string string_client_data (wxClientData* o);
+
extern void checked_set (wxFilePickerCtrl* widget, std::string value);
extern void checked_set (wxSpinCtrl* widget, int value);
extern void checked_set (wxComboBox* widget, int value);
+extern void checked_set (wxComboBox* widget, std::string value);
extern void checked_set (wxTextCtrl* widget, std::string value);
extern void checked_set (wxCheckBox* widget, bool value);
+extern void checked_set (wxRadioButton* widget, bool value);