Try to fix up paths for video MXFs, hashes and temporarily-stored frames.
authorCarl Hetherington <cth@carlh.net>
Wed, 23 Jan 2013 20:49:26 +0000 (20:49 +0000)
committerCarl Hetherington <cth@carlh.net>
Wed, 23 Jan 2013 20:49:26 +0000 (20:49 +0000)
.gitignore
src/lib/check_hashes_job.cc [deleted file]
src/lib/check_hashes_job.h [deleted file]
src/lib/dcp_video_frame.cc
src/lib/encoder.cc
src/lib/encoder.h
src/lib/film.cc
src/lib/film.h
src/lib/transcode_job.cc
src/lib/writer.cc
src/lib/wscript

index 4c0c1926d846114f0346326afb5f784bcf8ecce3..cc3351558baabbdbcfe257501c77ad3c333056cf 100644 (file)
@@ -17,4 +17,7 @@ doc/manual/pdf
 doc/manual/extensions.ent
 .be/id-cache
 *.pyc
-
+GPATH
+GRTAGS
+GSYMS
+GTAGS
diff --git a/src/lib/check_hashes_job.cc b/src/lib/check_hashes_job.cc
deleted file mode 100644 (file)
index 55a7445..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
-    Copyright (C) 2012 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
-    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.
-
-*/
-
-#include <fstream>
-#include <boost/lexical_cast.hpp>
-#include <boost/filesystem.hpp>
-#include "check_hashes_job.h"
-#include "options.h"
-#include "log.h"
-#include "job_manager.h"
-#include "ab_transcode_job.h"
-#include "transcode_job.h"
-#include "film.h"
-#include "exceptions.h"
-
-using std::string;
-using std::stringstream;
-using std::ifstream;
-using boost::shared_ptr;
-
-CheckHashesJob::CheckHashesJob (shared_ptr<Film> f, DecodeOptions o, shared_ptr<Job> req)
-       : Job (f, req)
-       , _decode_opt (o)
-       , _bad (0)
-{
-
-}
-
-string
-CheckHashesJob::name () const
-{
-       return String::compose ("Check hashes of %1", _film->name());
-}
-
-void
-CheckHashesJob::run ()
-{
-       _bad = 0;
-
-       if (!_film->dcp_intrinsic_duration()) {
-               throw EncodeError ("cannot check hashes of a DCP with unknown intrinsic duration");
-       }
-       
-       int const N = _film->dcp_intrinsic_duration().get();
-       for (int i = 0; i < N; ++i) {
-               string const j2k_file = _film->frame_out_path (i, false);
-               string const hash_file = _film->hash_out_path (i, false);
-
-               if (!boost::filesystem::exists (j2k_file)) {
-                       _film->log()->log (String::compose ("Frame %1 has a missing J2K file.", i));
-                       boost::filesystem::remove (hash_file);
-                       ++_bad;
-               } else if (!boost::filesystem::exists (hash_file)) {
-                       _film->log()->log (String::compose ("Frame %1 has a missing hash file.", i));
-                       boost::filesystem::remove (j2k_file);
-                       ++_bad;
-               } else {
-                       ifstream ref (hash_file.c_str ());
-                       string hash;
-                       ref >> hash;
-                       if (hash != md5_digest (j2k_file)) {
-                               _film->log()->log (String::compose ("Frame %1 has wrong hash; deleting.", i));
-                               boost::filesystem::remove (j2k_file);
-                               boost::filesystem::remove (hash_file);
-                               ++_bad;
-                       }
-               }
-
-               set_progress (float (i) / N);
-       }
-
-       if (_bad) {
-               shared_ptr<Job> tc;
-
-               if (_film->dcp_ab()) {
-                       tc.reset (new ABTranscodeJob (_film, _decode_opt, shared_from_this()));
-               } else {
-                       tc.reset (new TranscodeJob (_film, _decode_opt, shared_from_this()));
-               }
-               
-               JobManager::instance()->add_after (shared_from_this(), tc);
-               JobManager::instance()->add_after (tc, shared_ptr<Job> (new CheckHashesJob (_film, _decode_opt, tc)));
-       }
-               
-       set_progress (1);
-       set_state (FINISHED_OK);
-}
-
-string
-CheckHashesJob::status () const
-{
-       stringstream s;
-       s << Job::status ();
-       if (overall_progress() > 0) {
-               if (_bad == 0) {
-                       s << "; no bad frames found";
-               } else if (_bad == 1) {
-                       s << "; 1 bad frame found";
-               } else {
-                       s << "; " << _bad << " bad frames found";
-               }
-       }
-       return s.str ();
-}
diff --git a/src/lib/check_hashes_job.h b/src/lib/check_hashes_job.h
deleted file mode 100644 (file)
index 5fa1738..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-    Copyright (C) 2012 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
-    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.
-
-*/
-
-#include "job.h"
-#include "options.h"
-
-class CheckHashesJob : public Job
-{
-public:
-       CheckHashesJob (
-               boost::shared_ptr<Film> f,
-               DecodeOptions od,
-               boost::shared_ptr<Job> req
-               );
-
-       std::string name () const;
-       void run ();
-       std::string status () const;
-
-private:
-       DecodeOptions _decode_opt;
-       int _bad;
-};
index c3f0fed03dcff3932faf25eb5a854089cf23afbf..5df2d7a46b61b8219467c933671e505f138cd51d 100644 (file)
@@ -407,27 +407,27 @@ EncodedData::~EncodedData ()
 void
 EncodedData::write (shared_ptr<const Film> film, int frame) const
 {
-       string const tmp_j2k = film->frame_out_path (frame, true);
+       string const tmp_j2c = film->j2c_path (frame, true);
 
-       FILE* f = fopen (tmp_j2k.c_str (), "wb");
+       FILE* f = fopen (tmp_j2c.c_str (), "wb");
        
        if (!f) {
-               throw WriteFileError (tmp_j2k, errno);
+               throw WriteFileError (tmp_j2c, errno);
        }
 
        fwrite (_data, 1, _size, f);
        fclose (f);
 
-       string const real_j2k = film->frame_out_path (frame, false);
+       string const real_j2c = film->j2c_path (frame, false);
 
        /* Rename the file from foo.j2c.tmp to foo.j2c now that it is complete */
-       boost::filesystem::rename (tmp_j2k, real_j2k);
+       boost::filesystem::rename (tmp_j2c, real_j2c);
 }
 
 void
 EncodedData::write_hash (shared_ptr<const Film> film, int frame) const
 {
-       string const hash = film->hash_out_path (frame, false);
+       string const hash = film->hash_path (frame);
        ofstream h (hash.c_str());
        h << md5_digest (_data, _size) << "\n";
 }
