Rework audio to deinterleave straight away and pass data
[dcpomatic.git] / src / lib / util.cc
index d12bd3e775a52a32187fa8ee5a4fc0d75d30c92a..47a86da9e09907a98fd563d9c395d11f6fc890f4 100644 (file)
@@ -35,6 +35,7 @@
 #include <boost/algorithm/string.hpp>
 #include <boost/bind.hpp>
 #include <boost/lambda/lambda.hpp>
+#include <boost/lexical_cast.hpp>
 #include <openjpeg.h>
 #include <openssl/md5.h>
 #include <magick/MagickCore.h>
@@ -61,10 +62,6 @@ extern "C" {
 #include "player_manager.h"
 #endif
 
-#ifdef DEBUG_HASH
-#include <mhash.h>
-#endif
-
 using namespace std;
 using namespace boost;
 
@@ -204,10 +201,8 @@ audio_sample_format_to_string (AVSampleFormat s)
        case AV_SAMPLE_FMT_S16:
                return "S16";
        default:
-               break;
+               assert (false);
        }
-
-       return "Unknown";
 }
 
 /** @param s String representation of a sample format, as returned from audio_sample_format_to_string().
@@ -220,7 +215,7 @@ audio_sample_format_from_string (string s)
                return AV_SAMPLE_FMT_S16;
        }
 
-       return AV_SAMPLE_FMT_NONE;
+       assert (false);
 }
 
 /** @return Version of vobcopy that is on the path (and hence that we will use) */
@@ -347,28 +342,26 @@ split_at_spaces_considering_quotes (string s)
        return out;
 }
 
-#ifdef DEBUG_HASH
-void
-md5_data (string title, void const * data, int size)
+string
+md5_digest (void const * data, int size)
 {
-       MHASH ht = mhash_init (MHASH_MD5);
-       if (ht == MHASH_FAILED) {
-               throw EncodeError ("could not create hash thread");
-       }
-
-       mhash (ht, data, size);
-       
-       uint8_t hash[16];
-       mhash_deinit (ht, hash);
+       MD5_CTX md5_context;
+       MD5_Init (&md5_context);
+       MD5_Update (&md5_context, data, size);
+       unsigned char digest[MD5_DIGEST_LENGTH];
+       MD5_Final (digest, &md5_context);
        
-       printf ("%s [%d]: ", title.c_str (), size);
-       for (int i = 0; i < int (mhash_get_block_size (MHASH_MD5)); ++i) {
-               printf ("%.2x", hash[i]);
+       stringstream s;
+       for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
+               s << hex << setfill('0') << setw(2) << ((int) digest[i]);
        }
-       printf ("\n");
+
+       return s.str ();
 }
-#endif
 
+/** @param file File name.
+ *  @return MD5 digest of file's contents.
+ */
 string
 md5_digest (string file)
 {
@@ -404,6 +397,9 @@ md5_digest (string file)
        return s.str ();
 }
 
+/** @param An arbitrary sampling rate.
+ *  @return The appropriate DCP-approved sampling rate (48kHz or 96kHz).
+ */
 int
 dcp_audio_sample_rate (int fs)
 {
@@ -424,6 +420,9 @@ bool operator!= (Crop const & a, Crop const & b)
        return !(a == b);
 }
 
+/** @param index Colour LUT index.
+ *  @return Human-readable name.
+ */
 string
 colour_lut_index_to_name (int index)
 {
@@ -458,6 +457,10 @@ Socket::check ()
        _deadline.async_wait (boost::bind (&Socket::check, this));
 }
 
+/** Blocking connect with timeout.
+ *  @param endpoint End-point to connect to.
+ *  @param timeout Time-out in seconds.
+ */
 void
 Socket::connect (asio::ip::basic_resolver_entry<asio::ip::tcp> const & endpoint, int timeout)
 {
@@ -472,6 +475,11 @@ Socket::connect (asio::ip::basic_resolver_entry<asio::ip::tcp> const & endpoint,
        }
 }
 
