/*
- Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2017 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
_empty_condition.notify_all ();
}
-/** Write one video frame's worth of audio frames to the DCP.
+/** Write some audio frames to the DCP.
* @param audio Audio data or 0 if there is no audio to be written here (i.e. it is referenced).
* This method is not thread safe.
*/
void
Writer::write (shared_ptr<const AudioBuffers> audio)
{
- if (_audio_reel == _reels.end ()) {
- /* This audio is off the end of the last reel; ignore it */
- return;
- }
+ /* The audio we get might span a reel boundary, and if so we have to write it in bits */
+
+ int32_t offset = 0;
+ while (offset < audio->frames ()) {
- _audio_reel->write (audio);
+ if (_audio_reel == _reels.end ()) {
+ /* This audio is off the end of the last reel; ignore it */
+ return;
+ }
- /* written is in video frames, not audio frames */
- if (_audio_reel->total_written_audio_frames() >= _audio_reel->period().duration().frames_floor (_film->video_frame_rate())) {
- ++_audio_reel;
+ int32_t const this_time = min (
+ audio->frames() - offset,
+ (int32_t) (_audio_reel->period().duration().frames_floor(_film->audio_frame_rate()) - _audio_reel->total_written_audio_frames())
+ );
+
+ if (this_time == audio->frames()) {
+ /* Easy case: we can write all the audio to this reel */
+ _audio_reel->write (audio);
+ } else {
+ /* Write the part we can */
+ shared_ptr<AudioBuffers> part (new AudioBuffers (audio->channels(), this_time));
+ part->copy_from (audio.get(), this_time, offset, 0);
+ _audio_reel->write (part);
+ ++_audio_reel;
+ }
+
+ offset += this_time;
}
}
shared_ptr<boost::asio::io_service::work> work (new boost::asio::io_service::work (service));
- int const threads = max (1, Config::instance()->num_local_encoding_threads ());
+ int const threads = max (1, Config::instance()->master_encoding_threads ());
for (int i = 0; i < threads; ++i) {
pool.create_thread (boost::bind (&boost::asio::io_service::run, &service));
LOG_GENERAL (
N_("Wrote %1 FULL, %2 FAKE, %3 REPEAT, %4 pushed to disk"), _full_written, _fake_written, _repeat_written, _pushed_to_disk
);
+
+ write_cover_sheet ();
+}
+
+void
+Writer::write_cover_sheet ()
+{
+ boost::filesystem::path const cover = _film->file ("COVER_SHEET.txt");
+ FILE* f = fopen_boost (cover, "w");
+ if (!f) {
+ throw OpenFileError (cover, errno, false);
+ }
+
+ string text = Config::instance()->cover_sheet ();
+ boost::algorithm::replace_all (text, "$CPL_NAME", _film->name());
+ boost::algorithm::replace_all (text, "$TYPE", _film->dcp_content_type()->pretty_name());
+ boost::algorithm::replace_all (text, "$CONTAINER", _film->container()->nickname());
+
+ pair<int, int> ch = audio_channel_types (_film->mapped_audio_channels(), _film->audio_channels());
+ string description = String::compose("%1.%2", ch.first, ch.second);
+
+ if (description == "0.0") {
+ description = _("None");
+ } else if (description == "1.0") {
+ description = _("Mono");
+ } else if (description == "2.0") {
+ description = _("Stereo");
+ }
+ boost::algorithm::replace_all (text, "$AUDIO", description);
+
+ int h, m, s, fr;
+ _film->length().split (_film->video_frame_rate(), h, m, s, fr);
+ string length;
+ if (h == 0 && m == 0) {
+ length = String::compose("%1s", s);
+ } else if (h == 0 && m > 0) {
+ length = String::compose("%1m%2s", m, s);
+ } else if (h > 0 && m > 0) {
+ length = String::compose("%1h%2m%3s", h, m, s);
+ }
+
+ boost::algorithm::replace_all (text, "$LENGTH", length);
+
+ fwrite (text.c_str(), 1, text.length(), f);
+ fclose (f);
}
/** @param frame Frame index within the whole DCP.