Untested direct write of audio to MXF.
authorCarl Hetherington <cth@carlh.net>
Fri, 18 Jan 2013 21:49:49 +0000 (21:49 +0000)
committerCarl Hetherington <cth@carlh.net>
Fri, 18 Jan 2013 21:49:49 +0000 (21:49 +0000)
NOTES
src/lib/dcp_video_frame.cc
src/lib/dcp_video_frame.h
src/lib/encoder.cc
src/lib/encoder.h
src/lib/writer.cc
src/lib/writer.h

diff --git a/NOTES b/NOTES
index a771e9bfd6f1fa2f868b12ccea9366ec5a110409..b384cb6c0e9d43b1fa66bc957c0db9e9b9a72237 100644 (file)
--- a/NOTES
+++ b/NOTES
@@ -4,4 +4,4 @@ Get rid of DCP job entirely and make encoder write XML (since it has the *Asset
 ... 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
index da864ad9ff88c3389171e11d676b4a6aea1ef931..89db5761a1bb56f04a85e0ade660ef3a57ecd9ff 100644 (file)
@@ -405,7 +405,7 @@ EncodedData::~EncodedData ()
  *  @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);
 
index b446352c798a1938acf37d3dc85102a98ffb81b2..2ad2b0d444e9c5bd8631c7c9513cdef7930c9941 100644 (file)
@@ -48,7 +48,7 @@ public:
        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 {
index bad420f353531e3d011abb6e45d7900f485dfb39..c2416b87e754a0a50208aa4ced7c03e84e90890e 100644 (file)
@@ -57,37 +57,18 @@ Encoder::Encoder (shared_ptr<const Film> f)
        : _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 ();
@@ -162,25 +143,13 @@ Encoder::process_end ()
                        }
 
                        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 ()));
@@ -386,31 +355,9 @@ Encoder::process_audio (shared_ptr<AudioBuffers> data)
                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 ()
 {
index a277aca51d85f387926485a50ba7593e2a5041e2..fc89d674a3dd5b81511e40c5934d2cadb114de12 100644 (file)
@@ -39,7 +39,6 @@ extern "C" {
 #include <libswresample/swresample.h>
 }
 #endif
-#include <sndfile.h>
 #include "util.h"
 #include "video_sink.h"
 #include "audio_sink.h"
@@ -91,7 +90,6 @@ private:
        void frame_done ();
        void frame_skipped ();
        
-       void close_sound_files ();
        void write_audio (boost::shared_ptr<const AudioBuffers> audio);
 
        void encoder_thread (ServerDescription *);
@@ -113,19 +111,13 @@ private:
 
        /** 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;
index 0381ee37835708fa4ab0169179ad9bfa99c525b9..fbd371550fd9735ad68a65b46f64cbe684ffc7e1 100644 (file)
@@ -18,6 +18,7 @@
 */
 
 #include <libdcp/picture_asset.h>
+#include <libdcp/sound_asset.h>
 #include "writer.h"
 #include "compose.hpp"
 #include "film.h"
@@ -48,20 +49,41 @@ Writer::Writer (shared_ptr<const Film> f)
        
        _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;
        }
 };
@@ -94,7 +116,7 @@ Writer::thread ()
 
                /* 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 ();
@@ -115,7 +137,7 @@ Writer::thread ()
                           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 */
@@ -138,7 +160,7 @@ Writer::thread ()
 
                        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)));
@@ -169,6 +191,7 @@ Writer::finish ()
        _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 */
@@ -176,5 +199,5 @@ void
 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));
 }
index 8156308a6b9c86e9849703c28aef22c9ce9df584..77f98f160294a0c973677911885918f37f239a61 100644 (file)
 
 class Film;
 class EncodedData;
+class AudioBuffers;
 
 namespace libdcp {
        class MonoPictureAsset;
        class MonoPictureAssetWriter;
+       class SoundAsset;
+       class SoundAssetWriter;
 }
 
 class Writer
@@ -35,7 +38,8 @@ 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 ();
 
@@ -47,14 +51,16 @@ private:
 
        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;
 };