* and distributed under the GPL.
*
* Video files are decoded using FFmpeg (http://ffmpeg.org), so any video
- * supported by FFmpeg should be usable with DVD-o-matic. Most testing has, however,
- * happened with files from DVD. DVD-o-matic's output has been tested on Christie
- * digital projectors with Doremi servers.
+ * supported by FFmpeg should be usable with DVD-o-matic. DVD-o-matic's output has been
+ * tested on numerous digital projectors.
*
* DVD-o-matic allows you to crop black borders from movies, scale them to the correct
* aspect ratio and apply FFmpeg filters. The time-consuming encoding of JPEG2000 files
*
* DVD-o-matic can also make DCPs from still images, for advertisements and such-like.
*
- * Portions of DVD-o-matic are based on OpenDCP (http://code.google.com/p/opendcp),
+ * Parts of DVD-o-matic are based on OpenDCP (http://code.google.com/p/opendcp),
* written by Terrence Meiczinger.
*
* DVD-o-matic uses libopenjpeg (http://code.google.com/p/openjpeg/) for JPEG2000 encoding
* and libsndfile (http://www.mega-nerd.com/libsndfile/) for WAV file manipulation. It
- * also makes heavy use of the boost libraries (http://www.boost.org/). libtiff
- * (http://www.libtiff.org/) is used for TIFF encoding and decoding, and the GUI is
+ * also makes heavy use of the boost libraries (http://www.boost.org/). ImageMagick
+ * (http://www.imagemagick.org/) is used for still-image encoding and decoding, and the GUI is
* built using wxWidgets (http://wxwidgets.org/). It also uses libmhash (http://mhash.sourceforge.net/)
* for debugging purposes.
*
*/
+/** @file src/lib/audio_decoder.h
+ * @brief Parent class for audio decoders.
+ */
+
#ifndef DVDOMATIC_AUDIO_DECODER_H
#define DVDOMATIC_AUDIO_DECODER_H
#include "stream.h"
#include "decoder.h"
+/** @class AudioDecoder.
+ * @brief Parent class for audio decoders.
+ */
class AudioDecoder : public AudioSource, public virtual Decoder
{
public:
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;
};
+/*
+ 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.
+
+*/
+
#ifndef DVDOMATIC_AUDIO_SINK_H
#define DVDOMATIC_AUDIO_SINK_H
*/
+/** @file src/audio_source.h
+ * @brief Parent class for classes which emit audio data.
+ */
+
#ifndef DVDOMATIC_AUDIO_SOURCE_H
#define DVDOMATIC_AUDIO_SOURCE_H
class AudioBuffers;
class AudioSink;
+/** A class that emits audio data */
class AudioSource
{
public:
}
+/** Process video for the left half of the frame.
+ * @param image Frame image.
+ * @param sub Subtitle (which will be ignored)
+ */
void
Combiner::process_video (shared_ptr<Image> image, shared_ptr<Subtitle> sub)
{
_image = image;
}
+/** Process video for the right half of the frame.
+ * @param image Frame image.
+ * @param sub Subtitle (which will be put onto the whole frame)
+ */
void
Combiner::process_video_b (shared_ptr<Image> image, shared_ptr<Subtitle> sub)
{
/* Copy the right half of this image into our _image */
+ /* XXX: this should probably be in the Image class */
for (int i = 0; i < image->components(); ++i) {
int const line_size = image->line_size()[i];
int const half_line_size = line_size / 2;
*/
+/** @file src/lib/combiner.h
+ * @brief Class for combining two video streams.
+ */
+
#include "processor.h"
+/** @class Combiner
+ * @brief A class which can combine two video streams into one, with
+ * one image used for the left half of the screen and the other for
+ * the right.
+ */
class Combiner : public VideoProcessor
{
public:
void process_video_b (boost::shared_ptr<Image> i, boost::shared_ptr<Subtitle> s);
private:
+ /** The image that we are currently working on */
boost::shared_ptr<Image> _image;
};
_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> ();
/** Emitted when some property has changed */
mutable boost::signals2::signal<void (Property)> Changed;
+ /** Current version number of the state file */
static int const state_version;
private:
has the specified filters and post-processing.
*/
bool _dcp_ab;
+ /** The audio stream to use from our content */
boost::shared_ptr<AudioStream> _content_audio_stream;
+ /** List of filenames of external audio files, in channel order
+ (L, R, C, Lfe, Ls, Rs)
+ */
std::vector<std::string> _external_audio;
+ /** true to use audio from our content file; false to use external audio */
bool _use_content_audio;
/** Gain to apply to audio in dB */
float _audio_gain;
boost::optional<SourceFrame> _length;
/** MD5 digest of our content file */
std::string _content_digest;
- /** the audio streams in our content */
+ /** The audio streams in our content */
std::vector<boost::shared_ptr<AudioStream> > _content_audio_streams;
+ /** A stream to represent possible external audio (will always exist) */
boost::shared_ptr<AudioStream> _external_audio_stream;
/** the subtitle streams that we can use */
std::vector<boost::shared_ptr<SubtitleStream> > _subtitle_streams;
/** Frames per second of the source */
float _frames_per_second;
+ /** true if our state has changed since we last saved it */
mutable bool _dirty;
/** Mutex for all state except _directory */
}
AlignedImage::AlignedImage (shared_ptr<Image> im)
- : SimpleImage (im->pixel_format(), im->size(), boost::bind (stride_round_up, _1, _2, 1))
+ : SimpleImage (im->pixel_format(), im->size(), boost::bind (stride_round_up, _1, _2, 32))
{
assert (components() == im->components());
int* _stride; ///< array of strides for each line (including any alignment padding bytes)
};
+/** @class AlignedImage
+ * @brief An image whose pixel data is padded so that rows always start on 32-byte boundaries.
+ */
class AlignedImage : public SimpleImage
{
public:
AlignedImage (boost::shared_ptr<Image>);
};
+/** @class CompactImage
+ * @brief An image whose pixel data is not padded, so rows may start at any pixel alignment.
+ */
class CompactImage : public SimpleImage
{
public:
*/
+/** @file src/processor.h
+ * @brief Parent class for classes which accept and then emit video or audio data.
+ */
+
#ifndef DVDOMATIC_PROCESSOR_H
#define DVDOMATIC_PROCESSOR_H
class Log;
+/** @class Processor
+ * @brief Base class for processors.
+ */
class Processor
{
public:
Log* _log;
};
+/** @class AudioVideoProcessor
+ * @brief A processor which handles both video and audio data.
+ */
class AudioVideoProcessor : public Processor, public VideoSource, public VideoSink, public AudioSource, public AudioSink
{
public:
{}
};
+/** @class AudioProcessor
+ * @brief A processor which handles just audio data.
+ */
class AudioProcessor : public Processor, public AudioSource, public AudioSink
{
public:
{}
};
+/** @class VideoProcessor
+ * @brief A processor which handles just video data.
+ */
class VideoProcessor : public Processor, public VideoSource, public VideoSink
{
public:
return lexical_cast<int> (i->second);
}
+/** Construct an AudioBuffers. Audio data is undefined after this constructor.
+ * @param channels Number of channels.
+ * @param frames Number of frames to reserve space for.
+ */
AudioBuffers::AudioBuffers (int channels, int frames)
: _channels (channels)
, _frames (frames)
}
}
+/** Copy constructor.
+ * @param other Other AudioBuffers; data is copied.
+ */
AudioBuffers::AudioBuffers (AudioBuffers const & other)
: _channels (other._channels)
, _frames (other._frames)
delete[] _data;
}
+/** @param c Channel index.
+ * @return Buffer for this channel.
+ */
float*
AudioBuffers::data (int c) const
{
assert (c >= 0 && c < _channels);
return _data[c];
}
-
+
+/** Set the number of frames that these AudioBuffers will report themselves
+ * as having.
+ * @param f Frames; must be less than or equal to the number of allocated frames.
+ */
void
AudioBuffers::set_frames (int f)
{
_frames = f;
}
+/** Make all samples on all channels silent */
void
AudioBuffers::make_silent ()
{
}
}
+/** Make all samples on a given channel silent.
+ * @param c Channel.
+ */
void
AudioBuffers::make_silent (int c)
{
+ assert (c >= 0 && c < _channels);
+
for (int i = 0; i < _frames; ++i) {
_data[c][i] = 0;
}
}
+/** Copy data from another AudioBuffers to this one. All channels are copied.
+ * @param from AudioBuffers to copy from; must have the same number of channels as this.
+ * @param frames_to_copy Number of frames to copy.
+ * @param read_offset Offset to read from in `from'.
+ * @param write_offset Offset to write to in `to'.
+ */
void
AudioBuffers::copy_from (AudioBuffers* from, int frames_to_copy, int read_offset, int write_offset)
{
assert (from->channels() == channels());
+ assert (from);
+ assert (read_offset >= 0 && (read_offset + frames_to_copy) <= from->_allocated_frames);
+ assert (write_offset >= 0 && (write_offset + frames_to_copy) <= _allocated_frames);
+
for (int i = 0; i < _channels; ++i) {
memcpy (_data[i] + write_offset, from->_data[i] + read_offset, frames_to_copy * sizeof(float));
}
}
+/** Move audio data around.
+ * @param from Offset to move from.
+ * @param to Offset to move to.
+ * @param frames Number of frames to move.
+ */
+
void
AudioBuffers::move (int from, int to, int frames)
{
}
}
+/** Trip an assert if the caller is not in the UI thread */
void
ensure_ui_thread ()
{
assert (this_thread::get_id() == ui_thread);
}
+/** @param v Source video frame.
+ * @param audio_sample_rate Source audio sample rate.
+ * @param frames_per_second Number of video frames per second.
+ * @return Equivalent number of audio frames for `v'.
+ */
int64_t
video_frames_to_audio_frames (SourceFrame v, float audio_sample_rate, float frames_per_second)
{
return ((int64_t) v * audio_sample_rate / frames_per_second);
}
+/** @param f Filename.
+ * @return true if this file is a still image, false if it is something else.
+ */
bool
still_image_file (string f)
{
int _buffer_data;
};
+/** @class AudioBuffers
+ * @brief A class to hold multi-channel audio data in float format.
+ */
class AudioBuffers
{
public:
void move (int from, int to, int frames);
private:
+ /** Number of channels */
int _channels;
+ /** Number of frames (where a frame is one sample across all channels) */
int _frames;
+ /** Number of frames that _data can hold */
int _allocated_frames;
+ /** Audio data (so that, e.g. _data[2][6] is channel 2, sample 6) */
float** _data;
};
*/
+/** @file src/video_source.h
+ * @brief Parent class for classes which emit video data.
+ */
+
#ifndef DVDOMATIC_VIDEO_SOURCE_H
#define DVDOMATIC_VIDEO_SOURCE_H
class Subtitle;
class Image;
+/** @class VideoSink
+ * @param A class that emits video data.
+ */
class VideoSource
{
public:
/** Emitted when a video frame is ready.
- * First parameter is the frame within the source.
+ * First parameter is the video image.
* Second parameter is either 0 or a subtitle that should be on this frame.
*/
boost::signals2::signal<void (boost::shared_ptr<Image>, boost::shared_ptr<Subtitle>)> Video;