index 6b14b269820589cf2288007365b0fd37befd00a5..978d787e88985c97513b2dc425b635bd7bd54c97 100644 (file)
@@ -55,7 +55,6 @@ int const Encoder::_history_size = 25;
  */
 Encoder::Encoder (shared_ptr<Film> f)
        : _film (f)
-       , _just_skipped (false)
        , _video_frames_in (0)
        , _video_frames_out (0)
 #ifdef HAVE_SWRESAMPLE   
@@ -207,14 +206,6 @@ Encoder::current_frames_per_second () const
        return _history_size / (seconds (now) - seconds (_time_history.back ()));
 }
 
-/** @return true if the last frame to be processed was skipped as it already existed */
-bool
-Encoder::skipping () const
-{
-       boost::mutex::scoped_lock (_history_mutex);
-       return _just_skipped;
-}
-
 /** @return Number of video frames that have been sent out */
 int
 Encoder::video_frames_out () const
@@ -230,7 +221,6 @@ void
 Encoder::frame_done ()
 {
        boost::mutex::scoped_lock lock (_history_mutex);
-       _just_skipped = false;
        
        struct timeval tv;
        gettimeofday (&tv, 0);
@@ -240,16 +230,6 @@ Encoder::frame_done ()
        }
 }
 
-/** Called by a subclass when it has just skipped the processing
-    of a frame because it has already been done.
-*/
-void
-Encoder::frame_skipped ()
-{
-       boost::mutex::scoped_lock lock (_history_mutex);
-       _just_skipped = true;
-}
-
 void
 Encoder::process_video (shared_ptr<Image> image, bool same, boost::shared_ptr<Subtitle> sub)
 {
@@ -273,12 +253,6 @@ Encoder::process_video (shared_ptr<Image> image, bool same, boost::shared_ptr<Su
                return;
        }
 
-       /* Only do the processing if we don't already have a file for this frame */
-       if (boost::filesystem::exists (_film->frame_out_path (_video_frames_out, false))) {
-               frame_skipped ();
-               return;
-       }
-
        if (same && _have_a_real_frame) {
                /* Use the last frame that we encoded. */
                _writer->repeat (_video_frames_out);
index 429b46a18c4f1d60191e2b40585f9abdbda04939..8b02f70041af349d5e95dbd4a855c15c151a493e 100644 (file)
@@ -82,13 +82,11 @@ public:
        virtual void process_end ();
 
        float current_frames_per_second () const;
-       bool skipping () const;
        int video_frames_out () const;
 
 private:
        
        void frame_done ();
-       void frame_skipped ();
        
        void write_audio (boost::shared_ptr<const AudioBuffers> audio);
 
@@ -98,7 +96,7 @@ private:
        /** Film that we are encoding */
        boost::shared_ptr<Film> _film;
 
-       /** Mutex for _time_history, _just_skipped and _last_frame */
+       /** Mutex for _time_history and _last_frame */
        mutable boost::mutex _history_mutex;
        /** List of the times of completion of the last _history_size frames;
            first is the most recently completed.
@@ -106,8 +104,6 @@ private:
        std::list<struct timeval> _time_history;
        /** Number of frames that we should keep history for */
        static int const _history_size;
-       /** true if the last frame we processed was skipped (because it was already done) */
-       bool _just_skipped;
 
        /** Number of video frames received so far */
        SourceFrame _video_frames_in;
index ae9edbfdb0a93a954a6e7c13bc967738598430e4..dc308078c2e31aaa72ea672b8aa4f1ee38ccf347 100644 (file)
@@ -46,7 +46,6 @@
 #include "scaler.h"
 #include "decoder_factory.h"
 #include "config.h"
-#include "check_hashes_job.h"
 #include "version.h"
 #include "ui_signaller.h"
 #include "video_decoder.h"
@@ -194,24 +193,14 @@ Film::~Film ()
 {
        delete _log;
 }
-         
-/** @return The path to the directory to write JPEG2000 files to */
+
 string
-Film::j2k_dir () const
+Film::video_state_identifier () const
 {
-       assert (format());
-
-       boost::filesystem::path p;
-
-       /* Start with j2c */
-       p /= "j2c";
+       assert (format ());
 
        pair<string, string> f = Filter::ffmpeg_strings (filters());
 
-       /* Write stuff to specify the filter / post-processing settings that are in use,
-          so that we don't get confused about J2K files generated using different
-          settings.
-       */
        stringstream s;
        s << format()->id()
          << "_" << content_digest()
@@ -221,19 +210,33 @@ Film::j2k_dir () const
          << "_" << j2k_bandwidth()
          << "_" << boost::lexical_cast<int> (colour_lut());
 
-       p /= s.str ();
-
-       /* Similarly for the A/B case */
        if (dcp_ab()) {
-               stringstream s;
                pair<string, string> fa = Filter::ffmpeg_strings (Config::instance()->reference_filters());
                s << "ab_" << Config::instance()->reference_scaler()->id() << "_" << fa.first << "_" << fa.second;
-               p /= s.str ();
        }
-       
+
+       return s.str ();
+}
+         
+/** @return The path to the directory to write video frame hash files to */
+string
+Film::hash_dir () const
+{
+       boost::filesystem::path p;
+       p /= "hash";
+       p /= video_state_identifier ();
        return dir (p.string());
 }
 
+string
+Film::video_mxf_path () const
+{
+       boost::filesystem::path p;
+       p /= "video";
+       p /= video_state_identifier ();
+       return file (p.string());
+}
+
 /** Add suitable Jobs to the JobManager to create a DCP for this Film.
  *  @param true to transcode, false to use the WAV and J2K files that are already there.
  */
@@ -302,8 +305,6 @@ Film::make_dcp (bool transcode)
                        r = JobManager::instance()->add (shared_ptr<Job> (new TranscodeJob (shared_from_this(), od, shared_ptr<Job> ())));
                }
        }
