Merge writer-thread with original which was time-cleanup.
[dcpomatic.git] / src / lib / encoder.cc
index 731a39042ea0a8be2993aee073a75334192eb5a7..0f48310ef873ce9ec6a447509f7c9f1a20bea242 100644 (file)
@@ -34,6 +34,7 @@
 #include "config.h"
 #include "dcp_video_frame.h"
 #include "server.h"
+#include "format.h"
 #include "cross.h"
 
 using std::pair;
@@ -50,16 +51,16 @@ int const Encoder::_history_size = 25;
 /** @param f Film that we are encoding.
  *  @param o Options.
  */
-Encoder::Encoder (shared_ptr<const Film> f, shared_ptr<const EncodeOptions> o)
+Encoder::Encoder (shared_ptr<const Film> f)
        : _film (f)
-       , _opt (o)
        , _just_skipped (false)
-       , _video_frame (0)
-       , _audio_frame (0)
+       , _video_frames_in (0)
+       , _audio_frames_in (0)
+       , _video_frames_out (0)
+       , _audio_frames_out (0)
 #ifdef HAVE_SWRESAMPLE   
        , _swr_context (0)
 #endif   
-       , _audio_frames_written (0)
        , _terminate_encoder (false)
        , _writer_thread (0)
        , _terminate_writer (false)
@@ -74,9 +75,9 @@ Encoder::Encoder (shared_ptr<const Film> f, shared_ptr<const EncodeOptions> o)
                        /* We write mono files */
                        sf_info.channels = 1;
                        sf_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_24;
-                       SNDFILE* f = sf_open (_opt->multichannel_audio_out_path (i, true).c_str (), SFM_WRITE, &sf_info);
+                       SNDFILE* f = sf_open (_film->multichannel_audio_out_path (i, true).c_str (), SFM_WRITE, &sf_info);
                        if (f == 0) {
-                               throw CreateFileError (_opt->multichannel_audio_out_path (i, true));
+                               throw CreateFileError (_film->multichannel_audio_out_path (i, true));
                        }
                        _sound_files.push_back (f);
                }
@@ -170,10 +171,10 @@ Encoder::process_end ()
                
                /* Rename .wav.tmp files to .wav */
                for (int i = 0; i < dcp_audio_channels (_film->audio_channels()); ++i) {
-                       if (boost::filesystem::exists (_opt->multichannel_audio_out_path (i, false))) {
-                               boost::filesystem::remove (_opt->multichannel_audio_out_path (i, false));
+                       if (boost::filesystem::exists (_film->multichannel_audio_out_path (i, false))) {
+                               boost::filesystem::remove (_film->multichannel_audio_out_path (i, false));
                        }
-                       boost::filesystem::rename (_opt->multichannel_audio_out_path (i, true), _opt->multichannel_audio_out_path (i, false));
+                       boost::filesystem::rename (_film->multichannel_audio_out_path (i, true), _film->multichannel_audio_out_path (i, false));
                }
        }
 
@@ -208,7 +209,7 @@ Encoder::process_end ()
                _film->log()->log (String::compose ("Encode left-over frame %1", (*i)->frame ()));
                try {
                        shared_ptr<EncodedData> e = (*i)->encode_locally ();
-                       e->write (_opt, (*i)->frame ());
+                       e->write (_film, (*i)->frame ());
                        frame_done ();
                } catch (std::exception& e) {
                        _film->log()->log (String::compose ("Local encode failed (%1)", e.what ()));
@@ -222,8 +223,8 @@ Encoder::process_end ()
 
        /* Now do links (or copies on windows) to duplicate frames */
        for (list<pair<int, int> >::iterator i = _links_required.begin(); i != _links_required.end(); ++i) {
-               link (_opt->frame_out_path (i->first, false), _opt->frame_out_path (i->second, false));
-               link (_opt->hash_out_path (i->first, false), _opt->hash_out_path (i->second, false));
+               link (_film->frame_out_path (i->first, false), _film->frame_out_path (i->second, false));
+               link (_film->hash_out_path (i->first, false), _film->hash_out_path (i->second, false));
        }
 }      
 
@@ -252,12 +253,12 @@ Encoder::skipping () const
        return _just_skipped;
 }
 
