return "";
}
- return String::compose (_("Analyse audio of %1"), content->file().filename());
+ return String::compose (_("Analyse audio of %1"), content->path());
}
void
Content::Content (shared_ptr<const Film> f, boost::filesystem::path p)
: _film (f)
- , _file (p)
+ , _path (p)
, _start (0)
, _change_signals_frequent (false)
{
: _film (f)
, _change_signals_frequent (false)
{
- _file = node->string_child ("File");
+ _path = node->string_child ("Path");
_digest = node->string_child ("Digest");
_start = node->number_child<Time> ("Start");
}
Content::as_xml (xmlpp::Node* node) const
{
boost::mutex::scoped_lock lm (_mutex);
- node->add_child("File")->add_child_text (_file.string());
+ node->add_child("Path")->add_child_text (_path.string());
node->add_child("Digest")->add_child_text (_digest);
node->add_child("Start")->add_child_text (lexical_cast<string> (_start));
}
void
Content::examine (shared_ptr<Job>)
{
- string const d = md5_digest (_file);
+ string d;
+ if (boost::filesystem::is_regular_file (_path)) {
+ d = md5_digest (_path);
+ } else {
+ d = md5_digest_directory (_path);
+ }
+
boost::mutex::scoped_lock lm (_mutex);
_digest = d;
}
string
Content::technical_summary () const
{
- return String::compose ("%1 %2 %3", file(), digest(), start());
+ return String::compose ("%1 %2 %3", path(), digest(), start());
}
boost::shared_ptr<Content> clone () const;
- boost::filesystem::path file () const {
+ boost::filesystem::path path () const {
boost::mutex::scoped_lock lm (_mutex);
- return _file;
+ return _path;
}
- /** @return MD5 digest of the content's file */
+ /** @return MD5 digest of the content's file(s) */
std::string digest () const {
boost::mutex::scoped_lock lm (_mutex);
return _digest;
mutable boost::mutex _mutex;
private:
- boost::filesystem::path _file;
+ /** Path of a file or a directory containing files */
+ boost::filesystem::path _path;
std::string _digest;
Time _start;
bool _change_signals_frequent;
{
av_register_all ();
- if (avformat_open_input (&_format_context, _ffmpeg_content->file().string().c_str(), 0, 0) < 0) {
- throw OpenFileError (_ffmpeg_content->file().string ());
+ if (avformat_open_input (&_format_context, _ffmpeg_content->path().string().c_str(), 0, 0) < 0) {
+ throw OpenFileError (_ffmpeg_content->path().string ());
}
if (avformat_find_stream_info (_format_context, 0) < 0) {
string
FFmpegContent::summary () const
{
- return String::compose (_("%1 [movie]"), file().filename().string());
+ return String::compose (_("%1 [movie]"), path());
}
string
string
SndfileContent::summary () const
{
- return String::compose (_("%1 [audio]"), file().filename().string());
+ return String::compose (_("%1 [audio]"), path().filename().string());
}
string
, _deinterleave_buffer (0)
{
_info.format = 0;
- _sndfile = sf_open (_sndfile_content->file().string().c_str(), SFM_READ, &_info);
+ _sndfile = sf_open (_sndfile_content->path().string().c_str(), SFM_READ, &_info);
if (!_sndfile) {
throw DecodeError (_("could not open audio file for reading"));
}
string
StillImageContent::summary () const
{
- return String::compose (_("%1 [still]"), file().filename().string());
+ return String::compose (_("%1 [still]"), path());
}
string
return;
}
- Magick::Image* magick_image = new Magick::Image (_still_image_content->file().string ());
+ Magick::Image* magick_image = new Magick::Image (_still_image_content->path().string ());
_video_size = libdcp::Size (magick_image->columns(), magick_image->rows());
_image.reset (new Image (PIX_FMT_RGB24, _video_size.get(), false));
, _film (f)
{
using namespace MagickCore;
- Magick::Image* image = new Magick::Image (_still_image_content->file().string());
+ Magick::Image* image = new Magick::Image (_still_image_content->path().string());
_video_size = libdcp::Size (image->columns(), image->rows());
delete image;
}
return s.str ();
}
+string
+md5_digest_directory (boost::filesystem::path directory)
+{
+ int const buffer_size = 64 * 1024;
+ char buffer[buffer_size];
+
+ MD5_CTX md5_context;
+ MD5_Init (&md5_context);
+
+ for (boost::filesystem::directory_iterator i(directory); i != boost::filesystem::directory_iterator(); ++i) {
+ ifstream f (i->path().string().c_str(), std::ios::binary);
+ if (!f.good ()) {
+ throw OpenFileError (i->path().string());
+ }
+
+ f.seekg (0, std::ios::end);
+ int bytes = f.tellg ();
+ f.seekg (0, std::ios::beg);
+
+ while (bytes > 0) {
+ int const t = min (bytes, buffer_size);
+ f.read (buffer, t);
+ MD5_Update (&md5_context, buffer, t);
+ bytes -= t;
+ }
+ }
+
+ unsigned char digest[MD5_DIGEST_LENGTH];
+ MD5_Final (digest, &md5_context);
+
+ stringstream s;
+ for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
+ s << std::hex << std::setfill('0') << std::setw(2) << ((int) digest[i]);
+ }
+
+ return s.str ();
+}
+
static bool
about_equal (float a, float b)
{
extern void dcpomatic_setup_gettext_i18n (std::string);
extern std::vector<std::string> split_at_spaces_considering_quotes (std::string);
extern std::string md5_digest (boost::filesystem::path);
+extern std::string md5_digest_directory (boost::filesystem::path);
extern std::string md5_digest (void const *, int);
extern void ensure_ui_thread ();
extern std::string audio_channel_name (int);
_content_changed_connection = _content->Changed.connect (bind (&AudioDialog::content_changed, this, _2));
- SetTitle (wxString::Format (_("DCP-o-matic audio - %s"), std_to_wx(_content->file().filename().string()).data()));
+ SetTitle (wxString::Format (_("DCP-o-matic audio - %s"), std_to_wx(_content->path().filename().string()).data()));
}
void
gc->StrokePath (path);
gc->FillPath (path);
- wxString name = wxString::Format (wxT ("%s [%s]"), std_to_wx (cont->file().filename().string()).data(), type().data());
+ wxString name = wxString::Format (wxT ("%s [%s]"), std_to_wx (cont->path().filename().string()).data(), type().data());
wxDouble name_width;
wxDouble name_height;
wxDouble name_descent;