/*
- Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#include "audio_analysis.h"
#include "cross.h"
#include "util.h"
#include <iostream>
#include <inttypes.h>
-using std::ostream;
-using std::istream;
-using std::string;
-using std::vector;
+
using std::cout;
+using std::dynamic_pointer_cast;
+using std::istream;
+using std::list;
+using std::make_pair;
+using std::make_shared;
using std::max;
+using std::ostream;
using std::pair;
-using std::make_pair;
-using std::list;
using std::shared_ptr;
+using std::string;
+using std::vector;
using boost::optional;
-using std::dynamic_pointer_cast;
using dcp::raw_convert;
using namespace dcpomatic;
+
int const AudioAnalysis::_current_state_version = 3;
+
AudioAnalysis::AudioAnalysis (int channels)
{
_data.resize (channels);
}
+
AudioAnalysis::AudioAnalysis (boost::filesystem::path filename)
{
cxml::Document f ("AudioAnalysis");
for (auto i: f.node_children ("SamplePeak")) {
_sample_peak.push_back (
- PeakTime (
+ PeakTime(
dcp::raw_convert<float>(i->content()), DCPTime(i->number_attribute<Frame>("Time"))
)
);
}
- for (auto i: f.node_children ("TruePeak")) {
- _true_peak.push_back (dcp::raw_convert<float> (i->content ()));
+ for (auto i: f.node_children("TruePeak")) {
+ _true_peak.push_back (dcp::raw_convert<float>(i->content()));
}
- _integrated_loudness = f.optional_number_child<float> ("IntegratedLoudness");
- _loudness_range = f.optional_number_child<float> ("LoudnessRange");
+ _integrated_loudness = f.optional_number_child<float>("IntegratedLoudness");
+ _loudness_range = f.optional_number_child<float>("LoudnessRange");
- _analysis_gain = f.optional_number_child<double> ("AnalysisGain");
- _samples_per_point = f.number_child<int64_t> ("SamplesPerPoint");
- _sample_rate = f.number_child<int64_t> ("SampleRate");
+ _analysis_gain = f.optional_number_child<double>("AnalysisGain");
+ _samples_per_point = f.number_child<int64_t>("SamplesPerPoint");
+ _sample_rate = f.number_child<int64_t>("SampleRate");
_leqm = f.optional_number_child<double>("Leqm");
}
+
void
AudioAnalysis::add_point (int c, AudioPoint const & p)
{
_data[c].push_back (p);
}
+
AudioPoint
AudioAnalysis::get_point (int c, int p) const
{
- DCPOMATIC_ASSERT (p < points (c));
+ DCPOMATIC_ASSERT (p < points(c));
return _data[c][p];
}
+
int
AudioAnalysis::channels () const
{
return _data.size ();
}
+
int
AudioAnalysis::points (int c) const
{
- DCPOMATIC_ASSERT (c < channels ());
+ DCPOMATIC_ASSERT (c < channels());
return _data[c].size ();
}
+
void
AudioAnalysis::write (boost::filesystem::path filename)
{
- shared_ptr<xmlpp::Document> doc (new xmlpp::Document);
+ auto doc = make_shared<xmlpp::Document>();
xmlpp::Element* root = doc->create_root_node ("AudioAnalysis");
- root->add_child("Version")->add_child_text (raw_convert<string> (_current_state_version));
+ root->add_child("Version")->add_child_text(raw_convert<string>(_current_state_version));
for (auto& i: _data) {
- xmlpp::Element* channel = root->add_child ("Channel");
+ auto channel = root->add_child ("Channel");
for (auto& j: i) {
j.as_xml (channel->add_child ("Point"));
}
}
for (size_t i = 0; i < _sample_peak.size(); ++i) {
- xmlpp::Element* n = root->add_child("SamplePeak");
+ auto n = root->add_child("SamplePeak");
n->add_child_text (raw_convert<string> (_sample_peak[i].peak));
n->set_attribute ("Time", raw_convert<string> (_sample_peak[i].time.get()));
}
doc->write_to_file_formatted (filename.string ());
}
+
float
AudioAnalysis::gain_correction (shared_ptr<const Playlist> playlist)
{
what correction is now needed to make it look `right'.
*/
DCPOMATIC_ASSERT (playlist->content().front()->audio);
- return playlist->content().front()->audio->gain() - analysis_gain().get ();
+ return playlist->content().front()->audio->gain() - analysis_gain().get();
}
return 0.0f;
}
+
/** @return Peak across all channels, and the channel number it is on */
pair<AudioAnalysis::PeakTime, int>
AudioAnalysis::overall_sample_peak () const
{
- DCPOMATIC_ASSERT (!_sample_peak.empty ());
+ DCPOMATIC_ASSERT (!_sample_peak.empty());
optional<PeakTime> pt;
int c = 0;
return make_pair (pt.get(), c);
}
+
optional<float>
AudioAnalysis::overall_true_peak () const
{
/*
- Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#ifndef DCPOMATIC_AUDIO_ANALYSIS_H
#define DCPOMATIC_AUDIO_ANALYSIS_H
+
#include "dcpomatic_time.h"
#include "audio_point.h"
#include <libcxml/cxml.h>
#include <boost/filesystem.hpp>
#include <vector>
+
namespace xmlpp {
class Element;
}
+
class Playlist;
+
class AudioAnalysis : public boost::noncopyable
{
public:
float gain_correction (std::shared_ptr<const Playlist> playlist);
private:
- std::vector<std::vector<AudioPoint> > _data;
+ std::vector<std::vector<AudioPoint>> _data;
std::vector<PeakTime> _sample_peak;
std::vector<float> _true_peak;
boost::optional<float> _integrated_loudness;
* happened.
*/
boost::optional<double> _analysis_gain;
- int64_t _samples_per_point;
- int _sample_rate;
+ int64_t _samples_per_point = 0;
+ int _sample_rate = 0;
static int const _current_state_version;
};
+
#endif
*/
+
#include "audio_decoder.h"
#include "audio_buffers.h"
#include "audio_content.h"
#include "i18n.h"
+
using std::cout;
using std::map;
using std::pair;
using boost::optional;
using namespace dcpomatic;
+
AudioDecoder::AudioDecoder (Decoder* parent, shared_ptr<const AudioContent> content, bool fast)
: DecoderPart (parent)
, _content (content)
}
}
+
/** @param time_already_delayed true if the delay should not be added to time */
void
AudioDecoder::emit (shared_ptr<const Film> film, AudioStreamPtr stream, shared_ptr<const AudioBuffers> data, ContentTime time, bool time_already_delayed)
shared_ptr<Resampler> resampler;
auto i = _resamplers.find(stream);
- if (i != _resamplers.end ()) {
+ if (i != _resamplers.end()) {
resampler = i->second;
} else {
if (stream->frame_rate() != resampled_rate) {
_positions[stream] += data->frames();
}
+
/** @return Time just after the last thing that was emitted from a given stream */
ContentTime
AudioDecoder::stream_position (shared_ptr<const Film> film, AudioStreamPtr stream) const
return ContentTime::from_frames (i->second, _content->resampled_frame_rate(film));
}
+
boost::optional<ContentTime>
AudioDecoder::position (shared_ptr<const Film> film) const
{
return p;
}
+
void
AudioDecoder::seek ()
{
}
}
+
void
AudioDecoder::flush ()
{
}
}
+
void
AudioDecoder::silence (int milliseconds)
{
*/
+
/** @file src/lib/audio_decoder.h
* @brief Parent class for audio decoders.
*/
+
#ifndef DCPOMATIC_AUDIO_DECODER_H
#define DCPOMATIC_AUDIO_DECODER_H
+
#include "decoder.h"
#include "content_audio.h"
#include "audio_stream.h"
#include "decoder_part.h"
#include <boost/signals2.hpp>
+
class AudioBuffers;
class AudioContent;
class AudioDecoderStream;
class Film;
class Resampler;
+
/** @class AudioDecoder.
* @brief Parent class for audio decoders.
*/
*/
typedef std::map<AudioStreamPtr, Frame> PositionMap;
PositionMap _positions;
- typedef std::map<AudioStreamPtr, std::shared_ptr<Resampler> > ResamplerMap;
+ typedef std::map<AudioStreamPtr, std::shared_ptr<Resampler>> ResamplerMap;
ResamplerMap _resamplers;
bool _fast;
};
+
#endif
/*
- Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#include "cross.h"
#include "compose.hpp"
#include "log.h"
#include "i18n.h"
+
using std::pair;
-using std::list;
-using std::ifstream;
-using std::string;
-using std::wstring;
-using std::make_pair;
-using std::vector;
using std::cerr;
using std::cout;
-using std::runtime_error;
+using std::ifstream;
+using std::list;
+using std::make_pair;
using std::map;
+using std::runtime_error;
using std::shared_ptr;
+using std::string;
+using std::vector;
+using std::wstring;
using boost::optional;
-static std::vector<pair<HANDLE, string> > locked_volumes;
+
+static std::vector<pair<HANDLE, string>> locked_volumes;
+
/** @param s Number of seconds to sleep for */
void
Sleep (s * 1000);
}
+
void
dcpomatic_sleep_milliseconds (int ms)
{
Sleep (ms);
}
+
/** @return A string of CPU information (model name etc.) */
string
cpu_info ()
return info;
}
+
void
run_ffprobe (boost::filesystem::path content, boost::filesystem::path out)
{
return;
}
- FILE* o = fopen_boost (out, "w");
+ auto o = fopen_boost (out, "w");
if (!o) {
LOG_ERROR_NC (N_("ffprobe call failed (could not create output file)"));
return;
CloseHandle (child_stderr_read);
}
-list<pair<string, string> >
+
+list<pair<string, string>>
mount_info ()
{
- list<pair<string, string> > m;
- return m;
+ return {};
}
return _wfopen (p.c_str(), w.c_str ());
}
+
int
dcpomatic_fseek (FILE* stream, int64_t offset, int whence)
{
return _fseeki64 (stream, offset, whence);
}
+
void
Waker::nudge ()
{
SetThreadExecutionState (ES_SYSTEM_REQUIRED);
}
+
Waker::Waker ()
{
}
+
Waker::~Waker ()
{
void
start_tool (string executable)
{
- boost::filesystem::path batch = directory_containing_executable() / executable;
+ auto batch = directory_containing_executable() / executable;
STARTUPINFO startup_info;
ZeroMemory (&startup_info, sizeof (startup_info));
return (uint64_t) GetCurrentThreadId ();
}
+
static string
wchar_to_utf8 (wchar_t const * s)
{
return u;
}
+
int
avio_open_boost (AVIOContext** s, boost::filesystem::path file, int flags)
{
return avio_open (s, wchar_to_utf8(file.c_str()).c_str(), flags);
}
+
void
maybe_open_console ()
{
if (Config::instance()->win32_console ()) {
AllocConsole();
- HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
+ auto handle_out = GetStdHandle(STD_OUTPUT_HANDLE);
int hCrt = _open_osfhandle((intptr_t) handle_out, _O_TEXT);
- FILE* hf_out = _fdopen(hCrt, "w");
+ auto hf_out = _fdopen(hCrt, "w");
setvbuf(hf_out, NULL, _IONBF, 1);
*stdout = *hf_out;
- HANDLE handle_in = GetStdHandle(STD_INPUT_HANDLE);
+ auto handle_in = GetStdHandle(STD_INPUT_HANDLE);
hCrt = _open_osfhandle((intptr_t) handle_in, _O_TEXT);
- FILE* hf_in = _fdopen(hCrt, "r");
+ auto hf_in = _fdopen(hCrt, "r");
setvbuf(hf_in, NULL, _IONBF, 128);
*stdin = *hf_in;
}
}
+
boost::filesystem::path
home_directory ()
{
return boost::filesystem::path(getenv("HOMEDRIVE")) / boost::filesystem::path(getenv("HOMEPATH"));
}
+
/** @return true if this process is a 32-bit one running on a 64-bit-capable OS */
bool
running_32_on_64 ()
return p;
}
+
static optional<string>
get_friendly_name (HDEVINFO device_info, SP_DEVINFO_DATA* device_info_data)
{
return wchar_to_utf8 (buffer);
}
+
static const GUID GUID_DEVICE_INTERFACE_DISK = {
0x53F56307L, 0xB6BF, 0x11D0, { 0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B }
};
+
static optional<int>
get_device_number (HDEVINFO device_info, SP_DEVINFO_DATA* device_info_data)
{
SP_DEVICE_INTERFACE_DATA device_interface_data;
device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
- BOOL r = SetupDiEnumDeviceInterfaces (device_info, device_info_data, &GUID_DEVICE_INTERFACE_DISK, 0, &device_interface_data);
+ auto r = SetupDiEnumDeviceInterfaces (device_info, device_info_data, &GUID_DEVICE_INTERFACE_DISK, 0, &device_interface_data);
if (!r) {
LOG_DISK("SetupDiEnumDeviceInterfaces failed (%1)", GetLastError());
return optional<int>();
/* Open it. We would not be allowed GENERIC_READ access here but specifying 0 for
dwDesiredAccess allows us to query some metadata.
*/
- HANDLE device = CreateFileW (
+ auto device = CreateFileW (
device_detail_data->DevicePath, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
OPEN_EXISTING, 0, 0
CloseHandle (device);
if (!r) {
- return optional<int>();
+ return {};
}
return device_number.DeviceNumber;
}
-typedef map<int, vector<boost::filesystem::path> > MountPoints;
+
+typedef map<int, vector<boost::filesystem::path>> MountPoints;
+
/** Take a volume path (with a trailing \) and add any disk numbers related to that volume
* to @ref disks.
DCPOMATIC_ASSERT (len > 0);
volume[len - 1] = L'\0';
- HANDLE handle = CreateFileW (
+ auto handle = CreateFileW (
volume, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
OPEN_EXISTING, 0, 0
mount_points[extents.Extents[0].DiskNumber] = mp;
}
+
MountPoints
find_mount_points ()
{
MountPoints mount_points;
wchar_t volume_name[512];
- HANDLE volume = FindFirstVolumeW (volume_name, sizeof(volume_name) / sizeof(wchar_t));
+ auto volume = FindFirstVolumeW (volume_name, sizeof(volume_name) / sizeof(wchar_t));
if (volume == INVALID_HANDLE_VALUE) {
return MountPoints();
}
return mount_points;
}
+
vector<Drive>
Drive::get ()
{
vector<Drive> drives;
- MountPoints mount_points = find_mount_points ();
+ auto mount_points = find_mount_points ();
/* Get a `device information set' containing information about all disks */
- HDEVINFO device_info = SetupDiGetClassDevsA (&GUID_DEVICE_INTERFACE_DISK, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+ auto device_info = SetupDiGetClassDevsA (&GUID_DEVICE_INTERFACE_DISK, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (device_info == INVALID_HANDLE_VALUE) {
LOG_DISK_NC ("SetupDiClassDevsA failed");
return drives;
}
++i;
- optional<string> const friendly_name = get_friendly_name (device_info, &device_info_data);
- optional<int> device_number = get_device_number (device_info, &device_info_data);
+ auto const friendly_name = get_friendly_name (device_info, &device_info_data);
+ auto device_number = get_device_number (device_info, &device_info_data);
if (!device_number) {
continue;
}
LOG_DISK("Having a look through %1 locked volumes", locked_volumes.size());
bool locked = false;
- for (vector<pair<HANDLE, string> >::const_iterator i = locked_volumes.begin(); i != locked_volumes.end(); ++i) {
- if (i->second == physical_drive) {
+ for (auto const& i: locked_volumes) {
+ if (i.second == physical_drive) {
locked = true;
}
}
return p;
}
+
void
disk_write_finished ()
{
- for (vector<pair<HANDLE, string> >::const_iterator i = locked_volumes.begin(); i != locked_volumes.end(); ++i) {
- CloseHandle (i->first);
+ for (auto const& i: locked_volumes) {
+ CloseHandle (i.first);
}
}
/*
- Copyright (C) 2014-2018 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
-#include "dcp.h"
-#include "config.h"
-#include "film.h"
-#include "log.h"
-#include "dcpomatic_log.h"
+
#include "compose.hpp"
+#include "dcp.h"
#include "dcp_content.h"
+#include "dcpomatic_log.h"
+#include "log.h"
+#include "util.h"
#include <dcp/dcp.h>
#include <dcp/decrypted_kdm.h>
#include <dcp/exceptions.h>
#include "i18n.h"
+
using std::list;
using std::string;
using std::shared_ptr;
/** Find all the CPLs in our directories, cross-add assets and return the CPLs */
-list<shared_ptr<dcp::CPL> >
+list<shared_ptr<dcp::CPL>>
DCP::cpls () const
{
list<shared_ptr<dcp::DCP>> dcps;
}
if (_dcp_content->kdm ()) {
- dcp::DecryptedKDM k = decrypt_kdm_with_helpful_error (_dcp_content->kdm().get());
+ auto k = decrypt_kdm_with_helpful_error (_dcp_content->kdm().get());
for (auto i: dcps) {
i->add (k);
}
*/
+
#ifndef DCPOMATIC_DCP_H
#define DCPOMATIC_DCP_H
-#include <dcp/cpl.h>
+
#include <list>
-#include <iostream>
+#include <memory>
+
+
+namespace dcp {
+ class CPL;
+}
+
class DCPContent;
+
class DCP
{
public:
- std::list<std::shared_ptr<dcp::CPL> > cpls () const;
+ std::list<std::shared_ptr<dcp::CPL>> cpls () const;
protected:
explicit DCP (std::shared_ptr<const DCPContent> content, bool tolerant)
bool _tolerant;
};
+
#endif
/*
- Copyright (C) 2014-2018 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
/** @file src/lib/dcpomatic_time.h
* @brief Types to describe time.
*/
+
#ifndef DCPOMATIC_TIME_H
#define DCPOMATIC_TIME_H
+
#include "frame_rate_change.h"
#include "dcpomatic_assert.h"
#include <boost/optional.hpp>
#include <iomanip>
#include <cstdio>
+
struct dcpomatic_time_ceil_test;
struct dcpomatic_time_floor_test;
+
namespace dcpomatic {
* @param r Sampling rate.
*/
Time<S, O> ceil (double r) const {
- return Time<S, O> (llrint (HZ * frames_ceil(r) / r));
+ return Time<S, O> (llrint(HZ * frames_ceil(r) / r));
}
Time<S, O> floor (double r) const {
- return Time<S, O> (llrint (HZ * frames_floor(r) / r));
+ return Time<S, O> (llrint(HZ * frames_floor(r) / r));
}
Time<S, O> round (double r) const {
- return Time<S, O> (llrint (HZ * frames_round(r) / r));
+ return Time<S, O> (llrint(HZ * frames_round(r) / r));
}
double seconds () const {
}
Time<S, O> abs () const {
- return Time<S, O> (std::abs (_t));
+ return Time<S, O> (std::abs(_t));
}
template <typename T>
return buffer;
}
-
static Time<S, O> from_seconds (double s) {
return Time<S, O> (llrint (s * HZ));
}
Type _t;
};
+
class ContentTimeDifferentiator {};
class DCPTimeDifferentiator {};
+
/* Specializations for the two allowed explicit conversions */
template<>
template<>
Time<DCPTimeDifferentiator, ContentTimeDifferentiator>::Time (Time<ContentTimeDifferentiator, DCPTimeDifferentiator> d, FrameRateChange f);
+
/** Time relative to the start or position of a piece of content in its native frame rate */
typedef Time<ContentTimeDifferentiator, DCPTimeDifferentiator> ContentTime;
/** Time relative to the start of the output DCP in its frame rate */
return TimePeriod<T> (from + o, to + o);
}
- boost::optional<TimePeriod<T> > overlap (TimePeriod<T> const & other) const {
+ boost::optional<TimePeriod<T>> overlap (TimePeriod<T> const & other) const {
T const max_from = std::max (from, other.from);
T const min_to = std::min (to, other.to);
if (max_from >= min_to) {
- return boost::optional<TimePeriod<T> > ();
+ return {};
}
return TimePeriod<T> (max_from, min_to);
}
};
+
/** @param A Period which is subtracted from.
* @param B Periods to subtract from `A', must be in ascending order of start time and must not overlap.
*/
template <class T>
-std::list<TimePeriod<T> > subtract (TimePeriod<T> A, std::list<TimePeriod<T> > const & B)
+std::list<TimePeriod<T>> subtract (TimePeriod<T> A, std::list<TimePeriod<T>> const & B)
{
- std::list<TimePeriod<T> > result;
+ std::list<TimePeriod<T>> result;
result.push_back (A);
for (auto i: B) {
- std::list<TimePeriod<T> > new_result;
+ std::list<TimePeriod<T>> new_result;
for (auto j: result) {
- boost::optional<TimePeriod<T> > ov = i.overlap (j);
+ auto ov = i.overlap (j);
if (ov) {
if (*ov == i) {
/* A contains all of B */
if (i.from != j.from) {
- new_result.push_back (TimePeriod<T> (j.from, i.from));
+ new_result.push_back (TimePeriod<T>(j.from, i.from));
}
if (i.to != j.to) {
- new_result.push_back (TimePeriod<T> (i.to, j.to));
+ new_result.push_back (TimePeriod<T>(i.to, j.to));
}
} else if (*ov == j) {
/* B contains all of A */
} else if (i.from < j.from) {
/* B overlaps start of A */
- new_result.push_back (TimePeriod<T> (i.to, j.to));
+ new_result.push_back (TimePeriod<T>(i.to, j.to));
} else if (i.to > j.to) {
/* B overlaps end of A */
- new_result.push_back (TimePeriod<T> (j.from, i.from));
+ new_result.push_back (TimePeriod<T>(j.from, i.from));
}
} else {
new_result.push_back (j);
return result;
}
+
typedef TimePeriod<ContentTime> ContentTimePeriod;
typedef TimePeriod<DCPTime> DCPTimePeriod;
+
DCPTime min (DCPTime a, DCPTime b);
DCPTime max (DCPTime a, DCPTime b);
ContentTime min (ContentTime a, ContentTime b);
std::string to_string (DCPTime t);
std::string to_string (DCPTimePeriod p);
+
}
+
#endif
/*
- Copyright (C) 2017 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2017-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#include "dcpomatic_time.h"
#include <iostream>
+
namespace dcpomatic {
+
/** @param periods Set of periods in ascending order of from time */
template <class T>
-std::list<TimePeriod<T> > coalesce (std::list<TimePeriod<T> > periods)
+std::list<TimePeriod<T>> coalesce (std::list<TimePeriod<T>> periods)
{
bool did_something;
- std::list<TimePeriod<T> > coalesced;
+ std::list<TimePeriod<T>> coalesced;
do {
coalesced.clear ();
did_something = false;
return periods;
}
+
}
/*
- Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#include "dcpomatic_log.h"
#include "ffmpeg_examiner.h"
#include "ffmpeg_content.h"
#include "i18n.h"
-using std::string;
+
using std::cout;
+using std::make_shared;
using std::max;
-using std::vector;
using std::shared_ptr;
+using std::string;
+using std::vector;
using boost::optional;
using namespace dcpomatic;
/* Find audio and subtitle streams */
for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
- AVStream* s = _format_context->streams[i];
+ auto s = _format_context->streams[i];
DCPOMATIC_DISABLE_WARNINGS
if (s->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
DCPOMATIC_ASSERT (s->codec->codec->name);
_audio_streams.push_back (
- shared_ptr<FFmpegAudioStream> (
- new FFmpegAudioStream (
- stream_name (s),
- s->codec->codec->name,
- s->id,
- s->codec->sample_rate,
- llrint ((double (_format_context->duration) / AV_TIME_BASE) * s->codec->sample_rate),
- s->codec->channels
- )
+ make_shared<FFmpegAudioStream>(
+ stream_name (s),
+ s->codec->codec->name,
+ s->id,
+ s->codec->sample_rate,
+ llrint ((double(_format_context->duration) / AV_TIME_BASE) * s->codec->sample_rate),
+ s->codec->channels
)
);
return av_q2d(av_guess_frame_rate(_format_context, _format_context->streams[_video_stream.get()], 0));
}
+
dcp::Size
FFmpegExaminer::video_size () const
{
return dcp::Size (video_codec_context()->width, video_codec_context()->height);
}
+
/** @return Length according to our content's header */
Frame
FFmpegExaminer::video_length () const
return max (Frame (1), _video_length);
}
+
optional<double>
FFmpegExaminer::sample_aspect_ratio () const
{
DCPOMATIC_ASSERT (_video_stream);
- AVRational sar = av_guess_sample_aspect_ratio (_format_context, _format_context->streams[_video_stream.get()], 0);
+ auto sar = av_guess_sample_aspect_ratio (_format_context, _format_context->streams[_video_stream.get()], 0);
if (sar.num == 0) {
/* I assume this means that we don't know */
return {};
return double (sar.num) / sar.den;
}
+
string
FFmpegExaminer::subtitle_stream_name (AVStream* s) const
{
return n;
}
+
string
FFmpegExaminer::stream_name (AVStream* s) const
{
string n;
if (s->metadata) {
- AVDictionaryEntry const * lang = av_dict_get (s->metadata, "language", 0, 0);
+ auto const lang = av_dict_get (s->metadata, "language", 0, 0);
if (lang) {
n = lang->value;
}
- AVDictionaryEntry const * title = av_dict_get (s->metadata, "title", 0, 0);
+ auto const title = av_dict_get (s->metadata, "title", 0, 0);
if (title) {
if (!n.empty()) {
n += " ";
return n;
}
+
optional<int>
FFmpegExaminer::bits_per_pixel () const
{
if (video_codec_context()->pix_fmt == -1) {
- return optional<int>();
+ return {};
}
- AVPixFmtDescriptor const * d = av_pix_fmt_desc_get (video_codec_context()->pix_fmt);
+ auto const d = av_pix_fmt_desc_get (video_codec_context()->pix_fmt);
DCPOMATIC_ASSERT (d);
return av_get_bits_per_pixel (d);
}
+
bool
FFmpegExaminer::yuv () const
{
}
}
+
bool
FFmpegExaminer::has_video () const
{
- return static_cast<bool> (_video_stream);
+ return static_cast<bool>(_video_stream);
}
+
VideoRange
FFmpegExaminer::range () const
{
*/
+
#include "ffmpeg.h"
#include "video_examiner.h"
#include <boost/optional.hpp>
-struct AVStream;
+struct AVStream;
class FFmpegAudioStream;
class FFmpegSubtitleStream;
class Job;
+
class FFmpegExaminer : public FFmpeg, public VideoExaminer
{
public:
- FFmpegExaminer (std::shared_ptr<const FFmpegContent>, std::shared_ptr<Job> job = std::shared_ptr<Job> ());
+ FFmpegExaminer (std::shared_ptr<const FFmpegContent>, std::shared_ptr<Job> job = std::shared_ptr<Job>());
bool has_video () const;
boost::optional<double> sample_aspect_ratio () const;
bool yuv () const;
- std::vector<std::shared_ptr<FFmpegSubtitleStream> > subtitle_streams () const {
+ std::vector<std::shared_ptr<FFmpegSubtitleStream>> subtitle_streams () const {
return _subtitle_streams;
}
- std::vector<std::shared_ptr<FFmpegAudioStream> > audio_streams () const {
+ std::vector<std::shared_ptr<FFmpegAudioStream>> audio_streams () const {
return _audio_streams;
}
std::string subtitle_stream_name (AVStream* s) const;
boost::optional<dcpomatic::ContentTime> frame_time (AVStream* s) const;
- std::vector<std::shared_ptr<FFmpegSubtitleStream> > _subtitle_streams;
- std::vector<std::shared_ptr<FFmpegAudioStream> > _audio_streams;
+ std::vector<std::shared_ptr<FFmpegSubtitleStream>> _subtitle_streams;
+ std::vector<std::shared_ptr<FFmpegAudioStream>> _audio_streams;
boost::optional<dcpomatic::ContentTime> _first_video;
/** Video length, either obtained from the header or derived by running
* through the whole file.
dcpomatic::ContentTime time;
};
- typedef std::map<std::shared_ptr<FFmpegSubtitleStream>, boost::optional<SubtitleStart> > LastSubtitleMap;
+ typedef std::map<std::shared_ptr<FFmpegSubtitleStream>, boost::optional<SubtitleStart>> LastSubtitleMap;
LastSubtitleMap _last_subtitle_start;
};
/*
- Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
/** @file src/j2k_encoder.cc
* @brief J2K encoder class.
*/
+
#include "j2k_encoder.h"
#include "util.h"
#include "film.h"
#include "i18n.h"
+
using std::list;
using std::cout;
using std::exception;
using dcp::Data;
using namespace dcpomatic;
+
/** @param film Film that we are encoding.
* @param writer Writer that we are using.
*/
servers_list_changed ();
}
+
J2KEncoder::~J2KEncoder ()
{
boost::mutex::scoped_lock lm (_threads_mutex);
terminate_threads ();
}
+
void
J2KEncoder::begin ()
{
- weak_ptr<J2KEncoder> wp = shared_from_this ();
+ auto wp = shared_from_this ();
_server_found_connection = EncodeServerFinder::instance()->ServersListChanged.connect (
boost::bind (&J2KEncoder::call_servers_list_changed, wp)
);
}
+
/* We don't want the servers-list-changed callback trying to do things
during destruction of J2KEncoder, and I think this is the neatest way
to achieve that.
}
}
+
void
J2KEncoder::end ()
{
}
}
+
/** @return an estimate of the current number of frames we are encoding per second,
* if known.
*/
return _history.rate ();
}
+
/** @return Number of video frames that have been queued for encoding */
int
J2KEncoder::video_frames_enqueued () const
return _last_player_video_time->frames_floor (_film->video_frame_rate ());
}
+
/** Should be called when a frame has been encoded successfully */
void
J2KEncoder::frame_done ()
_history.event ();
}
+
/** Called to request encoding of the next video frame in the DCP. This is called in order,
* so each time the supplied frame is the one after the previous one.
* pv represents one video frame, and could be empty if there is nothing to encode
_threads.reset ();
}
+
void
J2KEncoder::encoder_thread (optional<EncodeServerDescription> server)
try
_full_condition.notify_all ();
}
+
void
J2KEncoder::servers_list_changed ()
{
/*
- Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#ifndef DCPOMATIC_J2K_ENCODER_H
#define DCPOMATIC_J2K_ENCODER_H
+
/** @file src/j2k_encoder.h
* @brief J2KEncoder class.
*/
+
#include "util.h"
#include "cross.h"
#include "event_history.h"
#include <list>
#include <stdint.h>
+
class Film;
class EncodeServerDescription;
class DCPVideo;
class Job;
class PlayerVideo;
+
/** @class J2KEncoder
* @brief Class to manage encoding to J2K.
*
* This class keeps a queue of frames to be encoded and distributes
* the work around threads and encoding servers.
*/
-
class J2KEncoder : public boost::noncopyable, public ExceptionStore, public std::enable_shared_from_this<J2KEncoder>
{
public:
std::shared_ptr<boost::thread_group> _threads;
mutable boost::mutex _queue_mutex;
- std::list<std::shared_ptr<DCPVideo> > _queue;
+ std::list<std::shared_ptr<DCPVideo>> _queue;
/** condition to manage thread wakeups when we have nothing to do */
boost::condition _empty_condition;
/** condition to manage thread wakeups when we have too much to do */
boost::signals2::scoped_connection _server_found_connection;
};
+
#endif
/*
- Copyright (C) 2014-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#include "json_server.h"
#include "job_manager.h"
#include "job.h"
#include <boost/thread.hpp>
#include <iostream>
+
using std::string;
using std::cout;
using std::map;
using boost::asio::ip::tcp;
using dcp::raw_convert;
+
#define MAX_LENGTH 512
+
enum State {
AWAITING_G,
AWAITING_E,
READING_URL,
};
+
JSONServer::JSONServer (int port)
{
#ifdef DCPOMATIC_LINUX
- thread* t = new thread (boost::bind (&JSONServer::run, this, port));
+ auto t = new thread (boost::bind (&JSONServer::run, this, port));
pthread_setname_np (t->native_handle(), "json-server");
#else
new thread (boost::bind (&JSONServer::run, this, port));
#endif
}
+
void
JSONServer::run (int port)
try
}
+
void
JSONServer::handle (shared_ptr<tcp::socket> socket)
{
break;
}
- char* p = data;
- char* e = data + len;
+ auto p = data;
+ auto e = data + len;
while (p != e) {
- State old_state = state;
+ auto old_state = state;
switch (state) {
case AWAITING_G:
if (*p == 'G') {
}
}
+
void
JSONServer::request (string url, shared_ptr<tcp::socket> socket)
{
cout << "request: " << url << "\n";
- map<string, string> r = split_get_request (url);
- for (map<string, string>::iterator i = r.begin(); i != r.end(); ++i) {
- cout << i->first << " => " << i->second << "\n";
+ auto r = split_get_request (url);
+ for (auto const& i: r) {
+ cout << i.first << " => " << i.second << "\n";
}
string action;
string json;
if (action == "status") {
- list<shared_ptr<Job> > jobs = JobManager::instance()->get ();
+ auto jobs = JobManager::instance()->get();
json += "{ \"jobs\": [";
- for (list<shared_ptr<Job> >::iterator i = jobs.begin(); i != jobs.end(); ++i) {
-
+ for (auto i = jobs.cbegin(); i != jobs.cend(); ++i) {
json += "{ ";
if ((*i)->film()) {
}
json += "\"name\": \"" + (*i)->json_name() + "\", ";
- if ((*i)->progress ()) {
+ if ((*i)->progress()) {
json += "\"progress\": " + raw_convert<string>((*i)->progress().get()) + ", ";
} else {
json += "\"progress\": unknown, ";
json += "\"status\": \"" + (*i)->json_status() + "\"";
json += " }";
- list<shared_ptr<Job> >::iterator j = i;
+ auto j = i;
++j;
if (j != jobs.end ()) {
json += ", ";
"\r\n"
+ json + "\r\n";
cout << "reply: " << json << "\n";
- boost::asio::write (*socket, boost::asio::buffer (reply.c_str(), reply.length()));
+ boost::asio::write (*socket, boost::asio::buffer(reply.c_str(), reply.length()));
}
/*
- Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#include "kdm_with_metadata.h"
#include "cinema.h"
#include "screen.h"
#include "i18n.h"
+
using std::string;
using std::cout;
using std::list;
using boost::optional;
using boost::function;
+
int
write_files (
list<KDMWithMetadataPtr> kdms,
/* Write KDMs to the specified directory */
for (auto i: kdms) {
- boost::filesystem::path out = directory / careful_string_filter(name_format.get(i->name_values(), ".xml"));
+ auto out = directory / careful_string_filter(name_format.get(i->name_values(), ".xml"));
if (!boost::filesystem::exists (out) || confirm_overwrite (out)) {
i->kdm_as_xml (out);
++written;
optional<string>
KDMWithMetadata::get (char k) const
{
- dcp::NameFormat::Map::const_iterator i = _name_values.find (k);
+ auto i = _name_values.find (k);
if (i == _name_values.end()) {
- return optional<string>();
+ return {};
}
return i->second;
Zipper zipper (zip_file);
for (auto i: kdms) {
- string const name = careful_string_filter(name_format.get(i->name_values(), ".xml"));
+ auto const name = careful_string_filter(name_format.get(i->name_values(), ".xml"));
zipper.add (name, i->kdm_as_xml());
}
/** Collect a list of KDMWithMetadatas into a list of lists so that
* each list contains the KDMs for one list.
*/
-list<list<KDMWithMetadataPtr> >
+list<list<KDMWithMetadataPtr>>
collect (list<KDMWithMetadataPtr> kdms)
{
- list<list<KDMWithMetadataPtr> > grouped;
+ list<list<KDMWithMetadataPtr>> grouped;
for (auto i: kdms) {
- list<list<KDMWithMetadataPtr> >::iterator j = grouped.begin ();
+ auto j = grouped.begin ();
while (j != grouped.end()) {
if (j->front()->group() == i->group()) {
/** Write one directory per list into another directory */
int
write_directories (
- list<list<KDMWithMetadataPtr> > kdms,
+ list<list<KDMWithMetadataPtr>> kdms,
boost::filesystem::path directory,
dcp::NameFormat container_name_format,
dcp::NameFormat filename_format,
/** Write one ZIP file per cinema into a directory */
int
write_zip_files (
- list<list<KDMWithMetadataPtr> > kdms,
+ list<list<KDMWithMetadataPtr>> kdms,
boost::filesystem::path directory,
dcp::NameFormat container_name_format,
dcp::NameFormat filename_format,
int written = 0;
for (auto const& i: kdms) {
- boost::filesystem::path path = directory;
+ auto path = directory;
path /= container_name_format.get(i.front()->name_values(), ".zip", "s");
if (!boost::filesystem::exists (path) || confirm_overwrite (path)) {
if (boost::filesystem::exists (path)) {
*/
void
email (
- list<list<KDMWithMetadataPtr> > kdms,
+ list<list<KDMWithMetadataPtr>> kdms,
dcp::NameFormat container_name_format,
dcp::NameFormat filename_format,
string cpl_name
)
{
- Config* config = Config::instance ();
+ auto config = Config::instance ();
if (config->mail_server().empty()) {
throw NetworkError (_("No mail server configured in preferences"));
continue;
}
- boost::filesystem::path zip_file = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
+ auto zip_file = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
boost::filesystem::create_directories (zip_file);
zip_file /= container_name_format.get(i.front()->name_values(), ".zip");
make_zip_file (i, zip_file, filename_format);
- string subject = config->kdm_subject();
+ auto subject = config->kdm_subject();
boost::algorithm::replace_all (subject, "$CPL_NAME", cpl_name);
boost::algorithm::replace_all (subject, "$START_TIME", i.front()->get('b').get_value_or(""));
boost::algorithm::replace_all (subject, "$END_TIME", i.front()->get('e').get_value_or(""));
boost::algorithm::replace_all (subject, "$CINEMA_NAME", i.front()->get('c').get_value_or(""));
- string body = config->kdm_email().c_str();
+ auto body = config->kdm_email();
boost::algorithm::replace_all (body, "$CPL_NAME", cpl_name);
boost::algorithm::replace_all (body, "$START_TIME", i.front()->get('b').get_value_or(""));
boost::algorithm::replace_all (body, "$END_TIME", i.front()->get('e').get_value_or(""));
string screens;
for (auto j: i) {
- optional<string> screen_name = j->get('n');
+ auto screen_name = j->get('n');
if (screen_name) {
screens += *screen_name + ", ";
}
for (auto i: config->kdm_cc()) {
email.add_cc (i);
}
- if (!config->kdm_bcc().empty ()) {
- email.add_bcc (config->kdm_bcc ());
+ if (!config->kdm_bcc().empty()) {
+ email.add_bcc (config->kdm_bcc());
}
email.add_attachment (zip_file, container_name_format.get(i.front()->name_values(), ".zip"), "application/zip");
- Config* c = Config::instance ();
-
try {
- email.send (c->mail_server(), c->mail_port(), c->mail_protocol(), c->mail_user(), c->mail_password());
+ email.send (config->mail_server(), config->mail_port(), config->mail_protocol(), config->mail_user(), config->mail_password());
} catch (...) {
boost::filesystem::remove (zip_file);
dcpomatic_log->log ("Email content follows", LogEntry::TYPE_DEBUG_EMAIL);
/*
- Copyright (C) 2013-2019 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#ifndef DCPOMATIC_KDM_WITH_METADATA_H
#define DCPOMATIC_KDM_WITH_METADATA_H
+
#include <dcp/encrypted_kdm.h>
#include <dcp/name_format.h>
+
class Cinema;
+
class KDMWithMetadata
{
public:
void make_zip_file (std::list<KDMWithMetadataPtr> kdms, boost::filesystem::path zip_file, dcp::NameFormat name_format);
-std::list<std::list<KDMWithMetadataPtr> > collect (std::list<KDMWithMetadataPtr> kdms);
+std::list<std::list<KDMWithMetadataPtr>> collect (std::list<KDMWithMetadataPtr> kdms);
int write_directories (
- std::list<std::list<KDMWithMetadataPtr> > kdms,
+ std::list<std::list<KDMWithMetadataPtr>> kdms,
boost::filesystem::path directory,
dcp::NameFormat container_name_format,
dcp::NameFormat filename_format,
int write_zip_files (
- std::list<std::list<KDMWithMetadataPtr> > kdms,
+ std::list<std::list<KDMWithMetadataPtr>> kdms,
boost::filesystem::path directory,
dcp::NameFormat container_name_format,
dcp::NameFormat filename_format,
void email (
- std::list<std::list<KDMWithMetadataPtr> > kdms,
+ std::list<std::list<KDMWithMetadataPtr>> kdms,
dcp::NameFormat container_name_format,
dcp::NameFormat filename_format,
std::string cpl_name
{
public:
void add_fonts (std::list<std::shared_ptr<dcpomatic::Font>> fonts_);
- std::list<std::shared_ptr<dcpomatic::Font> > fonts;
+ std::list<std::shared_ptr<dcpomatic::Font>> fonts;
/** BitmapTexts, with their rectangles transformed as specified by their content */
std::list<BitmapText> bitmap;
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#ifndef DCPOMATIC_RECT_H
#define DCPOMATIC_RECT_H
+
#include "position.h"
#include <boost/optional.hpp>
#include <algorithm>
+
/* Put this inside a namespace as Apple put a Rect in the global namespace */
namespace dcpomatic
{
+
/** @struct Rect
* @brief A rectangle.
*/
return Position<T> (x, y);
}
- boost::optional<Rect<T> > intersection (Rect<T> const & other) const
+ boost::optional<Rect<T>> intersection (Rect<T> const & other) const
{
/* This isn't exactly the paragon of mathematical precision */
);
if (r.width < 0 || r.height < 0) {
- return boost::optional<Rect<T> > ();
+ return {};
}
return r;
}
};
+
}
+
#endif
/*
- Copyright (C) 2014-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2014-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
-#include "render_text.h"
-#include "types.h"
-#include "image.h"
+
#include "cross.h"
-#include "font.h"
#include "dcpomatic_assert.h"
-#include "warnings.h"
+#include "font.h"
+#include "image.h"
+#include "render_text.h"
+#include "types.h"
#include "util.h"
+#include "warnings.h"
#include <dcp/raw_convert.h>
#include <fontconfig/fontconfig.h>
#include <cairomm/cairomm.h>
#include <boost/algorithm/string.hpp>
#include <iostream>
-using std::list;
+
+using std::cerr;
using std::cout;
-using std::string;
-using std::min;
+using std::list;
+using std::make_pair;
+using std::make_shared;
using std::max;
+using std::min;
using std::pair;
-using std::cerr;
-using std::make_pair;
using std::shared_ptr;
+using std::string;
using boost::optional;
using boost::algorithm::replace_all;
using namespace dcpomatic;
-static FcConfig* fc_config = 0;
-static list<pair<boost::filesystem::path, string> > fc_config_fonts;
+
+static FcConfig* fc_config = nullptr;
+static list<pair<boost::filesystem::path, string>> fc_config_fonts;
+
string
marked_up (list<StringText> subtitles, int target_height, float fade_factor)
return out;
}
+
static void
set_source_rgba (Cairo::RefPtr<Cairo::Context> context, dcp::Colour colour, float fade_factor)
{
create_image (dcp::Size size)
{
/* FFmpeg BGRA means first byte blue, second byte green, third byte red, fourth byte alpha */
- shared_ptr<Image> image (new Image(AV_PIX_FMT_BGRA, size, false));
+ auto image = make_shared<Image>(AV_PIX_FMT_BGRA, size, false);
image->make_black ();
return image;
}
create_surface (shared_ptr<Image> image)
{
#ifdef DCPOMATIC_HAVE_FORMAT_STRIDE_FOR_WIDTH
- Cairo::RefPtr<Cairo::ImageSurface> surface = Cairo::ImageSurface::create (
+ auto surface = Cairo::ImageSurface::create (
image->data()[0],
Cairo::FORMAT_ARGB32,
image->size().width,
/* Centos 5 does not have Cairo::ImageSurface::format_stride_for_width, so just use width * 4
which I hope is safe (if slow)
*/
- Cairo::RefPtr<Cairo::ImageSurface> surface = Cairo::ImageSurface::create (
+ auto surface = Cairo::ImageSurface::create (
image->data()[0],
Cairo::FORMAT_ARGB32,
image->size().width,
static string
-setup_font (StringText const& subtitle, list<shared_ptr<Font> > const& fonts)
+setup_font (StringText const& subtitle, list<shared_ptr<Font>> const& fonts)
{
if (!fc_config) {
fc_config = FcInitLoadConfig ();
}
- optional<boost::filesystem::path> font_file = default_font_file ();
+ auto font_file = default_font_file ();
for (auto i: fonts) {
if (i->id() == subtitle.font() && i->file()) {
- font_file = i->file ();
+ font_file = i->file().get();
}
}
- list<pair<boost::filesystem::path, string> >::const_iterator existing = fc_config_fonts.begin ();
- while (existing != fc_config_fonts.end() && existing->first != *font_file) {
+ auto existing = fc_config_fonts.cbegin ();
+ while (existing != fc_config_fonts.end() && existing->first != font_file) {
++existing;
}
font_name = existing->second;
} else {
/* Make this font available to DCP-o-matic */
- FcConfigAppFontAddFile (fc_config, reinterpret_cast<FcChar8 const *>(font_file->string().c_str()));
- FcPattern* pattern = FcPatternBuild (
- 0, FC_FILE, FcTypeString, font_file->string().c_str(), static_cast<char *> (0)
+ FcConfigAppFontAddFile (fc_config, reinterpret_cast<FcChar8 const *>(font_file.string().c_str()));
+ auto pattern = FcPatternBuild (
+ 0, FC_FILE, FcTypeString, font_file.string().c_str(), static_cast<char *>(0)
);
- FcObjectSet* object_set = FcObjectSetBuild (FC_FAMILY, FC_STYLE, FC_LANG, FC_FILE, static_cast<char *> (0));
- FcFontSet* font_set = FcFontList (fc_config, pattern, object_set);
+ auto object_set = FcObjectSetBuild (FC_FAMILY, FC_STYLE, FC_LANG, FC_FILE, static_cast<char *> (0));
+ auto font_set = FcFontList (fc_config, pattern, object_set);
if (font_set) {
for (int i = 0; i < font_set->nfont; ++i) {
FcPattern* font = font_set->fonts[i];
FcObjectSetDestroy (object_set);
FcPatternDestroy (pattern);
- fc_config_fonts.push_back (make_pair(*font_file, font_name));
+ fc_config_fonts.push_back (make_pair(font_file, font_name));
}
FcConfigSetCurrent (fc_config);
/* Round the fade start/end to the nearest frame start. Otherwise if a subtitle starts just after
the start of a frame it will be faded out.
*/
- DCPTime const fade_in_start = DCPTime::from_seconds(first.in().as_seconds()).round(frame_rate);
- DCPTime const fade_in_end = fade_in_start + DCPTime::from_seconds (first.fade_up_time().as_seconds ());
- DCPTime const fade_out_end = DCPTime::from_seconds (first.out().as_seconds()).round(frame_rate);
- DCPTime const fade_out_start = fade_out_end - DCPTime::from_seconds (first.fade_down_time().as_seconds ());
+ auto const fade_in_start = DCPTime::from_seconds(first.in().as_seconds()).round(frame_rate);
+ auto const fade_in_end = fade_in_start + DCPTime::from_seconds (first.fade_up_time().as_seconds ());
+ auto const fade_out_end = DCPTime::from_seconds (first.out().as_seconds()).round(frame_rate);
+ auto const fade_out_start = fade_out_end - DCPTime::from_seconds (first.fade_down_time().as_seconds ());
if (fade_in_start <= time && time <= fade_in_end && fade_in_start != fade_in_end) {
fade_factor *= DCPTime(time - fade_in_start).seconds() / DCPTime(fade_in_end - fade_in_start).seconds();
x_position (StringText const& first, int target_width, int layout_width)
{
int x = 0;
- switch (first.h_align ()) {
+ switch (first.h_align()) {
case dcp::HAlign::LEFT:
/* h_position is distance between left of frame and left of subtitle */
x = first.h_position() * target_width;
}
-
static int
y_position (StringText const& first, int target_height, int layout_height)
{
int y = 0;
- switch (first.v_align ()) {
+ switch (first.v_align()) {
case dcp::VAlign::TOP:
/* SMPTE says that v_position is the distance between top
of frame and top of subtitle, but this doesn't always seem to be
layout->set_markup (markup);
}
+
/** Create a Pango layout using a dummy context which we can use to calculate the size
* of the text we will render. Then we can transfer the layout over to the real context
* for the actual render.
static Glib::RefPtr<Pango::Layout>
create_layout()
{
- PangoFontMap* c_font_map = pango_cairo_font_map_new ();
+ auto c_font_map = pango_cairo_font_map_new ();
DCPOMATIC_ASSERT (c_font_map);
- Glib::RefPtr<Pango::FontMap> font_map = Glib::wrap (c_font_map);
- PangoContext* c_context = pango_font_map_create_context (c_font_map);
+ auto font_map = Glib::wrap (c_font_map);
+ auto c_context = pango_font_map_create_context (c_font_map);
DCPOMATIC_ASSERT (c_context);
- Glib::RefPtr<Pango::Context> context = Glib::wrap (c_context);
+ auto context = Glib::wrap (c_context);
return Pango::Layout::create (context);
}
* at the same time and with the same fade in/out.
*/
static PositionImage
-render_line (list<StringText> subtitles, list<shared_ptr<Font> > fonts, dcp::Size target, DCPTime time, int frame_rate)
+render_line (list<StringText> subtitles, list<shared_ptr<Font>> fonts, dcp::Size target, DCPTime time, int frame_rate)
{
/* XXX: this method can only handle italic / bold changes mid-line,
nothing else yet.
*/
DCPOMATIC_ASSERT (!subtitles.empty ());
- StringText const& first = subtitles.front ();
+ auto const& first = subtitles.front ();
- string const font_name = setup_font (first, fonts);
- float const fade_factor = calculate_fade_factor (first, time, frame_rate);
- string const markup = marked_up (subtitles, target.height, fade_factor);
- Glib::RefPtr<Pango::Layout> layout = create_layout ();
+ auto const font_name = setup_font (first, fonts);
+ auto const fade_factor = calculate_fade_factor (first, time, frame_rate);
+ auto const markup = marked_up (subtitles, target.height, fade_factor);
+ auto layout = create_layout ();
setup_layout (layout, font_name, markup);
dcp::Size size;
layout->get_pixel_size (size.width, size.height);
}
}
- float const border_width = first.effect() == dcp::Effect::BORDER ? (first.outline_width * target.width / 2048.0) : 0;
+ auto const border_width = first.effect() == dcp::Effect::BORDER ? (first.outline_width * target.width / 2048.0) : 0;
size.width += 2 * ceil (border_width);
size.height += 2 * ceil (border_width);
size.width += x_offset;
size.height += y_offset;
- shared_ptr<Image> image = create_image (size);
- Cairo::RefPtr<Cairo::Surface> surface = create_surface (image);
- Cairo::RefPtr<Cairo::Context> context = Cairo::Context::create (surface);
+ auto image = create_image (size);
+ auto surface = create_surface (image);
+ auto context = Cairo::Context::create (surface);
context->set_line_width (1);
context->scale (x_scale, y_scale);
* @param frame_rate DCP frame rate.
*/
list<PositionImage>
-render_text (list<StringText> subtitles, list<shared_ptr<Font> > fonts, dcp::Size target, DCPTime time, int frame_rate)
+render_text (list<StringText> subtitles, list<shared_ptr<Font>> fonts, dcp::Size target, DCPTime time, int frame_rate)
{
list<StringText> pending;
list<PositionImage> images;
pending.push_back (i);
}
- if (!pending.empty ()) {
+ if (!pending.empty()) {
images.push_back (render_line (pending, fonts, target, time, frame_rate));
}
/*
- Copyright (C) 2013-2020 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#include "send_kdm_email_job.h"
#include "compose.hpp"
#include "kdm_with_metadata.h"
#include "i18n.h"
+
using std::string;
using std::list;
using std::shared_ptr;
using boost::optional;
+
SendKDMEmailJob::SendKDMEmailJob (
list<KDMWithMetadataPtr> kdms,
dcp::NameFormat container_name_format,
}
}
+
/** @param kdms KDMs to email.
* @param container_name_format Format to ues for folders / ZIP files.
* @param filename_format Format to use for filenames.
}
+
SendKDMEmailJob::~SendKDMEmailJob ()
{
stop_thread ();
}
+
string
SendKDMEmailJob::name () const
{
- optional<string> f = _kdms.front().front()->get('f');
+ auto f = _kdms.front().front()->get('f');
if (!f || f->empty()) {
return _("Email KDMs");
}
return String::compose (_("Email KDMs for %2"), *f);
}
+
string
SendKDMEmailJob::json_name () const
{
return N_("send_kdm_email");
}
+
void
SendKDMEmailJob::run ()
{
/*
- Copyright (C) 2013-2019 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#include "job.h"
#include "kdm_with_metadata.h"
#include <dcp/types.h>
#include <dcp/name_format.h>
#include <boost/filesystem.hpp>
+
namespace dcpomatic {
class Screen;
}
+
class Log;
+
class SendKDMEmailJob : public Job
{
public:
);
SendKDMEmailJob (
- std::list<std::list<KDMWithMetadataPtr> > kdms,
+ std::list<std::list<KDMWithMetadataPtr>> kdms,
dcp::NameFormat container_name_format,
dcp::NameFormat filename_format,
std::string cpl_name
dcp::NameFormat _container_name_format;
dcp::NameFormat _filename_format;
std::string _cpl_name;
- std::list<std::list<KDMWithMetadataPtr> > _kdms;
+ std::list<std::list<KDMWithMetadataPtr>> _kdms;
};
/*
- Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2020-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#include "subtitle_analysis.h"
#include "exceptions.h"
#include "warnings.h"
#include <libxml++/libxml++.h>
DCPOMATIC_ENABLE_WARNINGS
+
+using std::make_shared;
+using std::shared_ptr;
using std::string;
using dcp::raw_convert;
-using std::shared_ptr;
+
int const SubtitleAnalysis::_current_state_version = 1;
void
SubtitleAnalysis::write (boost::filesystem::path path) const
{
- shared_ptr<xmlpp::Document> doc (new xmlpp::Document);
+ auto doc = make_shared<xmlpp::Document>();
xmlpp::Element* root = doc->create_root_node ("SubtitleAnalysis");
root->add_child("Version")->add_child_text (raw_convert<string>(_current_state_version));
if (_bounding_box) {
- xmlpp::Element* bounding_box = root->add_child("BoundingBox");
+ auto bounding_box = root->add_child("BoundingBox");
bounding_box->add_child("X")->add_child_text(raw_convert<string>(_bounding_box->x));
bounding_box->add_child("Y")->add_child_text(raw_convert<string>(_bounding_box->y));
bounding_box->add_child("Width")->add_child_text(raw_convert<string>(_bounding_box->width));
doc->write_to_file_formatted (path.string());
}
-
/*
- Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2020-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#include "rect.h"
#include <boost/noncopyable.hpp>
#include <boost/filesystem.hpp>
/** @class SubtitleAnalysis
* @brief Class to store the results of a SubtitleAnalysisJob.
*/
-
class SubtitleAnalysis : public boost::noncopyable
{
public:
explicit SubtitleAnalysis (boost::filesystem::path path);
SubtitleAnalysis (
- boost::optional<dcpomatic::Rect<double> > bounding_box,
+ boost::optional<dcpomatic::Rect<double>> bounding_box,
double analysis_x_offset_,
double analysis_y_offset_
)
void write (boost::filesystem::path path) const;
- boost::optional<dcpomatic::Rect<double> > bounding_box () const {
+ boost::optional<dcpomatic::Rect<double>> bounding_box () const {
return _bounding_box;
}
* expressed as a proportion of screen size (i.e. 0 is left hand side/top,
* 1 is right hand side/bottom), or empty if no subtitles were found.
*/
- boost::optional<dcpomatic::Rect<double> > _bounding_box;
+ boost::optional<dcpomatic::Rect<double>> _bounding_box;
double _analysis_x_offset;
double _analysis_y_offset;
/*
- Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
/** @file src/timer.cc
* @brief Some timing classes for debugging and profiling.
*/
+
+#include "compose.hpp"
#include "timer.h"
#include "util.h"
-#include "compose.hpp"
-#include <iostream>
#include <sys/time.h>
+#include <iostream>
#include "i18n.h"
-using namespace std;
+
+using std::cout;
+using std::list;
+using std::max;
+using std::pair;
+using std::string;
using boost::optional;
+
/** @param n Name to use when giving output */
PeriodTimer::PeriodTimer (string n)
: _name (n)
gettimeofday (&_start, 0);
}
+
/** Destroy PeriodTimer and output the time elapsed since its construction */
PeriodTimer::~PeriodTimer ()
{
cout << N_("T: ") << _name << N_(": ") << (seconds (stop) - seconds (_start)) << N_("\n");
}
+
StateTimer::StateTimer (string n, string s)
: _name (n)
{
_state = s;
}
+
StateTimer::StateTimer (string n)
: _name (n)
{
}
+
void
StateTimer::set (string s)
{
set_internal (s);
}
+
void
StateTimer::set_internal (optional<string> s)
{
_state = s;
}
+
void
StateTimer::unset ()
{
set_internal (optional<string>());
}
-bool compare (pair<double, string> a, pair<double, string> b)
-{
- return a.first > b.first;
-}
/** Destroy StateTimer and generate a summary of the state timings on cout */
StateTimer::~StateTimer ()
longest = max (longest, int(i.first.length()));
}
- list<pair<double, string> > sorted;
+ list<pair<double, string>> sorted;
for (auto const& i: _counts) {
string name = i.first + string(longest + 1 - i.first.size(), ' ');
sorted.push_back (make_pair(i.second.total_time, String::compose("\t%1%2 %3 %4", name, total_time, i.second.number, (i.second.total_time / i.second.number))));
}
- sorted.sort (compare);
+ sorted.sort ([](pair<double, string> const& a, pair<double, string> const& b) {
+ return a.first > b.first;
+ });
+
cout << _name << N_(":\n");
for (auto const& i: sorted) {
/*
- Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
/** @file src/timer.h
* @brief Some timing classes for debugging and profiling.
*/
+
#ifndef DCPOMATIC_TIMER_H
#define DCPOMATIC_TIMER_H
+
#include <sys/time.h>
#include <boost/optional.hpp>
#include <string>
#include <map>
+
/** @class PeriodTimer
* @brief A class to allow timing of a period within the caller.
*
public:
explicit VideoContent (Content* parent);
VideoContent (Content* parent, cxml::ConstNodePtr, int);
- VideoContent (Content* parent, std::vector<std::shared_ptr<Content> >);
+ VideoContent (Content* parent, std::vector<std::shared_ptr<Content>>);
void as_xml (xmlpp::Node *) const;
std::string technical_summary () const;
boost::optional<dcp::LanguageTag> _burnt_subtitle_language;
};
+
#endif
/*
- Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2020-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#include "zipper.h"
#include "exceptions.h"
#include "dcpomatic_assert.h"
#include <boost/filesystem.hpp>
#include <stdexcept>
+
using std::string;
using std::runtime_error;
using std::shared_ptr;
shared_ptr<string> copy(new string(content));
_store.push_back (copy);
- struct zip_source* source = zip_source_buffer (_zip, copy->c_str(), copy->length(), 0);
+ auto source = zip_source_buffer (_zip, copy->c_str(), copy->length(), 0);
if (!source) {
throw runtime_error ("could not create ZIP source");
}
/*
- Copyright (C) 2020 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2020-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#include <boost/noncopyable.hpp>
#include <boost/filesystem.hpp>
#include <vector>
+
class Zipper : public boost::noncopyable
{
public:
private:
struct zip* _zip;
- std::vector<std::shared_ptr<std::string> > _store;
+ std::vector<std::shared_ptr<std::string>> _store;
};
#include "lib/ffmpeg_content.h"
#include "lib/dcpomatic_log.h"
#include "lib/file_log.h"
+#include <dcp/cpl.h>
#include <dcp/dcp.h>
#include <dcp/raw_convert.h>
#include <dcp/exceptions.h>
/*
- Copyright (C) 2018-2020 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2018-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
-#include "../wx/wx_util.h"
-#include "../wx/wx_signal_manager.h"
-#include "../wx/content_view.h"
-#include "../wx/dcpomatic_button.h"
-#include "../wx/about_dialog.h"
-#include "../wx/playlist_editor_config_dialog.h"
-#include "../lib/util.h"
-#include "../lib/config.h"
-#include "../lib/cross.h"
-#include "../lib/film.h"
-#include "../lib/dcp_content.h"
-#include "../lib/spl_entry.h"
-#include "../lib/spl.h"
+
+#include "wx/wx_util.h"
+#include "wx/wx_signal_manager.h"
+#include "wx/content_view.h"
+#include "wx/dcpomatic_button.h"
+#include "wx/about_dialog.h"
+#include "wx/playlist_editor_config_dialog.h"
+#include "lib/config.h"
+#include "lib/cross.h"
+#include "lib/dcp_content.h"
+#include "lib/film.h"
+#include "lib/spl.h"
+#include "lib/spl_entry.h"
+#include "lib/util.h"
#include <wx/wx.h>
#include <wx/listctrl.h>
#include <wx/imaglist.h>
#include <wx/spinctrl.h>
#include <wx/preferences.h>
-using std::exception;
+
using std::cout;
-using std::string;
-using std::map;
+using std::exception;
using std::make_pair;
-using std::vector;
-using boost::optional;
+using std::make_shared;
+using std::map;
using std::shared_ptr;
+using std::string;
+using std::vector;
using std::weak_ptr;
using boost::bind;
+using boost::optional;
using std::dynamic_pointer_cast;
#if BOOST_VERSION >= 106100
using namespace boost::placeholders;
#endif
+
class ContentDialog : public wxDialog, public ContentStore
{
public:
{
_content_view->update ();
- wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
+ auto overall_sizer = new wxBoxSizer (wxVERTICAL);
SetSizer (overall_sizer);
overall_sizer->Add (_content_view, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
- wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
+ auto buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
if (buttons) {
overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
}
: _sizer (new wxBoxSizer(wxVERTICAL))
, _content_store (content_store)
{
- wxStaticText* label = new wxStaticText (parent, wxID_ANY, wxEmptyString);
+ auto label = new wxStaticText (parent, wxID_ANY, wxEmptyString);
label->SetLabelMarkup (_("<b>Playlists</b>"));
_sizer->Add (label, 0, wxTOP | wxLEFT, DCPOMATIC_SIZER_GAP * 2);
_list->AppendColumn (_("Name"), wxLIST_FORMAT_LEFT, 840);
_list->AppendColumn (_("Length"), wxLIST_FORMAT_LEFT, 100);
- wxBoxSizer* button_sizer = new wxBoxSizer (wxVERTICAL);
+ auto button_sizer = new wxBoxSizer (wxVERTICAL);
_new = new Button (parent, _("New"));
button_sizer->Add (_new, 0, wxEXPAND | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
_delete = new Button (parent, _("Delete"));
button_sizer->Add (_delete, 0, wxEXPAND | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
- wxSizer* list = new wxBoxSizer (wxHORIZONTAL);
+ auto list = new wxBoxSizer (wxHORIZONTAL);
list->Add (_list, 1, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP);
list->Add (button_sizer, 0, wxALL, DCPOMATIC_SIZER_GAP);
shared_ptr<SignalSPL> first_playlist () const
{
if (_playlists.empty()) {
- return shared_ptr<SignalSPL>();
+ return {};
}
return _playlists.front ();
void name_changed (weak_ptr<SignalSPL> wp)
{
- shared_ptr<SignalSPL> playlist = wp.lock ();
+ auto playlist = wp.lock ();
if (!playlist) {
return;
}
void load_playlists ()
{
- optional<boost::filesystem::path> path = Config::instance()->player_playlist_directory();
+ auto path = Config::instance()->player_playlist_directory();
if (!path) {
return;
}
_list->DeleteAllItems ();
_playlists.clear ();
- for (boost::filesystem::directory_iterator i(*path); i != boost::filesystem::directory_iterator(); ++i) {
- shared_ptr<SignalSPL> spl(new SignalSPL);
+ for (auto i: boost::filesystem::directory_iterator(*path)) {
+ auto spl = make_shared<SignalSPL>();
try {
- spl->read (*i, _content_store);
+ spl->read (i, _content_store);
add_playlist_to_model (spl);
} catch (...) {}
}
return;
}
- optional<boost::filesystem::path> dir = Config::instance()->player_playlist_directory();
+ auto dir = Config::instance()->player_playlist_directory();
if (!dir) {
return;
}
wxListCtrl* _list;
wxButton* _new;
wxButton* _delete;
- vector<shared_ptr<SignalSPL> > _playlists;
+ vector<shared_ptr<SignalSPL>> _playlists;
ContentStore* _content_store;
};
: _content_dialog (content_dialog)
, _sizer (new wxBoxSizer(wxVERTICAL))
{
- wxBoxSizer* title = new wxBoxSizer (wxHORIZONTAL);
- wxStaticText* label = new wxStaticText (parent, wxID_ANY, wxEmptyString);
+ auto title = new wxBoxSizer (wxHORIZONTAL);
+ auto label = new wxStaticText (parent, wxID_ANY, wxEmptyString);
label->SetLabelMarkup (_("<b>Playlist:</b>"));
title->Add (label, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, DCPOMATIC_SIZER_GAP);
_name = new wxTextCtrl (parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(400, -1));
title->Add (_name, 0, wxRIGHT, DCPOMATIC_SIZER_GAP);
_sizer->Add (title, 0, wxTOP | wxLEFT, DCPOMATIC_SIZER_GAP * 2);
- wxBoxSizer* list = new wxBoxSizer (wxHORIZONTAL);
+ auto list = new wxBoxSizer (wxHORIZONTAL);
_list = new wxListCtrl (
parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL
_list->AppendColumn (_("Type"), wxLIST_FORMAT_LEFT, 100);
_list->AppendColumn (_("Encrypted"), wxLIST_FORMAT_CENTRE, 90);
- wxImageList* images = new wxImageList (16, 16);
+ auto images = new wxImageList (16, 16);
wxIcon tick_icon;
wxIcon no_tick_icon;
tick_icon.LoadFile (bitmap_path("tick"), wxBITMAP_TYPE_PNG);
list->Add (_list, 1, wxEXPAND | wxALL, DCPOMATIC_SIZER_GAP);
- wxBoxSizer* button_sizer = new wxBoxSizer (wxVERTICAL);
+ auto button_sizer = new wxBoxSizer (wxVERTICAL);
_up = new Button (parent, _("Up"));
_down = new Button (parent, _("Down"));
_add = new Button (parent, _("Add"));
{
int const r = _content_dialog->ShowModal ();
if (r == wxID_OK) {
- shared_ptr<Content> content = _content_dialog->selected ();
+ auto content = _content_dialog->selected ();
if (content) {
SPLEntry e (content);
add (e);
DCPOMATIC_ASSERT (_playlist);
- SPLEntry tmp = (*_playlist)[s];
+ auto tmp = (*_playlist)[s];
(*_playlist)[s] = (*_playlist)[s-1];
(*_playlist)[s-1] = tmp;
DCPOMATIC_ASSERT (_playlist);
- SPLEntry tmp = (*_playlist)[s];
+ auto tmp = (*_playlist)[s];
(*_playlist)[s] = (*_playlist)[s+1];
(*_playlist)[s+1] = tmp;
{
public:
explicit DOMFrame (wxString const & title)
- : wxFrame (0, -1, title)
+ : wxFrame (nullptr, wxID_ANY, title)
, _content_dialog (new ContentDialog(this))
- , _config_dialog (0)
+ , _config_dialog (nullptr)
{
- wxMenuBar* bar = new wxMenuBar;
+ auto bar = new wxMenuBar;
setup_menu (bar);
SetMenuBar (bar);
/* Use a panel as the only child of the Frame so that we avoid
the dark-grey background on Windows.
*/
- wxPanel* overall_panel = new wxPanel (this, wxID_ANY);
- wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL);
+ auto overall_panel = new wxPanel (this, wxID_ANY);
+ auto sizer = new wxBoxSizer (wxVERTICAL);
_playlist_list = new PlaylistList (overall_panel, _content_dialog);
_playlist_content = new PlaylistContent (overall_panel, _content_dialog);
void help_about ()
{
- AboutDialog* d = new AboutDialog (this);
+ auto d = new AboutDialog (this);
d->ShowModal ();
d->Destroy ();
}
void change_playlist (shared_ptr<SignalSPL> playlist)
{
- shared_ptr<SignalSPL> old = _playlist_content->playlist ();
+ auto old = _playlist_content->playlist ();
if (old) {
save_playlist (old);
}
void save_playlist (shared_ptr<SignalSPL> playlist)
{
- optional<boost::filesystem::path> dir = Config::instance()->player_playlist_directory();
+ auto dir = Config::instance()->player_playlist_directory();
if (!dir) {
error_dialog (this, _("No playlist folder is specified in preferences. Please set one and then try again."));
return;
void setup_menu (wxMenuBar* m)
{
- wxMenu* file = new wxMenu;
+ auto file = new wxMenu;
#ifdef __WXOSX__
file->Append (wxID_EXIT, _("&Exit"));
#else
#endif
#ifndef __WXOSX__
- wxMenu* edit = new wxMenu;
+ auto edit = new wxMenu;
edit->Append (wxID_PREFERENCES, _("&Preferences...\tCtrl-P"));
#endif
- wxMenu* help = new wxMenu;
+ auto help = new wxMenu;
#ifdef __WXOSX__
help->Append (wxID_ABOUT, _("About DCP-o-matic"));
#else
}
}
-
ContentDialog* _content_dialog;
PlaylistList* _playlist_list;
PlaylistContent* _playlist_content;
boost::signals2::scoped_connection _config_changed_connection;
};
+
/** @class App
* @brief The magic App class for wxWidgets.
*/
public:
App ()
: wxApp ()
- , _frame (0)
+ , _frame (nullptr)
{}
private:
#include <iostream>
#include <iomanip>
-using std::string;
-using std::pair;
-using std::min;
-using std::max;
+
+using std::bad_alloc;
using std::cout;
+using std::dynamic_pointer_cast;
+using std::exception;
using std::list;
-using std::bad_alloc;
using std::make_pair;
-using std::exception;
+using std::make_shared;
+using std::max;
+using std::min;
+using std::pair;
using std::shared_ptr;
-using std::dynamic_pointer_cast;
+using std::string;
using std::vector;
using std::weak_ptr;
using boost::optional;
using dcp::Size;
using namespace dcpomatic;
+
static
int
rtaudio_callback (void* out, void *, unsigned int frames, double, RtAudioStreamStatus, void* data)
return reinterpret_cast<FilmViewer*>(data)->audio_callback (out, frames);
}
+
FilmViewer::FilmViewer (wxWindow* p)
- : _coalesce_player_changes (false)
- , _audio (DCPOMATIC_RTAUDIO_API)
- , _audio_channels (0)
- , _audio_block_size (1024)
- , _playing (false)
- , _suspended (0)
- , _latency_history_count (0)
+ : _audio (DCPOMATIC_RTAUDIO_API)
, _closed_captions_dialog (new ClosedCaptionsDialog(p, this))
- , _outline_content (false)
- , _pad_black (false)
- , _idle_get (false)
{
switch (Config::instance()->video_view_type()) {
case Config::VIDEO_VIEW_OPENGL:
_video_view->Sized.connect (boost::bind(&FilmViewer::video_view_sized, this));
_video_view->TooManyDropped.connect (boost::bind(&FilmViewer::too_many_frames_dropped, this));
- set_film (shared_ptr<Film> ());
+ set_film (shared_ptr<Film>());
- _config_changed_connection = Config::instance()->Changed.connect (bind (&FilmViewer::config_changed, this, _1));
+ _config_changed_connection = Config::instance()->Changed.connect(bind(&FilmViewer::config_changed, this, _1));
config_changed (Config::SOUND_OUTPUT);
}
+
FilmViewer::~FilmViewer ()
{
stop ();
}
+
/** Ask for ::get() to be called next time we are idle */
void
FilmViewer::request_idle_display_next_frame ()
signal_manager->when_idle (boost::bind(&FilmViewer::idle_handler, this));
}
+
void
FilmViewer::idle_handler ()
{
}
}
+
void
FilmViewer::set_film (shared_ptr<Film> film)
{
}
try {
- _player.reset (new Player(_film));
+ _player = make_shared<Player>(_film);
_player->set_fast ();
if (_dcp_decode_reduction) {
_player->set_dcp_decode_reduction (_dcp_decode_reduction);
slow_refresh ();
}
+
void
FilmViewer::recreate_butler ()
{
return;
}
- _butler.reset(
- new Butler(
- _film,
- _player,
- Config::instance()->audio_mapping(_audio_channels),
- _audio_channels,
- bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24),
- VideoRange::FULL,
- false,
- true
- )
+ _butler = std::make_shared<Butler>(
+ _film,
+ _player,
+ Config::instance()->audio_mapping(_audio_channels),
+ _audio_channels,
+ bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24),
+ VideoRange::FULL,
+ false,
+ true
);
if (!Config::instance()->sound() && !_audio.isStreamOpen()) {
resume ();
}
+
void
FilmViewer::set_outline_content (bool o)
{
void
-FilmViewer::set_outline_subtitles (optional<dcpomatic::Rect<double> > rect)
+FilmViewer::set_outline_subtitles (optional<dcpomatic::Rect<double>> rect)
{
_outline_subtitles = rect;
_video_view->update ();
slow_refresh ();
}
+
void
FilmViewer::video_view_sized ()
{
}
}
+
void
FilmViewer::calculate_sizes ()
{
return;
}
- Ratio const * container = _film->container ();
+ auto const container = _film->container ();
- float const view_ratio = float(_video_view->get()->GetSize().x) / _video_view->get()->GetSize().y;
- float const film_ratio = container ? container->ratio () : 1.78;
+ auto const view_ratio = float(_video_view->get()->GetSize().x) / _video_view->get()->GetSize().y;
+ auto const film_ratio = container ? container->ratio () : 1.78;
if (view_ratio < film_ratio) {
/* panel is less widscreen than the film; clamp width */
_player->set_video_container_size (_out_size);
}
+
void
FilmViewer::suspend ()
{
}
}
+
void
FilmViewer::resume ()
{
}
}
+
void
FilmViewer::start ()
{
return;
}
- optional<bool> v = PlaybackPermitted ();
+ auto v = PlaybackPermitted ();
if (v && !*v) {
/* Computer says no */
return;
_video_view->start ();
}
+
bool
FilmViewer::stop ()
{
return true;
}
+
void
FilmViewer::player_change (ChangeType type, int property, bool frequent)
{
player_change ({property});
}
+
void
FilmViewer::player_change (vector<int> properties)
{
}
}
+
void
FilmViewer::film_change (ChangeType type, Film::Property p)
{
}
}
+
void
FilmViewer::film_length_change ()
{
_video_view->set_length (_film->length());
}
+
/** Re-get the current frame slowly by seeking */
void
FilmViewer::slow_refresh ()
seek (_video_view->position(), true);
}
+
/** Try to re-get the current frame quickly by resetting the metadata
* in the PlayerVideo that we used last time.
* @return true if this was possible, false if not.
return _video_view->reset_metadata (_film, _player->video_container_size());
}
+
void
FilmViewer::seek (shared_ptr<Content> content, ContentTime t, bool accurate)
{
- optional<DCPTime> dt = _player->content_time_to_dcp (content, t);
+ auto dt = _player->content_time_to_dcp (content, t);
if (dt) {
seek (*dt, accurate);
}
}
+
void
FilmViewer::set_coalesce_player_changes (bool c)
{
}
}
+
void
FilmViewer::seek (DCPTime t, bool accurate)
{
return;
}
- if (t < DCPTime ()) {
+ if (t < DCPTime()) {
t = DCPTime ();
}
- if (t >= _film->length ()) {
+ if (t >= _film->length()) {
t = _film->length() - one_video_frame();
}
resume ();
}
+
void
FilmViewer::config_changed (Config::Property p)
{
}
}
+
DCPTime
FilmViewer::uncorrected_time () const
{
- if (_audio.isStreamRunning ()) {
+ if (_audio.isStreamRunning()) {
return DCPTime::from_seconds (const_cast<RtAudio*>(&_audio)->getStreamTime());
}
return _video_view->position();
}
+
optional<DCPTime>
FilmViewer::audio_time () const
{
if (!_audio.isStreamRunning()) {
- return optional<DCPTime>();
+ return {};
}
return DCPTime::from_seconds (const_cast<RtAudio*>(&_audio)->getStreamTime ()) -
DCPTime::from_frames (average_latency(), _film->audio_frame_rate());
}
+
DCPTime
FilmViewer::time () const
{
return audio_time().get_value_or(_video_view->position());
}
+
int
FilmViewer::audio_callback (void* out_p, unsigned int frames)
{
while (true) {
- optional<DCPTime> t = _butler->get_audio (reinterpret_cast<float*> (out_p), frames);
+ auto t = _butler->get_audio (reinterpret_cast<float*> (out_p), frames);
if (!t || DCPTime(uncorrected_time() - *t) < one_video_frame()) {
/* There was an underrun or this audio is on time; carry on */
break;
return 0;
}
+
Frame
FilmViewer::average_latency () const
{
return total / _latency_history.size();
}
+
void
FilmViewer::set_dcp_decode_reduction (optional<int> reduction)
{
}
}
+
optional<int>
FilmViewer::dcp_decode_reduction () const
{
return _dcp_decode_reduction;
}
+
DCPTime
FilmViewer::one_video_frame () const
{
return DCPTime::from_frames (1, _film ? _film->video_frame_rate() : 24);
}
+
/** Open a dialog box showing our film's closed captions */
void
FilmViewer::show_closed_captions ()
_closed_captions_dialog->Show();
}
+
void
FilmViewer::seek_by (DCPTime by, bool accurate)
{
seek (_video_view->position() + by, accurate);
}
+
void
FilmViewer::set_pad_black (bool p)
{
_pad_black = p;
}
+
/** Called when a player has finished the current film.
* May be called from a non-UI thread.
*/
emit (boost::bind(&FilmViewer::ui_finished, this));
}
+
/** Called by finished() in the UI thread */
void
FilmViewer::ui_finished ()
Finished ();
}
+
int
FilmViewer::dropped () const
{
void set_dcp_decode_reduction (boost::optional<int> reduction);
boost::optional<int> dcp_decode_reduction () const;
void set_outline_content (bool o);
- void set_outline_subtitles (boost::optional<dcpomatic::Rect<double> >);
+ void set_outline_subtitles (boost::optional<dcpomatic::Rect<double>>);
void set_eyes (Eyes e);
void set_pad_black (bool p);
bool outline_content () const {
return _outline_content;
}
- boost::optional<dcpomatic::Rect<double> > outline_subtitles () const {
+ boost::optional<dcpomatic::Rect<double>> outline_subtitles () const {
return _outline_subtitles;
}
bool pad_black () const {
std::shared_ptr<Film> _film;
std::shared_ptr<Player> _player;
- VideoView* _video_view;
- bool _coalesce_player_changes;
+ VideoView* _video_view = nullptr;
+ bool _coalesce_player_changes = false;
std::vector<int> _pending_player_changes;
/** Size of our output (including padding if we have any) */
dcp::Size _out_size;
RtAudio _audio;
- int _audio_channels;
- unsigned int _audio_block_size;
- bool _playing;
- int _suspended;
+ int _audio_channels = 0;
+ unsigned int _audio_block_size = 1024;
+ bool _playing = false;
+ int _suspended = 0;
std::shared_ptr<Butler> _butler;
std::list<Frame> _latency_history;
/** Mutex to protect _latency_history */
mutable boost::mutex _latency_history_mutex;
- int _latency_history_count;
+ int _latency_history_count = 0;
boost::optional<int> _dcp_decode_reduction;
- ClosedCaptionsDialog* _closed_captions_dialog;
+ ClosedCaptionsDialog* _closed_captions_dialog = nullptr;
- bool _outline_content;
- boost::optional<dcpomatic::Rect<double> > _outline_subtitles;
+ bool _outline_content = false;
+ boost::optional<dcpomatic::Rect<double>> _outline_subtitles;
/** true to pad the viewer panel with black, false to use
the normal window background colour.
*/
- bool _pad_black;
+ bool _pad_black = false;
/** true if an get() is required next time we are idle */
- bool _idle_get;
+ bool _idle_get = false;
boost::signals2::scoped_connection _config_changed_connection;
};
/*
- Copyright (C) 2015-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2015-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#include "timeline_reels_view.h"
#include "timeline.h"
#include <wx/wx.h>
#include <wx/graphics.h>
+
using std::min;
using std::list;
using namespace dcpomatic;
+
TimelineReelsView::TimelineReelsView (Timeline& tl, int y)
: TimelineView (tl)
, _y (y)
}
+
dcpomatic::Rect<int>
TimelineReelsView::bbox () const
{
return dcpomatic::Rect<int> (0, _y - 4, _timeline.width(), 24);
}
+
void
TimelineReelsView::set_y (int y)
{
force_redraw ();
}
+
void
-TimelineReelsView::do_paint (wxGraphicsContext* gc, list<dcpomatic::Rect<int> >)
+TimelineReelsView::do_paint (wxGraphicsContext* gc, list<dcpomatic::Rect<int>>)
{
if (!_timeline.pixels_per_second()) {
return;
gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 255), 1, wxPENSTYLE_SOLID));
- wxGraphicsPath path = gc->CreatePath ();
+ auto path = gc->CreatePath ();
path.MoveToPoint (time_x (DCPTime (0)), _y);
path.AddLineToPoint (time_x (_timeline.film()->length()), _y);
gc->StrokePath (path);
for (auto i: _timeline.film()->reels()) {
int const size = min (8.0, i.duration().seconds() * pps / 2);
- wxGraphicsPath path = gc->CreatePath ();
+ auto path = gc->CreatePath ();
path.MoveToPoint (time_x (i.from) + size, _y + size / 2);
path.AddLineToPoint (time_x (i.from), _y);
path.AddLineToPoint (time_x (i.from) + size, _y - size / 2);
path.AddLineToPoint (time_x (i.to) - size, _y - size / 2);
gc->StrokePath (path);
- wxString str = wxString::Format (_("Reel %d"), reel++);
+ auto str = wxString::Format (_("Reel %d"), reel++);
wxDouble str_width;
wxDouble str_height;
wxDouble str_descent;
wxDouble str_leading;
gc->GetTextExtent (str, &str_width, &str_height, &str_descent, &str_leading);
- int const available_width = time_x (DCPTime (i.to.get())) - time_x (DCPTime (i.from.get()));
+ int const available_width = time_x(DCPTime(i.to.get())) - time_x(DCPTime(i.from.get()));
if (available_width > str_width) {
- gc->DrawText (str, time_x (DCPTime (i.from.get())) + (available_width - str_width) / 2, _y + 4);
+ gc->DrawText (str, time_x(DCPTime(i.from.get())) + (available_width - str_width) / 2, _y + 4);
}
}
}
/*
- Copyright (C) 2015-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2015-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
#include "timeline_view.h"
+
class TimelineReelsView : public TimelineView
{
public:
void set_y (int y);
private:
- void do_paint (wxGraphicsContext* gc, std::list<dcpomatic::Rect<int> > overlaps);
+ void do_paint (wxGraphicsContext* gc, std::list<dcpomatic::Rect<int>> overlaps);
int _y;
};
/*
- Copyright (C) 2013-2020 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2021 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
*/
+
/** @file test/audio_merger_test.cc
* @brief Test AudioMerger class.
* @ingroup selfcontained
*/
+
#include "lib/cross.h"
#include "lib/audio_merger.h"
#include "lib/audio_buffers.h"
#include <boost/signals2.hpp>
#include <iostream>
+
using std::pair;
+using std::make_shared;
using std::list;
using std::cout;
using std::string;
using boost::bind;
using namespace dcpomatic;
+
static shared_ptr<const AudioBuffers> last_audio;
+
int const sampling_rate = 48000;
+
static void
push (AudioMerger& merger, int from, int to, int at)
{
- shared_ptr<AudioBuffers> buffers (new AudioBuffers (1, to - from));
+ auto buffers = make_shared<AudioBuffers>(1, to - from);
for (int i = 0; i < (to - from); ++i) {
buffers->data()[0][i] = from + i;
}
merger.push (buffers, DCPTime(at, sampling_rate));
}
+
/* Basic mixing, 2 overlapping pushes */
BOOST_AUTO_TEST_CASE (audio_merger_test1)
{
push (merger, 0, 64, 0);
push (merger, 0, 64, 22);
- list<pair<shared_ptr<AudioBuffers>, DCPTime> > tb = merger.pull (DCPTime::from_frames (22, sampling_rate));
+ auto tb = merger.pull (DCPTime::from_frames (22, sampling_rate));
BOOST_REQUIRE (tb.size() == 1U);
BOOST_CHECK (tb.front().first != shared_ptr<const AudioBuffers> ());
BOOST_CHECK_EQUAL (tb.front().first->frames(), 22);
}
}
+
/* Push at non-zero time */
BOOST_AUTO_TEST_CASE (audio_merger_test2)
{
push (merger, 0, 64, 9);
/* There's nothing from 0 to 9 */
- list<pair<shared_ptr<AudioBuffers>, DCPTime> > tb = merger.pull (DCPTime::from_frames (9, sampling_rate));
+ auto tb = merger.pull (DCPTime::from_frames (9, sampling_rate));
BOOST_CHECK_EQUAL (tb.size(), 0U);
/* Then there's our data at 9 */
}
}
+
/* Push two non contiguous blocks */
BOOST_AUTO_TEST_CASE (audio_merger_test3)
{
/* Get them back */
- list<pair<shared_ptr<AudioBuffers>, DCPTime> > tb = merger.pull (DCPTime::from_frames (100, sampling_rate));
+ auto tb = merger.pull (DCPTime::from_frames (100, sampling_rate));
BOOST_REQUIRE (tb.size() == 1U);
BOOST_CHECK_EQUAL (tb.front().first->frames(), 64);
BOOST_CHECK_EQUAL (tb.front().second.get(), DCPTime::from_frames(17, sampling_rate).get());
}
}
+
/* Reply a sequence of calls to AudioMerger that resulted in a crash */
BOOST_AUTO_TEST_CASE (audio_merger_test4)
{
- FILE* f = fopen_boost("test/data/audio_merger_bug1.log", "r");
+ auto f = fopen_boost("test/data/audio_merger_bug1.log", "r");
BOOST_REQUIRE (f);
list<string> tokens;
char buf[64];
}
shared_ptr<AudioMerger> merger;
- list<string>::const_iterator i = tokens.begin ();
+ auto i = tokens.begin ();
while (i != tokens.end()) {
BOOST_CHECK (*i++ == "I/AM");
string const cmd = *i++;
DCPTime time(dcp::raw_convert<DCPTime::Type>(*i++));
BOOST_REQUIRE (i != tokens.end());
int const frames = dcp::raw_convert<int>(*i++);
- shared_ptr<AudioBuffers> buffers(new AudioBuffers(1, frames));
+ auto buffers = make_shared<AudioBuffers>(1, frames);
BOOST_REQUIRE (merger);
merger->push (buffers, time);
} else if (cmd == "pull") {
}
}
-
#include "lib/job_manager.h"
#include "lib/config.h"
#include "test.h"
+#include <dcp/cpl.h>
#include <dcp/dcp.h>
#include <boost/test/unit_test.hpp>
#include <iostream>