-
-       // r = JobManager::instance()->add (shared_ptr<Job> (new CheckHashesJob (shared_from_this(), od, r)));
 }
 
 /** Start a job to examine our content file */
@@ -344,7 +345,7 @@ Film::encoded_frames () const
        }
 
        int N = 0;
-       for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (j2k_dir ()); i != boost::filesystem::directory_iterator(); ++i) {
+       for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (hash_dir ()); i != boost::filesystem::directory_iterator(); ++i) {
                ++N;
                boost::this_thread::interruption_point ();
        }
@@ -1391,44 +1392,37 @@ Film::audio_stream () const
        return _external_audio_stream;
 }
 
-/** @param f DCP frame index.
- *  @param t true to return a temporary file path, otherwise a permanent one.
- *  @return The path to write this video frame to.
- */
 string
-Film::frame_out_path (int f, bool t) const
+Film::hash_path (int f) const
 {
+       boost::filesystem::path p;
+       p /= hash_dir ();
+
        stringstream s;
-       s << j2k_dir() << "/";
        s.width (8);
-       s << std::setfill('0') << f << ".j2c";
+       s << setfill('0') << f << ".md5";
 
-       if (t) {
-               s << ".tmp";
-       }
-
-       return s.str ();
+       p /= s.str();
+       return p.string ();
 }
 
 string
