void
-FFmpegContent::as_xml (xmlpp::Node* node, bool with_paths) const
+FFmpegContent::as_xml(xmlpp::Element* element, bool with_paths) const
{
- node->add_child("Type")->add_child_text("FFmpeg");
- Content::as_xml (node, with_paths);
+ cxml::add_text_child(element, "Type", "FFmpeg");
+ Content::as_xml(element, with_paths);
if (video) {
- video->as_xml (node);
+ video->as_xml(element);
}
if (audio) {
- audio->as_xml (node);
+ audio->as_xml(element);
for (auto i: audio->streams()) {
auto f = dynamic_pointer_cast<FFmpegAudioStream> (i);
DCPOMATIC_ASSERT (f);
- f->as_xml (node->add_child("AudioStream"));
+ f->as_xml(cxml::add_child(element, "AudioStream"));
}
}
if (only_text()) {
- only_text()->as_xml (node);
+ only_text()->as_xml(element);
}
boost::mutex::scoped_lock lm (_mutex);
for (auto i: _subtitle_streams) {
- auto t = node->add_child("SubtitleStream");
+ auto t = cxml::add_child(element, "SubtitleStream");
if (_subtitle_stream && i == _subtitle_stream) {
- t->add_child("Selected")->add_child_text("1");
+ cxml::add_text_child(t, "Selected", "1");
}
i->as_xml (t);
}
for (auto i: _filters) {
- node->add_child("Filter")->add_child_text(i.id());
+ cxml::add_text_child(element, "Filter", i.id());
}
if (_first_video) {
- node->add_child("FirstVideo")->add_child_text(raw_convert<string>(_first_video.get().get()));
+ cxml::add_text_child(element, "FirstVideo", raw_convert<string>(_first_video.get().get()));
}
if (_color_range) {
- node->add_child("ColorRange")->add_child_text(raw_convert<string>(static_cast<int>(*_color_range)));
+ cxml::add_text_child(element, "ColorRange", raw_convert<string>(static_cast<int>(*_color_range)));
}
if (_color_primaries) {
- node->add_child("ColorPrimaries")->add_child_text(raw_convert<string>(static_cast<int>(*_color_primaries)));
+ cxml::add_text_child(element, "ColorPrimaries", raw_convert<string>(static_cast<int>(*_color_primaries)));
}
if (_color_trc) {
- node->add_child("ColorTransferCharacteristic")->add_child_text(raw_convert<string>(static_cast<int>(*_color_trc)));
+ cxml::add_text_child(element, "ColorTransferCharacteristic", raw_convert<string>(static_cast<int>(*_color_trc)));
}
if (_colorspace) {
- node->add_child("Colorspace")->add_child_text(raw_convert<string>(static_cast<int>(*_colorspace)));
+ cxml::add_text_child(element, "Colorspace", raw_convert<string>(static_cast<int>(*_colorspace)));
}
if (_bits_per_pixel) {
- node->add_child("BitsPerPixel")->add_child_text(raw_convert<string>(*_bits_per_pixel));
+ cxml::add_text_child(element, "BitsPerPixel", raw_convert<string>(*_bits_per_pixel));
}
}
_filters.push_back(*Filter::from_id("hflip"));
} else if (fabs (rot - 90) < 1.0) {
_filters.push_back(*Filter::from_id("90clock"));
+ video->rotate_size();
} else if (fabs (rot - 270) < 1.0) {
_filters.push_back(*Filter::from_id("90anticlock"));
+ video->rotate_size();
}
}
if (examiner->has_alpha()) {
auto codec = _codec_context[i] ? _codec_context[i]->codec : nullptr;
if (s->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && codec) {
- /* This is a hack; sometimes it seems that _audio_codec_context->channel_layout isn't set up,
- so bodge it here. No idea why we should have to do this.
- */
-
- if (s->codecpar->channel_layout == 0) {
- s->codecpar->channel_layout = av_get_default_channel_layout (s->codecpar->channels);
- }
-
DCPOMATIC_ASSERT (_format_context->duration != AV_NOPTS_VALUE);
DCPOMATIC_ASSERT (codec->name);
s->id,
s->codecpar->sample_rate,
llrint ((double(_format_context->duration) / AV_TIME_BASE) * s->codecpar->sample_rate),
- s->codecpar->channels,
+ s->codecpar->ch_layout.nb_channels,
s->codecpar->bits_per_raw_sample ? s->codecpar->bits_per_raw_sample : s->codecpar->bits_per_coded_sample
)
);
av_packet_free (&packet);
- if (_first_video && got_all_audio && temporal_reference.size() >= (PULLDOWN_CHECK_FRAMES * 2)) {
+ if (got_all_audio && (!_video_stream || (_first_video && temporal_reference.size() >= (PULLDOWN_CHECK_FRAMES * 2)))) {
/* All done */
break;
}
/* This code taken from get_rotation() in ffmpeg:cmdutils.c */
auto stream = _format_context->streams[*_video_stream];
auto rotate_tag = av_dict_get (stream->metadata, "rotate", 0, 0);
- _rotation = 0;
- uint8_t* displaymatrix = av_stream_get_side_data (stream, AV_PKT_DATA_DISPLAYMATRIX, 0);
--
if (rotate_tag && *rotate_tag->value && strcmp(rotate_tag->value, "0")) {
char *tail;
_rotation = av_strtod (rotate_tag->value, &tail);
}
}
- if (displaymatrix && !_rotation) {
- _rotation = - av_display_rotation_get ((int32_t*) displaymatrix);
+ auto side_data = av_packet_side_data_get(stream->codecpar->coded_side_data, stream->codecpar->nb_coded_side_data, AV_PKT_DATA_DISPLAYMATRIX);
+ if (side_data && !_rotation) {
+ _rotation = - av_display_rotation_get(reinterpret_cast<int32_t*>(side_data->data));
}
_rotation = *_rotation - 360 * floor (*_rotation / 360 + 0.9 / 360);
).get_value_or (ContentTime ()).frames_round (video_frame_rate().get ());
}
if (temporal_reference.size() < (PULLDOWN_CHECK_FRAMES * 2)) {
- temporal_reference += (_video_frame->top_field_first ? "T" : "B");
+ temporal_reference += ((_video_frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) ? "T" : "B");
temporal_reference += (_video_frame->repeat_pict ? "3" : "2");
}
void
-VideoContent::as_xml (xmlpp::Node* node) const
+VideoContent::as_xml(xmlpp::Element* element) const
{
boost::mutex::scoped_lock lm (_mutex);
- node->add_child("Use")->add_child_text (_use ? "1" : "0");
- node->add_child("VideoLength")->add_child_text (raw_convert<string> (_length));
+ cxml::add_text_child(element, "Use", _use ? "1" : "0");
+ cxml::add_text_child(element, "VideoLength", raw_convert<string>(_length));
if (_size) {
- node->add_child("VideoWidth")->add_child_text(raw_convert<string>(_size->width));
- node->add_child("VideoHeight")->add_child_text(raw_convert<string>(_size->height));
+ cxml::add_text_child(element, "VideoWidth", raw_convert<string>(_size->width));
+ cxml::add_text_child(element, "VideoHeight", raw_convert<string>(_size->height));
}
- node->add_child("VideoFrameType")->add_child_text (video_frame_type_to_string (_frame_type));
+ cxml::add_text_child(element, "VideoFrameType", video_frame_type_to_string(_frame_type));
if (_sample_aspect_ratio) {
- node->add_child("SampleAspectRatio")->add_child_text (raw_convert<string> (_sample_aspect_ratio.get ()));
+ cxml::add_text_child(element, "SampleAspectRatio", raw_convert<string> (_sample_aspect_ratio.get ()));
}
- _crop.as_xml (node);
+ _crop.as_xml(element);
if (_custom_ratio) {
- node->add_child("CustomRatio")->add_child_text(raw_convert<string>(*_custom_ratio));
+ cxml::add_text_child(element, "CustomRatio", raw_convert<string>(*_custom_ratio));
}
if (_custom_size) {
- node->add_child("CustomWidth")->add_child_text(raw_convert<string>(_custom_size->width));
- node->add_child("CustomHeight")->add_child_text(raw_convert<string>(_custom_size->height));
+ cxml::add_text_child(element, "CustomWidth", raw_convert<string>(_custom_size->width));
+ cxml::add_text_child(element, "CustomHeight", raw_convert<string>(_custom_size->height));
}
if (_colour_conversion) {
- _colour_conversion.get().as_xml (node->add_child("ColourConversion"));
+ _colour_conversion.get().as_xml(cxml::add_child(element, "ColourConversion"));
}
- node->add_child("YUV")->add_child_text (_yuv ? "1" : "0");
- node->add_child("FadeIn")->add_child_text (raw_convert<string> (_fade_in));
- node->add_child("FadeOut")->add_child_text (raw_convert<string> (_fade_out));
- node->add_child("Range")->add_child_text(_range == VideoRange::FULL ? "full" : "video");
- _pixel_quanta.as_xml(node->add_child("PixelQuanta"));
+ cxml::add_text_child(element, "YUV", _yuv ? "1" : "0");
+ cxml::add_text_child(element, "FadeIn", raw_convert<string>(_fade_in));
+ cxml::add_text_child(element, "FadeOut", raw_convert<string>(_fade_out));
+ cxml::add_text_child(element, "Range", _range == VideoRange::FULL ? "full" : "video");
+ _pixel_quanta.as_xml(cxml::add_child(element, "PixelQuanta"));
if (_burnt_subtitle_language) {
- node->add_child("BurntSubtitleLanguage")->add_child_text(_burnt_subtitle_language->to_string());
+ cxml::add_text_child(element, "BurntSubtitleLanguage", _burnt_subtitle_language->to_string());
}
}
}
-/** @param f Frame index within the whole (untrimmed) content.
+/** @param time Time within the whole (untrimmed) content.
* @return Fade factor (between 0 and 1) or unset if there is no fade.
*/
optional<double>
-VideoContent::fade (shared_ptr<const Film> film, Frame f) const
+VideoContent::fade(shared_ptr<const Film> film, ContentTime time) const
{
- DCPOMATIC_ASSERT (f >= 0);
+ DCPOMATIC_ASSERT(time.get() >= 0);
double const vfr = _parent->active_video_frame_rate(film);
- auto const ts = _parent->trim_start().frames_round(vfr);
- if ((f - ts) < fade_in()) {
- return double (f - ts) / fade_in();
+ auto const ts = _parent->trim_start();
+ auto const fade_in_time = ContentTime::from_frames(fade_in(), vfr);
+ if ((time - ts) < fade_in_time) {
+ return double(ContentTime(time - ts).get()) / fade_in_time.get();
}
- auto fade_out_start = length() - _parent->trim_end().frames_round(vfr) - fade_out();
- if (f >= fade_out_start) {
- return 1 - double (f - fade_out_start) / fade_out();
+ auto const fade_out_time = ContentTime::from_frames(fade_out(), vfr);
+ auto fade_out_start = ContentTime::from_frames(length(), vfr) - _parent->trim_end() - fade_out_time;
+ if (time >= fade_out_start) {
+ return 1 - double(ContentTime(time - fade_out_start).get()) / fade_out_time.get();
}
- return optional<double> ();
+ return {};
}
string
);
}
+
+ void
+ VideoContent::rotate_size()
+ {
+ if (_size) {
+ std::swap(_size->width, _size->height);
+ }
+ }
+
VideoContent (Content* parent, cxml::ConstNodePtr node, int version, VideoRange video_range_hint);
VideoContent (Content* parent, std::vector<std::shared_ptr<Content>>);
- void as_xml (xmlpp::Node *) const;
+ void as_xml(xmlpp::Element*) const;
std::string technical_summary () const;
std::string identifier () const;
void take_settings_from (std::shared_ptr<const VideoContent> c);
boost::optional<dcp::Size> size_after_crop() const;
boost::optional<dcp::Size> scaled_size(dcp::Size container_size);
- boost::optional<double> fade (std::shared_ptr<const Film> film, Frame) const;
+ boost::optional<double> fade(std::shared_ptr<const Film> film, dcpomatic::ContentTime time) const;
std::string processing_description (std::shared_ptr<const Film> film);
void modify_position (std::shared_ptr<const Film> film, dcpomatic::DCPTime& pos) const;
void modify_trim_start (dcpomatic::ContentTime& pos) const;
+ void rotate_size();
+
static std::shared_ptr<VideoContent> from_xml (Content* parent, cxml::ConstNodePtr node, int version, VideoRange video_range_hint);
private:
opt.add_option('--disable-tests', action='store_true', default=False, help='disable building of tests')
opt.add_option('--target-windows-64', action='store_true', default=False, help='set up to do a cross-compile for Windows 64-bit')
opt.add_option('--target-windows-32', action='store_true', default=False, help='set up to do a cross-compile for Windows 32-bit')
- opt.add_option('--target-macos-arm64', action='store_true', default=False, help='set up to do a cross-compile for macOS arm64')
opt.add_option('--static-dcpomatic', action='store_true', default=False, help='link to components of DCP-o-matic statically')
opt.add_option('--static-boost', action='store_true', default=False, help='link statically to Boost')
opt.add_option('--static-wxwidgets', action='store_true', default=False, help='link statically to wxWidgets')
opt.add_option('--workaround-gssapi', action='store_true', default=False, help='link to gssapi_krb5')
opt.add_option('--use-lld', action='store_true', default=False, help='use lld linker')
opt.add_option('--enable-disk', action='store_true', default=False, help='build dcpomatic2_disk tool; requires Boost process, lwext4 and nanomsg libraries')
+ opt.add_option('--enable-grok', action='store_true', default=False, help='build with support for grok J2K encoder')
opt.add_option('--warnings-are-errors', action='store_true', default=False, help='build with -Werror')
opt.add_option('--wx-config', help='path to wx-config')
opt.add_option('--enable-asan', action='store_true', help='build with asan')
opt.add_option('--disable-more-warnings', action='store_true', default=False, help='disable some warnings raised by Xcode 15 with the 2.16 branch')
+ opt.add_option('--c++17', action='store_true', default=False, help='build with C++17 and libxml++-4.0')
def configure(conf):
conf.load('compiler_cxx')
if conf.options.target_windows_64 or conf.options.target_windows_32:
conf.load('winres')
+ if vars(conf.options)['c++17']:
+ cpp_std = '17'
+ conf.env.XMLPP_API = '4.0'
+ conf.env.PANGOMM_API = '2.48'
+ conf.env.CAIROMM_API = '1.16'
+ else:
+ cpp_std = '11'
+ conf.env.XMLPP_API = '2.6'
+ conf.env.PANGOMM_API = '1.4'
+ conf.env.CAIROMM_API = '1.0'
+
# Save conf.options that we need elsewhere in conf.env
conf.env.DISABLE_GUI = conf.options.disable_gui
conf.env.DISABLE_TESTS = conf.options.disable_tests
conf.env.DEBUG = conf.options.enable_debug
conf.env.STATIC_DCPOMATIC = conf.options.static_dcpomatic
conf.env.ENABLE_DISK = conf.options.enable_disk
+ conf.env.ENABLE_GROK = conf.options.enable_grok
if conf.options.destdir == '':
conf.env.INSTALL_PREFIX = conf.options.prefix
else:
conf.env.INSTALL_PREFIX = conf.options.destdir
+ conf.check_cxx(cxxflags=['-msse', '-mfpmath=sse'], msg='Checking for SSE support', mandatory=False, define_name='SSE')
+
# Common CXXFLAGS
conf.env.append_value('CXXFLAGS', ['-D__STDC_CONSTANT_MACROS',
'-D__STDC_LIMIT_MACROS',
'-Wall',
'-Wextra',
'-Wwrite-strings',
+ # getMessengerLogger() in the grok code triggers these warnings
+ '-Wno-nonnull',
'-Wno-error=deprecated',
# I tried and failed to ignore these with _Pragma
'-Wno-ignored-qualifiers',
'-D_FILE_OFFSET_BITS=64',
- '-std=c++11'])
+ '-std=c++' + cpp_std])
if conf.options.disable_more_warnings:
# These are for Xcode 15.0.1 with the v2.16.x-era
if conf.options.warnings_are_errors:
conf.env.append_value('CXXFLAGS', '-Werror')
- if not conf.options.target_macos_arm64:
- conf.env.append_value('CXXFLAGS', '-msse')
+ if conf.env.SSE:
+ conf.env.append_value('CXXFLAGS', ['-msse', '-mfpmath=sse'])
if conf.options.enable_asan:
conf.env.append_value('CXXFLAGS', '-fsanitize=address')
conf.env.append_value('CXXFLAGS', ['-Wno-cast-function-type'])
# Most gccs still give these warnings from boost::optional
conf.env.append_value('CXXFLAGS', ['-Wno-maybe-uninitialized'])
- if int(gcc[0]) > 4:
+ if int(gcc[0]) > 8:
# gcc 4.8.5 on Centos 7 does not have this warning
+ # gcc 7.5.0 on Ubuntu 18.04 and gcc 8.3.0 on Debian 10 do, but
+ # I didn't manage to turn it back off again with a pragma
conf.env.append_value('CXXFLAGS', ['-Wsuggest-override'])
if conf.options.enable_debug:
if conf.options.enable_disk:
conf.env.append_value('CXXFLAGS', '-DDCPOMATIC_DISK')
+ if conf.options.enable_grok:
+ conf.env.append_value('CXXFLAGS', '-DDCPOMATIC_GROK')
+
if conf.options.use_lld:
try:
conf.find_program('ld.lld')
conf.env.append_value('CXXFLAGS', '-DWIN32_LEAN_AND_MEAN')
conf.env.append_value('CXXFLAGS', '-DBOOST_USE_WINDOWS_H')
conf.env.append_value('CXXFLAGS', '-DBOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN')
- conf.env.append_value('CXXFLAGS', '-mfpmath=sse')
conf.env.append_value('CXXFLAGS', '-Wcast-align')
wxrc = os.popen('wx-config --rescomp').read().split()[1:]
conf.env.append_value('WINRCFLAGS', wxrc)
# Linux
if conf.env.TARGET_LINUX:
- conf.env.append_value('CXXFLAGS', '-mfpmath=sse')
conf.env.append_value('CXXFLAGS', '-DLINUX_LOCALE_PREFIX="%s/share/locale"' % conf.env['INSTALL_PREFIX'])
conf.env.append_value('CXXFLAGS', '-DLINUX_SHARE_PREFIX="%s/share"' % conf.env['INSTALL_PREFIX'])
conf.env.append_value('CXXFLAGS', '-DDCPOMATIC_LINUX')
conf.check_cfg(package='fontconfig', args='--cflags --libs', uselib_store='FONTCONFIG', mandatory=True)
# pangomm
- conf.check_cfg(package='pangomm-1.4', args='--cflags --libs', uselib_store='PANGOMM', mandatory=True)
+ conf.check_cfg(package='pangomm-' + conf.env.PANGOMM_API, args='--cflags --libs', uselib_store='PANGOMM', mandatory=True)
# cairomm
- conf.check_cfg(package='cairomm-1.0', args='--cflags --libs', uselib_store='CAIROMM', mandatory=True)
+ conf.check_cfg(package='cairomm-' + conf.env.CAIROMM_API, args='--cflags --libs', uselib_store='CAIROMM', mandatory=True)
# leqm_nrt
conf.check_cfg(package='leqm_nrt', args='--cflags --libs', uselib_store='LEQM_NRT', mandatory=True)
if conf.options.static_dcp:
conf.check_cfg(package='libdcp-1.0', args='libdcp-1.0 >= %s --cflags' % libdcp_version, uselib_store='DCP', mandatory=True)
conf.env.DEFINES_DCP = [f.replace('\\', '') for f in conf.env.DEFINES_DCP]
- conf.env.STLIB_DCP = ['dcp-1.0', 'asdcp-carl', 'kumu-carl', 'openjp2']
+ conf.env.STLIB_DCP = ['dcp-1.0', 'asdcp-dcpomatic', 'kumu-dcpomatic', 'openjp2']
conf.env.LIB_DCP = ['glibmm-2.4', 'ssl', 'crypto', 'bz2', 'xslt', 'xerces-c']
else:
conf.check_cfg(package='libdcp-1.0', args='libdcp-1.0 >= %s --cflags --libs' % libdcp_version, uselib_store='DCP', mandatory=True)
# libxml++
if conf.options.static_xmlpp:
- conf.env.STLIB_XMLPP = ['xml++-2.6']
+ conf.env.STLIB_XMLPP = ['xml++-' + conf.env.XMLPP_API]
conf.env.LIB_XMLPP = ['xml2']
else:
- conf.check_cfg(package='libxml++-2.6', args='--cflags --libs', uselib_store='XMLPP', mandatory=True)
+ conf.check_cfg(package='libxml++-' + conf.env.XMLPP_API, args='--cflags --libs', uselib_store='XMLPP', mandatory=True)
# libxmlsec
if conf.options.static_xmlsec:
int main () { av_ebur128_get_true_peaks (0); }\n
""",
msg='Checking for EBUR128-patched FFmpeg',
- uselib='AVCODEC AVFILTER',
+ uselib='AVCODEC AVFILTER AVUTIL SWRESAMPLE',
define_name='DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG',
mandatory=False)
def build(bld):
create_version_cc(VERSION, bld.env.CXXFLAGS)
+ # waf can't find these dependencies by itself because they are only included if DCPOMATIC_GROK is defined,
+ # and I can't find a way to pass that to waf's dependency scanner
+ if bld.env.ENABLE_GROK:
+ for dep in (
+ 'src/lib/j2k_encoder.cc',
+ 'src/tools/dcpomatic.cc',
+ 'src/tools/dcpomatic_server.cc',
+ 'src/tools/dcpomatic_server_cli.cc',
+ 'src/tools/dcpomatic_batch.cc'
+ ):
+ bld.add_manual_dependency(bld.path.find_node(dep), bld.path.find_node('src/lib/grok/context.h'))
+ bld.add_manual_dependency(bld.path.find_node(dep), bld.path.find_node('src/lib/grok/messenger.h'))
+
+ bld.add_manual_dependency(bld.path.find_node('src/wx/full_config_dialog.cc'), bld.path.find_node('src/wx/grok/gpu_config_panel.h'))
+
bld.recurse('src')
bld.recurse('graphics')