doc/manual/extensions.ent
.be/id-cache
*.pyc
-
+GPATH
+GRTAGS
+GSYMS
+GTAGS
+++ /dev/null
-/*
- 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 ();
-}
+++ /dev/null
-/*
- 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;
-};
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";
}
*/
Encoder::Encoder (shared_ptr<Film> f)
: _film (f)
- , _just_skipped (false)
, _video_frames_in (0)
, _video_frames_out (0)
#ifdef HAVE_SWRESAMPLE
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
Encoder::frame_done ()
{
boost::mutex::scoped_lock lock (_history_mutex);
- _just_skipped = false;
struct timeval tv;
gettimeofday (&tv, 0);
}
}
-/** 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)
{
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);
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);
/** 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.
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;
#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"
{
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()
<< "_" << 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.
*/
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 */
}
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 ();
}
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 ();
}
+
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 ();
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;
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.
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 ();
_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()
)
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 ();
ab_transcoder.cc
audio_decoder.cc
audio_source.cc
- check_hashes_job.cc
config.cc
combiner.cc
cross.cc