Use MD5 digest of content file as part of the J2C directory, rather than the filename...
authorCarl Hetherington <cth@carlh.net>
Sun, 22 Jul 2012 23:42:37 +0000 (00:42 +0100)
committerCarl Hetherington <cth@carlh.net>
Sun, 22 Jul 2012 23:42:37 +0000 (00:42 +0100)
TODO
src/lib/film.cc
src/lib/film_state.cc
src/lib/film_state.h
src/lib/util.cc
src/lib/util.h
test/metadata.ref
test/test.cc

diff --git a/TODO b/TODO
index 1239613ffa7100e179ad72f75948e013cb874f19..83284a2ecc12dd36eac7072a813e53d5548efcc5 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,6 +1,7 @@
 Write still j2ks straight to a MXF.
 Seem to be problems when waiting for (failing) server threads at the end of an encode;
 their frames aren't reprocessed locally.
+md5_data to use openssl
 
 Standardise j2c/j2k
 Format name in ~/.dvdomatic screws up with spaces; use ID or something
index 502119db3dee9ee714794108cccd33e24bcd64de..f11d30abafb749e92ef4150fbd9b62a450f69232 100644 (file)
@@ -193,6 +193,7 @@ Film::set_content (string c)
        _state.audio_sample_rate = d->audio_sample_rate ();
        _state.audio_sample_format = d->audio_sample_format ();
 
+       _state.content_digest = md5_digest (c);
        _state.content = c;
        
        signal_changed (SIZE);
@@ -424,7 +425,7 @@ Film::j2k_dir () const
           settings.
        */
        s << _state.format->nickname()
-         << "_" << _state.content
+         << "_" << _state.content_digest
          << "_" << left_crop() << "_" << right_crop() << "_" << top_crop() << "_" << bottom_crop()
          << "_" << f.first << "_" << f.second
          << "_" << _state.scaler->id();
index 16378086c1fcd878e4781ff73192da02b33634cf..369e4c98693417a8d5ccd193dc4dad22361066ab 100644 (file)
@@ -92,6 +92,7 @@ FilmState::write_metadata (ofstream& f) const
        f << "audio_channels " << audio_channels << "\n";
        f << "audio_sample_rate " << audio_sample_rate << "\n";
        f << "audio_sample_format " << audio_sample_format_to_string (audio_sample_format) << "\n";
+       f << "content_digest " << content_digest << "\n";
 }
 
 /** Read state from a key / value pair.
@@ -161,6 +162,13 @@ FilmState::read_metadata (string k, string v)
                audio_sample_rate = atoi (v.c_str ());
        } else if (k == "audio_sample_format") {
                audio_sample_format = audio_sample_format_from_string (v);
+       } else if (k == "content_digest") {
+               content_digest = v;
+       }
+       
+       /* Itsy bitsy hack: compute digest here if don't have one (for backwards compatibility) */
+       if (content_digest.empty() && !content.empty()) {
+               content_digest = md5_digest (file (content));
        }
 }
 
index 52525ecd4ea17bfb5927a1a018ecb97caf262e92..62ca76c4190b2a4d2d97db9cd6c2ea8555678cd0 100644 (file)
@@ -147,6 +147,8 @@ public:
        int audio_sample_rate;
        /** Format of the audio samples */
        AVSampleFormat audio_sample_format;
+       /** MD5 digest of our content file */
+       std::string content_digest;
 
 private:
        std::string thumb_file_for_frame (int) const;
index 7388539cdf68080ead8e43a31bddea226acb313e..799d0e54e088e41b89ed58b9858f2cbfbe623c2e 100644 (file)
@@ -25,6 +25,7 @@
 #include <sstream>
 #include <iomanip>
 #include <iostream>
+#include <fstream>
 #ifdef DVDOMATIC_POSIX
 #include <execinfo.h>
 #include <cxxabi.h>
@@ -35,6 +36,7 @@
 #include <signal.h>
 #include <boost/algorithm/string.hpp>
 #include <openjpeg.h>
+#include <openssl/md5.h>
 #include <magick/MagickCore.h>
 #include <magick/version.h>
 #include <libdcp/version.h>
@@ -469,3 +471,37 @@ md5_data (string title, void const * data, int size)
 }
 #endif
 
+string
+md5_digest (string file)
+{
+       ifstream f (file.c_str(), ios::binary);
+       if (!f.good ()) {
+               throw OpenFileError (file);
+       }
+       
+       f.seekg (0, ios::end);
+       int bytes = f.tellg ();
+       f.seekg (0, ios::beg);
+
+       int const buffer_size = 64 * 1024;
+       char buffer[buffer_size];
+
+       MD5_CTX md5_context;
+       MD5_Init (&md5_context);
+       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 << hex << setfill('0') << setw(2) << ((int) digest[i]);
+       }
+
+       return s.str ();
+}
index 3901e7ec697e2fc058e4b3f0f045631dc51d8bac..1f635677aa81d3ba0d7cd14076bfaa4231197ddb 100644 (file)
@@ -45,6 +45,7 @@ extern void socket_write (int, uint8_t const *, int);
 extern double seconds (struct timeval);
 extern void dvdomatic_setup ();
 extern std::vector<std::string> split_at_spaces_considering_quotes (std::string);
+extern std::string md5_digest (std::string);
 
 enum ContentType {
        STILL,
index 58cddd163437dea3ad878e2aac6475e9e001e72e..817fecffdd6ede790a6b83b9fc6924efa56ea475 100644 (file)
@@ -22,3 +22,4 @@ length 0
 audio_channels 0
 audio_sample_rate 0
 audio_sample_format Unknown
+content_digest 
index 3128b46290974390b106ef1c42924c4e1fddc0a8..dd44f4a45bbbd4270b6abaa103e46651c9cbf0ff 100644 (file)
@@ -227,3 +227,11 @@ BOOST_AUTO_TEST_CASE (delay_line_test)
        do_negative_delay_line_test (-3, 512);
        do_negative_delay_line_test (-512, 3);
 }
+
+BOOST_AUTO_TEST_CASE (md5_digest_test)
+{
+       string const t = md5_digest ("test/md5.test");
+       BOOST_CHECK_EQUAL (t, "15058685ba99decdc4398c7634796eb0");
+
+       BOOST_CHECK_THROW (md5_digest ("foobar"), OpenFileError);
+}