Merge master.
authorCarl Hetherington <cth@carlh.net>
Tue, 16 Sep 2014 22:26:55 +0000 (23:26 +0100)
committerCarl Hetherington <cth@carlh.net>
Tue, 16 Sep 2014 22:26:55 +0000 (23:26 +0100)
1  2 
ChangeLog
debian/changelog
src/lib/audio_decoder.cc
src/wx/about_dialog.cc
src/wx/wx_util.cc

diff --combined ChangeLog
index 222a0eea15acdcf95e8a3407f9fbac80f21af7b8,f028d76f3a2a5f3e56ad6730f3b4b0c7aa78b6dd..65518b42bab72e50893d9e7dc899000381ad9914
+++ b/ChangeLog
@@@ -1,18 -1,25 +1,38 @@@
+ 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>
  
diff --combined debian/changelog
index 8dc45469bb6e0408514087fce7bfc1ea067ce6d0,16e2e433a5946ab9b2b6d6ca1cc5445775b90558..c71a60422ab52f203e25232b7be235be1446fc67
 -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
  
diff --combined src/lib/audio_decoder.cc
index 75619228635a845c2dd0d4680ea483a903e4e8e4,30bd2540a01ac361523fabc792dafe9ac1e27caa..f3251f306bf47284a71bc1d53917631e917c827b
@@@ -1,5 -1,5 +1,5 @@@
  /*
 -    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 ();
 +      }
  }
diff --combined src/wx/about_dialog.cc
index 44e8b935d1312867ef82a533b6a670c55b250fbd,ed5e327979421353db973e9dc99fb46da02cb35c..5ac732049a80880ef9fa1bd87f158ed28e5b1ff7
@@@ -1,5 -1,5 +1,5 @@@
  /*
 -    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"
@@@ -107,6 -103,7 +107,7 @@@ AboutDialog::AboutDialog (wxWindow* par
        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)
  {
diff --combined src/wx/wx_util.cc
index cf8b75dd24b78a66a6c0c7438514ca2b57bd2292,1e501f54fd5650a892b0ab5a2d189ba950482eac..003cc222f13ff400b1a64d4f4a06e112ee52a25a
@@@ -123,7 -123,7 +123,7 @@@ int const ThreadedStaticText::_update_e
   *  @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);
@@@ -139,7 -139,7 +139,7 @@@ ThreadedStaticText::~ThreadedStaticTex
  
  /** 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);
@@@ -193,7 -193,7 +193,7 @@@ voi
  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);
        }
  }