+/** Blocking write with timeout.
+ *  @param data Buffer to write.
+ *  @param size Number of bytes to write.
+ *  @param timeout Time-out, in seconds.
+ */
 void
 Socket::write (uint8_t const * data, int size, int timeout)
 {
@@ -488,6 +496,11 @@ Socket::write (uint8_t const * data, int size, int timeout)
        }
 }
 
+/** Blocking read with timeout.
+ *  @param data Buffer to read to.
+ *  @param size Number of bytes to read.
+ *  @param timeout Time-out, in seconds.
+ */
 int
 Socket::read (uint8_t* data, int size, int timeout)
 {
@@ -586,3 +599,126 @@ Socket::read_indefinite (uint8_t* data, int size, int timeout)
        assert (size >= _buffer_data);
        memcpy (data, _buffer, size);
 }
+
+Rect
+Rect::intersection (Rect const & other) const
+{
+       int const tx = max (x, other.x);
+       int const ty = max (y, other.y);
+       
+       return Rect (
+               tx, ty,
+               min (x + width, other.x + other.width) - tx,
+               min (y + height, other.y + other.height) - ty
+               );
+}
+
+/** Round a number up to the nearest multiple of another number.
+ *  @param a Number to round.
+ *  @param t Multiple to round to.
+ *  @return Rounded number.
+ */
+
+int
+round_up (int a, int t)
+{
+       a += (t - 1);
+       return a - (a % t);
+}
+
+/** Read a sequence of key / value pairs from a text stream;
+ *  the keys are the first words on the line, and the values are
+ *  the remainder of the line following the key.  Lines beginning
+ *  with # are ignored.
+ *  @param s Stream to read.
+ *  @return key/value pairs.
+ */
+multimap<string, string>
+read_key_value (istream &s) 
+{
+       multimap<string, string> kv;
+       
+       string line;
+       while (getline (s, line)) {
+               if (line.empty ()) {
+                       continue;
+               }
+               
+               if (line[0] == '#') {
+                       continue;
+               }
+
+               if (line[line.size() - 1] == '\r') {
+                       line = line.substr (0, line.size() - 1);
+               }
+
+               size_t const s = line.find (' ');
+               if (s == string::npos) {
+                       continue;
+               }
+
+               kv.insert (make_pair (line.substr (0, s), line.substr (s + 1)));
+       }
+
+       return kv;
+}
+
+string
+get_required_string (multimap<string, string> const & kv, string k)
+{
+       if (kv.count (k) > 1) {
+               throw StringError ("unexpected multiple keys in key-value set");
+       }
+
+       multimap<string, string>::const_iterator i = kv.find (k);
+       
+       if (i == kv.end ()) {
+               throw StringError (String::compose ("missing key %1 in key-value set", k));
+       }
+
+       return i->second;
+}
+
+int
+get_required_int (multimap<string, string> const & kv, string k)
+{
+       string const v = get_required_string (kv, k);
+       return lexical_cast<int> (v);
+}
+
+float
+get_required_float (multimap<string, string> const & kv, string k)
+{
+       string const v = get_required_string (kv, k);
+       return lexical_cast<float> (v);
+}
+
+string
+get_optional_string (multimap<string, string> const & kv, string k)
+{
+       if (kv.count (k) > 1) {
+               throw StringError ("unexpected multiple keys in key-value set");
+       }
+
+       multimap<string, string>::const_iterator i = kv.find (k);
+       if (i == kv.end ()) {
+               return "";
+       }
+
+       return i->second;
+}
+
+int
+get_optional_int (multimap<string, string> const & kv, string k)
+{
+       if (kv.count (k) > 1) {
+               throw StringError ("unexpected multiple keys in key-value set");
+       }
+
+       multimap<string, string>::const_iterator i = kv.find (k);
+       if (i == kv.end ()) {
+               return 0;
+       }
+
+       return lexical_cast<int> (i->second);
+}