X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Futil.cc;h=b69581eba56a1e8b282f75cff6ad02371d737aac;hb=7561918187d51eadcd59904a71c1eda30cc6ab31;hp=6221b8b62c6aacb0a2ee164595678a284ffdc8bf;hpb=c0e04acd1e9875fa67800a7861bd8a370157b49f;p=dcpomatic.git diff --git a/src/lib/util.cc b/src/lib/util.cc index 6221b8b62..b69581eba 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -56,12 +57,7 @@ extern "C" { #include "format.h" #include "dcp_content_type.h" #include "filter.h" -#include "screen.h" -#include "film_state.h" #include "sound_processor.h" -#ifndef DVDOMATIC_DISABLE_PLAYER -#include "player_manager.h" -#endif using namespace std; using namespace boost; @@ -192,34 +188,6 @@ stacktrace (ostream& out, int levels) } #endif -/** @return Version of vobcopy that is on the path (and hence that we will use) */ -static string -vobcopy_version () -{ - FILE* f = popen ("vobcopy -V 2>&1", "r"); - if (f == 0) { - throw EncodeError ("could not run vobcopy to check version"); - } - - string version = "unknown"; - - while (!feof (f)) { - char buf[256]; - if (fgets (buf, sizeof (buf), f)) { - string s (buf); - vector b; - split (b, s, is_any_of (" ")); - if (b.size() >= 2 && b[0] == "Vobcopy") { - version = b[1]; - } - } - } - - pclose (f); - - return version; -} - /** @param v Version as used by FFmpeg. * @return A string representation of v. */ @@ -237,7 +205,6 @@ dependency_version_summary () { stringstream s; s << "libopenjpeg " << opj_version () << ", " - << "vobcopy " << vobcopy_version() << ", " << "libavcodec " << ffmpeg_version_to_string (avcodec_version()) << ", " << "libavfilter " << ffmpeg_version_to_string (avfilter_version()) << ", " << "libavformat " << ffmpeg_version_to_string (avformat_version()) << ", " @@ -257,17 +224,6 @@ seconds (struct timeval t) return t.tv_sec + (double (t.tv_usec) / 1e6); } - -#ifdef DVDOMATIC_POSIX -void -sigchld_handler (int, siginfo_t* info, void *) -{ -#ifndef DVDOMATIC_DISABLE_PLAYER - PlayerManager::instance()->child_exited (info->si_pid); -#endif -} -#endif - /** Call the required functions to set up DVD-o-matic's static arrays, etc. * Must be called from the UI thread, if there is one. */ @@ -281,16 +237,12 @@ dvdomatic_setup () SoundProcessor::setup_sound_processors (); ui_thread = this_thread::get_id (); - -#ifdef DVDOMATIC_POSIX - struct sigaction sa; - sa.sa_flags = SA_SIGINFO; - sigemptyset (&sa.sa_mask); - sa.sa_sigaction = sigchld_handler; - sigaction (SIGCHLD, &sa, 0); -#endif } +/** @param start Start position for the crop within the image. + * @param size Size of the cropped area. + * @return FFmpeg crop filter string. + */ string crop_string (Position start, Size size) { @@ -299,6 +251,9 @@ crop_string (Position start, Size size) return s.str (); } +/** @param s A string. + * @return Parts of the string split at spaces, except when a space is within quotation marks. + */ vector split_at_spaces_considering_quotes (string s) { @@ -375,6 +330,27 @@ md5_digest (string file) return s.str (); } +/** @param fps Arbitrary frames-per-second value. + * @return DCPFrameRate for this frames-per-second. + */ +DCPFrameRate +dcp_frame_rate (float fps) +{ + DCPFrameRate dfr; + + dfr.run_fast = (fps != rint (fps)); + dfr.frames_per_second = rint (fps); + dfr.skip = 1; + + /* XXX: somewhat arbitrary */ + if (fps == 50) { + dfr.frames_per_second = 25; + dfr.skip = 2; + } + + return dfr; +} + /** @param An arbitrary sampling rate. * @return The appropriate DCP-approved sampling rate (48kHz or 96kHz). */ @@ -388,6 +364,11 @@ dcp_audio_sample_rate (int fs) return 96000; } +bool operator== (Size const & a, Size const & b) +{ + return (a.width == b.width && a.height == b.height); +} + bool operator== (Crop const & a, Crop const & b) { return (a.left == b.left && a.right == b.right && a.top == b.top && a.bottom == b.bottom); @@ -578,6 +559,9 @@ Socket::read_indefinite (uint8_t* data, int size, int timeout) memcpy (data, _buffer, size); } +/** @param other A Rect. + * @return The intersection of this with `other'. + */ Rect Rect::intersection (Rect const & other) const { @@ -596,14 +580,19 @@ Rect::intersection (Rect const & other) const * @param t Multiple to round to. * @return Rounded number. */ - int -round_up (int a, int t) +stride_round_up (int c, int const * stride, int t) { - a += (t - 1); + int const a = stride[c] + (t - 1); return a - (a % t); } +int +stride_lookup (int c, int const * stride) +{ + return stride[c]; +} + /** 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 @@ -621,7 +610,7 @@ read_key_value (istream &s) if (line.empty ()) { continue; } - + if (line[0] == '#') { continue; } @@ -701,9 +690,14 @@ get_optional_int (multimap const & kv, string k) return lexical_cast (i->second); } +/** Construct an AudioBuffers. Audio data is undefined after this constructor. + * @param channels Number of channels. + * @param frames Number of frames to reserve space for. + */ AudioBuffers::AudioBuffers (int channels, int frames) : _channels (channels) , _frames (frames) + , _allocated_frames (frames) { _data = new float*[_channels]; for (int i = 0; i < _channels; ++i) { @@ -711,6 +705,22 @@ AudioBuffers::AudioBuffers (int channels, int frames) } } +/** Copy constructor. + * @param other Other AudioBuffers; data is copied. + */ +AudioBuffers::AudioBuffers (AudioBuffers const & other) + : _channels (other._channels) + , _frames (other._frames) + , _allocated_frames (other._frames) +{ + _data = new float*[_channels]; + for (int i = 0; i < _channels; ++i) { + _data[i] = new float[_frames]; + memcpy (_data[i], other._data[i], _frames * sizeof (float)); + } +} + +/** AudioBuffers destructor */ AudioBuffers::~AudioBuffers () { for (int i = 0; i < _channels; ++i) { @@ -720,22 +730,127 @@ AudioBuffers::~AudioBuffers () delete[] _data; } +/** @param c Channel index. + * @return Buffer for this channel. + */ float* AudioBuffers::data (int c) const { assert (c >= 0 && c < _channels); return _data[c]; } - + +/** Set the number of frames that these AudioBuffers will report themselves + * as having. + * @param f Frames; must be less than or equal to the number of allocated frames. + */ void AudioBuffers::set_frames (int f) { - assert (f <= _frames); + assert (f <= _allocated_frames); _frames = f; } +/** Make all samples on all channels silent */ +void +AudioBuffers::make_silent () +{ + for (int i = 0; i < _channels; ++i) { + make_silent (i); + } +} + +/** Make all samples on a given channel silent. + * @param c Channel. + */ +void +AudioBuffers::make_silent (int c) +{ + assert (c >= 0 && c < _channels); + + for (int i = 0; i < _frames; ++i) { + _data[c][i] = 0; + } +} + +/** Copy data from another AudioBuffers to this one. All channels are copied. + * @param from AudioBuffers to copy from; must have the same number of channels as this. + * @param frames_to_copy Number of frames to copy. + * @param read_offset Offset to read from in `from'. + * @param write_offset Offset to write to in `to'. + */ +void +AudioBuffers::copy_from (AudioBuffers* from, int frames_to_copy, int read_offset, int write_offset) +{ + assert (from->channels() == channels()); + + assert (from); + assert (read_offset >= 0 && (read_offset + frames_to_copy) <= from->_allocated_frames); + assert (write_offset >= 0 && (write_offset + frames_to_copy) <= _allocated_frames); + + for (int i = 0; i < _channels; ++i) { + memcpy (_data[i] + write_offset, from->_data[i] + read_offset, frames_to_copy * sizeof(float)); + } +} + +/** Move audio data around. + * @param from Offset to move from. + * @param to Offset to move to. + * @param frames Number of frames to move. + */ + +void +AudioBuffers::move (int from, int to, int frames) +{ + if (frames == 0) { + return; + } + + assert (from >= 0); + assert (from < _frames); + assert (to >= 0); + assert (to < _frames); + assert (frames > 0); + assert (frames <= _frames); + assert ((from + frames) <= _frames); + assert ((to + frames) <= _frames); + + for (int i = 0; i < _channels; ++i) { + memmove (_data[i] + to, _data[i] + from, frames * sizeof(float)); + } +} + +/** Trip an assert if the caller is not in the UI thread */ void ensure_ui_thread () { assert (this_thread::get_id() == ui_thread); } + +/** @param v Source video frame. + * @param audio_sample_rate Source audio sample rate. + * @param frames_per_second Number of video frames per second. + * @return Equivalent number of audio frames for `v'. + */ +int64_t +video_frames_to_audio_frames (SourceFrame v, float audio_sample_rate, float frames_per_second) +{ + return ((int64_t) v * audio_sample_rate / frames_per_second); +} + +/** @param f Filename. + * @return true if this file is a still image, false if it is something else. + */ +bool +still_image_file (string f) +{ +#if BOOST_FILESYSTEM_VERSION == 3 + string ext = boost::filesystem::path(f).extension().string(); +#else + string ext = boost::filesystem::path(f).extension(); +#endif + + transform (ext.begin(), ext.end(), ext.begin(), ::tolower); + + return (ext == ".tif" || ext == ".tiff" || ext == ".jpg" || ext == ".jpeg" || ext == ".png"); +}