+ 2014-09-16 Carl Hetherington <cth@carlh.net>
+
+ * Version 1.73.7 released.
+
+ 2014-09-16 Carl Hetherington <cth@carlh.net>
+
+ * Fix non-update of audio gain when changing selected content.
+
+ 2014-09-14 Carl Hetherington <cth@carlh.net>
+
+ * Version 1.73.6 released.
+
+ 2014-09-14 Carl Hetherington <cth@carlh.net>
+
+ * Version 1.73.5 released.
+
+ 2014-09-14 Carl Hetherington <cth@carlh.net>
+
+ * Update to nl_NL translation from Cherif Ben Brahim.
+
2014-09-12 Carl Hetherington <cth@carlh.net>
+ * Version 2.0.9 released.
+
+2014-09-12 Carl Hetherington <cth@carlh.net>
+
+ * Add "re-examine" option to content context menu (#339).
+
+2014-09-11 Carl Hetherington <cth@carlh.net>
+
+ * Restore encoding optimisations for still-image sources.
+
+ * Add option to re-make signing chain with specified organisation,
+ common names etc. (#354)
+
* Allow separate X and Y scale for subtitles (#337).
2014-09-10 Carl Hetherington <cth@carlh.net>
* Fix hidden advanced preferences button in some locales.
-2014-09-08 Carl Hetherington <cth@carlh.net>
+ * Version 2.0.8 released.
+
+2014-09-10 Carl Hetherington <cth@carlh.net>
- * Version 1.73.4 released.
+ * Fix loading of 1.x films.
+
+ * Fix crash on audio analysis in some cases.
+
+2014-09-09 Carl Hetherington <cth@carlh.net>
+
+ * Version 2.0.7 released.
+
+2014-09-09 Carl Hetherington <cth@carlh.net>
+
+ * Version 2.0.6 released.
+
+2014-09-09 Carl Hetherington <cth@carlh.net>
+
+ * Fix missing OS X dependencies.
+
+ * Use a different directory for DCP-o-matic 2
+ configuration (not the same as 1.x).
2014-09-08 Carl Hetherington <cth@carlh.net>
- * Fix failure to load Targa files.
+ * Version 2.0.5 released.
-2014-09-07 Carl Hetherington <cth@carlh.net>
+ * Fix hidden advanced preferences button in some locales.
- * Version 1.73.3 released.
+2014-09-08 Carl Hetherington <cth@carlh.net>
+
+ * Fix failure to load Targa files.
2014-09-07 Carl Hetherington <cth@carlh.net>
* Fix a few bad fuzzy translations from the preferences dialog.
-2014-09-03 Carl Hetherington <cth@carlh.net>
-
- * Version 1.73.2 released.
-
2014-09-03 Carl Hetherington <cth@carlh.net>
* Fix server certificate downloads on OS X (#376).
2014-08-29 Carl Hetherington <cth@carlh.net>
+ * Version 2.0.4 released.
+
+2014-08-24 Carl Hetherington <cth@carlh.net>
+
+ * Version 2.0.3 released.
+
+2014-08-24 Carl Hetherington <cth@carlh.net>
+
+ * Version 2.0.2 released.
+
+2014-08-06 Carl Hetherington <cth@carlh.net>
+
+ * Version 2.0.1 released.
+
+2014-07-15 Carl Hetherington <cth@carlh.net>
+
+ * 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 <cth@carlh.net>
+
+ * Add subtitle view.
* Some improvements to the manual.
2014-08-26 Carl Hetherington <cth@carlh.net>
* 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 <cth@carlh.net>
2014-07-10 Carl Hetherington <cth@carlh.net>
* Version 1.72.2 released.
+>>>>>>> origin/master
2014-07-10 Carl Hetherington <cth@carlh.net>
-dcpomatic (1.73.7-1) UNRELEASED; urgency=low
+dcpomatic (2.0.9-1) UNRELEASED; urgency=low
* New upstream release.
- * New upstream release.
- * New upstream release.
- * New upstream release.
- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
-- * New upstream release.
- -- Carl Hetherington <carl@d1stkfactory> Tue, 16 Sep 2014 21:19:53 +0100
+ -- Carl Hetherington <carl@d1stkfactory> Fri, 12 Sep 2014 00:17:46 +0100
dcpomatic (0.87-1) UNRELEASED; urgency=low
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
*/
+ #include <iostream>
#include "audio_decoder.h"
#include "audio_buffers.h"
-#include "exceptions.h"
-#include "log.h"
+#include "audio_processor.h"
#include "resampler.h"
+#include "util.h"
#include "i18n.h"
using std::list;
using std::pair;
using std::cout;
+using std::min;
+using std::max;
using boost::optional;
using boost::shared_ptr;
-AudioDecoder::AudioDecoder (shared_ptr<const Film> film, shared_ptr<const AudioContent> content)
- : Decoder (film)
- , _audio_content (content)
- , _audio_position (0)
+AudioDecoder::AudioDecoder (shared_ptr<const AudioContent> content)
+ : _audio_content (content)
{
+ if (content->resampled_audio_frame_rate() != content->audio_frame_rate() && content->audio_channels ()) {
+ _resampler.reset (new Resampler (content->audio_frame_rate(), content->resampled_audio_frame_rate(), content->audio_channels ()));
+ }
+ if (content->audio_processor ()) {
+ _processor = content->audio_processor()->clone (content->resampled_audio_frame_rate ());
+ }
+
+ reset_decoded_audio ();
}
void
-AudioDecoder::audio (shared_ptr<const AudioBuffers> data, AudioContent::Frame frame)
+AudioDecoder::reset_decoded_audio ()
{
- Audio (data, frame);
- _audio_position = frame + data->frames ();
+ _decoded_audio = ContentAudio (shared_ptr<AudioBuffers> (new AudioBuffers (_audio_content->processed_audio_channels(), 0)), 0);
}
-/** This is a bit odd, but necessary when we have (e.g.) FFmpegDecoders with no audio.
- * The player needs to know that there is no audio otherwise it will keep trying to
- * pass() the decoder to get it to emit audio.
+shared_ptr<ContentAudio>
+AudioDecoder::get_audio (AudioFrame frame, AudioFrame length, bool accurate)
+{
+ shared_ptr<ContentAudio> dec;
+
+ AudioFrame const end = frame + length - 1;
+
+ if (frame < _decoded_audio.frame || end > (_decoded_audio.frame + length * 4)) {
+ /* Either we have no decoded data, or what we do have is a long way from what we want: seek */
+ seek (ContentTime::from_frames (frame, _audio_content->audio_frame_rate()), accurate);
+ }
+
+ /* Offset of the data that we want from the start of _decoded_audio.audio
+ (to be set up shortly)
+ */
+ AudioFrame decoded_offset = 0;
+
+ /* Now enough pass() calls will either:
+ * (a) give us what we want, or
+ * (b) hit the end of the decoder.
+ *
+ * If we are being accurate, we want the right frames,
+ * otherwise any frames will do.
+ */
+ if (accurate) {
+ /* Keep stuffing data into _decoded_audio until we have enough data, or the subclass does not want to give us any more */
+ while ((_decoded_audio.frame > frame || (_decoded_audio.frame + _decoded_audio.audio->frames()) < end) && !pass ()) {}
+ decoded_offset = frame - _decoded_audio.frame;
+ } else {
+ while (_decoded_audio.audio->frames() < length && !pass ()) {}
+ /* Use decoded_offset of 0, as we don't really care what frames we return */
+ }
+
+ /* The amount of data available in _decoded_audio.audio starting from `frame'. This could be -ve
+ if pass() returned true before we got enough data.
+ */
+ AudioFrame const available = _decoded_audio.audio->frames() - decoded_offset;
+
+ /* We will return either that, or the requested amount, whichever is smaller */
+ AudioFrame const to_return = max ((AudioFrame) 0, min (available, length));
+
+ /* Copy our data to the output */
+ shared_ptr<AudioBuffers> out (new AudioBuffers (_decoded_audio.audio->channels(), to_return));
+ out->copy_from (_decoded_audio.audio.get(), to_return, decoded_offset, 0);
+
+ AudioFrame const remaining = max ((AudioFrame) 0, available - to_return);
+
+ /* Clean up decoded; first, move the data after what we just returned to the start of the buffer */
+ _decoded_audio.audio->move (decoded_offset + to_return, 0, remaining);
+ /* And set up the number of frames we have left */
+ _decoded_audio.audio->set_frames (remaining);
+ /* Also bump where those frames are in terms of the content */
+ _decoded_audio.frame += decoded_offset + to_return;
+
+ return shared_ptr<ContentAudio> (new ContentAudio (out, frame));
+}
+
+/** Called by subclasses when audio data is ready.
+ *
+ * Audio timestamping is made hard by many factors, but perhaps the most entertaining is resampling.
+ * We have to assume that we are feeding continuous data into the resampler, and so we get continuous
+ * data out. Hence we do the timestamping here, post-resampler, just by counting samples.
+ *
+ * The time is passed in here so that after a seek we can set up our _audio_position. The
+ * time is ignored once this has been done.
*/
-bool
-AudioDecoder::has_audio () const
+void
+AudioDecoder::audio (shared_ptr<const AudioBuffers> data, ContentTime time)
+{
+ if (_resampler) {
+ data = _resampler->run (data);
+ }
+
+ if (_processor) {
+ data = _processor->run (data);
+ }
+
+ AudioFrame const frame_rate = _audio_content->resampled_audio_frame_rate ();
+
+ if (_seek_reference) {
+ /* We've had an accurate seek and now we're seeing some data */
+ ContentTime const delta = time - _seek_reference.get ();
+ AudioFrame const delta_frames = delta.frames (frame_rate);
+ if (delta_frames > 0) {
+ /* This data comes after the seek time. Pad the data with some silence. */
+ shared_ptr<AudioBuffers> padded (new AudioBuffers (data->channels(), data->frames() + delta_frames));
+ padded->make_silent ();
+ padded->copy_from (data.get(), data->frames(), 0, delta_frames);
+ data = padded;
+ time -= delta;
+ } else if (delta_frames < 0) {
+ /* This data comes before the seek time. Throw some data away */
+ AudioFrame const to_discard = min (-delta_frames, static_cast<AudioFrame> (data->frames()));
+ AudioFrame const to_keep = data->frames() - to_discard;
+ if (to_keep == 0) {
+ /* We have to throw all this data away, so keep _seek_reference and
+ try again next time some data arrives.
+ */
+ return;
+ }
+ shared_ptr<AudioBuffers> trimmed (new AudioBuffers (data->channels(), to_keep));
+ trimmed->copy_from (data.get(), to_keep, to_discard, 0);
+ data = trimmed;
+ time += ContentTime::from_frames (to_discard, frame_rate);
+ }
+ _seek_reference = optional<ContentTime> ();
+ }
+
+ if (!_audio_position) {
+ _audio_position = time.frames (frame_rate);
+ }
+
+ assert (_audio_position.get() >= (_decoded_audio.frame + _decoded_audio.audio->frames()));
+
+ add (data);
+}
+
+void
+AudioDecoder::add (shared_ptr<const AudioBuffers> data)
+{
+ if (!_audio_position) {
+ /* This should only happen when there is a seek followed by a flush, but
+ we need to cope with it.
+ */
+ return;
+ }
+
+ /* Resize _decoded_audio to fit the new data */
+ int new_size = 0;
+ if (_decoded_audio.audio->frames() == 0) {
+ /* There's nothing in there, so just store the new data */
+ new_size = data->frames ();
+ _decoded_audio.frame = _audio_position.get ();
+ } else {
+ /* Otherwise we need to extend _decoded_audio to include the new stuff */
+ new_size = _audio_position.get() + data->frames() - _decoded_audio.frame;
+ }
+
+ _decoded_audio.audio->ensure_size (new_size);
+ _decoded_audio.audio->set_frames (new_size);
+
+ /* Copy new data in */
+ _decoded_audio.audio->copy_from (data.get(), data->frames(), 0, _audio_position.get() - _decoded_audio.frame);
+ _audio_position = _audio_position.get() + data->frames ();
+
+ /* Limit the amount of data we keep in case nobody is asking for it */
+ int const max_frames = _audio_content->resampled_audio_frame_rate () * 10;
+ if (_decoded_audio.audio->frames() > max_frames) {
+ int const to_remove = _decoded_audio.audio->frames() - max_frames;
+ _decoded_audio.frame += to_remove;
+ _decoded_audio.audio->move (to_remove, 0, max_frames);
+ _decoded_audio.audio->set_frames (max_frames);
+ }
+}
+
+void
+AudioDecoder::flush ()
+{
+ if (!_resampler) {
+ return;
+ }
+
+ shared_ptr<const AudioBuffers> b = _resampler->flush ();
+ if (b) {
+ add (b);
+ }
+}
+
+void
+AudioDecoder::seek (ContentTime t, bool accurate)
{
- return _audio_content->audio_channels () > 0;
+ _audio_position.reset ();
+ reset_decoded_audio ();
+ if (accurate) {
+ _seek_reference = t;
+ }
+ if (_processor) {
+ _processor->flush ();
+ }
}
/*
- Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
*/
+/** @file src/wx/about_dialog.cc
+ * @brief The "about DCP-o-matic" dialogue box.
+ */
+
#include <wx/notebook.h>
#include <wx/hyperlink.h>
#include "lib/version.h"
translated_by.Add (wxT ("Max Aeschlimann"));
translated_by.Add (wxT ("Carsten Kurz"));
translated_by.Add (wxT ("Grégoire Ausina"));
+ translated_by.Add (wxT ("Cherif Ben Brahim"));
add_section (_("Translated by"), translated_by);
wxArrayString artwork_by;
SetSizerAndFit (overall_sizer);
}
+/** Add a section of credits.
+ * @param name Name of section.
+ * @param credits List of names.
+ */
void
AboutDialog::add_section (wxString name, wxArrayString credits)
{
* @param initial Initial text for the wxStaticText while the computation is being run.
* @param fn Function which works out what the wxStaticText content should be and returns it.
*/
-ThreadedStaticText::ThreadedStaticText (wxWindow* parent, wxString initial, function<string ()> fn)
+ThreadedStaticText::ThreadedStaticText (wxWindow* parent, wxString initial, boost::function<string ()> fn)
: wxStaticText (parent, wxID_ANY, initial)
{
Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ThreadedStaticText::thread_finished, this, _1), _update_event_id);
/** Run our thread and post the result to the GUI thread via AddPendingEvent */
void
-ThreadedStaticText::run (function<string ()> fn)
+ThreadedStaticText::run (boost::function<string ()> fn)
try
{
wxCommandEvent ev (wxEVT_COMMAND_TEXT_UPDATED, _update_event_id);
checked_set (wxSpinCtrlDouble* widget, double value)
{
/* XXX: completely arbitrary epsilon */
- if (fabs (widget->GetValue() - value) < 1e-16) {
+ if (fabs (widget->GetValue() - value) > 1e-16) {
widget->SetValue (value);
}
}