2015-04-20 Carl Hetherington <cth@carlh.net>
+ * Hand-apply 47770097cf6a5d7dbbdded8977da5f3de53dfd33;
+ single-file hashes.
+
* Hand-apply e1d0d24146592e311d46781a1961fe080f6357cf;
attempt to fix confusion with the JPEG2000 bandwidth
control when a user enters a value directly rather than
Colour conversion fixes between 1.78.1 and 1.78.2
b6df85a81f9dadb6ce778aaf3290cd39221b6170
-47770097cf6a5d7dbbdded8977da5f3de53dfd33
+
/*
- Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2015 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
}
void
-EncodedData::write_info (shared_ptr<const Film> film, int frame, Eyes eyes, dcp::FrameInfo fin) const
+EncodedData::write_info (shared_ptr<const Film> film, int frame, Eyes eyes, dcp::FrameInfo info) const
{
- boost::filesystem::path const info = film->info_path (frame, eyes);
- FILE* h = fopen_boost (info, "w");
- if (!h) {
- throw OpenFileError (info);
+ FILE* file = fopen_boost (film->info_file(), "ab");
+ if (!file) {
+ throw OpenFileError (film->info_file ());
}
- fin.write (h);
- fclose (h);
+ write_frame_info (file, frame, eyes, info);
+ fclose (file);
}
/** Send this data to a socket.
return s.str ();
}
-/** @return The path to the directory to write video frame info files to */
+/** @return The file to write video frame info to */
boost::filesystem::path
-Film::info_dir () const
+Film::info_file () const
{
boost::filesystem::path p;
p /= "info";
p /= video_identifier ();
- return dir (p);
+ return file (p);
}
boost::filesystem::path
JobManager::instance()->add (j);
}
-/** Count the number of frames that have been encoded for this film.
- * @return frame count.
- */
-int
-Film::encoded_frames () const
-{
- if (container() == 0) {
- return 0;
- }
-
- int N = 0;
- for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (info_dir ()); i != boost::filesystem::directory_iterator(); ++i) {
- ++N;
- boost::this_thread::interruption_point ();
- }
-
- return N;
-}
-
shared_ptr<xmlpp::Document>
Film::metadata () const
{
_isdcf_date = boost::gregorian::day_clock::local_day ();
}
-boost::filesystem::path
-Film::info_path (int f, Eyes e) const
-{
- boost::filesystem::path p;
- p /= info_dir ();
-
- SafeStringStream s;
- s.width (8);
- s << setfill('0') << f;
-
- if (e == EYES_LEFT) {
- s << ".L";
- } else if (e == EYES_RIGHT) {
- s << ".R";
- }
-
- s << ".md5";
-
- p /= s.str();
-
- /* info_dir() will already have added any initial bit of the path,
- so don't call file() on this.
- */
- return p;
-}
-
boost::filesystem::path
Film::j2c_path (int f, Eyes e, bool t) const
{
Film (boost::filesystem::path, bool log = true);
~Film ();
- boost::filesystem::path info_dir () const;
+ boost::filesystem::path info_file () const;
boost::filesystem::path j2c_path (int, Eyes, bool) const;
- boost::filesystem::path info_path (int, Eyes) const;
boost::filesystem::path internal_video_mxf_dir () const;
boost::filesystem::path internal_video_mxf_filename () const;
boost::filesystem::path audio_analysis_dir () const;
return _log;
}
- int encoded_frames () const;
-
boost::filesystem::path file (boost::filesystem::path f) const;
boost::filesystem::path dir (boost::filesystem::path d) const;
}
boost::uintmax_t this_time = min (to_do, boost::filesystem::file_size (files[i]));
- fseek (f, -this_time, SEEK_END);
+ dcpomatic_fseek (f, -this_time, SEEK_END);
fread (p, 1, this_time, f);
p += this_time;
to_do -= this_time;
return r;
}
+
+long
+frame_info_position (int frame, Eyes eyes)
+{
+ static int const info_size = 48;
+
+ switch (eyes) {
+ case EYES_BOTH:
+ return frame * info_size;
+ case EYES_LEFT:
+ return frame * info_size * 2;
+ case EYES_RIGHT:
+ return frame * info_size * 2 + info_size;
+ default:
+ DCPOMATIC_ASSERT (false);
+ }
+
+ DCPOMATIC_ASSERT (false);
+}
+
+dcp::FrameInfo
+read_frame_info (FILE* file, int frame, Eyes eyes)
+{
+ dcp::FrameInfo info;
+ dcpomatic_fseek (file, frame_info_position (frame, eyes), SEEK_SET);
+ fread (&info.offset, sizeof (info.offset), 1, file);
+ fread (&info.size, sizeof (info.size), 1, file);
+
+ char hash_buffer[33];
+ fread (hash_buffer, 1, 32, file);
+ hash_buffer[32] = '\0';
+ info.hash = hash_buffer;
+
+ return info;
+}
+
+void
+write_frame_info (FILE* file, int frame, Eyes eyes, dcp::FrameInfo info)
+{
+ dcpomatic_fseek (file, frame_info_position (frame, eyes), SEEK_SET);
+ fwrite (&info.offset, sizeof (info.offset), 1, file);
+ fwrite (&info.size, sizeof (info.size), 1, file);
+ fwrite (info.hash.c_str(), 1, info.hash.size(), file);
+}
#include "exceptions.h"
#include "dcpomatic_time.h"
#include <dcp/util.h>
+#include <dcp/picture_mxf_writer.h>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavfilter/avfilter.h>
extern void* wrapped_av_malloc (size_t);
extern ContentTimePeriod subtitle_period (AVSubtitle const &);
extern void set_backtrace_file (boost::filesystem::path);
+extern dcp::FrameInfo read_frame_info (FILE* file, int frame, Eyes eyes);
+extern void write_frame_info (FILE* file, int frame, Eyes eyes, dcp::FrameInfo info);
extern int64_t video_frames_to_audio_frames (VideoFrame v, float audio_sample_rate, float frames_per_second);
extern std::map<std::string, std::string> split_get_request (std::string url);
/*
- Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2015 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
_full_condition.wait (lock);
}
- FILE* ifi = fopen_boost (_film->info_path (frame, eyes), "r");
- if (!ifi) {
- throw ReadFileError (_film->info_path (frame, eyes));
+ FILE* file = fopen_boost (_film->info_file (), "rb");
+ if (!file) {
+ throw ReadFileError (_film->info_file ());
}
- dcp::FrameInfo info (ifi);
- fclose (ifi);
+ dcp::FrameInfo info = read_frame_info (file, frame, eyes);
+ fclose (file);
QueueItem qi;
qi.type = QueueItem::FAKE;
Writer::check_existing_picture_mxf_frame (FILE* mxf, int f, Eyes eyes)
{
/* Read the frame info as written */
- FILE* ifi = fopen_boost (_film->info_path (f, eyes), "r");
- if (!ifi) {
+ FILE* file = fopen_boost (_film->info_file (), "rb");
+ if (!file) {
LOG_GENERAL ("Existing frame %1 has no info file", f);
return false;
}
- dcp::FrameInfo info (ifi);
- fclose (ifi);
+ dcp::FrameInfo info = read_frame_info (file, f, eyes);
+ fclose (file);
if (info.size == 0) {
LOG_GENERAL ("Existing frame %1 has no info file", f);
return false;
return;
}
- int N = 0;
- for (boost::filesystem::directory_iterator i (_film->info_dir ()); i != boost::filesystem::directory_iterator (); ++i) {
- ++N;
- }
-
while (true) {
shared_ptr<Job> job = _job.lock ();
DCPOMATIC_ASSERT (job);
- if (N > 0) {
- job->set_progress (float (_first_nonexistant_frame) / N);
- }
+ job->set_progress_unknown ();
if (_film->three_d ()) {
if (!check_existing_picture_mxf_frame (mxf, _first_nonexistant_frame, EYES_LEFT)) {
add (_("Disk space required"), true);
_disk = add (new wxStaticText (this, wxID_ANY, wxT ("")));
- add (_("Frames already encoded"), true);
- _encoded = add (new ThreadedStaticText (this, _("counting..."), boost::bind (&PropertiesDialog::frames_already_encoded, this)));
- _encoded_connection = _encoded->Finished.connect (boost::bind (&PropertiesDialog::layout, this));
_frames->SetLabel (std_to_wx (lexical_cast<string> (_film->length().frames (_film->video_frame_rate ()))));
double const disk = double (_film->required_disk_space()) / 1073741824.0f;
SafeStringStream s;
layout ();
}
-
-string
-PropertiesDialog::frames_already_encoded () const
-{
- SafeStringStream u;
- try {
- u << _film->encoded_frames ();
- } catch (boost::thread_interrupted &) {
- return "";
- }
-
- uint64_t const frames = _film->length().frames (_film->video_frame_rate ());
- if (frames) {
- /* XXX: encoded_frames() should check which frames have been encoded */
- u << " (" << (_film->encoded_frames() * 100 / frames) << "%)";
- }
- return u.str ();
-}
#include "table_dialog.h"
class Film;
-class ThreadedStaticText;
class PropertiesDialog : public TableDialog
{
PropertiesDialog (wxWindow *, boost::shared_ptr<Film>);
private:
- std::string frames_already_encoded () const;
-
boost::shared_ptr<Film> _film;
wxStaticText* _frames;
wxStaticText* _disk;
- ThreadedStaticText* _encoded;
boost::signals2::scoped_connection _encoded_connection;
};
/*
- Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2015 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
return wxString (s.c_str(), wxConvUTF8);
}
-int const ThreadedStaticText::_update_event_id = 10000;
-
-/** @param parent Parent for the wxStaticText.
- * @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, boost::function<string ()> fn)
- : wxStaticText (parent, wxID_ANY, initial)
-{
- Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ThreadedStaticText::thread_finished, this, _1), _update_event_id);
- _thread = new thread (bind (&ThreadedStaticText::run, this, fn));
-}
-
-ThreadedStaticText::~ThreadedStaticText ()
-{
- _thread->interrupt ();
- _thread->join ();
- delete _thread;
-}
-
-/** Run our thread and post the result to the GUI thread via AddPendingEvent */
-void
-ThreadedStaticText::run (boost::function<string ()> fn)
-try
-{
- wxCommandEvent ev (wxEVT_COMMAND_TEXT_UPDATED, _update_event_id);
- ev.SetString (std_to_wx (fn ()));
- GetEventHandler()->AddPendingEvent (ev);
-}
-catch (...)
-{
- /* Ignore exceptions; marginally better than the program quitting, but
- only marginally.
- */
-}
-
-/** Called in the GUI thread when our worker thread has finished */
-void
-ThreadedStaticText::thread_finished (wxCommandEvent& ev)
-{
- SetLabel (ev.GetString ());
- Finished ();
-}
-
string
string_client_data (wxClientData* o)
{
/*
- Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2015 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
extern wxString std_to_wx (std::string);
extern void dcpomatic_setup_i18n ();
extern wxString context_translation (wxString);
-
-/** @class ThreadedStaticText
- *
- * @brief A wxStaticText whose content is computed in a separate thread, to avoid holding
- * up the GUI while work is done.
- */
-class ThreadedStaticText : public wxStaticText
-{
-public:
- ThreadedStaticText (wxWindow* parent, wxString initial, boost::function<std::string ()> fn);
- ~ThreadedStaticText ();
-
- /** Emitted in the UI thread when the text has been set up */
- boost::signals2::signal<void()> Finished;
-
-private:
- void run (boost::function<std::string ()> fn);
- void thread_finished (wxCommandEvent& ev);
-
- /** Thread to do our work in */
- boost::thread* _thread;
-
- static const int _update_event_id;
-};
-
extern std::string string_client_data (wxClientData* o);
extern void checked_set (wxFilePickerCtrl* widget, std::string value);