-/** @return Number of video frames that have been received */
-SourceFrame
-Encoder::video_frame () const
+/** @return Number of video frames that have been sent out */
+int
+Encoder::video_frames_out () const
 {
        boost::mutex::scoped_lock (_history_mutex);
-       return _video_frame;
+       return _video_frames_out;
 }
 
 /** Should be called when a frame has been encoded successfully.
@@ -290,19 +291,13 @@ Encoder::frame_skipped ()
 void
 Encoder::process_video (shared_ptr<Image> image, bool same, boost::shared_ptr<Subtitle> sub)
 {
-       if (_opt->video_skip != 0 && (_video_frame % _opt->video_skip) != 0) {
-               ++_video_frame;
+       DCPFrameRate dfr (_film->frames_per_second ());
+       
+       if (dfr.skip && (_video_frames_in % 2)) {
+               ++_video_frames_in;
                return;
        }
 
-       if (_opt->video_range) {
-               pair<SourceFrame, SourceFrame> const r = _opt->video_range.get();
-               if (_video_frame < r.first || _video_frame >= r.second) {
-                       ++_video_frame;
-                       return;
-               }
-       }
-
        boost::mutex::scoped_lock lock (_worker_mutex);
 
        /* Wait until the queue has gone down a bit */
@@ -317,7 +312,7 @@ Encoder::process_video (shared_ptr<Image> image, bool same, boost::shared_ptr<Su
        }
 
        /* Only do the processing if we don't already have a file for this frame */
-       if (boost::filesystem::exists (_opt->frame_out_path (_video_frame, false))) {
+       if (boost::filesystem::exists (_film->frame_out_path (_video_frames_out, false))) {
                frame_skipped ();
                return;
        }
@@ -327,54 +322,37 @@ Encoder::process_video (shared_ptr<Image> image, bool same, boost::shared_ptr<Su
                   as on windows the link is really a copy and the reference frame might not have
                   finished encoding yet.
                */
-               _links_required.push_back (make_pair (_last_real_frame.get(), _video_frame));
+               _links_required.push_back (make_pair (_last_real_frame.get(), _video_frames_out));
        } else {
                /* Queue this new frame for encoding */
                pair<string, string> const s = Filter::ffmpeg_strings (_film->filters());
                TIMING ("adding to queue of %1", _encode_queue.size ());
                _encode_queue.push_back (boost::shared_ptr<DCPVideoFrame> (
                                          new DCPVideoFrame (
-                                                 image, sub, _opt->out_size, _opt->padding, _film->subtitle_offset(), _film->subtitle_scale(),
-                                                 _film->scaler(), _video_frame, _film->frames_per_second(), s.second,
-                                                 Config::instance()->colour_lut_index (), Config::instance()->j2k_bandwidth (),
+                                                 image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_film),
+                                                 _film->subtitle_offset(), _film->subtitle_scale(),
+                                                 _film->scaler(), _video_frames_out, _film->frames_per_second(), s.second,
+                                                 _film->colour_lut(), _film->j2k_bandwidth(),
                                                  _film->log()
                                                  )
                                          ));
                
                _worker_condition.notify_all ();
-               _last_real_frame = _video_frame;
+               _last_real_frame = _video_frames_out;
        }
 
-       ++_video_frame;
+       ++_video_frames_in;
+       ++_video_frames_out;
+
+       if (dfr.repeat) {
+               _links_required.push_back (make_pair (_video_frames_out, _video_frames_out - 1));
+               ++_video_frames_out;
+       }
 }
 
 void
 Encoder::process_audio (shared_ptr<AudioBuffers> data)
 {
-       if (_opt->audio_range) {
-               shared_ptr<AudioBuffers> trimmed (new AudioBuffers (*data.get ()));
-               
-               /* Range that we are encoding */
-               pair<int64_t, int64_t> required_range = _opt->audio_range.get();
-               /* Range of this block of data */
-               pair<int64_t, int64_t> this_range (_audio_frame, _audio_frame + trimmed->frames());
-
-               if (this_range.second < required_range.first || required_range.second < this_range.first) {
-                       /* No part of this audio is within the required range */
-                       return;
-               } else if (required_range.first >= this_range.first && required_range.first < this_range.second) {
-                       /* Trim start */
-                       int64_t const shift = required_range.first - this_range.first;
-                       trimmed->move (shift, 0, trimmed->frames() - shift);
-                       trimmed->set_frames (trimmed->frames() - shift);
-               } else if (required_range.second >= this_range.first && required_range.second < this_range.second) {
-                       /* Trim end */
-                       trimmed->set_frames (required_range.second - this_range.first);
-               }
-
-               data = trimmed;
-       }
-
 #if HAVE_SWRESAMPLE
        /* Maybe sample-rate convert */
        if (_swr_context) {
@@ -418,7 +396,7 @@ Encoder::process_audio (shared_ptr<AudioBuffers> data)
 
        write_audio (data);
        
-       _audio_frame += data->frames ();
+       _audio_frames_in += data->frames ();
 }
 
 void
@@ -428,7 +406,7 @@ Encoder::write_audio (shared_ptr<const AudioBuffers> audio)
                sf_write_float (_sound_files[i], audio->data(i), audio->frames());
        }
 
-       _audio_frames_written += audio->frames ();
+       _audio_frames_out += audio->frames ();
 }
 
 void