-Film::hash_out_path (int f, bool t) const
+Film::j2c_path (int f, bool t) const
 {
-       return frame_out_path (f, t) + ".md5";
-}
+       boost::filesystem::path p;
+       p /= "j2c";
+       p /= video_state_identifier ();
 
-/** @param c Audio channel index.
- *  @param t true to return a temporary file path, otherwise a permanent one.
- *  @return The path to write this audio file to.
- */
-string
-Film::multichannel_audio_out_path (int c, bool t) const
-{
        stringstream s;
-       s << dir ("wavs") << "/" << (c + 1) << ".wav";
+       s.width (8);
+       s << setfill('0') << f << ".j2c";
+
        if (t) {
                s << ".tmp";
        }
-       
-       return s.str ();
+
+       p /= s.str();
+       return p.string ();
 }
 
+
index 60646b0c8d78adc52f6fa8da0740d704926ac1c9..4d2819be30c9226bd67d0cbc8f44d1293a87b907 100644 (file)
@@ -59,7 +59,10 @@ public:
        Film (Film const &);
        ~Film ();
 
-       std::string j2k_dir () const;
+       std::string hash_dir () const;
+       std::string j2c_path (int f, bool t) const;
+       std::string hash_path (int f) const;
+       std::string video_mxf_path () const;
 
        void examine_content ();
        void send_dcp_to_tms ();
@@ -78,10 +81,6 @@ public:
        std::string file (std::string f) const;
        std::string dir (std::string d) const;
 
-       std::string frame_out_path (int f, bool t) const;
-       std::string hash_out_path (int f, bool t) const;
-       std::string multichannel_audio_out_path (int c, bool t) const;
-       
        std::string content_path () const;
        ContentType content_type () const;
        
@@ -413,6 +412,7 @@ private:
 
        void signal_changed (Property);
        void examine_content_finished ();
+       std::string video_state_identifier () const;
 
        /** Complete path to directory containing the film metadata;
         *  must not be relative.
index 6dd74c36c6ee9fd62dcc6eb31f1a8eaa3b045094..e9a59c743ad3fc81e12abceb3c320f11a4db485d 100644 (file)
@@ -89,11 +89,6 @@ TranscodeJob::status () const
                return "0%";
        }
 
-       if (_encoder->skipping () && !finished ()) {
-               return "skipping already-encoded frames";
-       }
-               
-       
        float const fps = _encoder->current_frames_per_second ();
        if (fps == 0) {
                return Job::status ();
index a434db0ec2f39997475f81c0beb9b79763921609..16ed5c3493cdf717f08e20607bd2f8756441364f 100644 (file)
@@ -42,7 +42,7 @@ Writer::Writer (shared_ptr<Film> f)
        _picture_asset.reset (
                new libdcp::MonoPictureAsset (
                        _film->dir (_film->dcp_name()),
-                       "video.mxf",
+                       _film->video_mxf_path(),
                        DCPFrameRate (_film->frames_per_second()).frames_per_second,
                        _film->format()->dcp_size()
                        )
@@ -164,9 +164,9 @@ Writer::thread ()
                        lock.unlock ();
                        _film->log()->log (String::compose ("Writer pulls %1 back from disk", fetch));
                        shared_ptr<const EncodedData> encoded;
-                       if (boost::filesystem::exists (_film->frame_out_path (fetch, false))) {
+                       if (boost::filesystem::exists (_film->j2c_path (fetch, false))) {
                                /* It's an actual frame (not a repeat-last); load it in */
-                               encoded.reset (new EncodedData (_film->frame_out_path (fetch, false)));
+                               encoded.reset (new EncodedData (_film->j2c_path (fetch, false)));
                        }
                        lock.lock ();
 
index 02c4263735ef5972636265c7764a755f806c8be0..5d676f249f35c135dd2ba117b8c6d4b1d76a632a 100644 (file)
@@ -14,7 +14,6 @@ def build(bld):
                 ab_transcoder.cc
                  audio_decoder.cc
                  audio_source.cc
-                 check_hashes_job.cc
                 config.cc
                  combiner.cc
                  cross.cc