From: Carl Hetherington Date: Sat, 23 Aug 2014 21:50:40 +0000 (+0100) Subject: Merge master. X-Git-Tag: v2.0.48~647 X-Git-Url: https://git.carlh.net/gitweb/?p=dcpomatic.git;a=commitdiff_plain;h=8c7a308c03e4b4196b4e2379a26d432b100ae2b1 Merge master. --- 8c7a308c03e4b4196b4e2379a26d432b100ae2b1 diff --cc ChangeLog index 23ccae190,8b0a5cd3e..e100fd23e --- a/ChangeLog +++ b/ChangeLog @@@ -1,21 -1,24 +1,43 @@@ +2014-08-06 Carl Hetherington + + * Version 2.0.1 released. + +2014-07-15 Carl Hetherington + + * A variety of changes were made on the 2.0 branch + but not documented in the ChangeLog. Most sigificantly: + + - DCP import + - Creation of DCPs with proper XML subtitles + - Import of .srt and .xml subtitles + - Audio processing framework (with some basic processors). + +2014-03-07 Carl Hetherington + + * Add subtitle view. + + 2014-08-23 Carl Hetherington + + * Version 1.72.12 released. + + 2014-08-23 Carl Hetherington + + * Revert previous use of AVFormatContext::start_time when + computing the length of video. I think this is wrong, and + causes bits to be missed off the end of videos (and other + problems). + + 2014-08-20 Carl Hetherington + + * Version 1.72.11 released. + + 2014-08-19 Carl Hetherington + + * Attempt to fix random crashes on OS X (especially during encodes) + thought to be caused by multiple threads using (different) stringstreams + at the same time; see src/lib/safe_stringstream. ++>>>>>>> origin/master + 2014-08-09 Carl Hetherington * Version 1.72.10 released. diff --cc debian/changelog index 1da8a1f91,f5d36b9df..09d401782 --- a/debian/changelog +++ b/debian/changelog @@@ -171,15 -171,12 +171,8 @@@ dcpomatic (2.0.1-1) UNRELEASED; urgency * New upstream release. * New upstream release. * New upstream release. - <<<<<<< HEAD - * New upstream release. - * New upstream release. - * New upstream release. - * New upstream release. - -- Carl Hetherington Sat, 23 Aug 2014 18:47:52 +0100 + -- Carl Hetherington Wed, 06 Aug 2014 18:59:35 +0100 - ======= - * New upstream release. - * New upstream release. - - -- Carl Hetherington Sat, 09 Aug 2014 12:38:18 +0100 - >>>>>>> origin/master dcpomatic (0.87-1) UNRELEASED; urgency=low diff --cc src/lib/content.cc index bbbe9b6ce,11a4b21cc..21e49a2c9 --- a/src/lib/content.cc +++ b/src/lib/content.cc @@@ -225,12 -230,12 +225,12 @@@ Content::length_after_trim () cons string Content::identifier () const { - stringstream s; + SafeStringStream s; s << Content::digest() - << "_" << position() - << "_" << trim_start() - << "_" << trim_end(); + << "_" << position().get() + << "_" << trim_start().get() + << "_" << trim_end().get(); return s.str (); } diff --cc src/lib/dcp_video.cc index 9b1c8c33e,000000000..d84986651 mode 100644,000000..100644 --- a/src/lib/dcp_video.cc +++ b/src/lib/dcp_video.cc @@@ -1,320 -1,0 +1,317 @@@ +/* + Copyright (C) 2012-2014 Carl Hetherington + Taken from code Copyright (C) 2010-2011 Terrence Meiczinger + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file src/dcp_video_frame.cc + * @brief A single frame of video destined for a DCP. + * + * Given an Image and some settings, this class knows how to encode + * the image to J2K either on the local host or on a remote server. + * + * Objects of this class are used for the queue that we keep + * of images that require encoding. + */ + +#include +#include +#include +#include +#include +#include - #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "film.h" +#include "dcp_video.h" +#include "config.h" +#include "exceptions.h" +#include "server.h" +#include "util.h" +#include "scaler.h" +#include "image.h" +#include "log.h" +#include "cross.h" +#include "player_video.h" +#include "encoded_data.h" + +#define LOG_GENERAL(...) _log->log (String::compose (__VA_ARGS__), Log::TYPE_GENERAL); + +#include "i18n.h" + +using std::string; - using std::stringstream; +using std::cout; +using boost::shared_ptr; +using boost::lexical_cast; +using dcp::Size; +using dcp::raw_convert; + +#define DCI_COEFFICENT (48.0 / 52.37) + +/** Construct a DCP video frame. + * @param frame Input frame. + * @param index Index of the frame within the DCP. + * @param bw J2K bandwidth to use (see Config::j2k_bandwidth ()) + * @param l Log to write to. + */ +DCPVideo::DCPVideo ( + shared_ptr frame, int index, int dcp_fps, int bw, Resolution r, bool b, shared_ptr l + ) + : _frame (frame) + , _index (index) + , _frames_per_second (dcp_fps) + , _j2k_bandwidth (bw) + , _resolution (r) + , _burn_subtitles (b) + , _log (l) +{ + +} + +DCPVideo::DCPVideo (shared_ptr frame, shared_ptr node, shared_ptr log) + : _frame (frame) + , _log (log) +{ + _index = node->number_child ("Index"); + _frames_per_second = node->number_child ("FramesPerSecond"); + _j2k_bandwidth = node->number_child ("J2KBandwidth"); + _resolution = Resolution (node->optional_number_child("Resolution").get_value_or (RESOLUTION_2K)); + _burn_subtitles = node->bool_child ("BurnSubtitles"); +} + +/** J2K-encode this frame on the local host. + * @return Encoded data. + */ +shared_ptr +DCPVideo::encode_locally () +{ + shared_ptr in_lut = dcp::GammaLUT::cache.get ( + 12, _frame->colour_conversion().input_gamma, _frame->colour_conversion().input_gamma_linearised + ); + + /* XXX: libdcp should probably use boost */ + + double matrix[3][3]; + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + matrix[i][j] = _frame->colour_conversion().matrix (i, j); + } + } + + shared_ptr xyz = dcp::rgb_to_xyz ( + _frame->image (_burn_subtitles), + in_lut, + dcp::GammaLUT::cache.get (16, 1 / _frame->colour_conversion().output_gamma, false), + matrix + ); + + /* Set the max image and component sizes based on frame_rate */ + int max_cs_len = ((float) _j2k_bandwidth) / 8 / _frames_per_second; + if (_frame->eyes() == EYES_LEFT || _frame->eyes() == EYES_RIGHT) { + /* In 3D we have only half the normal bandwidth per eye */ + max_cs_len /= 2; + } + int const max_comp_size = max_cs_len / 1.25; + + /* get a J2K compressor handle */ + opj_cinfo_t* cinfo = opj_create_compress (CODEC_J2K); + if (cinfo == 0) { + throw EncodeError (N_("could not create JPEG2000 encoder")); + } + + /* Set encoding parameters to default values */ + opj_cparameters_t parameters; + opj_set_default_encoder_parameters (¶meters); + + /* Set default cinema parameters */ + parameters.tile_size_on = false; + parameters.cp_tdx = 1; + parameters.cp_tdy = 1; + + /* Tile part */ + parameters.tp_flag = 'C'; + parameters.tp_on = 1; + + /* Tile and Image shall be at (0,0) */ + parameters.cp_tx0 = 0; + parameters.cp_ty0 = 0; + parameters.image_offset_x0 = 0; + parameters.image_offset_y0 = 0; + + /* Codeblock size = 32x32 */ + parameters.cblockw_init = 32; + parameters.cblockh_init = 32; + parameters.csty |= 0x01; + + /* The progression order shall be CPRL */ + parameters.prog_order = CPRL; + + /* No ROI */ + parameters.roi_compno = -1; + + parameters.subsampling_dx = 1; + parameters.subsampling_dy = 1; + + /* 9-7 transform */ + parameters.irreversible = 1; + + parameters.tcp_rates[0] = 0; + parameters.tcp_numlayers++; + parameters.cp_disto_alloc = 1; + parameters.cp_rsiz = _resolution == RESOLUTION_2K ? CINEMA2K : CINEMA4K; + if (_resolution == RESOLUTION_4K) { + parameters.numpocs = 2; + parameters.POC[0].tile = 1; + parameters.POC[0].resno0 = 0; + parameters.POC[0].compno0 = 0; + parameters.POC[0].layno1 = 1; + parameters.POC[0].resno1 = parameters.numresolution - 1; + parameters.POC[0].compno1 = 3; + parameters.POC[0].prg1 = CPRL; + parameters.POC[1].tile = 1; + parameters.POC[1].resno0 = parameters.numresolution - 1; + parameters.POC[1].compno0 = 0; + parameters.POC[1].layno1 = 1; + parameters.POC[1].resno1 = parameters.numresolution; + parameters.POC[1].compno1 = 3; + parameters.POC[1].prg1 = CPRL; + } + + parameters.cp_comment = strdup (N_("DCP-o-matic")); + parameters.cp_cinema = _resolution == RESOLUTION_2K ? CINEMA2K_24 : CINEMA4K_24; + + /* 3 components, so use MCT */ + parameters.tcp_mct = 1; + + /* set max image */ + parameters.max_comp_size = max_comp_size; + parameters.tcp_rates[0] = ((float) (3 * xyz->size().width * xyz->size().height * 12)) / (max_cs_len * 8); + + /* Set event manager to null (openjpeg 1.3 bug) */ + cinfo->event_mgr = 0; + + /* Setup the encoder parameters using the current image and user parameters */ + opj_setup_encoder (cinfo, ¶meters, xyz->opj_image ()); + + opj_cio_t* cio = opj_cio_open ((opj_common_ptr) cinfo, 0, 0); + if (cio == 0) { + opj_destroy_compress (cinfo); + throw EncodeError (N_("could not open JPEG2000 stream")); + } + + int const r = opj_encode (cinfo, cio, xyz->opj_image(), 0); + if (r == 0) { + opj_cio_close (cio); + opj_destroy_compress (cinfo); + throw EncodeError (N_("JPEG2000 encoding failed")); + } + + switch (_frame->eyes()) { + case EYES_BOTH: + LOG_GENERAL (N_("Finished locally-encoded frame %1 for mono"), _index); + break; + case EYES_LEFT: + LOG_GENERAL (N_("Finished locally-encoded frame %1 for L"), _index); + break; + case EYES_RIGHT: + LOG_GENERAL (N_("Finished locally-encoded frame %1 for R"), _index); + break; + default: + break; + } + + shared_ptr enc (new LocallyEncodedData (cio->buffer, cio_tell (cio))); + + opj_cio_close (cio); + free (parameters.cp_comment); + opj_destroy_compress (cinfo); + + return enc; +} + +/** Send this frame to a remote server for J2K encoding, then read the result. + * @param serv Server to send to. + * @return Encoded data. + */ +shared_ptr +DCPVideo::encode_remotely (ServerDescription serv) +{ + boost::asio::io_service io_service; + boost::asio::ip::tcp::resolver resolver (io_service); + boost::asio::ip::tcp::resolver::query query (serv.host_name(), raw_convert (Config::instance()->server_port_base ())); + boost::asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve (query); + + shared_ptr socket (new Socket); + + socket->connect (*endpoint_iterator); + + /* Collect all XML metadata */ + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("EncodingRequest"); + root->add_child("Version")->add_child_text (raw_convert (SERVER_LINK_VERSION)); + add_metadata (root); + + LOG_GENERAL (N_("Sending frame %1 to remote"), _index); + + /* Send XML metadata */ - stringstream xml; - doc.write_to_stream (xml, "UTF-8"); - socket->write (xml.str().length() + 1); - socket->write ((uint8_t *) xml.str().c_str(), xml.str().length() + 1); ++ string xml = doc.write_to_string ("UTF-8"); ++ socket->write (xml.length() + 1); ++ socket->write ((uint8_t *) xml.c_str(), xml.length() + 1); + + /* Send binary data */ + _frame->send_binary (socket, _burn_subtitles); + + /* Read the response (JPEG2000-encoded data); this blocks until the data + is ready and sent back. + */ + shared_ptr e (new RemotelyEncodedData (socket->read_uint32 ())); + socket->read (e->data(), e->size()); + + LOG_GENERAL (N_("Finished remotely-encoded frame %1"), _index); + + return e; +} + +void +DCPVideo::add_metadata (xmlpp::Element* el) const +{ + el->add_child("Index")->add_child_text (raw_convert (_index)); + el->add_child("FramesPerSecond")->add_child_text (raw_convert (_frames_per_second)); + el->add_child("J2KBandwidth")->add_child_text (raw_convert (_j2k_bandwidth)); + el->add_child("Resolution")->add_child_text (raw_convert (int (_resolution))); + el->add_child("BurnSubtitles")->add_child_text (_burn_subtitles ? "1" : "0"); + _frame->add_metadata (el, _burn_subtitles); +} + +Eyes +DCPVideo::eyes () const +{ + return _frame->eyes (); +} + diff --cc src/lib/ffmpeg_content.cc index 0af53d883,a4209f5b6..bb4e02230 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@@ -235,9 -241,9 +235,9 @@@ FFmpegContent::information () cons return ""; } - stringstream s; + SafeStringStream s; - s << String::compose (_("%1 frames; %2 frames per second"), video_length_after_3d_combine(), video_frame_rate()) << "\n"; + s << String::compose (_("%1 frames; %2 frames per second"), video_length_after_3d_combine().frames (video_frame_rate()), video_frame_rate()) << "\n"; s << VideoContent::information (); return s.str (); diff --cc src/lib/ffmpeg_examiner.cc index 62b909b1d,5ccc8028b..48d85da6f --- a/src/lib/ffmpeg_examiner.cc +++ b/src/lib/ffmpeg_examiner.cc @@@ -23,9 -23,7 +23,10 @@@ extern "C" } #include "ffmpeg_examiner.h" #include "ffmpeg_content.h" +#include "ffmpeg_audio_stream.h" +#include "ffmpeg_subtitle_stream.h" +#include "util.h" + #include "safe_stringstream.h" #include "i18n.h" @@@ -159,25 -118,27 +159,25 @@@ FFmpegExaminer::frame_time (AVStream* s float FFmpegExaminer::video_frame_rate () const { - AVStream* s = _format_context->streams[_video_stream]; - - if (s->avg_frame_rate.num && s->avg_frame_rate.den) { - return av_q2d (s->avg_frame_rate); - } - - return av_q2d (s->r_frame_rate); + /* This use of r_frame_rate is debateable; there's a few different + * frame rates in the format context, but this one seems to be the most + * reliable. + */ + return av_q2d (av_stream_get_r_frame_rate (_format_context->streams[_video_stream])); } -libdcp::Size +dcp::Size FFmpegExaminer::video_size () const { - return libdcp::Size (video_codec_context()->width, video_codec_context()->height); + return dcp::Size (video_codec_context()->width, video_codec_context()->height); } -/** @return Length (in video frames) according to our content's header */ -VideoContent::Frame +/** @return Length according to our content's header */ +ContentTime FFmpegExaminer::video_length () const { - ContentTime const length = ContentTime::from_seconds (double (_format_context->duration - _format_context->start_time) / AV_TIME_BASE); - VideoContent::Frame const length = (double (_format_context->duration) / AV_TIME_BASE) * video_frame_rate(); - return max (1, length); ++ ContentTime const length = ContentTime::from_seconds (double (_format_context->duration) / AV_TIME_BASE); + return ContentTime (max (ContentTime::Type (1), length.get ())); } string diff --cc src/lib/image_content.cc index 70d777bca,915da7beb..84b0b75c9 --- a/src/lib/image_content.cc +++ b/src/lib/image_content.cc @@@ -24,7 -25,7 +24,8 @@@ #include "film.h" #include "job.h" #include "frame_rate_change.h" +#include "exceptions.h" + #include "safe_stringstream.h" #include "i18n.h" @@@ -134,9 -138,9 +134,9 @@@ ImageContent::full_length () cons string ImageContent::identifier () const { - stringstream s; + SafeStringStream s; s << VideoContent::identifier (); - s << "_" << video_length(); + s << "_" << video_length().get(); return s.str (); } diff --cc src/lib/server.cc index 5598ef69f,9591be188..d2c573c1b --- a/src/lib/server.cc +++ b/src/lib/server.cc @@@ -34,11 -33,11 +33,12 @@@ #include "util.h" #include "scaler.h" #include "image.h" -#include "dcp_video_frame.h" +#include "dcp_video.h" #include "config.h" #include "cross.h" -#include "player_video_frame.h" +#include "player_video.h" +#include "encoded_data.h" + #include "safe_stringstream.h" #include "i18n.h" diff --cc src/lib/sndfile_content.cc index a573d43c4,ba3bd0a77..1a1797665 --- a/src/lib/sndfile_content.cc +++ b/src/lib/sndfile_content.cc @@@ -29,10 -30,9 +30,9 @@@ #include "i18n.h" using std::string; - using std::stringstream; using std::cout; using boost::shared_ptr; -using libdcp::raw_convert; +using dcp::raw_convert; SndfileContent::SndfileContent (shared_ptr f, boost::filesystem::path p) : Content (f, p) diff --cc src/lib/transcode_job.cc index 1a162b654,831c74b3b..23a46d06d --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@@ -34,10 -35,8 +35,9 @@@ #define LOG_ERROR_NC(...) _film->log()->log (__VA_ARGS__, Log::TYPE_ERROR); using std::string; - using std::stringstream; using std::fixed; using std::setprecision; +using std::cout; using boost::shared_ptr; /** @param s Film to use. diff --cc src/lib/update.cc index 44ecbb232,7bec061e9..0146df484 --- a/src/lib/update.cc +++ b/src/lib/update.cc @@@ -109,14 -100,11 +109,13 @@@ UpdateChecker::thread ( set_state (FAILED); return; } + + /* Parse the reply */ _buffer[_offset] = '\0'; - stringstream s; - s << _buffer; + string s (_buffer); cxml::Document doc ("Update"); - doc.read_stream (s); + doc.read_string (s); { boost::mutex::scoped_lock lm (_data_mutex); diff --cc src/lib/util.cc index 60953b544,d96001d13..c9685aa44 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@@ -69,9 -68,8 +68,10 @@@ extern "C" #include "job.h" #include "cross.h" #include "video_content.h" +#include "rect.h" #include "md5_digester.h" +#include "audio_processor.h" + #include "safe_stringstream.h" #ifdef DCPOMATIC_WINDOWS #include "stack.hpp" #endif @@@ -885,27 -951,6 +884,27 @@@ divide_with_round (int64_t a, int64_t b } } +/** Return a user-readable string summarising the versions of our dependencies */ +string +dependency_version_summary () +{ - stringstream s; ++ SafeStringStream s; + s << N_("libopenjpeg ") << opj_version () << N_(", ") + << N_("libavcodec ") << ffmpeg_version_to_string (avcodec_version()) << N_(", ") + << N_("libavfilter ") << ffmpeg_version_to_string (avfilter_version()) << N_(", ") + << N_("libavformat ") << ffmpeg_version_to_string (avformat_version()) << N_(", ") + << N_("libavutil ") << ffmpeg_version_to_string (avutil_version()) << N_(", ") + << N_("libswscale ") << ffmpeg_version_to_string (swscale_version()) << N_(", ") + << MagickVersion << N_(", ") + << N_("libssh ") << ssh_version (0) << N_(", ") + << N_("libdcp ") << dcp::version << N_(" git ") << dcp::git_commit; + + return s.str (); +} + +/** Construct a ScopedTemporary. A temporary filename is decided but the file is not opened + * until ::open() is called. + */ ScopedTemporary::ScopedTemporary () : _open (0) { diff --cc src/lib/video_content.cc index 0a3e378ee,b0d4c2de5..796e6575a --- a/src/lib/video_content.cc +++ b/src/lib/video_content.cc @@@ -31,7 -31,7 +31,8 @@@ #include "film.h" #include "exceptions.h" #include "frame_rate_change.h" +#include "log.h" + #include "safe_stringstream.h" #include "i18n.h" diff --cc src/lib/wscript index 15f26c34f,1e4efddc4..2510ebe2a --- a/src/lib/wscript +++ b/src/lib/wscript @@@ -55,16 -41,14 +55,17 @@@ sources = "" job_manager.cc kdm.cc log.cc + magick_image_proxy.cc md5_digester.cc - piece.cc + mid_side_decoder.cc player.cc - player_video_frame.cc + player_video.cc playlist.cc ratio.cc + raw_image_proxy.cc + render_subtitles.cc resampler.cc + safe_stringstream.cc scp_dcp_job.cc scaler.cc send_kdm_email_job.cc diff --cc src/wx/film_editor.cc index 37a8c8808,87310d21a..1ce4695d6 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@@ -44,7 -45,7 +44,8 @@@ #include "lib/playlist.h" #include "lib/content.h" #include "lib/content_factory.h" +#include "lib/dcp_content.h" + #include "lib/safe_stringstream.h" #include "timecode.h" #include "wx_util.h" #include "film_editor.h" @@@ -107,9 -420,96 +107,8 @@@ FilmEditor::film_changed (Film::Propert return; } - SafeStringStream s; - - for (list::iterator i = _panels.begin(); i != _panels.end(); ++i) { - (*i)->film_changed (p); - } - - switch (p) { - case Film::NONE: - break; - case Film::CONTENT: - setup_content (); - break; - case Film::CONTAINER: - setup_container (); - break; - case Film::NAME: - checked_set (_name, _film->name()); - setup_dcp_name (); - break; - case Film::WITH_SUBTITLES: - setup_dcp_name (); - break; - case Film::DCP_CONTENT_TYPE: - checked_set (_dcp_content_type, DCPContentType::as_index (_film->dcp_content_type ())); - setup_dcp_name (); - break; - case Film::SCALER: - checked_set (_scaler, Scaler::as_index (_film->scaler ())); - break; - case Film::SIGNED: - checked_set (_signed, _film->is_signed ()); - break; - case Film::ENCRYPTED: - checked_set (_encrypted, _film->encrypted ()); - if (_film->encrypted ()) { - _film->set_signed (true); - _signed->Enable (false); - } else { - _signed->Enable (_generally_sensitive); - } - break; - case Film::RESOLUTION: - checked_set (_resolution, _film->resolution() == RESOLUTION_2K ? 0 : 1); - setup_dcp_name (); - break; - case Film::J2K_BANDWIDTH: - checked_set (_j2k_bandwidth, _film->j2k_bandwidth() / 1000000); - break; - case Film::USE_ISDCF_NAME: - checked_set (_use_isdcf_name, _film->use_isdcf_name ()); - setup_dcp_name (); - break; - case Film::ISDCF_METADATA: - setup_dcp_name (); - break; - case Film::VIDEO_FRAME_RATE: - { - bool done = false; - for (unsigned int i = 0; i < _frame_rate_choice->GetCount(); ++i) { - if (wx_to_std (_frame_rate_choice->GetString(i)) == boost::lexical_cast (_film->video_frame_rate())) { - checked_set (_frame_rate_choice, i); - done = true; - break; - } - } - - if (!done) { - checked_set (_frame_rate_choice, -1); - } - - _frame_rate_spin->SetValue (_film->video_frame_rate ()); - - _best_frame_rate->Enable (_film->best_video_frame_rate () != _film->video_frame_rate ()); - break; - } - case Film::AUDIO_CHANNELS: - checked_set (_audio_channels, _film->audio_channels ()); - setup_dcp_name (); - break; - case Film::SEQUENCE_VIDEO: - checked_set (_sequence_video, _film->sequence_video ()); - break; - case Film::THREE_D: - checked_set (_three_d, _film->three_d ()); - setup_dcp_name (); - break; - case Film::INTEROP: - checked_set (_standard, _film->interop() ? 1 : 0); - break; - } + _content_panel->film_changed (p); + _dcp_panel->film_changed (p); - } void @@@ -171,4 -720,343 +170,3 @@@ FilmEditor::active_jobs_changed (bool a { set_general_sensitivity (!a); } - -void -FilmEditor::setup_dcp_name () -{ - string s = _film->dcp_name (true); - if (s.length() > 28) { - _dcp_name->SetLabel (std_to_wx (s.substr (0, 28)) + N_("...")); - _dcp_name->SetToolTip (std_to_wx (s)); - } else { - _dcp_name->SetLabel (std_to_wx (s)); - } -} - -void -FilmEditor::best_frame_rate_clicked () -{ - if (!_film) { - return; - } - - _film->set_video_frame_rate (_film->best_video_frame_rate ()); -} - -void -FilmEditor::setup_content () -{ - string selected_summary; - int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - if (s != -1) { - selected_summary = wx_to_std (_content->GetItemText (s)); - } - - _content->DeleteAllItems (); - - ContentList content = _film->content (); - sort (content.begin(), content.end(), ContentSorter ()); - - for (ContentList::iterator i = content.begin(); i != content.end(); ++i) { - int const t = _content->GetItemCount (); - bool const valid = (*i)->paths_valid (); - - string s = (*i)->summary (); - if (!valid) { - s = _("MISSING: ") + s; - } - - _content->InsertItem (t, std_to_wx (s)); - - if ((*i)->summary() == selected_summary) { - _content->SetItemState (t, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); - } - - if (!valid) { - _content->SetItemTextColour (t, *wxRED); - } - } - - if (selected_summary.empty () && !content.empty ()) { - /* Select the item of content if none was selected before */ - _content->SetItemState (0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); - } -} - -void -FilmEditor::content_add_file_clicked () -{ - /* The wxFD_CHANGE_DIR here prevents a `could not set working directory' error 123 on Windows when using - non-Latin filenames or paths. - */ - wxFileDialog* d = new wxFileDialog (this, _("Choose a file or files"), wxT (""), wxT (""), wxT ("*.*"), wxFD_MULTIPLE | wxFD_CHANGE_DIR); - int const r = d->ShowModal (); - - if (r != wxID_OK) { - d->Destroy (); - return; - } - - wxArrayString paths; - d->GetPaths (paths); - - /* XXX: check for lots of files here and do something */ - - for (unsigned int i = 0; i < paths.GetCount(); ++i) { - _film->examine_and_add_content (content_factory (_film, wx_to_std (paths[i]))); - } - - d->Destroy (); -} - -void -FilmEditor::content_add_folder_clicked () -{ - wxDirDialog* d = new wxDirDialog (this, _("Choose a folder"), wxT (""), wxDD_DIR_MUST_EXIST); - int const r = d->ShowModal (); - d->Destroy (); - - if (r != wxID_OK) { - return; - } - - shared_ptr ic; - - try { - ic.reset (new ImageContent (_film, boost::filesystem::path (wx_to_std (d->GetPath ())))); - } catch (FileError& e) { - error_dialog (this, std_to_wx (e.what ())); - return; - } - - _film->examine_and_add_content (ic); -} - -void -FilmEditor::content_remove_clicked () -{ - ContentList c = selected_content (); - for (ContentList::iterator i = c.begin(); i != c.end(); ++i) { - _film->remove_content (*i); - } - - content_selection_changed (); -} - -void -FilmEditor::content_selection_changed () -{ - setup_content_sensitivity (); - - for (list::iterator i = _panels.begin(); i != _panels.end(); ++i) { - (*i)->content_selection_changed (); - } -} - -/** Set up broad sensitivity based on the type of content that is selected */ -void -FilmEditor::setup_content_sensitivity () -{ - _content_add_file->Enable (_generally_sensitive); - _content_add_folder->Enable (_generally_sensitive); - - ContentList selection = selected_content (); - VideoContentList video_selection = selected_video_content (); - AudioContentList audio_selection = selected_audio_content (); - - _content_remove->Enable (!selection.empty() && _generally_sensitive); - _content_earlier->Enable (selection.size() == 1 && _generally_sensitive); - _content_later->Enable (selection.size() == 1 && _generally_sensitive); - _content_timeline->Enable (!_film->content().empty() && _generally_sensitive); - - _video_panel->Enable (!video_selection.empty() && _generally_sensitive); - _audio_panel->Enable (!audio_selection.empty() && _generally_sensitive); - _subtitle_panel->Enable (selection.size() == 1 && dynamic_pointer_cast (selection.front()) && _generally_sensitive); - _timing_panel->Enable (!selection.empty() && _generally_sensitive); -} - -ContentList -FilmEditor::selected_content () -{ - ContentList sel; - - if (!_film) { - return sel; - } - - /* The list was populated using a sorted content list, so we must sort it here too - so that we can look up by index and get the right thing. - */ - ContentList content = _film->content (); - sort (content.begin(), content.end(), ContentSorter ()); - - long int s = -1; - while (true) { - s = _content->GetNextItem (s, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); - if (s == -1) { - break; - } - - if (s < int (_film->content().size ())) { - sel.push_back (content[s]); - } - } - - return sel; -} - -VideoContentList -FilmEditor::selected_video_content () -{ - ContentList c = selected_content (); - VideoContentList vc; - - for (ContentList::iterator i = c.begin(); i != c.end(); ++i) { - shared_ptr t = dynamic_pointer_cast (*i); - if (t) { - vc.push_back (t); - } - } - - return vc; -} - -AudioContentList -FilmEditor::selected_audio_content () -{ - ContentList c = selected_content (); - AudioContentList ac; - - for (ContentList::iterator i = c.begin(); i != c.end(); ++i) { - shared_ptr t = dynamic_pointer_cast (*i); - if (t) { - ac.push_back (t); - } - } - - return ac; -} - -SubtitleContentList -FilmEditor::selected_subtitle_content () -{ - ContentList c = selected_content (); - SubtitleContentList sc; - - for (ContentList::iterator i = c.begin(); i != c.end(); ++i) { - shared_ptr t = dynamic_pointer_cast (*i); - if (t) { - sc.push_back (t); - } - } - - return sc; -} - -FFmpegContentList -FilmEditor::selected_ffmpeg_content () -{ - ContentList c = selected_content (); - FFmpegContentList sc; - - for (ContentList::iterator i = c.begin(); i != c.end(); ++i) { - shared_ptr t = dynamic_pointer_cast (*i); - if (t) { - sc.push_back (t); - } - } - - return sc; -} - -void -FilmEditor::content_timeline_clicked () -{ - if (_timeline_dialog) { - _timeline_dialog->Destroy (); - _timeline_dialog = 0; - } - - _timeline_dialog = new TimelineDialog (this, _film); - _timeline_dialog->Show (); -} - -void -FilmEditor::set_selection (weak_ptr wc) -{ - ContentList content = _film->content (); - for (size_t i = 0; i < content.size(); ++i) { - if (content[i] == wc.lock ()) { - _content->SetItemState (i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); - } else { - _content->SetItemState (i, 0, wxLIST_STATE_SELECTED); - } - } -} - -void -FilmEditor::sequence_video_changed () -{ - if (!_film) { - return; - } - - _film->set_sequence_video (_sequence_video->GetValue ()); -} - -void -FilmEditor::content_right_click (wxListEvent& ev) -{ - _menu.popup (_film, selected_content (), ev.GetPoint ()); -} - -void -FilmEditor::three_d_changed () -{ - if (!_film) { - return; - } - - _film->set_three_d (_three_d->GetValue ()); -} - -void -FilmEditor::content_earlier_clicked () -{ - ContentList sel = selected_content (); - if (sel.size() == 1) { - _film->move_content_earlier (sel.front ()); - content_selection_changed (); - } -} - -void -FilmEditor::content_later_clicked () -{ - ContentList sel = selected_content (); - if (sel.size() == 1) { - _film->move_content_later (sel.front ()); - content_selection_changed (); - } -} - -void -FilmEditor::config_changed () -{ - _j2k_bandwidth->SetRange (1, Config::instance()->maximum_j2k_bandwidth() / 1000000); - setup_frame_rate_widget (); -} - -void -FilmEditor::setup_frame_rate_widget () -{ - if (Config::instance()->allow_any_dcp_frame_rate ()) { - _frame_rate_choice->Hide (); - _frame_rate_spin->Show (); - } else { - _frame_rate_choice->Show (); - _frame_rate_spin->Hide (); - } -- - _frame_rate_sizer->Layout (); -} diff --cc src/wx/properties_dialog.cc index 801996efa,53ca23755..27fc75b1b --- a/src/wx/properties_dialog.cc +++ b/src/wx/properties_dialog.cc @@@ -45,9 -45,10 +45,9 @@@ PropertiesDialog::PropertiesDialog (wxW add (_("Frames already encoded"), true); _encoded = add (new ThreadedStaticText (this, _("counting..."), boost::bind (&PropertiesDialog::frames_already_encoded, this))); _encoded->Finished.connect (boost::bind (&PropertiesDialog::layout, this)); - - _frames->SetLabel (std_to_wx (lexical_cast (_film->time_to_video_frames (_film->length())))); + _frames->SetLabel (std_to_wx (lexical_cast (_film->length().frames (_film->video_frame_rate ())))); double const disk = double (_film->required_disk_space()) / 1073741824.0f; - stringstream s; + SafeStringStream s; s << fixed << setprecision (1) << disk << wx_to_std (_("Gb")); _disk->SetLabel (std_to_wx (s.str ())); diff --cc test/film_metadata_test.cc index f0a544e50,c9f4a2c38..01cff5b06 --- a/test/film_metadata_test.cc +++ b/test/film_metadata_test.cc @@@ -17,11 -17,6 +17,10 @@@ */ +/** @file test/film_metadata_test.cc + * @brief Test some basic reading/writing of film metadata. + */ + - #include #include #include #include