\end{verbatim}
Then Film has a \texttt{Playlist} which has a
-\texttt{vector<shared\_ptr<Content>}. And it can answer questions
+\texttt{vector<shared\_ptr<Content> >}. It can answer questions
about audio/video length, frame rate, audio channels and so on.
\texttt{Playlist} can also be a source of video and audio, so clients can do:
}
\end{verbatim}
-Playlist could be created on-demand for all the difference it would make.
+Playlist could be created on-demand for all the difference it would
+make. And perhaps it should, since it will hold Decoders which are
+probably run-once.
\end{document}
{
try {
/* _film_b is the one with reference filters */
- ABTranscoder w (_film_b, _film, _decode_opt, this, shared_ptr<Encoder> (new Encoder (_film)));
+ ABTranscoder w (_film_b, _film, _decode_opt, shared_from_this ());
w.go ();
set_progress (1);
set_state (FINISHED_OK);
void run ();
private:
- DecodeOptions _decode_opt;
-
/** Copy of our Film using the reference filters and scaler */
boost::shared_ptr<Film> _film_b;
+ DecodeOptions _decode_opt;
};
#include <boost/shared_ptr.hpp>
#include "ab_transcoder.h"
#include "film.h"
-#include "video_decoder.h"
-#include "audio_decoder.h"
#include "encoder.h"
#include "job.h"
#include "options.h"
#include "image.h"
-#include "decoder_factory.h"
+#include "playlist.h"
#include "matcher.h"
#include "delay_line.h"
#include "gain.h"
* @param e Encoder to use.
*/
-ABTranscoder::ABTranscoder (
- shared_ptr<Film> a, shared_ptr<Film> b, DecodeOptions o, Job* j, shared_ptr<Encoder> e)
+ABTranscoder::ABTranscoder (shared_ptr<Film> a, shared_ptr<Film> b, DecodeOptions o, shared_ptr<Job> j)
: _film_a (a)
, _film_b (b)
+ , _playlist_a (_film_a->playlist ())
+ , _playlist_b (_film_b->playlist ())
, _job (j)
- , _encoder (e)
+ , _encoder (new Encoder (_film_a, _playlist_a))
, _combiner (new Combiner (a->log()))
{
- _da = decoder_factory (_film_a, o);
- _db = decoder_factory (_film_b, o);
-
- if (_film_a->audio_stream()) {
- shared_ptr<AudioStream> st = _film_a->audio_stream();
- _matcher.reset (new Matcher (_film_a->log(), st->sample_rate(), _film_a->source_frame_rate()));
- _delay_line.reset (new DelayLine (_film_a->log(), st->channels(), _film_a->audio_delay() * st->sample_rate() / 1000));
+ if (_playlist_a->has_audio ()) {
+ _matcher.reset (new Matcher (_film_a->log(), _playlist_a->audio_frame_rate(), _playlist_a->video_frame_rate()));
+ _delay_line.reset (new DelayLine (_film_a->log(), _playlist_a->audio_channels(), _film_a->audio_delay() * _playlist_a->audio_frame_rate() / 1000));
_gain.reset (new Gain (_film_a->log(), _film_a->audio_gain()));
}
- /* Set up the decoder to use the film's set streams */
- _da.video->set_subtitle_stream (_film_a->subtitle_stream ());
- _db.video->set_subtitle_stream (_film_a->subtitle_stream ());
- _da.audio->set_audio_stream (_film_a->audio_stream ());
-
- _da.video->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3));
- _db.video->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3));
+ _playlist_a->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3));
+ _playlist_b->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3));
if (_matcher) {
_combiner->connect_video (_matcher);
}
if (_matcher && _delay_line) {
- _da.audio->connect_audio (_delay_line);
+ _playlist_a->connect_audio (_delay_line);
_delay_line->connect_audio (_matcher);
_matcher->connect_audio (_gain);
_gain->connect_audio (_encoder);
{
_encoder->process_begin ();
- bool done[3] = { false, false, false };
+ bool done[2] = { false, false };
while (1) {
- done[0] = _da.video->pass ();
- done[1] = _db.video->pass ();
-
- if (!done[2] && _da.audio && dynamic_pointer_cast<Decoder> (_da.audio) != dynamic_pointer_cast<Decoder> (_da.video)) {
- done[2] = _da.audio->pass ();
- } else {
- done[2] = true;
- }
+ done[0] = _playlist_a->pass ();
+ done[1] = _playlist_b->pass ();
if (_job) {
- _da.video->set_progress (_job);
+ _playlist_a->set_progress (_job);
}
- if (done[0] && done[1] && done[2]) {
+ if (done[0] && done[1]) {
break;
}
}
class Job;
class Encoder;
-class VideoDecoder;
-class AudioDecoder;
class Image;
class Log;
-class Subtitle;
class Film;
class Matcher;
class DelayLine;
class Gain;
class Combiner;
+class Playlist;
/** @class ABTranscoder
* @brief A transcoder which uses one Film for the left half of the screen, and a different one
boost::shared_ptr<Film> a,
boost::shared_ptr<Film> b,
DecodeOptions o,
- Job* j,
- boost::shared_ptr<Encoder> e
+ boost::shared_ptr<Job> j
);
void go ();
private:
boost::shared_ptr<Film> _film_a;
boost::shared_ptr<Film> _film_b;
- Job* _job;
+ boost::shared_ptr<Playlist> _playlist_a;
+ boost::shared_ptr<Playlist> _playlist_b;
+ boost::shared_ptr<Job> _job;
boost::shared_ptr<Encoder> _encoder;
- Decoders _da;
- Decoders _db;
boost::shared_ptr<Combiner> _combiner;
boost::shared_ptr<Matcher> _matcher;
boost::shared_ptr<DelayLine> _delay_line;
#include "compose.hpp"
#include "film.h"
#include "options.h"
-#include "decoder_factory.h"
-#include "audio_decoder.h"
+#include "playlist.h"
#include "i18n.h"
void
AnalyseAudioJob::run ()
{
- if (!_film->audio_stream () || !_film->length()) {
- set_progress (1);
- set_state (FINISHED_ERROR);
- return;
- }
-
- DecodeOptions options;
- options.decode_video = false;
-
- Decoders decoders = decoder_factory (_film, options);
- assert (decoders.audio);
+ shared_ptr<Playlist> playlist = _film->playlist ();
+ playlist->disable_video ();
- decoders.audio->set_audio_stream (_film->audio_stream ());
- decoders.audio->Audio.connect (bind (&AnalyseAudioJob::audio, this, _1));
+ playlist->Audio.connect (bind (&AnalyseAudioJob::audio, this, _1));
- int64_t total_audio_frames = video_frames_to_audio_frames (_film->length().get(), _film->audio_stream()->sample_rate(), _film->source_frame_rate());
- _samples_per_point = max (int64_t (1), total_audio_frames / _num_points);
+ _samples_per_point = max (int64_t (1), playlist->audio_length() / _num_points);
- _current.resize (_film->audio_stream()->channels ());
- _analysis.reset (new AudioAnalysis (_film->audio_stream()->channels()));
+ _current.resize (playlist->audio_channels ());
+ _analysis.reset (new AudioAnalysis (playlist->audio_channels()));
- while (!decoders.audio->pass()) {
- set_progress (float (_done) / total_audio_frames);
+ while (!playlist->pass()) {
+ set_progress (float (_done) / playlist->audio_length ());
}
_analysis->write (_film->audio_analysis_path ());
--- /dev/null
+#include "audio_content.h"
+
+AudioContent::AudioContent (boost::filesystem::path f)
+ : Content (f)
+{
+
+}
+#ifndef DVDOMATIC_AUDIO_CONTENT_H
+#define DVDOMATIC_AUDIO_CONTENT_H
+
#include "content.h"
+#include "util.h"
class AudioContent : public virtual Content
{
public:
-
+ AudioContent (boost::filesystem::path);
+ virtual int audio_channels () const = 0;
+ virtual ContentAudioFrame audio_length () const = 0;
+ virtual int audio_frame_rate () const = 0;
+ virtual int64_t audio_channel_layout () const = 0;
+
};
+
+#endif
*/
#include "audio_decoder.h"
-#include "stream.h"
using boost::optional;
using boost::shared_ptr;
-AudioDecoder::AudioDecoder (shared_ptr<Film> f, DecodeOptions o)
+AudioDecoder::AudioDecoder (shared_ptr<const Film> f, shared_ptr<AudioContent> c, DecodeOptions o)
: Decoder (f, o)
{
}
-
-void
-AudioDecoder::set_audio_stream (shared_ptr<AudioStream> s)
-{
- _audio_stream = s;
-}
#define DVDOMATIC_AUDIO_DECODER_H
#include "audio_source.h"
-#include "stream.h"
#include "decoder.h"
+class AudioContent;
+
/** @class AudioDecoder.
* @brief Parent class for audio decoders.
*/
class AudioDecoder : public AudioSource, public virtual Decoder
{
public:
- AudioDecoder (boost::shared_ptr<Film>, DecodeOptions);
-
- virtual void set_audio_stream (boost::shared_ptr<AudioStream>);
-
- /** @return Audio stream that we are using */
- boost::shared_ptr<AudioStream> audio_stream () const {
- return _audio_stream;
- }
-
- /** @return All available audio streams */
- std::vector<boost::shared_ptr<AudioStream> > audio_streams () const {
- return _audio_streams;
- }
-
-protected:
- /** Audio stream that we are using */
- boost::shared_ptr<AudioStream> _audio_stream;
- /** All available audio streams */
- std::vector<boost::shared_ptr<AudioStream> > _audio_streams;
+ AudioDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<AudioContent>, DecodeOptions);
};
#endif
--- /dev/null
+#include <boost/thread/mutex.hpp>
+#include "content.h"
+#include "util.h"
+
+using std::string;
+using boost::shared_ptr;
+
+Content::Content (boost::filesystem::path f)
+ : _file (f)
+{
+
+}
+
+void
+Content::examine (shared_ptr<Film>, shared_ptr<Job>, bool)
+{
+ string const d = md5_digest (_file);
+ boost::mutex::scoped_lock lm (_mutex);
+ _digest = d;
+}
+#ifndef DVDOMATIC_CONTENT_H
+#define DVDOMATIC_CONTENT_H
+
#include <boost/filesystem.hpp>
+#include <boost/signals2.hpp>
#include <boost/thread/mutex.hpp>
+class Job;
+class Film;
+
class Content
{
public:
+ Content (boost::filesystem::path);
+
+ virtual void examine (boost::shared_ptr<Film>, boost::shared_ptr<Job>, bool);
+ virtual std::string summary () const = 0;
+
boost::filesystem::path file () const {
boost::mutex::scoped_lock lm (_mutex);
return _file;
}
+ boost::signals2::signal<void (int)> Changed;
+
protected:
- boost::mutex _mutex;
+ mutable boost::mutex _mutex;
private:
boost::filesystem::path _file;
+ std::string _digest;
};
+
+#endif
*/
#include <iostream>
-#include <stdint.h>
-#include <boost/lexical_cast.hpp>
#include "film.h"
-#include "format.h"
#include "options.h"
#include "exceptions.h"
-#include "image.h"
#include "util.h"
-#include "log.h"
#include "decoder.h"
-#include "delay_line.h"
-#include "subtitle.h"
-#include "filter_graph.h"
#include "i18n.h"
using std::string;
-using std::stringstream;
-using std::min;
-using std::pair;
-using std::list;
using boost::shared_ptr;
-using boost::optional;
/** @param f Film.
* @param o Decode options.
*/
-Decoder::Decoder (boost::shared_ptr<Film> f, DecodeOptions o)
+Decoder::Decoder (shared_ptr<const Film> f, DecodeOptions o)
: _film (f)
, _opt (o)
{
#include <boost/shared_ptr.hpp>
#include <boost/signals2.hpp>
#include "util.h"
-#include "stream.h"
#include "video_source.h"
#include "audio_source.h"
#include "film.h"
class Decoder
{
public:
- Decoder (boost::shared_ptr<Film>, DecodeOptions);
+ Decoder (boost::shared_ptr<const Film>, DecodeOptions);
virtual ~Decoder () {}
virtual bool pass () = 0;
boost::signals2::signal<void()> OutputChanged;
protected:
- /** our Film */
- boost::shared_ptr<Film> _film;
+ boost::shared_ptr<const Film> _film;
/** our decode options */
DecodeOptions _opt;
private:
virtual void film_changed (Film::Property) {}
-
+
boost::signals2::scoped_connection _film_connection;
};
shared_ptr<Film> f, DecodeOptions o
)
{
- if (f->content().empty()) {
- return Decoders ();
- }
-
- if (boost::filesystem::is_directory (f->content_path()) || f->content_type() == STILL) {
- /* A single image file, or a directory of them */
- return Decoders (
- shared_ptr<VideoDecoder> (new ImageMagickDecoder (f, o)),
- shared_ptr<AudioDecoder> (new SndfileDecoder (f, o))
- );
- }
-
- shared_ptr<FFmpegDecoder> fd (new FFmpegDecoder (f, o));
- if (f->use_content_audio()) {
- return Decoders (fd, fd);
- }
-
- return Decoders (fd, shared_ptr<AudioDecoder> (new SndfileDecoder (f, o)));
+ return Decoders ();
}
#include "format.h"
#include "cross.h"
#include "writer.h"
+#include "playlist.h"
#include "i18n.h"
int const Encoder::_history_size = 25;
/** @param f Film that we are encoding */
-Encoder::Encoder (shared_ptr<Film> f)
+Encoder::Encoder (shared_ptr<Film> f, shared_ptr<Playlist> p)
: _film (f)
+ , _playlist (p)
, _video_frames_in (0)
, _video_frames_out (0)
#ifdef HAVE_SWRESAMPLE
void
Encoder::process_begin ()
{
- if (_film->audio_stream() && _film->audio_stream()->sample_rate() != _film->target_audio_sample_rate()) {
+ if (_playlist->has_audio() && _playlist->audio_frame_rate() != _film->target_audio_sample_rate()) {
#ifdef HAVE_SWRESAMPLE
stringstream s;
- s << String::compose (N_("Will resample audio from %1 to %2"), _film->audio_stream()->sample_rate(), _film->target_audio_sample_rate());
+ s << String::compose (N_("Will resample audio from %1 to %2"), _playlist->audio_frame_rate(), _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()->channel_layout(),
+ _playlist->audio_channel_layout(),
AV_SAMPLE_FMT_FLTP,
_film->target_audio_sample_rate(),
- _film->audio_stream()->channel_layout(),
+ _playlist->audio_channel_layout(),
AV_SAMPLE_FMT_FLTP,
- _film->audio_stream()->sample_rate(),
+ _playlist->audio_frame_rate(),
0, 0
);
}
}
- _writer.reset (new Writer (_film));
+ _writer.reset (new Writer (_film, _playlist));
}
Encoder::process_end ()
{
#if HAVE_SWRESAMPLE
- if (_film->audio_stream() && _film->audio_stream()->channels() && _swr_context) {
+ if (_playlist->has_audio() && _playlist->audio_channels() && _swr_context) {
- shared_ptr<AudioBuffers> out (new AudioBuffers (_film->audio_stream()->channels(), 256));
+ shared_ptr<AudioBuffers> out (new AudioBuffers (_playlist->audio_channels(), 256));
while (1) {
int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0);
void
Encoder::process_video (shared_ptr<Image> image, bool same, boost::shared_ptr<Subtitle> sub)
{
- FrameRateConversion frc (_film->source_frame_rate(), _film->dcp_frame_rate());
+ FrameRateConversion frc (_playlist->video_frame_rate(), _film->dcp_frame_rate());
if (frc.skip && (_video_frames_in % 2)) {
++_video_frames_in;
TIMING ("adding to queue of %1", _queue.size ());
_queue.push_back (boost::shared_ptr<DCPVideoFrame> (
new DCPVideoFrame (
- image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_film),
+ image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_playlist),
_film->subtitle_offset(), _film->subtitle_scale(),
_film->scaler(), _video_frames_out, _film->dcp_frame_rate(), s.second,
_film->colour_lut(), _film->j2k_bandwidth(),
if (_swr_context) {
/* Compute the resampled frames count and add 32 for luck */
- int const max_resampled_frames = ceil ((int64_t) data->frames() * _film->target_audio_sample_rate() / _film->audio_stream()->sample_rate()) + 32;
+ int const max_resampled_frames = ceil ((int64_t) data->frames() * _film->target_audio_sample_rate() / _playlist->audio_frame_rate()) + 32;
- shared_ptr<AudioBuffers> resampled (new AudioBuffers (_film->audio_stream()->channels(), max_resampled_frames));
+ shared_ptr<AudioBuffers> resampled (new AudioBuffers (_playlist->audio_channels(), max_resampled_frames));
/* Resample audio */
int const resampled_frames = swr_convert (
void
Encoder::write_audio (shared_ptr<const AudioBuffers> data)
{
- AudioMapping m (_film->audio_channels ());
- if (m.dcp_channels() != _film->audio_channels()) {
+ AudioMapping m (_playlist->audio_channels ());
+ if (m.dcp_channels() != _playlist->audio_channels()) {
/* Remap (currently just for mono -> 5.1) */
class DCPVideoFrame;
class EncodedData;
class Writer;
+class Playlist;
/** @class Encoder
* @brief Encoder to J2K and WAV for DCP.
class Encoder : public VideoSink, public AudioSink
{
public:
- Encoder (boost::shared_ptr<Film> f);
+ Encoder (boost::shared_ptr<Film> f, boost::shared_ptr<Playlist>);
virtual ~Encoder ();
/** Called to indicate that a processing run is about to begin */
/** Film that we are encoding */
boost::shared_ptr<Film> _film;
+ boost::shared_ptr<Playlist> _playlist;
/** Mutex for _time_history and _last_frame */
mutable boost::mutex _history_mutex;
*/
-/** @file src/examine_content_job.cc
- * @brief A class to run through content at high speed to find its length.
- */
-
#include <boost/filesystem.hpp>
#include "examine_content_job.h"
#include "options.h"
-#include "decoder_factory.h"
-#include "decoder.h"
-#include "transcoder.h"
#include "log.h"
-#include "film.h"
-#include "video_decoder.h"
+#include "content.h"
#include "i18n.h"
using std::string;
-using std::vector;
-using std::pair;
using boost::shared_ptr;
-ExamineContentJob::ExamineContentJob (shared_ptr<Film> f)
+ExamineContentJob::ExamineContentJob (shared_ptr<Film> f, shared_ptr<Content> c, bool q)
: Job (f)
+ , _content (c)
+ , _quick (q)
{
}
string
ExamineContentJob::name () const
{
- if (_film->name().empty ()) {
- return _("Examine content");
- }
-
- return String::compose (_("Examine content of %1"), _film->name());
+ return _("Examine content");
}
void
ExamineContentJob::run ()
{
- descend (0.5);
- _film->set_content_digest (md5_digest (_film->content_path ()));
- ascend ();
-
- descend (0.5);
-
- /* Set the film's length to either
- a) a length judged by running through the content or
- b) the length from a decoder's header.
- */
- if (!_film->trust_content_header()) {
- /* 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 ();
- _film->set_crop (Crop ());
-
- DecodeOptions o;
- o.decode_audio = false;
-
- Decoders decoders = decoder_factory (_film, o);
-
- set_progress_unknown ();
- while (!decoders.video->pass()) {
- /* keep going */
- }
-
- _film->set_length (decoders.video->video_frame());
-
- _film->log()->log (String::compose (N_("Video length examined as %1 frames"), _film->length().get()));
-
- } else {
-
- /* Get a quick decoder to get the content's length from its header */
-
- Decoders d = decoder_factory (_film, DecodeOptions());
- _film->set_length (d.video->length());
-
- _film->log()->log (String::compose (N_("Video length obtained from header as %1 frames"), _film->length().get()));
- }
-
- ascend ();
+ _content->examine (_film, shared_from_this (), _quick);
set_progress (1);
set_state (FINISHED_OK);
}
*/
-/** @file src/examine_content_job.h
- * @brief A class to obtain the length and MD5 digest of a content file.
- */
-
+#include <boost/shared_ptr.hpp>
#include "job.h"
-/** @class ExamineContentJob
- * @brief A class to obtain the length and MD5 digest of a content file.
- */
+class Content;
+class Log;
+
class ExamineContentJob : public Job
{
public:
- ExamineContentJob (boost::shared_ptr<Film>);
+ ExamineContentJob (boost::shared_ptr<Film>, boost::shared_ptr<Content>, bool);
~ExamineContentJob ();
std::string name () const;
void run ();
+
+private:
+ boost::shared_ptr<Content> _content;
+ bool _quick;
};
{
public:
/** @param f File that we were trying to open */
+ /* XXX: should be boost::filesystem::path */
OpenFileError (std::string f);
};
--- /dev/null
+#include "ffmpeg_content.h"
+#include "ffmpeg_decoder.h"
+#include "options.h"
+#include "compose.hpp"
+#include "job.h"
+#include "util.h"
+#include "log.h"
+
+#include "i18n.h"
+
+using std::string;
+using boost::shared_ptr;
+
+int const FFmpegContentProperty::SUBTITLE_STREAMS = 100;
+int const FFmpegContentProperty::SUBTITLE_STREAM = 101;
+int const FFmpegContentProperty::AUDIO_STREAMS = 102;
+int const FFmpegContentProperty::AUDIO_STREAM = 103;
+
+FFmpegContent::FFmpegContent (boost::filesystem::path f)
+ : Content (f)
+ , VideoContent (f)
+ , AudioContent (f)
+{
+
+}
+
+void
+FFmpegContent::examine (shared_ptr<Film> film, shared_ptr<Job> job, bool quick)
+{
+ job->descend (0.5);
+ Content::examine (film, job, quick);
+ job->ascend ();
+
+ job->set_progress_unknown ();
+
+ DecodeOptions o;
+ o.decode_audio = false;
+ shared_ptr<FFmpegDecoder> decoder (new FFmpegDecoder (film, shared_from_this (), o));
+
+ ContentVideoFrame video_length = 0;
+ if (quick) {
+ video_length = decoder->video_length ();
+ film->log()->log (String::compose ("Video length obtained from header as %1 frames", decoder->video_length ()));
+ } else {
+ while (!decoder->pass ()) {
+ /* keep going */
+ }
+
+ video_length = decoder->video_frame ();
+ film->log()->log (String::compose ("Video length examined as %1 frames", decoder->video_frame ()));
+ }
+
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+
+ _video_length = video_length;
+
+ _subtitle_streams = decoder->subtitle_streams ();
+ if (!_subtitle_streams.empty ()) {
+ _subtitle_stream = _subtitle_streams.front ();
+ }
+
+ _audio_streams = decoder->audio_streams ();
+ if (!_audio_streams.empty ()) {
+ _audio_stream = _audio_streams.front ();
+ }
+ }
+
+ take_from_video_decoder (decoder);
+
+ Changed (VideoContentProperty::VIDEO_LENGTH);
+ Changed (FFmpegContentProperty::SUBTITLE_STREAMS);
+ Changed (FFmpegContentProperty::SUBTITLE_STREAM);
+ Changed (FFmpegContentProperty::AUDIO_STREAMS);
+ Changed (FFmpegContentProperty::AUDIO_STREAM);
+}
+
+string
+FFmpegContent::summary () const
+{
+ return String::compose (_("Movie: %1"), file().filename ());
+}
+
+void
+FFmpegContent::set_subtitle_stream (FFmpegSubtitleStream s)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _subtitle_stream = s;
+ }
+
+ Changed (FFmpegContentProperty::SUBTITLE_STREAM);
+}
+
+void
+FFmpegContent::set_audio_stream (FFmpegAudioStream s)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _audio_stream = s;
+ }
+
+ Changed (FFmpegContentProperty::AUDIO_STREAM);
+}
+
+ContentAudioFrame
+FFmpegContent::audio_length () const
+{
+ if (!_audio_stream) {
+ return 0;
+ }
+
+ return video_frames_to_audio_frames (_video_length, audio_frame_rate(), video_frame_rate());
+}
+
+int
+FFmpegContent::audio_channels () const
+{
+ if (!_audio_stream) {
+ return 0;
+ }
+
+ return _audio_stream->channels ();
+}
+
+int
+FFmpegContent::audio_frame_rate () const
+{
+ if (!_audio_stream) {
+ return 0;
+ }
+
+ return _audio_stream->frame_rate;
+}
+
+int64_t
+FFmpegContent::audio_channel_layout () const
+{
+ if (!_audio_stream) {
+ return 0;
+ }
+
+ return _audio_stream->channel_layout;
+}
+
+bool
+operator== (FFmpegSubtitleStream const & a, FFmpegSubtitleStream const & b)
+{
+ return a.id == b.id;
+}
+
+bool
+operator== (FFmpegAudioStream const & a, FFmpegAudioStream const & b)
+{
+ return a.id == b.id;
+}
-#include "content.h"
+#ifndef DVDOMATIC_FFMPEG_CONTENT_H
+#define DVDOMATIC_FFMPEG_CONTENT_H
-class FFmpegContent : public VideoContent, public AudioContent
+#include <boost/enable_shared_from_this.hpp>
+#include "video_content.h"
+#include "audio_content.h"
+
+class FFmpegAudioStream
+{
+public:
+ FFmpegAudioStream (std::string n, int i, int f, int64_t c)
+ : name (n)
+ , id (i)
+ , frame_rate (f)
+ , channel_layout (c)
+ {}
+
+ int channels () const {
+ return av_get_channel_layout_nb_channels (channel_layout);
+ }
+
+ std::string name;
+ int id;
+ int frame_rate;
+ int64_t channel_layout;
+};
+
+extern bool operator== (FFmpegAudioStream const & a, FFmpegAudioStream const & b);
+
+class FFmpegSubtitleStream
+{
+public:
+ FFmpegSubtitleStream (std::string n, int i)
+ : name (n)
+ , id (i)
+ {}
+
+ std::string name;
+ int id;
+};
+
+extern bool operator== (FFmpegSubtitleStream const & a, FFmpegSubtitleStream const & b);
+
+class FFmpegContentProperty : public VideoContentProperty
+{
+public:
+ static int const SUBTITLE_STREAMS;
+ static int const SUBTITLE_STREAM;
+ static int const AUDIO_STREAMS;
+ static int const AUDIO_STREAM;
+};
+
+class FFmpegContent : public VideoContent, public AudioContent, public boost::enable_shared_from_this<FFmpegContent>
{
public:
+ FFmpegContent (boost::filesystem::path);
+ void examine (boost::shared_ptr<Film>, boost::shared_ptr<Job>, bool);
+ std::string summary () const;
+ /* AudioContent */
+ int audio_channels () const;
+ ContentAudioFrame audio_length () const;
+ int audio_frame_rate () const;
+ int64_t audio_channel_layout () const;
+
+ std::vector<FFmpegSubtitleStream> subtitle_streams () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _subtitle_streams;
+ }
+
+ boost::optional<FFmpegSubtitleStream> subtitle_stream () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _subtitle_stream;
+ }
+
+ std::vector<FFmpegAudioStream> audio_streams () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _audio_streams;
+ }
+
+ boost::optional<FFmpegAudioStream> audio_stream () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _audio_stream;
+ }
+
+ void set_subtitle_stream (FFmpegSubtitleStream);
+ void set_audio_stream (FFmpegAudioStream);
+
+private:
+ std::vector<FFmpegSubtitleStream> _subtitle_streams;
+ boost::optional<FFmpegSubtitleStream> _subtitle_stream;
+ std::vector<FFmpegAudioStream> _audio_streams;
+ boost::optional<FFmpegAudioStream> _audio_stream;
};
+
+#endif
using boost::dynamic_pointer_cast;
using libdcp::Size;
-FFmpegDecoder::FFmpegDecoder (shared_ptr<Film> f, DecodeOptions o)
+FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<FFmpegContent> c, DecodeOptions o)
: Decoder (f, o)
- , VideoDecoder (f, o)
- , AudioDecoder (f, o)
+ , VideoDecoder (f, c, o)
+ , AudioDecoder (f, c, o)
+ , _ffmpeg_content (c)
, _format_context (0)
, _video_stream (-1)
, _frame (0)
{
av_register_all ();
- if (avformat_open_input (&_format_context, _film->content_path().c_str(), 0, 0) < 0) {
- throw OpenFileError (_film->content_path ());
+ if (avformat_open_input (&_format_context, _ffmpeg_content->file().string().c_str(), 0, 0) < 0) {
+ throw OpenFileError (_ffmpeg_content->file().string ());
}
if (avformat_find_stream_info (_format_context, 0) < 0) {
}
_audio_streams.push_back (
- shared_ptr<AudioStream> (
- new FFmpegAudioStream (stream_name (s), i, s->codec->sample_rate, s->codec->channel_layout)
- )
+ 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 (
- shared_ptr<SubtitleStream> (
- new SubtitleStream (stream_name (s), i)
- )
- );
+ _subtitle_streams.push_back (FFmpegSubtitleStream (stream_name (s), i));
}
}
void
FFmpegDecoder::setup_audio ()
{
- if (!_audio_stream) {
+ if (!_ffmpeg_content->audio_stream ()) {
return;
}
- shared_ptr<FFmpegAudioStream> ffa = dynamic_pointer_cast<FFmpegAudioStream> (_audio_stream);
- assert (ffa);
-
- _audio_codec_context = _format_context->streams[ffa->id()]->codec;
+ _audio_codec_context = _format_context->streams[_ffmpeg_content->audio_stream()->id]->codec;
_audio_codec = avcodec_find_decoder (_audio_codec_context->codec_id);
if (_audio_codec == 0) {
void
FFmpegDecoder::setup_subtitle ()
{
- if (!_subtitle_stream || _subtitle_stream->id() >= int (_format_context->nb_streams)) {
+ if (!_ffmpeg_content->subtitle_stream() || _ffmpeg_content->subtitle_stream()->id >= int (_format_context->nb_streams)) {
return;
}
- _subtitle_codec_context = _format_context->streams[_subtitle_stream->id()]->codec;
+ _subtitle_codec_context = _format_context->streams[_ffmpeg_content->subtitle_stream()->id]->codec;
_subtitle_codec = avcodec_find_decoder (_subtitle_codec_context->codec_id);
if (_subtitle_codec == 0) {
}
}
- if (_audio_stream && _opt.decode_audio) {
+ if (_ffmpeg_content->audio_stream() && _opt.decode_audio) {
decode_audio_packet ();
}
avcodec_get_frame_defaults (_frame);
- shared_ptr<FFmpegAudioStream> ffa = dynamic_pointer_cast<FFmpegAudioStream> (_audio_stream);
-
if (_packet.stream_index == _video_stream && _opt.decode_video) {
int frame_finished;
}
}
- } else if (ffa && _packet.stream_index == ffa->id() && _opt.decode_audio) {
+ } else if (_ffmpeg_content->audio_stream() && _packet.stream_index == _ffmpeg_content->audio_stream()->id && _opt.decode_audio) {
decode_audio_packet ();
- } else if (_subtitle_stream && _packet.stream_index == _subtitle_stream->id() && _opt.decode_subtitles && _first_video) {
+ } else if (_ffmpeg_content->subtitle_stream() && _packet.stream_index == _ffmpeg_content->subtitle_stream()->id && _opt.decode_subtitles && _first_video) {
int got_subtitle;
AVSubtitle sub;
shared_ptr<AudioBuffers>
FFmpegDecoder::deinterleave_audio (uint8_t** data, int size)
{
- assert (_film->audio_channels());
+ assert (_ffmpeg_content->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() * ffa->channels())) == 0);
+ assert ((size % (bytes_per_audio_sample() * _ffmpeg_content->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 (ffa->channels(), frames));
+ int const frames = total_samples / _ffmpeg_content->audio_channels();
+ shared_ptr<AudioBuffers> audio (new AudioBuffers (_ffmpeg_content->audio_channels(), frames));
switch (audio_sample_format()) {
case AV_SAMPLE_FMT_S16:
audio->data(channel)[sample] = float(*p++) / (1 << 15);
++channel;
- if (channel == _film->audio_channels()) {
+ if (channel == _ffmpeg_content->audio_channels()) {
channel = 0;
++sample;
}
case AV_SAMPLE_FMT_S16P:
{
int16_t** p = reinterpret_cast<int16_t **> (data);
- for (int i = 0; i < _film->audio_channels(); ++i) {
+ for (int i = 0; i < _ffmpeg_content->audio_channels(); ++i) {
for (int j = 0; j < frames; ++j) {
audio->data(i)[j] = static_cast<float>(p[i][j]) / (1 << 15);
}
audio->data(channel)[sample] = static_cast<float>(*p++) / (1 << 31);
++channel;
- if (channel == _film->audio_channels()) {
+ if (channel == _ffmpeg_content->audio_channels()) {
channel = 0;
++sample;
}
audio->data(channel)[sample] = *p++;
++channel;
- if (channel == _film->audio_channels()) {
+ if (channel == _ffmpeg_content->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) {
+ for (int i = 0; i < _ffmpeg_content->audio_channels(); ++i) {
memcpy (audio->data(i), p[i], frames * sizeof(float));
}
}
return av_get_bytes_per_sample (audio_sample_format ());
}
-void
-FFmpegDecoder::set_audio_stream (shared_ptr<AudioStream> s)
-{
- AudioDecoder::set_audio_stream (s);
- setup_audio ();
-}
-
-void
-FFmpegDecoder::set_subtitle_stream (shared_ptr<SubtitleStream> s)
-{
- VideoDecoder::set_subtitle_stream (s);
- setup_subtitle ();
- OutputChanged ();
-}
-
void
FFmpegDecoder::filter_and_emit_video (AVFrame* frame)
{
return r < 0;
}
-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 != N_("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 == N_("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 (N_("ffmpeg %1 %2 %3 %4"), _id, _sample_rate, _channel_layout, _name);
-}
-
void
FFmpegDecoder::out_with_sync ()
{
}
/** @return Length (in video frames) according to our content's header */
-SourceFrame
-FFmpegDecoder::length () const
+ContentVideoFrame
+FFmpegDecoder::video_length () const
{
return (double(_format_context->duration) / AV_TIME_BASE) * frames_per_second();
}
void
FFmpegDecoder::decode_audio_packet ()
{
- shared_ptr<FFmpegAudioStream> ffa = dynamic_pointer_cast<FFmpegAudioStream> (_audio_stream);
- assert (ffa);
-
/* Audio packets can contain multiple frames, so we may have to call avcodec_decode_audio4
several times.
*/
*/
/* frames of silence that we must push */
- int const s = rint ((_first_audio.get() - _first_video.get()) * ffa->sample_rate ());
+ int const s = rint ((_first_audio.get() - _first_video.get()) * _ffmpeg_content->audio_frame_rate ());
_film->log()->log (
String::compose (
N_("First video at %1, first audio at %2, pushing %3 audio frames of silence for %4 channels (%5 bytes per sample)"),
- _first_video.get(), _first_audio.get(), s, ffa->channels(), bytes_per_audio_sample()
+ _first_video.get(), _first_audio.get(), s, _ffmpeg_content->audio_channels(), bytes_per_audio_sample()
)
);
if (s) {
- shared_ptr<AudioBuffers> audio (new AudioBuffers (ffa->channels(), s));
+ shared_ptr<AudioBuffers> audio (new AudioBuffers (_ffmpeg_content->audio_channels(), s));
audio->make_silent ();
Audio (audio);
}
0, _audio_codec_context->channels, _frame->nb_samples, audio_sample_format (), 1
);
- assert (_audio_codec_context->channels == _film->audio_channels());
+ assert (_audio_codec_context->channels == _ffmpeg_content->audio_channels());
Audio (deinterleave_audio (_frame->data, data_size));
}
}
#include "video_decoder.h"
#include "audio_decoder.h"
#include "film.h"
+#include "ffmpeg_content.h"
struct AVFilterGraph;
struct AVCodecContext;
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.
*/
class FFmpegDecoder : public VideoDecoder, public AudioDecoder
{
public:
- FFmpegDecoder (boost::shared_ptr<Film>, DecodeOptions);
+ FFmpegDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<FFmpegContent>, DecodeOptions);
~FFmpegDecoder ();
float frames_per_second () const;
libdcp::Size native_size () const;
- SourceFrame length () const;
+ ContentVideoFrame video_length () const;
int time_base_numerator () const;
int time_base_denominator () const;
int sample_aspect_ratio_numerator () const;
int sample_aspect_ratio_denominator () const;
- void set_audio_stream (boost::shared_ptr<AudioStream>);
- void set_subtitle_stream (boost::shared_ptr<SubtitleStream>);
+ std::vector<FFmpegSubtitleStream> subtitle_streams () const {
+ return _subtitle_streams;
+ }
+
+ std::vector<FFmpegAudioStream> audio_streams () const {
+ return _audio_streams;
+ }
bool seek (double);
bool seek_to_last ();
+ bool pass ();
private:
- bool pass ();
bool do_seek (double p, bool);
PixelFormat pixel_format () const;
AVSampleFormat audio_sample_format () const;
std::string stream_name (AVStream* s) const;
+ boost::shared_ptr<FFmpegContent> _ffmpeg_content;
+
AVFormatContext* _format_context;
int _video_stream;
std::list<boost::shared_ptr<FilterGraph> > _filter_graphs;
boost::mutex _filter_graphs_mutex;
+
+ std::vector<FFmpegSubtitleStream> _subtitle_streams;
+ std::vector<FFmpegAudioStream> _audio_streams;
};
#include "audio_decoder.h"
#include "sndfile_decoder.h"
#include "analyse_audio_job.h"
+#include "playlist.h"
#include "i18n.h"
}
}
- _sndfile_stream = SndfileStream::create ();
-
if (must_exist) {
read_metadata ();
}
, _dcp_ab (o._dcp_ab)
, _audio_gain (o._audio_gain)
, _audio_delay (o._audio_delay)
- , _still_duration (o._still_duration)
, _with_subtitles (o._with_subtitles)
, _subtitle_offset (o._subtitle_offset)
, _subtitle_scale (o._subtitle_scale)
{
assert (format ());
+ return "XXX";
+
+#if 0
+
pair<string, string> f = Filter::ffmpeg_strings (filters());
stringstream s;
}
return s.str ();
+#endif
}
/** @return The path to the directory to write video frame info files to */
{
boost::filesystem::path p;
p /= "analysis";
- p /= content_digest();
+ p /= "XXX";//content_digest();
return file (p.string ());
}
log()->log (String::compose ("Starting to make DCP on %1", buffer));
}
- log()->log (String::compose ("Content is %1; type %2", content_path(), (content_type() == STILL ? _("still") : _("video"))));
- if (length()) {
- log()->log (String::compose ("Content length %1", length().get()));
- }
- log()->log (String::compose ("Content digest %1", content_digest()));
- log()->log (String::compose ("Content at %1 fps, DCP at %2 fps", source_frame_rate(), dcp_frame_rate()));
+// log()->log (String::compose ("Content is %1; type %2", content_path(), (content_type() == STILL ? _("still") : _("video"))));
+// if (length()) {
+// log()->log (String::compose ("Content length %1", length().get()));
+// }
+// log()->log (String::compose ("Content digest %1", content_digest()));
+// log()->log (String::compose ("Content at %1 fps, DCP at %2 fps", source_frame_rate(), dcp_frame_rate()));
log()->log (String::compose ("%1 threads", Config::instance()->num_local_encoding_threads()));
log()->log (String::compose ("J2K bandwidth %1", j2k_bandwidth()));
#ifdef DVDOMATIC_DEBUG
JobManager::instance()->add (_analyse_audio_job);
}
-/** Start a job to examine our content file */
+/** Start a job to examine a piece of content */
void
-Film::examine_content ()
+Film::examine_content (shared_ptr<Content> c)
{
- if (_examine_content_job) {
- return;
- }
-
- _examine_content_job.reset (new ExamineContentJob (shared_from_this()));
- _examine_content_job->Finished.connect (bind (&Film::examine_content_finished, this));
- JobManager::instance()->add (_examine_content_job);
+ shared_ptr<Job> j (new ExamineContentJob (shared_from_this(), c, trust_content_header ()));
+ j->Finished.connect (bind (&Film::examine_content_finished, this));
+ JobManager::instance()->add (j);
}
void
void
Film::examine_content_finished ()
{
- _examine_content_job.reset ();
+ /* XXX */
}
/** Start a job to send our DCP to the configured TMS */
/* User stuff */
f << "name " << _name << endl;
f << "use_dci_name " << _use_dci_name << endl;
- f << "content " << _content << endl;
+// f << "content " << _content << endl;
f << "trust_content_header " << (_trust_content_header ? "1" : "0") << endl;
if (_dcp_content_type) {
f << "dcp_content_type " << _dcp_content_type->dci_name () << endl;
f << "trim_start " << _trim_start << endl;
f << "trim_end " << _trim_end << endl;
f << "dcp_ab " << (_dcp_ab ? "1" : "0") << endl;
- if (_content_audio_stream) {
- f << "selected_content_audio_stream " << _content_audio_stream->to_string() << endl;
- }
- for (vector<string>::const_iterator i = _external_audio.begin(); i != _external_audio.end(); ++i) {
- f << "external_audio " << *i << endl;
- }
- f << "use_content_audio " << (_use_content_audio ? "1" : "0") << endl;
+// if (_content_audio_stream) {
+// f << "selected_content_audio_stream " << _content_audio_stream->to_string() << endl;
+// }
+// for (vector<string>::const_iterator i = _external_audio.begin(); i != _external_audio.end(); ++i) {
+// f << "external_audio " << *i << endl;
+// }
+// f << "use_content_audio " << (_use_content_audio ? "1" : "0") << endl;
f << "audio_gain " << _audio_gain << endl;
f << "audio_delay " << _audio_delay << endl;
- f << "still_duration " << _still_duration << endl;
- if (_subtitle_stream) {
- f << "selected_subtitle_stream " << _subtitle_stream->to_string() << endl;
- }
+// f << "still_duration " << _still_duration << endl;
+// if (_subtitle_stream) {
+// f << "selected_subtitle_stream " << _subtitle_stream->to_string() << endl;
+// }
f << "with_subtitles " << _with_subtitles << endl;
f << "subtitle_offset " << _subtitle_offset << endl;
f << "subtitle_scale " << _subtitle_scale << endl;
_dci_metadata.write (f);
f << "dci_date " << boost::gregorian::to_iso_string (_dci_date) << endl;
f << "dcp_frame_rate " << _dcp_frame_rate << endl;
- f << "width " << _size.width << endl;
- f << "height " << _size.height << endl;
- f << "length " << _length.get_value_or(0) << endl;
- f << "content_digest " << _content_digest << endl;
+// f << "width " << _size.width << endl;
+// f << "height " << _size.height << endl;
+// f << "length " << _length.get_value_or(0) << endl;
+// f << "content_digest " << _content_digest << endl;
- 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 () << endl;
- }
+// 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 () << endl;
+// }
- f << "external_audio_stream " << _sndfile_stream->to_string() << endl;
+// f << "external_audio_stream " << _sndfile_stream->to_string() << endl;
- for (vector<shared_ptr<SubtitleStream> >::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) {
- f << "subtitle_stream " << (*i)->to_string () << endl;
- }
+// for (vector<shared_ptr<SubtitleStream> >::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) {
+// f << "subtitle_stream " << (*i)->to_string () << endl;
+// }
- f << "source_frame_rate " << _source_frame_rate << endl;
+// f << "source_frame_rate " << _source_frame_rate << endl;
_dirty = false;
}
{
boost::mutex::scoped_lock lm (_state_mutex);
- _external_audio.clear ();
- _content_audio_streams.clear ();
- _subtitle_streams.clear ();
+// _external_audio.clear ();
+// _content_audio_streams.clear ();
+// _subtitle_streams.clear ();
boost::optional<int> version;
} else if (k == "use_dci_name") {
_use_dci_name = (v == "1");
} else if (k == "content") {
- _content = v;
+// _content = v;
} else if (k == "trust_content_header") {
_trust_content_header = (v == "1");
} else if (k == "dcp_content_type") {
if (!version) {
audio_stream_index = atoi (v.c_str ());
} else {
- _content_audio_stream = audio_stream_factory (v, version);
+// _content_audio_stream = audio_stream_factory (v, version);
}
} else if (k == "external_audio") {
- _external_audio.push_back (v);
+// _external_audio.push_back (v);
} else if (k == "use_content_audio") {
- _use_content_audio = (v == "1");
+// _use_content_audio = (v == "1");
} else if (k == "audio_gain") {
_audio_gain = atof (v.c_str ());
} else if (k == "audio_delay") {
_audio_delay = atoi (v.c_str ());
} else if (k == "still_duration") {
- _still_duration = atoi (v.c_str ());
+// _still_duration = atoi (v.c_str ());
} else if (k == "selected_subtitle_stream") {
if (!version) {
subtitle_stream_index = atoi (v.c_str ());
} else {
- _subtitle_stream = subtitle_stream_factory (v, version);
+// _subtitle_stream = subtitle_stream_factory (v, version);
}
} else if (k == "with_subtitles") {
_with_subtitles = (v == "1");
/* Cached stuff */
if (k == "width") {
- _size.width = atoi (v.c_str ());
+// _size.width = atoi (v.c_str ());
} else if (k == "height") {
- _size.height = atoi (v.c_str ());
+// _size.height = atoi (v.c_str ());
} else if (k == "length") {
int const vv = atoi (v.c_str ());
if (vv) {
- _length = vv;
+// _length = vv;
}
} else if (k == "content_digest") {
- _content_digest = v;
+// _content_digest = v;
} else if (k == "content_audio_stream" || (!version && k == "audio_stream")) {
- _content_audio_streams.push_back (audio_stream_factory (v, version));
+// _content_audio_streams.push_back (audio_stream_factory (v, version));
} else if (k == "external_audio_stream") {
- _sndfile_stream = audio_stream_factory (v, version);
+// _sndfile_stream = audio_stream_factory (v, version);
} else if (k == "subtitle_stream") {
- _subtitle_streams.push_back (subtitle_stream_factory (v, version));
+// _subtitle_streams.push_back (subtitle_stream_factory (v, version));
} else if (k == "source_frame_rate") {
- _source_frame_rate = atof (v.c_str ());
+// _source_frame_rate = atof (v.c_str ());
} else if (version < 4 && k == "frames_per_second") {
- _source_frame_rate = atof (v.c_str ());
+// _source_frame_rate = atof (v.c_str ());
/* Fill in what would have been used for DCP frame rate by the older version */
- _dcp_frame_rate = best_dcp_frame_rate (_source_frame_rate);
+// _dcp_frame_rate = best_dcp_frame_rate (_source_frame_rate);
}
}
- if (!version) {
- if (audio_sample_rate) {
- /* version < 1 didn't specify sample rate in the audio streams, so fill it in here */
- 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) _content_audio_streams.size()) {
- _content_audio_stream = _content_audio_streams[audio_stream_index.get()];
- }
-
- /* similarly the subtitle */
- if (subtitle_stream_index && subtitle_stream_index.get() >= 0 && subtitle_stream_index.get() < (int) _subtitle_streams.size()) {
- _subtitle_stream = _subtitle_streams[subtitle_stream_index.get()];
- }
- }
-
_dirty = false;
}
return p.string ();
}
-/** @return full path of the content (actual video) file
- * of the Film.
- */
-string
-Film::content_path () const
-{
- boost::mutex::scoped_lock lm (_state_mutex);
- if (boost::filesystem::path(_content).has_root_directory ()) {
- return _content;
- }
-
- return file (_content);
-}
-
-ContentType
-Film::content_type () const
-{
- if (boost::filesystem::is_directory (_content)) {
- /* Directory of images, we assume */
- return VIDEO;
- }
-
- if (still_image_file (_content)) {
- return STILL;
- }
-
- return VIDEO;
-}
-
/** @return The sampling rate that we will resample the audio to */
int
Film::target_audio_sample_rate () const
{
- if (!audio_stream()) {
+ /* XXX: how often is this method called? */
+
+ boost::shared_ptr<Playlist> p = playlist ();
+ if (p->has_audio ()) {
return 0;
}
/* Resample to a DCI-approved sample rate */
- double t = dcp_audio_sample_rate (audio_stream()->sample_rate());
+ double t = dcp_audio_sample_rate (p->audio_frame_rate());
- FrameRateConversion frc (source_frame_rate(), dcp_frame_rate());
+ FrameRateConversion frc (p->video_frame_rate(), dcp_frame_rate());
/* Compensate if the DCP is being run at a different frame rate
to the source; that is, if the video is run such that it will
*/
if (frc.change_speed) {
- t *= source_frame_rate() * frc.factor() / dcp_frame_rate();
+ t *= p->video_frame_rate() * frc.factor() / dcp_frame_rate();
}
return rint (t);
}
-int
-Film::still_duration_in_frames () const
-{
- return still_duration() * source_frame_rate();
-}
-
/** @return a DCI-compliant name for a DCP of this film */
string
Film::dci_name (bool if_created_now) const
}
}
- switch (audio_channels()) {
+ /* XXX */
+ switch (2) {
case 1:
d << "_10";
break;
signal_changed (USE_DCI_NAME);
}
-void
-Film::set_content (string c)
-{
- string check = directory ();
-
- boost::filesystem::path slash ("/");
- string platform_slash = slash.make_preferred().string ();
-
- if (!ends_with (check, platform_slash)) {
- check += platform_slash;
- }
-
- if (boost::filesystem::path(c).has_root_directory () && starts_with (c, check)) {
- c = c.substr (_directory.length() + 1);
- }
-
- string old_content;
-
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- if (c == _content) {
- return;
- }
-
- old_content = _content;
- _content = c;
- }
-
- /* Reset streams here in case the new content doesn't have one or the other */
- _content_audio_stream = shared_ptr<AudioStream> ();
- _subtitle_stream = shared_ptr<SubtitleStream> ();
-
- /* Start off using content audio */
- set_use_content_audio (true);
-
- /* Create a temporary decoder so that we can get information
- about the content.
- */
-
- try {
- Decoders d = decoder_factory (shared_from_this(), DecodeOptions());
-
- set_size (d.video->native_size ());
- set_source_frame_rate (d.video->frames_per_second ());
- set_dcp_frame_rate (best_dcp_frame_rate (source_frame_rate ()));
- set_subtitle_streams (d.video->subtitle_streams ());
- if (d.audio) {
- set_content_audio_streams (d.audio->audio_streams ());
- }
-
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _content = c;
- }
-
- signal_changed (CONTENT);
-
- /* Start off with the first audio and subtitle streams */
- if (d.audio && !d.audio->audio_streams().empty()) {
- set_content_audio_stream (d.audio->audio_streams().front());
- }
-
- if (!d.video->subtitle_streams().empty()) {
- set_subtitle_stream (d.video->subtitle_streams().front());
- }
-
- examine_content ();
-
- } catch (...) {
-
- boost::mutex::scoped_lock lm (_state_mutex);
- _content = old_content;
- throw;
-
- }
-
- /* Default format */
- switch (content_type()) {
- case STILL:
- set_format (Format::from_id ("var-185"));
- break;
- case VIDEO:
- set_format (Format::from_id ("185"));
- break;
- }
-
- /* Still image DCPs must use external audio */
- if (content_type() == STILL) {
- set_use_content_audio (false);
- }
-}
-
void
Film::set_trust_content_header (bool t)
{
if (!_trust_content_header && !content().empty()) {
/* We just said that we don't trust the content's header */
- examine_content ();
+ /* XXX */
+// examine_content ();
}
}
signal_changed (DCP_AB);
}
-void
-Film::set_content_audio_stream (shared_ptr<AudioStream> s)
-{
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _content_audio_stream = s;
- }
- signal_changed (CONTENT_AUDIO_STREAM);
-}
-
-void
-Film::set_external_audio (vector<string> a)
-{
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _external_audio = a;
- }
-
- shared_ptr<SndfileDecoder> decoder (new SndfileDecoder (shared_from_this(), DecodeOptions()));
- if (decoder->audio_stream()) {
- _sndfile_stream = decoder->audio_stream ();
- }
-
- signal_changed (EXTERNAL_AUDIO);
-}
-
-void
-Film::set_use_content_audio (bool e)
-{
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _use_content_audio = e;
- }
-
- signal_changed (USE_CONTENT_AUDIO);
-}
-
void
Film::set_audio_gain (float g)
{
signal_changed (AUDIO_DELAY);
}
-void
-Film::set_still_duration (int d)
-{
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _still_duration = d;
- }
- signal_changed (STILL_DURATION);
-}
-
-void
-Film::set_subtitle_stream (shared_ptr<SubtitleStream> s)
-{
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _subtitle_stream = s;
- }
- signal_changed (SUBTITLE_STREAM);
-}
-
void
Film::set_with_subtitles (bool w)
{
signal_changed (DCP_FRAME_RATE);
}
-void
-Film::set_size (libdcp::Size s)
-{
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _size = s;
- }
- signal_changed (SIZE);
-}
-
-void
-Film::set_length (SourceFrame l)
-{
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _length = l;
- }
- signal_changed (LENGTH);
-}
-
-void
-Film::unset_length ()
-{
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _length = boost::none;
- }
- signal_changed (LENGTH);
-}
-
-void
-Film::set_content_digest (string d)
-{
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _content_digest = d;
- }
- _dirty = true;
-}
-
-void
-Film::set_content_audio_streams (vector<shared_ptr<AudioStream> > s)
-{
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _content_audio_streams = s;
- }
- signal_changed (CONTENT_AUDIO_STREAMS);
-}
-
-void
-Film::set_subtitle_streams (vector<shared_ptr<SubtitleStream> > s)
-{
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _subtitle_streams = s;
- }
- signal_changed (SUBTITLE_STREAMS);
-}
-
-void
-Film::set_source_frame_rate (float f)
-{
- {
- boost::mutex::scoped_lock lm (_state_mutex);
- _source_frame_rate = f;
- }
- signal_changed (SOURCE_FRAME_RATE);
-}
-
void
Film::signal_changed (Property p)
{
}
}
-int
-Film::audio_channels () const
-{
- shared_ptr<AudioStream> s = audio_stream ();
- if (!s) {
- return 0;
- }
-
- return s->channels ();
-}
-
void
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 _sndfile_stream;
-}
-
string
Film::info_path (int f) const
{
return true;
}
-bool
-Film::has_audio () const
+shared_ptr<Playlist>
+Film::playlist () const
{
- if (use_content_audio()) {
- return audio_stream();
- }
+ boost::mutex::scoped_lock lm (_state_mutex);
+ return shared_ptr<Playlist> (new Playlist (shared_from_this (), _content));
+}
- vector<string> const e = external_audio ();
- for (vector<string>::const_iterator i = e.begin(); i != e.end(); ++i) {
- if (!i->empty ()) {
- return true;
- }
+void
+Film::add_content (shared_ptr<Content> c)
+{
+ {
+ boost::mutex::scoped_lock lm (_state_mutex);
+ _content.push_back (c);
}
- return false;
-}
+ signal_changed (CONTENT);
+ examine_content (c);
+}
}
#include "dcp_content_type.h"
#include "util.h"
-#include "stream.h"
#include "dci_metadata.h"
class Format;
class AnalyseAudioJob;
class ExternalAudioStream;
class Content;
+class Playlist;
/** @class Film
* @brief A representation of a video, maybe with sound.
std::string video_mxf_filename () const;
std::string audio_analysis_path () const;
- void examine_content ();
+ void examine_content (boost::shared_ptr<Content>);
void analyse_audio ();
void send_dcp_to_tms ();
std::string file (std::string f) const;
std::string dir (std::string d) const;
- std::string content_path () const;
- ContentType content_type () const;
-
int target_audio_sample_rate () const;
void write_metadata () const;
return _dirty;
}
- int audio_channels () const;
-
void set_dci_date_today ();
bool have_dcp () const;
+ boost::shared_ptr<Playlist> playlist () const;
+
/** Identifiers for the parts of our state;
used for signalling changes.
*/
NAME,
USE_DCI_NAME,
TRUST_CONTENT_HEADER,
+ CONTENT,
DCP_CONTENT_TYPE,
FORMAT,
CROP,
return _trust_content_header;
}
+ std::list<boost::shared_ptr<Content> > content () const {
+ boost::mutex::scoped_lock lm (_state_mutex);
+ return _content;
+ }
+
DCPContentType const * dcp_content_type () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _dcp_content_type;
return _audio_delay;
}
- boost::shared_ptr<SubtitleStream> subtitle_stream () const {
- boost::mutex::scoped_lock lm (_state_mutex);
- return _subtitle_stream;
- }
-
bool with_subtitles () const {
boost::mutex::scoped_lock lm (_state_mutex);
return _with_subtitles;
return _dcp_frame_rate;
}
- boost::shared_ptr<AudioStream> audio_stream () const;
- bool has_audio () const;
-
/* SET */
void set_directory (std::string);
void set_name (std::string);
void set_use_dci_name (bool);
void set_trust_content_header (bool);
+ void add_content (boost::shared_ptr<Content>);
void set_dcp_content_type (DCPContentType const *);
void set_format (Format const *);
void set_crop (Crop);
/** Log to write to */
boost::shared_ptr<Log> _log;
- /** Any running ExamineContentJob, or 0 */
- boost::shared_ptr<ExamineContentJob> _examine_content_job;
/** Any running AnalyseAudioJob, or 0 */
boost::shared_ptr<AnalyseAudioJob> _analyse_audio_job;
std::string _name;
/** True if a auto-generated DCI-compliant name should be used for our DCP */
bool _use_dci_name;
- std::list<boost::shared_ptr<Content> > _content;
+ typedef std::list<boost::shared_ptr<Content> > ContentList;
+ ContentList _content;
/** If this is true, we will believe the length specified by the content
* file's header; if false, we will run through the whole content file
* the first time we see it in order to obtain the length.
* @param s Size of the images to process.
* @param p Pixel format of the images to process.
*/
-FilterGraph::FilterGraph (shared_ptr<Film> film, FFmpegDecoder* decoder, libdcp::Size s, AVPixelFormat p)
+FilterGraph::FilterGraph (shared_ptr<const Film> film, FFmpegDecoder* decoder, libdcp::Size s, AVPixelFormat p)
: _buffer_src_context (0)
, _buffer_sink_context (0)
, _size (s)
class FilterGraph
{
public:
- FilterGraph (boost::shared_ptr<Film> film, FFmpegDecoder* decoder, libdcp::Size s, AVPixelFormat p);
+ FilterGraph (boost::shared_ptr<const Film>, FFmpegDecoder* decoder, libdcp::Size s, AVPixelFormat p);
bool can_process (libdcp::Size s, AVPixelFormat p) const;
std::list<boost::shared_ptr<Image> > process (AVFrame const * frame);
#include <iostream>
#include "format.h"
#include "film.h"
+#include "playlist.h"
#include "i18n.h"
* (so there are dcp_padding() pixels on the left and dcp_padding() on the right)
*/
int
-Format::dcp_padding (shared_ptr<const Film> f) const
+Format::dcp_padding (shared_ptr<const Playlist> p) const
{
- int p = rint ((_dcp_size.width - (_dcp_size.height * ratio_as_integer(f) / 100.0)) / 2.0);
+ int pad = rint ((_dcp_size.width - (_dcp_size.height * ratio_as_integer(p) / 100.0)) / 2.0);
/* This comes out -ve for Scope; bodge it */
- if (p < 0) {
- p = 0;
+ if (pad < 0) {
+ pad = 0;
}
- return p;
+ return pad;
}
float
}
int
-VariableFormat::ratio_as_integer (shared_ptr<const Film> f) const
+VariableFormat::ratio_as_integer (shared_ptr<const Playlist> p) const
{
- return rint (ratio_as_float (f) * 100);
+ return rint (ratio_as_float (p) * 100);
}
float
-VariableFormat::ratio_as_float (shared_ptr<const Film> f) const
+VariableFormat::ratio_as_float (shared_ptr<const Playlist> p) const
{
- return float (f->size().width) / f->size().height;
+ return float (p->video_size().width) / p->video_size().height;
}
/** @return A name to be presented to the user */
#include <vector>
#include "util.h"
-class Film;
+class Playlist;
class Format
{
/** @return the aspect ratio multiplied by 100
* (e.g. 239 for Cinemascope 2.39:1)
*/
- virtual int ratio_as_integer (boost::shared_ptr<const Film> f) const = 0;
+ virtual int ratio_as_integer (boost::shared_ptr<const Playlist> f) const = 0;
/** @return the ratio as a floating point number */
- virtual float ratio_as_float (boost::shared_ptr<const Film> f) const = 0;
+ virtual float ratio_as_float (boost::shared_ptr<const Playlist> f) const = 0;
/** @return the ratio of the container (including any padding) as a floating point number */
float container_ratio_as_float () const;
- int dcp_padding (boost::shared_ptr<const Film> f) const;
+ int dcp_padding (boost::shared_ptr<const Playlist>) const;
/** @return size in pixels of the images that we should
* put in a DCP for this ratio. This size will not correspond
public:
FixedFormat (int, libdcp::Size, std::string, std::string, std::string, std::string);
- int ratio_as_integer (boost::shared_ptr<const Film>) const {
+ int ratio_as_integer (boost::shared_ptr<const Playlist>) const {
return _ratio;
}
- float ratio_as_float (boost::shared_ptr<const Film>) const {
+ float ratio_as_float (boost::shared_ptr<const Playlist>) const {
return _ratio / 100.0;
}
public:
VariableFormat (libdcp::Size, std::string, std::string, std::string, std::string);
- int ratio_as_integer (boost::shared_ptr<const Film> f) const;
- float ratio_as_float (boost::shared_ptr<const Film> f) const;
+ int ratio_as_integer (boost::shared_ptr<const Playlist> f) const;
+ float ratio_as_float (boost::shared_ptr<const Playlist> f) const;
std::string name () const;
};
--- /dev/null
+#include "imagemagick_content.h"
+
class ImageMagickContent : public VideoContent
{
-
+public:
+ ImageMagickContent (boost::filesystem::path);
};
#include <iostream>
#include <boost/filesystem.hpp>
#include <Magick++.h>
+#include "imagemagick_content.h"
#include "imagemagick_decoder.h"
#include "image.h"
#include "film.h"
using libdcp::Size;
ImageMagickDecoder::ImageMagickDecoder (
- boost::shared_ptr<Film> f, DecodeOptions o)
+ shared_ptr<const Film> f, shared_ptr<ImageMagickContent> c, DecodeOptions o)
: Decoder (f, o)
- , VideoDecoder (f, o)
+ , VideoDecoder (f, c, o)
+ , _imagemagick_content (c)
+ , _position (0)
{
- if (boost::filesystem::is_directory (_film->content_path())) {
- for (
- boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (_film->content_path());
- i != boost::filesystem::directory_iterator();
- ++i) {
-
- if (still_image_file (i->path().string())) {
- _files.push_back (i->path().string());
- }
- }
- } else {
- _files.push_back (_film->content_path ());
- }
-
- _iter = _files.begin ();
+
}
libdcp::Size
ImageMagickDecoder::native_size () const
{
- if (_files.empty ()) {
- throw DecodeError (_("no still image files found"));
- }
-
- /* Look at the first file and assume its size holds for all */
using namespace MagickCore;
- Magick::Image* image = new Magick::Image (_film->content_path ());
+ Magick::Image* image = new Magick::Image (_imagemagick_content->file().string());
libdcp::Size const s = libdcp::Size (image->columns(), image->rows());
delete image;
bool
ImageMagickDecoder::pass ()
{
- if (_iter == _files.end()) {
- if (video_frame() >= _film->still_duration_in_frames()) {
- return true;
- }
-
+ if (_position > 0 && _position < _imagemagick_content->video_length ()) {
repeat_last_video ();
+ _position++;
return false;
+ } else if (_position >= _imagemagick_content->video_length ()) {
+ return true;
}
- Magick::Image* magick_image = new Magick::Image (_film->content_path ());
+ Magick::Image* magick_image = new Magick::Image (_imagemagick_content->file().string ());
libdcp::Size size = native_size ();
shared_ptr<Image> image (new SimpleImage (PIX_FMT_RGB24, size, false));
emit_video (image, 0);
- ++_iter;
+ ++_position;
return false;
}
bool
ImageMagickDecoder::seek_to_last ()
{
- if (_iter == _files.end()) {
- _iter = _files.begin();
- } else {
- --_iter;
+ if (_position > 0) {
+ --_position;
}
return false;
bool
ImageMagickDecoder::seek (double t)
{
- int const f = t * frames_per_second();
-
- _iter = _files.begin ();
- for (int i = 0; i < f; ++i) {
- if (_iter == _files.end()) {
- return true;
- }
- ++_iter;
+ int const f = t * _imagemagick_content->video_frame_rate ();
+
+ if (f >= _imagemagick_content->video_length()) {
+ _position = 0;
+ return true;
}
-
+
+ _position = f;
return false;
}
class Image;
}
+class ImageMagickContent;
+
class ImageMagickDecoder : public VideoDecoder
{
public:
- ImageMagickDecoder (boost::shared_ptr<Film>, DecodeOptions);
+ ImageMagickDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<ImageMagickContent>, DecodeOptions);
float frames_per_second () const {
/* We don't know */
libdcp::Size native_size () const;
- SourceFrame length () const {
+ ContentVideoFrame video_length () const {
/* We don't know */
return 0;
}
bool seek (double);
bool seek_to_last ();
+ bool pass ();
protected:
- bool pass ();
PixelFormat pixel_format () const;
int time_base_numerator () const {
private:
void film_changed (Film::Property);
-
- std::list<std::string> _files;
- std::list<std::string>::iterator _iter;
+
+ boost::shared_ptr<ImageMagickContent> _imagemagick_content;
+ ContentVideoFrame _position;
};
using std::stringstream;
using boost::shared_ptr;
-/** @param s Film that we are operating on.
- */
Job::Job (shared_ptr<Film> f)
: _film (f)
, _thread (0)
class Job : public boost::enable_shared_from_this<Job>
{
public:
- Job (boost::shared_ptr<Film> s);
+ Job (boost::shared_ptr<Film>);
virtual ~Job() {}
/** @return user-readable name of this job */
void set_state (State);
void set_error (std::string s, std::string d);
- /** Film for this job */
boost::shared_ptr<Film> _film;
private:
--- /dev/null
+/*
+ Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <boost/shared_ptr.hpp>
+#include "playlist.h"
+#include "sndfile_content.h"
+#include "sndfile_decoder.h"
+#include "ffmpeg_content.h"
+#include "ffmpeg_decoder.h"
+#include "imagemagick_content.h"
+#include "imagemagick_decoder.h"
+
+using std::list;
+using boost::shared_ptr;
+using boost::dynamic_pointer_cast;
+
+Playlist::Playlist (shared_ptr<const Film> f, list<shared_ptr<Content> > c)
+ : _video_from (VIDEO_NONE)
+ , _audio_from (AUDIO_NONE)
+ , _ffmpeg_decoder_done (false)
+{
+ for (list<shared_ptr<Content> >::const_iterator i = c.begin(); i != c.end(); ++i) {
+ shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (*i);
+ if (fc) {
+ assert (!_ffmpeg);
+ _ffmpeg = fc;
+ _video_from = VIDEO_FFMPEG;
+ if (_audio_from == AUDIO_NONE) {
+ _audio_from = AUDIO_FFMPEG;
+ }
+ }
+
+ shared_ptr<ImageMagickContent> ic = dynamic_pointer_cast<ImageMagickContent> (*i);
+ if (ic) {
+ _imagemagick.push_back (ic);
+ if (_video_from == VIDEO_NONE) {
+ _video_from = VIDEO_IMAGEMAGICK;
+ }
+ }
+
+ shared_ptr<SndfileContent> sc = dynamic_pointer_cast<SndfileContent> (*i);
+ if (sc) {
+ _sndfile.push_back (sc);
+ _audio_from = AUDIO_SNDFILE;
+ }
+ }
+
+ if (_video_from == VIDEO_FFMPEG || _audio_from == AUDIO_FFMPEG) {
+ DecodeOptions o;
+ /* XXX: decodeoptions */
+ _ffmpeg_decoder.reset (new FFmpegDecoder (f, _ffmpeg, o));
+ }
+
+ if (_video_from == VIDEO_FFMPEG) {
+ _ffmpeg_decoder->connect_video (shared_from_this ());
+ }
+
+ if (_audio_from == AUDIO_FFMPEG) {
+ _ffmpeg_decoder->connect_audio (shared_from_this ());
+ }
+
+ if (_video_from == VIDEO_IMAGEMAGICK) {
+ for (list<shared_ptr<ImageMagickContent> >::iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) {
+ DecodeOptions o;
+ /* XXX: decodeoptions */
+ shared_ptr<ImageMagickDecoder> d (new ImageMagickDecoder (f, *i, o));
+ _imagemagick_decoders.push_back (d);
+ d->connect_video (shared_from_this ());
+ }
+
+ _imagemagick_decoder = _imagemagick_decoders.begin ();
+ }
+
+ if (_audio_from == AUDIO_SNDFILE) {
+ for (list<shared_ptr<SndfileContent> >::iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) {
+ DecodeOptions o;
+ /* XXX: decodeoptions */
+ shared_ptr<SndfileDecoder> d (new SndfileDecoder (f, *i, o));
+ _sndfile_decoders.push_back (d);
+ d->connect_audio (shared_from_this ());
+ }
+ }
+}
+
+ContentAudioFrame
+Playlist::audio_length () const
+{
+ switch (_audio_from) {
+ case AUDIO_NONE:
+ return 0;
+ case AUDIO_FFMPEG:
+ return _ffmpeg->audio_length ();
+ case AUDIO_SNDFILE:
+ {
+ ContentAudioFrame l = 0;
+ for (list<shared_ptr<SndfileContent> >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) {
+ l += (*i)->audio_length ();
+ }
+ return l;
+ }
+ }
+
+ return 0;
+}
+
+int
+Playlist::audio_channels () const
+{
+ switch (_audio_from) {
+ case AUDIO_NONE:
+ return 0;
+ case AUDIO_FFMPEG:
+ return _ffmpeg->audio_channels ();
+ case AUDIO_SNDFILE:
+ {
+ int c = 0;
+ for (list<shared_ptr<SndfileContent> >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) {
+ c += (*i)->audio_channels ();
+ }
+ return c;
+ }
+ }
+
+ return 0;
+}
+
+int
+Playlist::audio_frame_rate () const
+{
+ switch (_audio_from) {
+ case AUDIO_NONE:
+ return 0;
+ case AUDIO_FFMPEG:
+ return _ffmpeg->audio_frame_rate ();
+ case AUDIO_SNDFILE:
+ return _sndfile.front()->audio_frame_rate ();
+ }
+
+ return 0;
+}
+
+int64_t
+Playlist::audio_channel_layout () const
+{
+ switch (_audio_from) {
+ case AUDIO_NONE:
+ return 0;
+ case AUDIO_FFMPEG:
+ return _ffmpeg->audio_channel_layout ();
+ case AUDIO_SNDFILE:
+ /* XXX */
+ return 0;
+ }
+
+ return 0;
+}
+
+float
+Playlist::video_frame_rate () const
+{
+ switch (_video_from) {
+ case VIDEO_NONE:
+ return 0;
+ case VIDEO_FFMPEG:
+ return _ffmpeg->video_frame_rate ();
+ case VIDEO_IMAGEMAGICK:
+ return 24;
+ }
+
+ return 0;
+}
+
+libdcp::Size
+Playlist::video_size () const
+{
+ switch (_video_from) {
+ case VIDEO_NONE:
+ return libdcp::Size ();
+ case VIDEO_FFMPEG:
+ return _ffmpeg->video_size ();
+ case VIDEO_IMAGEMAGICK:
+ /* XXX */
+ return _imagemagick.front()->video_size ();
+ }
+
+ return libdcp::Size ();
+}
+
+bool
+Playlist::has_audio () const
+{
+ return _audio_from != AUDIO_NONE;
+}
+
+void
+Playlist::disable_video ()
+{
+ _video_from = VIDEO_NONE;
+}
+
+bool
+Playlist::pass ()
+{
+ bool done = true;
+
+ if (_video_from == VIDEO_FFMPEG || _audio_from == AUDIO_FFMPEG) {
+ if (!_ffmpeg_decoder_done) {
+ if (_ffmpeg_decoder->pass ()) {
+ _ffmpeg_decoder_done = true;
+ } else {
+ done = false;
+ }
+ }
+ }
+
+ if (_video_from == VIDEO_IMAGEMAGICK) {
+ if (_imagemagick_decoder != _imagemagick_decoders.end ()) {
+ if ((*_imagemagick_decoder)->pass ()) {
+ _imagemagick_decoder++;
+ }
+
+ if (_imagemagick_decoder != _imagemagick_decoders.end ()) {
+ done = false;
+ }
+ }
+ }
+
+ /* XXX: sndfile */
+
+ return done;
+}
+
+void
+Playlist::set_progress (shared_ptr<Job> job)
+{
+ /* XXX */
+}
+
+void
+Playlist::process_video (shared_ptr<Image> i, bool same, shared_ptr<Subtitle> s)
+{
+ Video (i, same, s);
+}
+
+void
+Playlist::process_audio (shared_ptr<AudioBuffers> b)
+{
+ Audio (b);
+}
+
*/
+#include <list>
#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
#include "video_source.h"
+#include "audio_source.h"
#include "video_sink.h"
+#include "audio_sink.h"
class Content;
+class FFmpegContent;
+class FFmpegDecoder;
+class ImageMagickContent;
+class ImageMagickDecoder;
+class SndfileContent;
+class SndfileDecoder;
+class Job;
+class Film;
-class Playlist : public VideoSource, public AudioSource
+class Playlist : public VideoSource, public AudioSource, public VideoSink, public AudioSink, public boost::enable_shared_from_this<Playlist>
{
public:
- Playlist (std::list<boost::shared_ptr<Content> >);
+ Playlist (boost::shared_ptr<const Film>, std::list<boost::shared_ptr<Content> >);
+
+ ContentAudioFrame audio_length () const;
+ int audio_channels () const;
+ int audio_frame_rate () const;
+ int64_t audio_channel_layout () const;
+ bool has_audio () const;
+
+ float video_frame_rate () const;
+ libdcp::Size video_size () const;
+
+ void disable_video ();
+
+ bool pass ();
+ void set_progress (boost::shared_ptr<Job>);
+
+private:
+ void process_video (boost::shared_ptr<Image> i, bool same, boost::shared_ptr<Subtitle> s);
+ void process_audio (boost::shared_ptr<AudioBuffers>);
+
+ enum {
+ VIDEO_NONE,
+ VIDEO_FFMPEG,
+ VIDEO_IMAGEMAGICK
+ } _video_from;
+
+ enum {
+ AUDIO_NONE,
+ AUDIO_FFMPEG,
+ AUDIO_SNDFILE
+ } _audio_from;
+
+ boost::shared_ptr<FFmpegContent> _ffmpeg;
+ std::list<boost::shared_ptr<ImageMagickContent> > _imagemagick;
+ std::list<boost::shared_ptr<SndfileContent> > _sndfile;
+
+ boost::shared_ptr<FFmpegDecoder> _ffmpeg_decoder;
+ bool _ffmpeg_decoder_done;
+ std::list<boost::shared_ptr<ImageMagickDecoder> > _imagemagick_decoders;
+ std::list<boost::shared_ptr<ImageMagickDecoder> >::iterator _imagemagick_decoder;
+ std::list<boost::shared_ptr<SndfileDecoder> > _sndfile_decoders;
};
private:
void set_status (std::string);
-
+
mutable boost::mutex _status_mutex;
std::string _status;
};
--- /dev/null
+#include "sndfile_content.h"
+#include "compose.hpp"
+
+#include "i18n.h"
+
+using namespace std;
+
+string
+SndfileContent::summary () const
+{
+ return String::compose (_("Sound file: %1"), file().filename ());
+}
+
+int
+SndfileContent::audio_channels () const
+{
+ /* XXX */
+ return 0;
+}
+
+ContentAudioFrame
+SndfileContent::audio_length () const
+{
+ /* XXX */
+ return 0;
+}
+
+int
+SndfileContent::audio_frame_rate () const
+{
+ /* XXX */
+ return 0;
+}
+
+int64_t
+SndfileContent::audio_channel_layout () const
+{
+ /* XXX */
+ return 0;
+}
+
class SndfileContent : public AudioContent
{
public:
+ std::string summary () const;
+ /* AudioDecoder */
+ int audio_channels () const;
+ ContentAudioFrame audio_length () const;
+ int audio_frame_rate () const;
+ int64_t audio_channel_layout () const;
};
#include <iostream>
#include <sndfile.h>
+#include "sndfile_content.h"
#include "sndfile_decoder.h"
#include "film.h"
#include "exceptions.h"
using boost::shared_ptr;
using boost::optional;
-SndfileDecoder::SndfileDecoder (shared_ptr<Film> f, DecodeOptions o)
+/* XXX */
+
+SndfileDecoder::SndfileDecoder (shared_ptr<const Film> f, shared_ptr<SndfileContent> c, DecodeOptions o)
: Decoder (f, o)
- , AudioDecoder (f, o)
+ , AudioDecoder (f, c, o)
{
sf_count_t frames;
- vector<SNDFILE*> sf = open_files (frames);
- close_files (sf);
+ SNDFILE* sf = open_file (frames);
+ sf_close (sf);
}
-vector<SNDFILE*>
-SndfileDecoder::open_files (sf_count_t & frames)
+SNDFILE*
+SndfileDecoder::open_file (sf_count_t & frames)
{
- vector<string> const files = _film->external_audio ();
-
- int N = 0;
- for (size_t i = 0; i < files.size(); ++i) {
- if (!files[i].empty()) {
- N = i + 1;
- }
- }
-
- if (N == 0) {
- return vector<SNDFILE*> ();
- }
-
- bool first = true;
frames = 0;
- vector<SNDFILE*> sndfiles;
- for (size_t i = 0; i < (size_t) N; ++i) {
- if (files[i].empty ()) {
- sndfiles.push_back (0);
- } else {
- SF_INFO info;
- SNDFILE* s = sf_open (files[i].c_str(), SFM_READ, &info);
- if (!s) {
- throw DecodeError (_("could not open external audio file for reading"));
- }
-
- if (info.channels != 1) {
- throw DecodeError (_("external audio files must be mono"));
- }
-
- sndfiles.push_back (s);
-
- if (first) {
- shared_ptr<SndfileStream> st (
- new SndfileStream (
- info.samplerate, av_get_default_channel_layout (N)
- )
- );
-
- _audio_streams.push_back (st);
- _audio_stream = st;
- frames = info.frames;
- first = false;
- } else {
- if (info.frames != frames) {
- throw DecodeError (_("external audio files have differing lengths"));
- }
- }
- }
+ SF_INFO info;
+ SNDFILE* s = sf_open (_sndfile_content->file().string().c_str(), SFM_READ, &info);
+ if (!s) {
+ throw DecodeError (_("could not open external audio file for reading"));
}
- return sndfiles;
+ frames = info.frames;
+ return s;
}
bool
SndfileDecoder::pass ()
{
sf_count_t frames;
- vector<SNDFILE*> sndfiles = open_files (frames);
- if (sndfiles.empty()) {
- return true;
- }
+ SNDFILE* sndfile = open_file (frames);
/* Do things in half second blocks as I think there may be limits
to what FFmpeg (and in particular the resampler) can cope with.
*/
- sf_count_t const block = _audio_stream->sample_rate() / 2;
+ sf_count_t const block = _sndfile_content->audio_frame_rate() / 2;
- shared_ptr<AudioBuffers> audio (new AudioBuffers (_audio_stream->channels(), block));
+ shared_ptr<AudioBuffers> audio (new AudioBuffers (_sndfile_content->audio_channels(), block));
while (frames > 0) {
sf_count_t const this_time = min (block, frames);
- for (size_t i = 0; i < sndfiles.size(); ++i) {
- if (!sndfiles[i]) {
- audio->make_silent (i);
- } else {
- sf_read_float (sndfiles[i], audio->data(i), block);
- }
- }
-
+ sf_read_float (sndfile, audio->data(0), this_time);
audio->set_frames (this_time);
Audio (audio);
frames -= this_time;
}
- close_files (sndfiles);
+ sf_close (sndfile);
return true;
}
-
-void
-SndfileDecoder::close_files (vector<SNDFILE*> const & sndfiles)
-{
- for (size_t i = 0; i < sndfiles.size(); ++i) {
- sf_close (sndfiles[i]);
- }
-}
-
-shared_ptr<SndfileStream>
-SndfileStream::create ()
-{
- return shared_ptr<SndfileStream> (new SndfileStream);
-}
-
-shared_ptr<SndfileStream>
-SndfileStream::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<SndfileStream> ();
- }
-
- stringstream s (t);
- string type;
- s >> type;
- if (type != N_("external")) {
- return shared_ptr<SndfileStream> ();
- }
-
- return shared_ptr<SndfileStream> (new SndfileStream (t, v));
-}
-
-SndfileStream::SndfileStream (string t, optional<int> v)
-{
- assert (v);
-
- stringstream s (t);
- string type;
- s >> type >> _sample_rate >> _channel_layout;
-}
-
-SndfileStream::SndfileStream ()
-{
-
-}
-
-string
-SndfileStream::to_string () const
-{
- return String::compose (N_("external %1 %2"), _sample_rate, _channel_layout);
-}
#include <sndfile.h>
#include "decoder.h"
#include "audio_decoder.h"
-#include "stream.h"
-class SndfileStream : public AudioStream
-{
-public:
- SndfileStream (int sample_rate, int64_t layout)
- : AudioStream (sample_rate, layout)
- {}
-
- std::string to_string () const;
-
- static boost::shared_ptr<SndfileStream> create ();
- static boost::shared_ptr<SndfileStream> create (std::string t, boost::optional<int> v);
-
-private:
- friend class stream_test;
-
- SndfileStream ();
- SndfileStream (std::string t, boost::optional<int> v);
-};
+class SndfileContent;
class SndfileDecoder : public AudioDecoder
{
public:
- SndfileDecoder (boost::shared_ptr<Film>, DecodeOptions);
+ SndfileDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<SndfileContent>, DecodeOptions);
bool pass ();
private:
- std::vector<SNDFILE*> open_files (sf_count_t &);
- void close_files (std::vector<SNDFILE*> const &);
+ SNDFILE* open_file (sf_count_t &);
+ void close_file (SNDFILE*);
+
+ boost::shared_ptr<SndfileContent> _sndfile_content;
};
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <sstream>
-#include "compose.hpp"
-#include "stream.h"
-#include "ffmpeg_decoder.h"
-#include "sndfile_decoder.h"
-
-#include "i18n.h"
-
-using std::string;
-using std::stringstream;
-using boost::shared_ptr;
-using boost::optional;
-
-/** Construct a SubtitleStream from a value returned from to_string().
- * @param t String returned from to_string().
- * @param v State file version.
- */
-SubtitleStream::SubtitleStream (string t, boost::optional<int>)
-{
- stringstream n (t);
- n >> _id;
-
- size_t const s = t.find (' ');
- if (s != string::npos) {
- _name = t.substr (s + 1);
- }
-}
-
-/** @return A canonical string representation of this stream */
-string
-SubtitleStream::to_string () const
-{
- return String::compose (N_("%1 %2"), _id, _name);
-}
-
-/** Create a SubtitleStream from a value returned from to_string().
- * @param t String returned from to_string().
- * @param v State file version.
- */
-shared_ptr<SubtitleStream>
-SubtitleStream::create (string t, optional<int> v)
-{
- return shared_ptr<SubtitleStream> (new SubtitleStream (t, v));
-}
-
-/** Create an AudioStream from a string returned from to_string().
- * @param t String returned from to_string().
- * @param v State file version.
- * @return AudioStream, or 0.
- */
-shared_ptr<AudioStream>
-audio_stream_factory (string t, optional<int> v)
-{
- shared_ptr<AudioStream> s;
-
- s = FFmpegAudioStream::create (t, v);
- if (!s) {
- s = SndfileStream::create (t, v);
- }
-
- return s;
-}
-
-/** Create a SubtitleStream from a string returned from to_string().
- * @param t String returned from to_string().
- * @param v State file version.
- * @return SubtitleStream, or 0.
- */
-shared_ptr<SubtitleStream>
-subtitle_stream_factory (string t, optional<int> v)
-{
- return SubtitleStream::create (t, v);
-}
+++ /dev/null
-/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/** @file src/lib/stream.h
- * @brief Representations of audio and subtitle streams.
- *
- * Some content may have multiple `streams' of audio and/or subtitles; perhaps
- * for multiple languages, or for stereo / surround mixes. These classes represent
- * those streams, and know about their details.
- */
-
-#ifndef DVDOMATIC_STREAM_H
-#define DVDOMATIC_STREAM_H
-
-#include <stdint.h>
-#include <boost/shared_ptr.hpp>
-#include <boost/optional.hpp>
-extern "C" {
-#include <libavutil/audioconvert.h>
-}
-
-/** @class Stream
- * @brief Parent class for streams.
- */
-class Stream
-{
-public:
- virtual ~Stream () {}
- virtual std::string to_string () const = 0;
-};
-
-/** @class AudioStream
- * @brief A stream of audio data.
- */
-struct AudioStream : public Stream
-{
-public:
- AudioStream (int r, int64_t l)
- : _sample_rate (r)
- , _channel_layout (l)
- {}
-
- /* Only used for backwards compatibility for state file version < 1 */
- void set_sample_rate (int s) {
- _sample_rate = s;
- }
-
- int channels () const {
- return av_get_channel_layout_nb_channels (_channel_layout);
- }
-
- int sample_rate () const {
- return _sample_rate;
- }
-
- int64_t channel_layout () const {
- return _channel_layout;
- }
-
-protected:
- AudioStream ()
- : _sample_rate (0)
- , _channel_layout (0)
- {}
-
- int _sample_rate;
- int64_t _channel_layout;
-};
-
-/** @class SubtitleStream
- * @brief A stream of subtitle data.
- */
-class SubtitleStream : public Stream
-{
-public:
- SubtitleStream (std::string n, int 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
_film->log()->log (N_("Transcode job starting"));
_film->log()->log (String::compose (N_("Audio delay is %1ms"), _film->audio_delay()));
- _encoder.reset (new Encoder (_film));
- Transcoder w (_film, _decode_opt, this, _encoder);
+ Transcoder w (_film, _decode_opt, shared_from_this ());
w.go ();
set_progress (1);
set_state (FINISHED_OK);
string
TranscodeJob::status () const
{
- if (!_encoder) {
- return _("0%");
- }
+// if (!_encoder) {
+// return _("0%");
+// }
- float const fps = _encoder->current_frames_per_second ();
+ /* XXX */
+// float const fps = _encoder->current_frames_per_second ();
+ float const fps = 0;
if (fps == 0) {
return Job::status ();
}
int
TranscodeJob::remaining_time () const
{
+ return 0;
+#if 0
+ XXX
float fps = _encoder->current_frames_per_second ();
if (fps == 0) {
return 0;
}
- if (!_film->length()) {
+ if (!_video->length()) {
return 0;
}
/* We assume that dcp_length() is valid, if it is set */
int const left = length - _encoder->video_frames_out();
return left / fps;
+#endif
}
private:
DecodeOptions _decode_opt;
- boost::shared_ptr<Encoder> _encoder;
};
#include "gain.h"
#include "video_decoder.h"
#include "audio_decoder.h"
+#include "playlist.h"
using std::string;
using boost::shared_ptr;
* @param j Job that we are running under, or 0.
* @param e Encoder to use.
*/
-Transcoder::Transcoder (shared_ptr<Film> f, DecodeOptions o, Job* j, shared_ptr<Encoder> e)
+Transcoder::Transcoder (shared_ptr<Film> f, DecodeOptions o, shared_ptr<Job> j)
: _job (j)
- , _encoder (e)
- , _decoders (decoder_factory (f, o))
+ , _playlist (f->playlist ())
+ , _encoder (new Encoder (f, _playlist))
{
- assert (_encoder);
-
- if (f->audio_stream()) {
- shared_ptr<AudioStream> st = f->audio_stream();
- _matcher.reset (new Matcher (f->log(), st->sample_rate(), f->source_frame_rate()));
- _delay_line.reset (new DelayLine (f->log(), st->channels(), f->audio_delay() * st->sample_rate() / 1000));
+ if (_playlist->has_audio ()) {
+ _matcher.reset (new Matcher (f->log(), _playlist->audio_frame_rate(), _playlist->video_frame_rate()));
+ _delay_line.reset (new DelayLine (f->log(), _playlist->audio_channels(), f->audio_delay() * _playlist->audio_frame_rate() / 1000));
_gain.reset (new Gain (f->log(), f->audio_gain()));
}
- /* Set up the decoder to use the film's set streams */
- _decoders.video->set_subtitle_stream (f->subtitle_stream ());
- if (_decoders.audio) {
- _decoders.audio->set_audio_stream (f->audio_stream ());
- }
-
if (_matcher) {
- _decoders.video->connect_video (_matcher);
+ _playlist->connect_video (_matcher);
_matcher->connect_video (_encoder);
} else {
- _decoders.video->connect_video (_encoder);
+ _playlist->connect_video (_encoder);
}
- if (_matcher && _delay_line && _decoders.audio) {
- _decoders.audio->connect_audio (_delay_line);
+ if (_matcher && _delay_line && _playlist->has_audio ()) {
+ _playlist->connect_audio (_delay_line);
_delay_line->connect_audio (_matcher);
_matcher->connect_audio (_gain);
_gain->connect_audio (_encoder);
}
}
-/** Run the decoder, passing its output to the encoder, until the decoder
- * has no more data to present.
- */
void
Transcoder::go ()
{
_encoder->process_begin ();
try {
- bool done[2] = { false, false };
-
while (1) {
- if (!done[0]) {
- done[0] = _decoders.video->pass ();
- if (_job) {
- _decoders.video->set_progress (_job);
- }
- }
-
- if (!done[1] && _decoders.audio && dynamic_pointer_cast<Decoder> (_decoders.audio) != dynamic_pointer_cast<Decoder> (_decoders.video)) {
- done[1] = _decoders.audio->pass ();
- } else {
- done[1] = true;
- }
-
- if (done[0] && done[1]) {
+ if (_playlist->pass ()) {
break;
}
+ _playlist->set_progress (_job);
}
} catch (...) {
class Matcher;
class VideoFilter;
class Gain;
-class VideoDecoder;
-class AudioDecoder;
class DelayLine;
+class Playlist;
/** @class Transcoder
* @brief A class which takes a Film and some Options, then uses those to transcode the film.
Transcoder (
boost::shared_ptr<Film> f,
DecodeOptions o,
- Job* j,
- boost::shared_ptr<Encoder> e
+ boost::shared_ptr<Job> j
);
void go ();
- boost::shared_ptr<VideoDecoder> video_decoder () const {
- return _decoders.video;
- }
-
protected:
/** A Job that is running this Transcoder, or 0 */
- Job* _job;
- /** The encoder that we will use */
+ boost::shared_ptr<Job> _job;
+ boost::shared_ptr<Playlist> _playlist;
boost::shared_ptr<Encoder> _encoder;
- /** The decoders that we will use */
- Decoders _decoders;
boost::shared_ptr<Matcher> _matcher;
boost::shared_ptr<DelayLine> _delay_line;
boost::shared_ptr<Gain> _gain;
* @return MD5 digest of file's contents.
*/
string
-md5_digest (string file)
+md5_digest (boost::filesystem::path file)
{
- ifstream f (file.c_str(), ios::binary);
+ ifstream f (file.string().c_str(), ios::binary);
if (!f.good ()) {
- throw OpenFileError (file);
+ throw OpenFileError (file.string());
}
f.seekg (0, ios::end);
extern void dvdomatic_setup ();
extern void dvdomatic_setup_i18n (std::string);
extern std::vector<std::string> split_at_spaces_considering_quotes (std::string);
-extern std::string md5_digest (std::string);
+extern std::string md5_digest (boost::filesystem::path);
extern std::string md5_digest (void const *, int);
extern void ensure_ui_thread ();
extern std::string audio_channel_name (int);
#endif
typedef int SourceFrame;
+typedef int64_t ContentAudioFrame;
+typedef int ContentVideoFrame;
struct FrameRateConversion
{
--- /dev/null
+#include "video_content.h"
+#include "video_decoder.h"
+
+int const VideoContentProperty::VIDEO_LENGTH = 0;
+int const VideoContentProperty::VIDEO_SIZE = 1;
+int const VideoContentProperty::VIDEO_FRAME_RATE = 2;
+
+using boost::shared_ptr;
+
+VideoContent::VideoContent (boost::filesystem::path f)
+ : Content (f)
+ , _video_length (0)
+{
+
+}
+
+void
+VideoContent::take_from_video_decoder (shared_ptr<VideoDecoder> d)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _video_size = d->native_size ();
+ _video_frame_rate = d->frames_per_second ();
+ }
+
+ Changed (VideoContentProperty::VIDEO_SIZE);
+ Changed (VideoContentProperty::VIDEO_FRAME_RATE);
+}
+#ifndef DVDOMATIC_VIDEO_CONTENT_H
+#define DVDOMATIC_VIDEO_CONTENT_H
+
#include "content.h"
+#include "util.h"
+
+class VideoDecoder;
+
+class VideoContentProperty
+{
+public:
+ static int const VIDEO_LENGTH;
+ static int const VIDEO_SIZE;
+ static int const VIDEO_FRAME_RATE;
+};
class VideoContent : public virtual Content
{
public:
+ VideoContent (boost::filesystem::path);
+
+ ContentVideoFrame video_length () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _video_length;
+ }
+
+ libdcp::Size video_size () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _video_size;
+ }
+ float video_frame_rate () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _video_frame_rate;
+ }
+
+protected:
+ void take_from_video_decoder (boost::shared_ptr<VideoDecoder>);
+ ContentVideoFrame _video_length;
+
+private:
+ libdcp::Size _video_size;
+ float _video_frame_rate;
};
+
+#endif
using boost::shared_ptr;
using boost::optional;
-VideoDecoder::VideoDecoder (shared_ptr<Film> f, DecodeOptions o)
+VideoDecoder::VideoDecoder (shared_ptr<const Film> f, shared_ptr<VideoContent> c, DecodeOptions o)
: Decoder (f, o)
, _video_frame (0)
, _last_source_time (0)
}
}
-/** Set which stream of subtitles we should use from our source.
- * @param s Stream to use.
- */
-void
-VideoDecoder::set_subtitle_stream (shared_ptr<SubtitleStream> s)
-{
- _subtitle_stream = s;
-}
-
void
VideoDecoder::set_progress (Job* j) const
{
assert (j);
-
+
+#if 0
+ XXX
if (_film->length()) {
j->set_progress (float (_video_frame) / _film->length().get());
}
+#endif
}
#define DVDOMATIC_VIDEO_DECODER_H
#include "video_source.h"
-#include "stream.h"
#include "decoder.h"
+class VideoContent;
+
class VideoDecoder : public VideoSource, public virtual Decoder
{
public:
- VideoDecoder (boost::shared_ptr<Film>, DecodeOptions);
+ VideoDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<VideoContent>, DecodeOptions);
/** @return video frames per second, or 0 if unknown */
virtual float frames_per_second () const = 0;
/** @return native size in pixels */
virtual libdcp::Size native_size () const = 0;
- /** @return length (in source video frames), according to our content's header */
- virtual SourceFrame length () const = 0;
+ /** @return length according to our content's header */
+ virtual ContentVideoFrame video_length () const = 0;
virtual int time_base_numerator () const = 0;
virtual int time_base_denominator () const = 0;
virtual int sample_aspect_ratio_numerator () const = 0;
virtual int sample_aspect_ratio_denominator () const = 0;
- virtual void set_subtitle_stream (boost::shared_ptr<SubtitleStream>);
-
void set_progress (Job *) const;
int video_frame () const {
return _video_frame;
}
- boost::shared_ptr<SubtitleStream> subtitle_stream () const {
- return _subtitle_stream;
- }
-
- std::vector<boost::shared_ptr<SubtitleStream> > subtitle_streams () const {
- return _subtitle_streams;
- }
-
double last_source_time () const {
return _last_source_time;
}
void emit_subtitle (boost::shared_ptr<TimedSubtitle>);
void repeat_last_video ();
- /** Subtitle stream to use when decoding */
- boost::shared_ptr<SubtitleStream> _subtitle_stream;
- /** Subtitle streams that this decoder's content has */
- std::vector<boost::shared_ptr<SubtitleStream> > _subtitle_streams;
-
private:
void signal_video (boost::shared_ptr<Image>, bool, boost::shared_ptr<Subtitle>);
#include "format.h"
#include "log.h"
#include "dcp_video_frame.h"
+#include "playlist.h"
#include "i18n.h"
int const Writer::_maximum_frames_in_memory = 8;
-Writer::Writer (shared_ptr<Film> f)
+Writer::Writer (shared_ptr<Film> f, shared_ptr<Playlist> p)
: _film (f)
+ , _playlist (p)
, _first_nonexistant_frame (0)
, _thread (0)
, _finish (false)
_picture_asset_writer = _picture_asset->start_write (_first_nonexistant_frame > 0);
- AudioMapping m (_film->audio_channels ());
+ AudioMapping m (_playlist->audio_channels ());
if (m.dcp_channels() > 0) {
_sound_asset.reset (
N_("audio.mxf"),
_film->dcp_frame_rate (),
m.dcp_channels (),
- dcp_audio_sample_rate (_film->audio_stream()->sample_rate())
+ dcp_audio_sample_rate (_playlist->audio_frame_rate())
)
);
class Film;
class EncodedData;
class AudioBuffers;
+class Playlist;
namespace libdcp {
class MonoPictureAsset;
class Writer : public ExceptionStore
{
public:
- Writer (boost::shared_ptr<Film>);
+ Writer (boost::shared_ptr<Film>, boost::shared_ptr<Playlist>);
bool can_fake_write (int) const;
/** our Film */
boost::shared_ptr<Film> _film;
+ boost::shared_ptr<Playlist> _playlist;
/** the first frame index that does not already exist in our MXF */
int _first_nonexistant_frame;
ab_transcoder.cc
analyse_audio_job.cc
audio_analysis.cc
+ audio_content.cc
audio_decoder.cc
audio_source.cc
config.cc
combiner.cc
+ content.cc
cross.cc
dci_metadata.cc
dcp_content_type.cc
exceptions.cc
filter_graph.cc
ffmpeg_compatibility.cc
+ ffmpeg_content.cc
ffmpeg_decoder.cc
film.cc
filter.cc
format.cc
gain.cc
image.cc
+ imagemagick_content.cc
imagemagick_decoder.cc
job.cc
job_manager.cc
log.cc
lut.cc
matcher.cc
+ playlist.cc
scp_dcp_job.cc
scaler.cc
server.cc
+ sndfile_content.cc
sndfile_decoder.cc
sound_processor.cc
- stream.cc
subtitle.cc
timer.cc
transcode_job.cc
ui_signaller.cc
util.cc
version.cc
+ video_content.cc
video_decoder.cc
video_source.cc
writer.cc
set_menu_sensitivity ();
- /* XXX: calling these here is a bit of a hack */
- film_editor->setup_visibility ();
-
film_editor->FileChanged.connect (bind (&Frame::file_changed, this, _1));
if (film) {
file_changed (film->directory ());
}
cout << "DCP for " << film->name() << "\n";
cout << "Test mode: " << (test_mode ? "yes" : "no") << "\n";
- cout << "Content: " << film->content() << "\n";
+// cout << "Content: " << film->content() << "\n";
pair<string, string> const f = Filter::ffmpeg_strings (film->filters ());
cout << "Filters: " << f.first << " " << f.second << "\n";
*/
#include <boost/filesystem.hpp>
+#include "lib/audio_analysis.h"
+#include "lib/film.h"
+#include "lib/playlist.h"
#include "audio_dialog.h"
#include "audio_plot.h"
-#include "audio_analysis.h"
-#include "film.h"
#include "wx_util.h"
using boost::shared_ptr;
_film_audio_analysis_succeeded_connection.disconnect ();
_film = f;
+ _playlist = _film->playlist ();
try_to_load_analysis ();
setup_channels ();
void
AudioDialog::setup_channels ()
{
- if (!_film->audio_stream()) {
+ if (!_playlist->has_audio()) {
return;
}
- AudioMapping m (_film->audio_stream()->channels ());
+ AudioMapping m (_playlist->audio_channels ());
for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) {
if (m.dcp_to_source(static_cast<libdcp::Channel>(i))) {
_plot->set_analysis (a);
- AudioMapping m (_film->audio_stream()->channels ());
+ AudioMapping m (_playlist->audio_channels ());
optional<libdcp::Channel> c = m.source_to_dcp (0);
if (c) {
_channel_checkbox[c.get()]->SetValue (true);
assert (c < MAX_AUDIO_CHANNELS);
- AudioMapping m (_film->audio_stream()->channels ());
+ AudioMapping m (_playlist->audio_channels ());
optional<int> s = m.dcp_to_source (static_cast<libdcp::Channel> (c));
if (s) {
_plot->set_channel_visible (s.get(), _channel_checkbox[c]->GetValue ());
case Film::AUDIO_GAIN:
_plot->set_gain (_film->audio_gain ());
break;
- case Film::CONTENT_AUDIO_STREAM:
- case Film::EXTERNAL_AUDIO:
- case Film::USE_CONTENT_AUDIO:
+ case Film::CONTENT:
+ _playlist = _film->playlist ();
setup_channels ();
break;
default:
class AudioPlot;
class Film;
+class Playlist;
class AudioDialog : public wxDialog
{
void setup_channels ();
boost::shared_ptr<Film> _film;
+ boost::shared_ptr<Playlist> _playlist;
AudioPlot* _plot;
wxCheckBox* _channel_checkbox[MAX_AUDIO_CHANNELS];
wxCheckBox* _type_checkbox[AudioPoint::COUNT];
#include <iomanip>
#include <wx/wx.h>
#include <wx/notebook.h>
+#include <wx/listctrl.h>
#include <boost/thread.hpp>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
, _audio_dialog (0)
{
wxBoxSizer* 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_content_panel ();
+ _notebook->AddPage (_content_panel, _("Content"), false);
make_video_panel ();
_notebook->AddPage (_video_panel, _("Video"), false);
make_audio_panel ();
bind (&FilmEditor::active_jobs_changed, this, _1)
);
- setup_visibility ();
setup_formats ();
+
+ SetSizerAndFit (s);
}
void
grid->Add (_edit_dci_button, wxGBPosition (r, 1), wxDefaultSpan);
++r;
- add_label_to_grid_bag_sizer (grid, _film_panel, _("Content"), wxGBPosition (r, 0));
- _content = new wxFilePickerCtrl (_film_panel, wxID_ANY, wxT (""), _("Select Content File"), wxT("*.*"));
- grid->Add (_content, wxGBPosition (r, 1), wxDefaultSpan, wxEXPAND);
- ++r;
-
_trust_content_header = new wxCheckBox (_film_panel, wxID_ANY, _("Trust content's header"));
- video_control (_trust_content_header);
grid->Add (_trust_content_header, wxGBPosition (r, 0), wxGBSpan(1, 2));
++r;
grid->Add (_dcp_content_type, wxGBPosition (r, 1));
++r;
- video_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Original Frame Rate"), wxGBPosition (r, 0)));
+ add_label_to_grid_bag_sizer (grid, _film_panel, _("Original Frame Rate"), wxGBPosition (r, 0));
_source_frame_rate = new wxStaticText (_film_panel, wxID_ANY, wxT (""));
- grid->Add (video_control (_source_frame_rate), wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+ grid->Add (_source_frame_rate, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
++r;
{
++r;
_frame_rate_description = new wxStaticText (_film_panel, wxID_ANY, wxT (" \n "), wxDefaultPosition, wxDefaultSize);
- grid->Add (video_control (_frame_rate_description), wxGBPosition (r, 0), wxGBSpan (1, 2), wxEXPAND | wxALIGN_CENTER_VERTICAL | wxALL, 6);
+ grid->Add (_frame_rate_description, wxGBPosition (r, 0), wxGBSpan (1, 2), wxEXPAND | wxALIGN_CENTER_VERTICAL | wxALL, 6);
wxFont font = _frame_rate_description->GetFont();
font.SetStyle(wxFONTSTYLE_ITALIC);
font.SetPointSize(font.GetPointSize() - 1);
_frame_rate_description->SetFont(font);
++r;
- video_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Original Size"), wxGBPosition (r, 0)));
+ add_label_to_grid_bag_sizer (grid, _film_panel, _("Original Size"), wxGBPosition (r, 0));
_original_size = new wxStaticText (_film_panel, wxID_ANY, wxT (""));
- grid->Add (video_control (_original_size), wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+ grid->Add (_original_size, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
++r;
- video_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Length"), wxGBPosition (r, 0)));
+ add_label_to_grid_bag_sizer (grid, _film_panel, _("Length"), wxGBPosition (r, 0));
_length = new wxStaticText (_film_panel, wxID_ANY, wxT (""));
- grid->Add (video_control (_length), wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+ grid->Add (_length, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
++r;
{
- video_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Trim frames"), wxGBPosition (r, 0)));
+ add_label_to_grid_bag_sizer (grid, _film_panel, _("Trim frames"), wxGBPosition (r, 0));
wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- video_control (add_label_to_sizer (s, _film_panel, _("Start")));
+ add_label_to_sizer (s, _film_panel, _("Start"));
_trim_start = new wxSpinCtrl (_film_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
- s->Add (video_control (_trim_start));
- video_control (add_label_to_sizer (s, _film_panel, _("End")));
+ s->Add (_trim_start);
+ add_label_to_sizer (s, _film_panel, _("End"));
_trim_end = new wxSpinCtrl (_film_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1));
- s->Add (video_control (_trim_end));
+ s->Add (_trim_end);
grid->Add (s, wxGBPosition (r, 1));
}
++r;
_dcp_ab = new wxCheckBox (_film_panel, wxID_ANY, _("A/B"));
- video_control (_dcp_ab);
grid->Add (_dcp_ab, wxGBPosition (r, 0));
++r;
- /* STILL-only stuff */
- {
- still_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Duration"), wxGBPosition (r, 0)));
- wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _still_duration = new wxSpinCtrl (_film_panel);
- still_control (_still_duration);
- s->Add (_still_duration, 1, wxEXPAND);
- /// TRANSLATORS: `s' here is an abbreviation for seconds, the unit of time
- still_control (add_label_to_sizer (s, _film_panel, _("s")));
- grid->Add (s, wxGBPosition (r, 1));
- }
- ++r;
-
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 ()));
_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_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::format_changed), 0, this);
- _content->Connect (wxID_ANY, wxEVT_COMMAND_FILEPICKER_CHANGED, wxCommandEventHandler (FilmEditor::content_changed), 0, this);
_trust_content_header->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::trust_content_header_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);
_dcp_frame_rate->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::dcp_frame_rate_changed), 0, this);
_best_dcp_frame_rate->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::best_dcp_frame_rate_clicked), 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);
_trim_start->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::trim_start_changed), 0, this);
_trim_end->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::trim_end_changed), 0, this);
_with_subtitles->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::with_subtitles_toggled), 0, this);
_subtitle_scale->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_scale_changed), 0, this);
_colour_lut->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::colour_lut_changed), 0, this);
_j2k_bandwidth->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::j2k_bandwidth_changed), 0, this);
- _subtitle_stream->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::subtitle_stream_changed), 0, this);
- _audio_stream->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::audio_stream_changed), 0, this);
+// _ffmpeg_subtitle_stream->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::ffmpeg_subtitle_stream_changed), 0, this);
+// _ffmpeg_audio_stream->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::ffmpeg_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
);
_show_audio->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::show_audio_clicked), 0, this);
_audio_delay->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::audio_delay_changed), 0, this);
- _use_content_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
- );
- }
}
void
/* VIDEO-only stuff */
{
- video_control (add_label_to_grid_bag_sizer (grid, _video_panel, _("Filters"), wxGBPosition (r, 0)));
+ add_label_to_grid_bag_sizer (grid, _video_panel, _("Filters"), wxGBPosition (r, 0));
wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
_filters = new wxStaticText (_video_panel, wxID_ANY, _("None"));
- video_control (_filters);
s->Add (_filters, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM | wxRIGHT, 6);
_filters_button = new wxButton (_video_panel, wxID_ANY, _("Edit..."));
- video_control (_filters_button);
s->Add (_filters_button, 0);
grid->Add (s, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
}
++r;
- video_control (add_label_to_grid_bag_sizer (grid, _video_panel, _("Scaler"), wxGBPosition (r, 0)));
+ add_label_to_grid_bag_sizer (grid, _video_panel, _("Scaler"), wxGBPosition (r, 0));
_scaler = new wxChoice (_video_panel, wxID_ANY);
- grid->Add (video_control (_scaler), wxGBPosition (r, 1));
+ grid->Add (_scaler, wxGBPosition (r, 1));
++r;
vector<Scaler const *> const sc = Scaler::all ();
_top_crop->SetRange (0, 1024);
_right_crop->SetRange (0, 1024);
_bottom_crop->SetRange (0, 1024);
- _still_duration->SetRange (1, 60 * 60);
_trim_start->SetRange (0, 100);
_trim_end->SetRange (0, 100);
_j2k_bandwidth->SetRange (50, 250);
}
+void
+FilmEditor::make_content_panel ()
+{
+ _content_panel = new wxPanel (_notebook);
+ _content_sizer = new wxBoxSizer (wxVERTICAL);
+ _content_panel->SetSizer (_content_sizer);
+
+ wxGridBagSizer* grid = new wxGridBagSizer (4, 4);
+ _content_sizer->Add (grid, 0, wxALL, 8);
+
+ int r = 0;
+
+ {
+ wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+
+ _content = new wxListCtrl (_content_panel, wxID_ANY, wxDefaultPosition, wxSize (320, 160), wxLC_REPORT | wxLC_NO_HEADER | wxLC_SINGLE_SEL);
+ s->Add (_content, 1, wxEXPAND | wxTOP | wxBOTTOM, 6);
+
+ _content->InsertColumn (0, "");
+
+ wxBoxSizer* b = new wxBoxSizer (wxVERTICAL);
+ _content_add = new wxButton (_content_panel, wxID_ANY, _("Add..."));
+ b->Add (_content_add);
+ _content_remove = new wxButton (_content_panel, wxID_ANY, _("Remove"));
+ b->Add (_content_remove);
+ _content_earlier = new wxButton (_content_panel, wxID_ANY, _("Earlier"));
+ b->Add (_content_earlier);
+ _content_later = new wxButton (_content_panel, wxID_ANY, _("Later"));
+ b->Add (_content_later);
+
+ s->Add (b, 0, wxALL, 4);
+
+ grid->Add (s, wxGBPosition (r, 0), wxGBSpan (1, 2), wxEXPAND);
+ ++r;
+ }
+}
+
void
FilmEditor::make_audio_panel ()
{
grid->AddSpacer (0);
{
- video_control (add_label_to_sizer (grid, _audio_panel, _("Audio Gain")));
+ add_label_to_sizer (grid, _audio_panel, _("Audio Gain"));
wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
_audio_gain = new wxSpinCtrl (_audio_panel);
- s->Add (video_control (_audio_gain), 1);
- video_control (add_label_to_sizer (s, _audio_panel, _("dB")));
+ s->Add (_audio_gain, 1);
+ 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);
grid->Add (s);
}
{
- video_control (add_label_to_sizer (grid, _audio_panel, _("Audio Delay")));
+ add_label_to_sizer (grid, _audio_panel, _("Audio Delay"));
wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
_audio_delay = new wxSpinCtrl (_audio_panel);
- s->Add (video_control (_audio_delay), 1);
+ s->Add (_audio_delay, 1);
/// TRANSLATORS: this is an abbreviation for milliseconds, the unit of time
- video_control (add_label_to_sizer (s, _audio_panel, _("ms")));
+ add_label_to_sizer (s, _audio_panel, _("ms"));
grid->Add (s);
}
- {
- _use_content_audio = new wxRadioButton (_audio_panel, wxID_ANY, _("Use content's audio"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
- grid->Add (video_control (_use_content_audio));
- wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
- _audio_stream = new wxChoice (_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);
- grid->Add (s, 1, wxEXPAND);
- }
-
- _use_external_audio = new wxRadioButton (_audio_panel, wxID_ANY, _("Use external audio"));
- grid->Add (_use_external_audio);
- grid->AddSpacer (0);
-
- for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) {
- add_label_to_sizer (grid, _audio_panel, std_to_wx (audio_channel_name (i)));
- _external_audio[i] = new wxFilePickerCtrl (_audio_panel, wxID_ANY, wxT (""), _("Select Audio File"), wxT ("*.wav"));
- grid->Add (_external_audio[i], 1, wxEXPAND);
- }
-
_audio_gain->SetRange (-60, 60);
_audio_delay->SetRange (-1000, 1000);
}
_subtitle_sizer->Add (grid, 0, wxALL, 8);
_with_subtitles = new wxCheckBox (_subtitle_panel, wxID_ANY, _("With Subtitles"));
- video_control (_with_subtitles);
grid->Add (_with_subtitles, 1);
- _subtitle_stream = new wxChoice (_subtitle_panel, wxID_ANY);
- grid->Add (video_control (_subtitle_stream));
+ _ffmpeg_subtitle_stream = new wxChoice (_subtitle_panel, wxID_ANY);
+ grid->Add (_ffmpeg_subtitle_stream);
- video_control (add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Offset")));
+ add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Offset"));
_subtitle_offset = new wxSpinCtrl (_subtitle_panel);
- grid->Add (video_control (_subtitle_offset), 1);
+ grid->Add (_subtitle_offset, 1);
{
- video_control (add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Scale")));
+ add_label_to_sizer (grid, _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, _("%")));
+ s->Add (_subtitle_scale);
+ add_label_to_sizer (s, _subtitle_panel, _("%"));
grid->Add (s);
}
_film->set_bottom_crop (_bottom_crop->GetValue ());
}
-/** Called when the content filename has been changed */
-void
-FilmEditor::content_changed (wxCommandEvent &)
-{
- if (!_film) {
- return;
- }
-
- try {
- _film->set_content (wx_to_std (_content->GetPath ()));
- } catch (std::exception& e) {
- _content->SetPath (std_to_wx (_film->directory ()));
- error_dialog (this, wxString::Format (_("Could not set content: %s"), std_to_wx (e.what()).data()));
- }
-}
-
void
FilmEditor::trust_content_header_changed (wxCommandEvent &)
{
case Film::NONE:
break;
case Film::CONTENT:
- checked_set (_content, _film->content ());
- setup_visibility ();
+ setup_content ();
setup_formats ();
setup_subtitle_control_sensitivity ();
setup_streams ();
case Film::TRUST_CONTENT_HEADER:
checked_set (_trust_content_header, _film->trust_content_header ());
break;
- case Film::SUBTITLE_STREAMS:
- setup_subtitle_control_sensitivity ();
- setup_streams ();
- break;
- case Film::CONTENT_AUDIO_STREAMS:
- setup_streams ();
- setup_show_audio_sensitivity ();
- break;
+// case Film::SUBTITLE_STREAMS:
+// setup_subtitle_control_sensitivity ();
+// setup_streams ();
+// break;
+// case Film::CONTENT_AUDIO_STREAMS:
+// setup_streams ();
+// setup_show_audio_sensitivity ();
+// break;
case Film::FORMAT:
{
int n = 0;
checked_set (_name, _film->name());
setup_dcp_name ();
break;
- case Film::SOURCE_FRAME_RATE:
- s << fixed << setprecision(2) << _film->source_frame_rate();
- _source_frame_rate->SetLabel (std_to_wx (s.str ()));
- break;
- case Film::SIZE:
- if (_film->size().width == 0 && _film->size().height == 0) {
- _original_size->SetLabel (wxT (""));
- } else {
- s << _film->size().width << " x " << _film->size().height;
- _original_size->SetLabel (std_to_wx (s.str ()));
- }
- break;
- case Film::LENGTH:
- if (_film->source_frame_rate() > 0 && _film->length()) {
- s << _film->length().get() << " "
- << wx_to_std (_("frames")) << "; " << seconds_to_hms (_film->length().get() / _film->source_frame_rate());
- } else if (_film->length()) {
- s << _film->length().get() << " "
- << wx_to_std (_("frames"));
- }
- _length->SetLabel (std_to_wx (s.str ()));
- if (_film->length()) {
- _trim_start->SetRange (0, _film->length().get());
- _trim_end->SetRange (0, _film->length().get());
- }
- break;
+// case Film::SOURCE_FRAME_RATE:
+// s << fixed << setprecision(2) << _film->source_frame_rate();
+// _source_frame_rate->SetLabel (std_to_wx (s.str ()));
+// break;
+// case Film::SIZE:
+// if (_film->size().width == 0 && _film->size().height == 0) {
+// _original_size->SetLabel (wxT (""));
+// } else {
+// s << _film->size().width << " x " << _film->size().height;
+// _original_size->SetLabel (std_to_wx (s.str ()));
+// }
+// break;
+// case Film::LENGTH:
+// if (_film->source_frame_rate() > 0 && _film->length()) {
+// s << _film->length().get() << " "
+// << wx_to_std (_("frames")) << "; " << seconds_to_hms (_film->length().get() / _film->source_frame_rate());
+// } else if (_film->length()) {
+// s << _film->length().get() << " "
+// << wx_to_std (_("frames"));
+// }
+// _length->SetLabel (std_to_wx (s.str ()));
+// if (_film->length()) {
+// _trim_start->SetRange (0, _film->length().get());
+// _trim_end->SetRange (0, _film->length().get());
+// }
+// break;
case Film::DCP_CONTENT_TYPE:
checked_set (_dcp_content_type, DCPContentType::as_index (_film->dcp_content_type ()));
setup_dcp_name ();
case Film::AUDIO_DELAY:
checked_set (_audio_delay, _film->audio_delay ());
break;
- case Film::STILL_DURATION:
- checked_set (_still_duration, _film->still_duration ());
- break;
case Film::WITH_SUBTITLES:
checked_set (_with_subtitles, _film->with_subtitles ());
setup_subtitle_control_sensitivity ();
case Film::DCI_METADATA:
setup_dcp_name ();
break;
- case Film::CONTENT_AUDIO_STREAM:
- if (_film->content_audio_stream()) {
- checked_set (_audio_stream, _film->content_audio_stream()->to_string());
- }
- setup_dcp_name ();
- setup_audio_details ();
- setup_audio_control_sensitivity ();
- setup_show_audio_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());
- setup_dcp_name ();
- setup_audio_details ();
- setup_audio_control_sensitivity ();
- setup_show_audio_sensitivity ();
- break;
- case Film::SUBTITLE_STREAM:
- if (_film->subtitle_stream()) {
- checked_set (_subtitle_stream, _film->subtitle_stream()->to_string());
- }
- 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 ();
- setup_show_audio_sensitivity ();
- break;
- }
- case Film::DCP_FRAME_RATE:
- for (unsigned int i = 0; i < _dcp_frame_rate->GetCount(); ++i) {
- if (wx_to_std (_dcp_frame_rate->GetString(i)) == boost::lexical_cast<string> (_film->dcp_frame_rate())) {
- if (_dcp_frame_rate->GetSelection() != int(i)) {
- _dcp_frame_rate->SetSelection (i);
- break;
- }
- }
- }
-
- if (_film->source_frame_rate()) {
- _frame_rate_description->SetLabel (std_to_wx (FrameRateConversion (_film->source_frame_rate(), _film->dcp_frame_rate()).description));
- _best_dcp_frame_rate->Enable (best_dcp_frame_rate (_film->source_frame_rate ()) != _film->dcp_frame_rate ());
- } else {
- _frame_rate_description->SetLabel (wxT (""));
- _best_dcp_frame_rate->Disable ();
- }
+// case Film::CONTENT_AUDIO_STREAM:
+// if (_film->content_audio_stream()) {
+// checked_set (_audio_stream, _film->content_audio_stream()->to_string());
+// }
+// setup_dcp_name ();
+// setup_audio_details ();
+// setup_show_audio_sensitivity ();
+// break;
+// case Film::SUBTITLE_STREAM:
+// if (_film->subtitle_stream()) {
+// checked_set (_subtitle_stream, _film->subtitle_stream()->to_string());
+// }
+// break;
+// case Film::DCP_FRAME_RATE:
+// for (unsigned int i = 0; i < _dcp_frame_rate->GetCount(); ++i) {
+// if (wx_to_std (_dcp_frame_rate->GetString(i)) == boost::lexical_cast<string> (_film->dcp_frame_rate())) {
+// if (_dcp_frame_rate->GetSelection() != int(i)) {
+// _dcp_frame_rate->SetSelection (i);
+// break;
+// }
+// }
+// }
+
+// if (_film->source_frame_rate()) {
+// _frame_rate_description->SetLabel (std_to_wx (FrameRateConversion (_film->source_frame_rate(), _film->dcp_frame_rate()).description));
+// _best_dcp_frame_rate->Enable (best_dcp_frame_rate (_film->source_frame_rate ()) != _film->dcp_frame_rate ());
+// } else {
+// _frame_rate_description->SetLabel (wxT (""));
+// _best_dcp_frame_rate->Disable ();
+// }
}
}
film_changed (Film::TRIM_START);
film_changed (Film::TRIM_END);
film_changed (Film::DCP_AB);
- 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::STILL_DURATION);
film_changed (Film::WITH_SUBTITLES);
film_changed (Film::SUBTITLE_OFFSET);
film_changed (Film::SUBTITLE_SCALE);
film_changed (Film::COLOUR_LUT);
film_changed (Film::J2K_BANDWIDTH);
film_changed (Film::DCI_METADATA);
- film_changed (Film::SIZE);
- film_changed (Film::LENGTH);
- film_changed (Film::CONTENT_AUDIO_STREAMS);
- film_changed (Film::SUBTITLE_STREAMS);
- film_changed (Film::SOURCE_FRAME_RATE);
film_changed (Film::DCP_FRAME_RATE);
}
_bottom_crop->Enable (s);
_filters_button->Enable (s);
_scaler->Enable (s);
- _audio_stream->Enable (s);
+// _ffmpeg_audio_stream->Enable (s);
_dcp_content_type->Enable (s);
_dcp_frame_rate->Enable (s);
_trim_start->Enable (s);
_audio_gain_calculate_button->Enable (s);
_show_audio->Enable (s);
_audio_delay->Enable (s);
- _still_duration->Enable (s);
setup_subtitle_control_sensitivity ();
- setup_audio_control_sensitivity ();
setup_show_audio_sensitivity ();
}
_film->set_audio_delay (_audio_delay->GetValue ());
}
-wxControl *
-FilmEditor::video_control (wxControl* c)
-{
- _video_controls.push_back (c);
- return c;
-}
-
-wxControl *
-FilmEditor::still_control (wxControl* c)
-{
- _still_controls.push_back (c);
- return c;
-}
-
-void
-FilmEditor::setup_visibility ()
-{
- ContentType c = VIDEO;
-
- if (_film) {
- c = _film->content_type ();
- }
-
- for (list<wxControl*>::iterator i = _video_controls.begin(); i != _video_controls.end(); ++i) {
- (*i)->Show (c == VIDEO);
- }
-
- for (list<wxControl*>::iterator i = _still_controls.begin(); i != _still_controls.end(); ++i) {
- (*i)->Show (c == STILL);
- }
-
- _notebook->InvalidateBestSize ();
-
- _film_sizer->Layout ();
- _film_sizer->SetSizeHints (_film_panel);
- _video_sizer->Layout ();
- _video_sizer->SetSizeHints (_video_panel);
- _audio_sizer->Layout ();
- _audio_sizer->SetSizeHints (_audio_panel);
- _subtitle_sizer->Layout ();
- _subtitle_sizer->SetSizeHints (_subtitle_panel);
-
- _notebook->Fit ();
- Fit ();
-}
-
-void
-FilmEditor::still_duration_changed (wxCommandEvent &)
-{
- if (!_film) {
- return;
- }
-
- _film->set_still_duration (_still_duration->GetValue ());
-}
-
void
FilmEditor::trim_start_changed (wxCommandEvent &)
{
void
FilmEditor::setup_formats ()
{
- ContentType c = VIDEO;
-
- if (_film) {
- c = _film->content_type ();
- }
-
- _formats.clear ();
-
- vector<Format const *> fmt = Format::all ();
- for (vector<Format const *>::iterator i = fmt.begin(); i != fmt.end(); ++i) {
- if (c == VIDEO || (c == STILL && dynamic_cast<VariableFormat const *> (*i))) {
- _formats.push_back (*i);
- }
- }
+ _formats = Format::all ();
_format->Clear ();
for (vector<Format const *>::iterator i = _formats.begin(); i != _formats.end(); ++i) {
{
bool h = false;
if (_generally_sensitive && _film) {
- h = !_film->subtitle_streams().empty();
+// h = !_film->subtitle_streams().empty();
}
_with_subtitles->Enable (h);
j = _film->with_subtitles ();
}
- _subtitle_stream->Enable (j);
+ _ffmpeg_subtitle_stream->Enable (j);
_subtitle_offset->Enable (j);
_subtitle_scale->Enable (j);
}
-void
-FilmEditor::setup_audio_control_sensitivity ()
-{
- _use_content_audio->Enable (_generally_sensitive && _film && !_film->content_audio_streams().empty());
- _use_external_audio->Enable (_generally_sensitive);
-
- bool const source = _generally_sensitive && _use_content_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 &)
{
void
FilmEditor::setup_streams ()
{
- _audio_stream->Clear ();
- 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);
- assert (ffa);
- _audio_stream->Append (std_to_wx (ffa->name()), new wxStringClientData (std_to_wx (ffa->to_string ())));
- }
+// _ffmpeg_audio_stream->Clear ();
+ vector<FFmpegAudioStream> a;// = _film->content_audio_streams ();
+// for (vector<FFmpegAudioStream>::iterator i = a.begin(); i != a.end(); ++i) {
+// _audio_stream->Append (std_to_wx (ffa->name()), new wxStringClientData (std_to_wx (i->to_string ())));
+// }
- if (_film->use_content_audio() && _film->audio_stream()) {
- checked_set (_audio_stream, _film->audio_stream()->to_string());
- }
-
- _subtitle_stream->Clear ();
- 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()->to_string());
- } else {
- _subtitle_stream->SetSelection (wxNOT_FOUND);
- }
+// if (_film->use_content_audio() && _film->audio_stream()) {
+// checked_set (_audio_stream, _film->audio_stream()->to_string());
+// }
+
+ _ffmpeg_subtitle_stream->Clear ();
+// 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()->to_string());
+// } else {
+// _subtitle_stream->SetSelection (wxNOT_FOUND);
+// }
}
void
-FilmEditor::audio_stream_changed (wxCommandEvent &)
+FilmEditor::ffmpeg_audio_stream_changed (wxCommandEvent &)
{
if (!_film) {
return;
}
+#if 0
_film->set_content_audio_stream (
audio_stream_factory (
string_client_data (_audio_stream->GetClientObject (_audio_stream->GetSelection ())),
Film::state_version
)
);
+#endif
}
void
-FilmEditor::subtitle_stream_changed (wxCommandEvent &)
+FilmEditor::ffmpeg_subtitle_stream_changed (wxCommandEvent &)
{
if (!_film) {
return;
}
+#if 0
_film->set_subtitle_stream (
subtitle_stream_factory (
string_client_data (_subtitle_stream->GetClientObject (_subtitle_stream->GetSelection ())),
Film::state_version
)
);
+#endif
}
void
FilmEditor::setup_audio_details ()
{
+#if 0
if (!_film->content_audio_stream()) {
_audio->SetLabel (wxT (""));
} else {
s << ", " << _film->audio_stream()->sample_rate() << wx_to_std (_("Hz"));
_audio->SetLabel (std_to_wx (s.str ()));
}
+#endif
}
void
set_things_sensitive (!a);
}
-void
-FilmEditor::use_audio_changed (wxCommandEvent &)
-{
- _film->set_use_content_audio (_use_content_audio->GetValue());
-}
-
-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);
-}
-
void
FilmEditor::setup_dcp_name ()
{
return;
}
- _film->set_dcp_frame_rate (best_dcp_frame_rate (_film->source_frame_rate ()));
+// _film->set_dcp_frame_rate (best_dcp_frame_rate (_film->source_frame_rate ()));
}
void
FilmEditor::setup_show_audio_sensitivity ()
{
- _show_audio->Enable (_film && _film->has_audio ());
+// _show_audio->Enable (_film && _film->has_audio ());
+}
+
+void
+FilmEditor::setup_content ()
+{
+ _content->DeleteAllItems ();
+
+ list<shared_ptr<Content> > content = _film->content ();
+ for (list<shared_ptr<Content> >::iterator i = content.begin(); i != content.end(); ++i) {
+ _content->InsertItem (_content->GetItemCount(), std_to_wx ((*i)->summary ()));
+ }
}
+
#include "lib/film.h"
class wxNotebook;
+class wxListCtrl;
class Film;
class AudioDialog;
FilmEditor (boost::shared_ptr<Film>, wxWindow *);
void set_film (boost::shared_ptr<Film>);
- void setup_visibility ();
boost::signals2::signal<void (std::string)> FileChanged;
private:
void make_film_panel ();
+ void make_content_panel ();
void make_video_panel ();
void make_audio_panel ();
void make_subtitle_panel ();
void right_crop_changed (wxCommandEvent &);
void top_crop_changed (wxCommandEvent &);
void bottom_crop_changed (wxCommandEvent &);
- void content_changed (wxCommandEvent &);
void trust_content_header_changed (wxCommandEvent &);
void format_changed (wxCommandEvent &);
void trim_start_changed (wxCommandEvent &);
void subtitle_scale_changed (wxCommandEvent &);
void colour_lut_changed (wxCommandEvent &);
void j2k_bandwidth_changed (wxCommandEvent &);
- 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 &);
+ void ffmpeg_audio_stream_changed (wxCommandEvent &);
+ void ffmpeg_subtitle_stream_changed (wxCommandEvent &);
void dcp_frame_rate_changed (wxCommandEvent &);
void best_dcp_frame_rate_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 ();
void setup_dcp_name ();
void setup_show_audio_sensitivity ();
+ void setup_content ();
- wxControl* video_control (wxControl *);
- wxControl* still_control (wxControl *);
-
void active_jobs_changed (bool);
wxNotebook* _notebook;
wxPanel* _film_panel;
wxSizer* _film_sizer;
+ wxPanel* _content_panel;
+ wxSizer* _content_sizer;
wxPanel* _video_panel;
wxSizer* _video_sizer;
wxPanel* _audio_panel;
wxTextCtrl* _name;
wxStaticText* _dcp_name;
wxCheckBox* _use_dci_name;
+ wxListCtrl* _content;
+ wxButton* _content_add;
+ wxButton* _content_remove;
+ wxButton* _content_earlier;
+ wxButton* _content_later;
wxButton* _edit_dci_button;
- /** The Film's format */
wxChoice* _format;
wxStaticText* _format_description;
- /** The Film's content file */
- wxFilePickerCtrl* _content;
wxCheckBox* _trust_content_header;
- /** The Film's left crop */
wxSpinCtrl* _left_crop;
- /** The Film's right crop */
wxSpinCtrl* _right_crop;
- /** The Film's top crop */
wxSpinCtrl* _top_crop;
- /** The Film's bottom crop */
wxSpinCtrl* _bottom_crop;
- /** Currently-applied filters */
wxStaticText* _filters;
- /** Button to open the filters dialogue */
wxButton* _filters_button;
- /** The Film's scaler */
wxChoice* _scaler;
- wxRadioButton* _use_content_audio;
- wxChoice* _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 */
wxButton* _audio_gain_calculate_button;
wxButton* _show_audio;
- /** The Film's audio delay */
wxSpinCtrl* _audio_delay;
wxCheckBox* _with_subtitles;
- wxChoice* _subtitle_stream;
+ wxChoice* _ffmpeg_subtitle_stream;
wxSpinCtrl* _subtitle_offset;
wxSpinCtrl* _subtitle_scale;
wxChoice* _colour_lut;
wxSpinCtrl* _j2k_bandwidth;
- /** The Film's DCP content type */
wxChoice* _dcp_content_type;
- /** The Film's source frame rate */
wxStaticText* _source_frame_rate;
wxChoice* _dcp_frame_rate;
wxButton* _best_dcp_frame_rate;
wxStaticText* _frame_rate_description;
- /** The Film's original size */
wxStaticText* _original_size;
- /** The Film's length */
wxStaticText* _length;
/** The Film's audio details */
wxStaticText* _audio;
- /** The Film's duration for still sources */
- wxSpinCtrl* _still_duration;
wxSpinCtrl* _trim_start;
wxSpinCtrl* _trim_end;
/** Selector to generate an A/B comparison DCP */
wxCheckBox* _dcp_ab;
- std::list<wxControl*> _video_controls;
- std::list<wxControl*> _still_controls;
-
std::vector<Format const *> _formats;
bool _generally_sensitive;
}
_decoders.video->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3));
_decoders.video->OutputChanged.connect (boost::bind (&FilmViewer::decoder_changed, this));
- _decoders.video->set_subtitle_stream (_film->subtitle_stream());
+// _decoders.video->set_subtitle_stream (_film->subtitle_stream());
calculate_sizes ();
get_frame ();
_panel->Refresh ();
- _slider->Show (_film->content_type() == VIDEO);
- _play_button->Show (_film->content_type() == VIDEO);
_v_sizer->Layout ();
break;
}
break;
case Film::SUBTITLE_STREAM:
if (_decoders.video) {
- _decoders.video->set_subtitle_stream (_film->subtitle_stream ());
+// _decoders.video->set_subtitle_stream (_film->subtitle_stream ());
}
break;
default:
get_frame ();
- if (_film->length()) {
- int const new_slider_position = 4096 * _decoders.video->last_source_time() / (_film->length().get() / _film->source_frame_rate());
- if (new_slider_position != _slider->GetValue()) {
- _slider->SetValue (new_slider_position);
- }
- }
+// if (_film->length()) {
+// int const new_slider_position = 4096 * _decoders.video->last_source_time() / (_film->length().get() / _film->source_frame_rate());
+// if (new_slider_position != _slider->GetValue()) {
+// _slider->SetValue (new_slider_position);
+// }
+// }
}
void
FilmViewer::slider_moved (wxScrollEvent &)
{
- if (!_film || !_film->length() || !_decoders.video) {
- return;
- }
+// if (!_film || !_film->length() || !_decoders.video) {
+// return;
+// }
- if (_decoders.video->seek (_slider->GetValue() * _film->length().get() / (4096 * _film->source_frame_rate()))) {
- return;
- }
+// if (_decoders.video->seek (_slider->GetValue() * _film->length().get() / (4096 * _film->source_frame_rate()))) {
+// return;
+// }
get_frame ();
_panel->Refresh ();
_clear_required = true;
}
+#if 0
if (_raw_sub) {
/* Our output is already cropped by the decoder, so we need to account for that
} else {
_display_sub.reset ();
}
+#endif
}
void
of our _display_frame.
*/
_display_frame_x = 0;
- if (format) {
- _display_frame_x = static_cast<float> (format->dcp_padding (_film)) * _out_size.width / format->dcp_size().width;
- }
+// if (format) {
+// _display_frame_x = static_cast<float> (format->dcp_padding (_film)) * _out_size.width / format->dcp_size().width;
+// }
_film_size = _out_size;
_film_size.width -= _display_frame_x * 2;
}
if (_play_button->GetValue()) {
- _timer.Start (1000 / _film->source_frame_rate());
+// _timer.Start (1000 / _film->source_frame_rate());
} else {
_timer.Stop ();
}
_encoded = new ThreadedStaticText (this, _("counting..."), boost::bind (&PropertiesDialog::frames_already_encoded, this));
table->Add (_encoded, 1, wxALIGN_CENTER_VERTICAL);
+#if 0
if (_film->length()) {
_frames->SetLabel (std_to_wx (lexical_cast<string> (_film->length().get())));
FrameRateConversion frc (_film->source_frame_rate(), _film->dcp_frame_rate());
_frames->SetLabel (_("unknown"));
_disk->SetLabel (_("unknown"));
}
+#endif
wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
overall_sizer->Add (table, 0, wxALL, 6);
return "";
}
- if (_film->length()) {
- /* XXX: encoded_frames() should check which frames have been encoded */
- u << " (" << (_film->encoded_frames() * 100 / _film->length().get()) << "%)";
- }
+// if (_film->length()) {
+// /* XXX: encoded_frames() should check which frames have been encoded */
+// u << " (" << (_film->encoded_frames() * 100 / _film->length().get()) << "%)";
+// }
return u.str ();
}
BOOST_CHECK (f->filters ().empty());
f->set_name ("fred");
- BOOST_CHECK_THROW (f->set_content ("jim"), OpenFileError);
+// BOOST_CHECK_THROW (f->set_content ("jim"), OpenFileError);
f->set_dcp_content_type (DCPContentType::from_pretty_name ("Short"));
f->set_format (Format::from_nickname ("Flat"));
f->set_left_crop (1);
BOOST_CHECK_EQUAL (::system (s.str().c_str ()), 0);
}
-BOOST_AUTO_TEST_CASE (stream_test)
-{
- FFmpegAudioStream a ("ffmpeg 4 44100 1 hello there world", boost::optional<int> (1));
- BOOST_CHECK_EQUAL (a.id(), 4);
- BOOST_CHECK_EQUAL (a.sample_rate(), 44100);
- BOOST_CHECK_EQUAL (a.channel_layout(), 1);
- BOOST_CHECK_EQUAL (a.name(), "hello there world");
- BOOST_CHECK_EQUAL (a.to_string(), "ffmpeg 4 44100 1 hello there world");
-
- SndfileStream e ("external 44100 1", boost::optional<int> (1));
- BOOST_CHECK_EQUAL (e.sample_rate(), 44100);
- BOOST_CHECK_EQUAL (e.channel_layout(), 1);
- BOOST_CHECK_EQUAL (e.to_string(), "external 44100 1");
-
- SubtitleStream s ("5 a b c", boost::optional<int> (1));
- BOOST_CHECK_EQUAL (s.id(), 5);
- BOOST_CHECK_EQUAL (s.name(), "a b c");
-
- shared_ptr<AudioStream> ff = audio_stream_factory ("ffmpeg 4 44100 1 hello there world", boost::optional<int> (1));
- shared_ptr<FFmpegAudioStream> cff = dynamic_pointer_cast<FFmpegAudioStream> (ff);
- BOOST_CHECK (cff);
- BOOST_CHECK_EQUAL (cff->id(), 4);
- BOOST_CHECK_EQUAL (cff->sample_rate(), 44100);
- BOOST_CHECK_EQUAL (cff->channel_layout(), 1);
- BOOST_CHECK_EQUAL (cff->name(), "hello there world");
- BOOST_CHECK_EQUAL (cff->to_string(), "ffmpeg 4 44100 1 hello there world");
-
- shared_ptr<AudioStream> fe = audio_stream_factory ("external 44100 1", boost::optional<int> (1));
- BOOST_CHECK_EQUAL (fe->sample_rate(), 44100);
- BOOST_CHECK_EQUAL (fe->channel_layout(), 1);
- BOOST_CHECK_EQUAL (fe->to_string(), "external 44100 1");
-}
-
BOOST_AUTO_TEST_CASE (format_test)
{
Format::setup_formats ();
Format const * f = Format::from_nickname ("Flat");
BOOST_CHECK (f);
- BOOST_CHECK_EQUAL (f->ratio_as_integer(shared_ptr<const Film> ()), 185);
+// BOOST_CHECK_EQUAL (f->ratio_as_integer(shared_ptr<const Film> ()), 185);
f = Format::from_nickname ("Scope");
BOOST_CHECK (f);
- BOOST_CHECK_EQUAL (f->ratio_as_integer(shared_ptr<const Film> ()), 239);
+// BOOST_CHECK_EQUAL (f->ratio_as_integer(shared_ptr<const Film> ()), 239);
}
BOOST_AUTO_TEST_CASE (util_test)
BOOST_CHECK_THROW (md5_digest ("foobar"), OpenFileError);
}
-BOOST_AUTO_TEST_CASE (paths_test)
-{
- shared_ptr<Film> f = new_test_film ("paths_test");
- f->set_directory ("build/test/a/b/c/d/e");
-
- f->_content = "/foo/bar/baz";
- BOOST_CHECK_EQUAL (f->content_path(), "/foo/bar/baz");
- f->_content = "foo/bar/baz";
- BOOST_CHECK_EQUAL (f->content_path(), "build/test/a/b/c/d/e/foo/bar/baz");
-}
-
void
do_remote_encode (shared_ptr<DCPVideoFrame> frame, ServerDescription* description, shared_ptr<EncodedData> locally_encoded)
{
{
shared_ptr<Film> film = new_test_film ("make_dcp_test");
film->set_name ("test_film2");
- film->set_content ("../../../test/test.mp4");
+// film->set_content ("../../../test/test.mp4");
film->set_format (Format::from_nickname ("Flat"));
film->set_dcp_content_type (DCPContentType::from_pretty_name ("Test"));
film->make_dcp ();
{
shared_ptr<Film> film = new_test_film ("make_dcp_with_range_test");
film->set_name ("test_film3");
- film->set_content ("../../../test/test.mp4");
- film->examine_content ();
+// film->set_content ("../../../test/test.mp4");
+// film->examine_content ();
film->set_format (Format::from_nickname ("Flat"));
film->set_dcp_content_type (DCPContentType::from_pretty_name ("Test"));
film->set_trim_end (42);
Config::instance()->set_allowed_dcp_frame_rates (afr);
shared_ptr<Film> f = new_test_film ("audio_sampling_rate_test");
- f->set_source_frame_rate (24);
+// f->set_source_frame_rate (24);
f->set_dcp_frame_rate (24);
- f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 48000, 0)));
+// f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 48000, 0)));
BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 48000);
- f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 44100, 0)));
+// f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 44100, 0)));
BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 48000);
- f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 80000, 0)));
+// f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 80000, 0)));
BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 96000);
- f->set_source_frame_rate (23.976);
+// f->set_source_frame_rate (23.976);
f->set_dcp_frame_rate (best_dcp_frame_rate (23.976));
- f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 48000, 0)));
+// f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 48000, 0)));
BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 47952);
- f->set_source_frame_rate (29.97);
+// f->set_source_frame_rate (29.97);
f->set_dcp_frame_rate (best_dcp_frame_rate (29.97));
BOOST_CHECK_EQUAL (f->dcp_frame_rate (), 30);
- f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 48000, 0)));
+// f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 48000, 0)));
BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 47952);
- f->set_source_frame_rate (25);
+// f->set_source_frame_rate (25);
f->set_dcp_frame_rate (24);
- f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 48000, 0)));
+// f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 48000, 0)));
BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 50000);
- f->set_source_frame_rate (25);
+// f->set_source_frame_rate (25);
f->set_dcp_frame_rate (24);
- f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 44100, 0)));
+// f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 44100, 0)));
BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 50000);
/* Check some out-there conversions (not the best) */
- f->set_source_frame_rate (14.99);
+// f->set_source_frame_rate (14.99);
f->set_dcp_frame_rate (25);
- f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 16000, 0)));
+// f->set_content_audio_stream (shared_ptr<AudioStream> (new FFmpegAudioStream ("a", 42, 16000, 0)));
/* The FrameRateConversion within target_audio_sample_rate should choose to double-up
the 14.99 fps video to 30 and then run it slow at 25.
*/