... perhaps generate the CPL hash on the fly
Write hashes of frames after successful write.
Make check of hashes optional; recovery in general
-
+Fix multi-reel or remove it
\ No newline at end of file
* @param frame DCP Frame index.
*/
void
-EncodedData::write (shared_ptr<const Film> film, int frame)
+EncodedData::write (shared_ptr<const Film> film, int frame) const
{
string const tmp_j2k = film->frame_out_path (frame, true);
virtual ~EncodedData ();
void send (boost::shared_ptr<Socket> socket);
- void write (boost::shared_ptr<const Film>, int);
+ void write (boost::shared_ptr<const Film>, int) const;
/** @return data */
uint8_t* data () const {
: _film (f)
, _just_skipped (false)
, _video_frames_in (0)
- , _audio_frames_in (0)
, _video_frames_out (0)
- , _audio_frames_out (0)
#ifdef HAVE_SWRESAMPLE
, _swr_context (0)
#endif
, _have_a_real_frame (false)
, _terminate_encoder (false)
{
- if (_film->audio_stream()) {
- /* Create sound output files with .tmp suffixes; we will rename
- them if and when we complete.
- */
- for (int i = 0; i < dcp_audio_channels (_film->audio_channels()); ++i) {
- SF_INFO sf_info;
- sf_info.samplerate = dcp_audio_sample_rate (_film->audio_stream()->sample_rate());
- /* We write mono files */
- sf_info.channels = 1;
- sf_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_24;
- SNDFILE* f = sf_open (_film->multichannel_audio_out_path (i, true).c_str (), SFM_WRITE, &sf_info);
- if (f == 0) {
- throw CreateFileError (_film->multichannel_audio_out_path (i, true));
- }
- _sound_files.push_back (f);
- }
- }
+
}
Encoder::~Encoder ()
{
- close_sound_files ();
terminate_worker_threads ();
if (_writer) {
_writer->finish ();
}
out->set_frames (frames);
- write_audio (out);
+ _writer->write (out);
}
swr_free (&_swr_context);
}
#endif
- if (_film->audio_stream()) {
- close_sound_files ();
-
- /* Rename .wav.tmp files to .wav */
- for (int i = 0; i < dcp_audio_channels (_film->audio_channels()); ++i) {
- if (boost::filesystem::exists (_film->multichannel_audio_out_path (i, false))) {
- boost::filesystem::remove (_film->multichannel_audio_out_path (i, false));
- }
- boost::filesystem::rename (_film->multichannel_audio_out_path (i, true), _film->multichannel_audio_out_path (i, false));
- }
- }
-
boost::mutex::scoped_lock lock (_worker_mutex);
_film->log()->log ("Clearing queue of " + lexical_cast<string> (_encode_queue.size ()));
data = b;
}
- write_audio (data);
-
- _audio_frames_in += data->frames ();
+ _writer->write (data);
}
-void
-Encoder::write_audio (shared_ptr<const AudioBuffers> audio)
-{
- for (int i = 0; i < audio->channels(); ++i) {
- sf_write_float (_sound_files[i], audio->data(i), audio->frames());
- }
-
- _audio_frames_out += audio->frames ();
-}
-
-void
-Encoder::close_sound_files ()
-{
- for (vector<SNDFILE*>::iterator i = _sound_files.begin(); i != _sound_files.end(); ++i) {
- sf_close (*i);
- }
-
- _sound_files.clear ();
-}
-
void
Encoder::terminate_worker_threads ()
{
#include <libswresample/swresample.h>
}
#endif
-#include <sndfile.h>
#include "util.h"
#include "video_sink.h"
#include "audio_sink.h"
void frame_done ();
void frame_skipped ();
- void close_sound_files ();
void write_audio (boost::shared_ptr<const AudioBuffers> audio);
void encoder_thread (ServerDescription *);
/** Number of video frames received so far */
SourceFrame _video_frames_in;
- /** Number of audio frames received so far */
- int64_t _audio_frames_in;
/** Number of video frames written for the DCP so far */
int _video_frames_out;
- /** Number of audio frames written for the DCP so far */
- int64_t _audio_frames_out;
#if HAVE_SWRESAMPLE
SwrContext* _swr_context;
#endif
- std::vector<SNDFILE*> _sound_files;
-
bool _have_a_real_frame;
bool _terminate_encoder;
std::list<boost::shared_ptr<DCPVideoFrame> > _encode_queue;
*/
#include <libdcp/picture_asset.h>
+#include <libdcp/sound_asset.h>
#include "writer.h"
#include "compose.hpp"
#include "film.h"
_picture_asset_writer = _picture_asset->start_write ();
+ if (_film->audio_channels() > 0) {
+ _sound_asset.reset (
+ new libdcp::SoundAsset (
+ _film->dir (_film->dcp_name()),
+ String::compose ("audio_%1.mxf", 0),
+ DCPFrameRate (_film->frames_per_second()).frames_per_second,
+ _film->audio_channels(),
+ _film->audio_stream()->sample_rate()
+ )
+ );
+
+ _sound_asset_writer = _sound_asset->start_write ();
+ }
+
_thread = new boost::thread (boost::bind (&Writer::thread, this));
}
void
-Writer::write (shared_ptr<EncodedData> encoded, int frame)
+Writer::write (shared_ptr<const EncodedData> encoded, int frame)
{
boost::mutex::scoped_lock lock (_mutex);
_queue.push_back (make_pair (encoded, frame));
_condition.notify_all ();
}
+/** This method is not thread safe */
+void
+Writer::write (shared_ptr<const AudioBuffers> audio)
+{
+ _sound_asset_writer->write (audio->data(), audio->frames());
+}
+
struct QueueSorter
{
- bool operator() (pair<shared_ptr<EncodedData>, int> const & a, pair<shared_ptr<EncodedData>, int> const & b) {
+ bool operator() (pair<shared_ptr<const EncodedData>, int> const & a, pair<shared_ptr<const EncodedData>, int> const & b) {
return a.second < b.second;
}
};
/* Write any frames that we can write; i.e. those that are in sequence */
while (!_queue.empty() && _queue.front().second == (_last_written_frame + 1)) {
- pair<boost::shared_ptr<EncodedData>, int> encoded = _queue.front ();
+ pair<boost::shared_ptr<const EncodedData>, int> encoded = _queue.front ();
_queue.pop_front ();
lock.unlock ();
Put some to disk.
*/
- pair<boost::shared_ptr<EncodedData>, int> encoded = _queue.back ();
+ pair<boost::shared_ptr<const EncodedData>, int> encoded = _queue.back ();
_queue.pop_back ();
if (!encoded.first) {
/* This is a `repeat-last' frame, so no need to write it to disk */
lock.unlock ();
_film->log()->log (String::compose ("Writer pulls %1 back from disk", fetch));
- shared_ptr<EncodedData> encoded;
+ shared_ptr<const EncodedData> encoded;
if (boost::filesystem::exists (_film->frame_out_path (fetch, false))) {
/* It's an actual frame (not a repeat-last); load it in */
encoded.reset (new EncodedData (_film->frame_out_path (fetch, false)));
_thread = 0;
_picture_asset_writer->finalize ();
+ _sound_asset_writer->finalize ();
}
/** Tell the writer that frame `f' should be a repeat of the frame before it */
Writer::repeat (int f)
{
boost::mutex::scoped_lock lock (_mutex);
- _queue.push_back (make_pair (shared_ptr<EncodedData> (), f));
+ _queue.push_back (make_pair (shared_ptr<const EncodedData> (), f));
}
class Film;
class EncodedData;
+class AudioBuffers;
namespace libdcp {
class MonoPictureAsset;
class MonoPictureAssetWriter;
+ class SoundAsset;
+ class SoundAssetWriter;
}
class Writer
public:
Writer (boost::shared_ptr<const Film>);
- void write (boost::shared_ptr<EncodedData>, int);
+ void write (boost::shared_ptr<const EncodedData>, int);
+ void write (boost::shared_ptr<const AudioBuffers>);
void repeat (int f);
void finish ();
boost::thread* _thread;
bool _finish;
- std::list<std::pair<boost::shared_ptr<EncodedData>, int> > _queue;
+ std::list<std::pair<boost::shared_ptr<const EncodedData>, int> > _queue;
mutable boost::mutex _mutex;
boost::condition _condition;
- boost::shared_ptr<EncodedData> _last_written;
+ boost::shared_ptr<const EncodedData> _last_written;
std::list<int> _pending;
int _last_written_frame;
static const unsigned int _maximum_frames_in_memory;
boost::shared_ptr<libdcp::MonoPictureAsset> _picture_asset;
boost::shared_ptr<libdcp::MonoPictureAssetWriter> _picture_asset_writer;
+ boost::shared_ptr<libdcp::SoundAsset> _sound_asset;
+ boost::shared_ptr<libdcp::SoundAssetWriter> _sound_asset_writer;
};