Improve FFmpeg sync, in theory.
[dcpomatic.git] / src / lib / ffmpeg_content.cc
index fcc775f0a9488efb0e9e7836d97b6efd15d3a05b..1135cc9a3add1f07e2416bba28a279748120de8c 100644 (file)
@@ -1,5 +1,3 @@
-/* -*- c-basic-offset: 8; default-tab-width: 8; -*- */
-
 /*
     Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
 
 
 #include <libcxml/cxml.h>
 #include "ffmpeg_content.h"
-#include "ffmpeg_decoder.h"
+#include "ffmpeg_examiner.h"
 #include "compose.hpp"
 #include "job.h"
 #include "util.h"
+#include "filter.h"
+#include "film.h"
 #include "log.h"
 
 #include "i18n.h"
@@ -41,19 +41,20 @@ int const FFmpegContentProperty::SUBTITLE_STREAMS = 100;
 int const FFmpegContentProperty::SUBTITLE_STREAM = 101;
 int const FFmpegContentProperty::AUDIO_STREAMS = 102;
 int const FFmpegContentProperty::AUDIO_STREAM = 103;
+int const FFmpegContentProperty::FILTERS = 104;
 
-FFmpegContent::FFmpegContent (boost::filesystem::path f)
-       : Content (f)
-       , VideoContent (f)
-       , AudioContent (f)
+FFmpegContent::FFmpegContent (shared_ptr<const Film> f, boost::filesystem::path p)
+       : Content (f, p)
+       , VideoContent (f, p)
+       , AudioContent (f, p)
 {
 
 }
 
-FFmpegContent::FFmpegContent (shared_ptr<const cxml::Node> node)
-       : Content (node)
-       , VideoContent (node)
-       , AudioContent (node)
+FFmpegContent::FFmpegContent (shared_ptr<const Film> f, shared_ptr<const cxml::Node> node)
+       : Content (f, node)
+       , VideoContent (f, node)
+       , AudioContent (f, node)
 {
        list<shared_ptr<cxml::Node> > c = node->node_children ("SubtitleStream");
        for (list<shared_ptr<cxml::Node> >::const_iterator i = c.begin(); i != c.end(); ++i) {
@@ -70,6 +71,13 @@ FFmpegContent::FFmpegContent (shared_ptr<const cxml::Node> node)
                        _audio_stream = _audio_streams.back ();
                }
        }
+
+       c = node->node_children ("Filter");
+       for (list<shared_ptr<cxml::Node> >::iterator i = c.begin(); i != c.end(); ++i) {
+               _filters.push_back (Filter::from_id ((*i)->content ()));
+       }
+
+       _first_video = node->optional_number_child<Time> ("FirstVideo");
 }
 
 FFmpegContent::FFmpegContent (FFmpegContent const & o)
@@ -109,49 +117,53 @@ FFmpegContent::as_xml (xmlpp::Node* node) const
                }
                (*i)->as_xml (t);
        }
+
+       for (vector<Filter const *>::const_iterator i = _filters.begin(); i != _filters.end(); ++i) {
+               node->add_child("Filter")->add_child_text ((*i)->id ());
+       }
+
+       if (_first_video) {
+               node->add_child("FirstVideo")->add_child_text (lexical_cast<string> (_first_video.get ()));
+       }
 }
 
 void
-FFmpegContent::examine (shared_ptr<Film> film, shared_ptr<Job> job, bool quick)
+FFmpegContent::examine (shared_ptr<Job> job)
 {
        job->set_progress_unknown ();
 
-       Content::examine (film, job, quick);
+       Content::examine (job);
 
-       shared_ptr<FFmpegDecoder> decoder (new FFmpegDecoder (film, shared_from_this (), true, false, false));
+       shared_ptr<const Film> film = _film.lock ();
+       assert (film);
 
-       ContentVideoFrame video_length = 0;
-       if (quick) {
-               video_length = decoder->video_length ();
-                film->log()->log (String::compose ("Video length obtained from header as %1 frames", decoder->video_length ()));
-        } else {
-                while (!decoder->pass ()) {
-                        /* keep going */
-                }
+       shared_ptr<FFmpegExaminer> examiner (new FFmpegExaminer (shared_from_this ()));
 
-                video_length = decoder->video_frame ();
-                film->log()->log (String::compose ("Video length examined as %1 frames", decoder->video_frame ()));
-        }
+       VideoContent::Frame video_length = 0;
+       video_length = examiner->video_length ();
+       film->log()->log (String::compose ("Video length obtained from header as %1 frames", video_length));
 
         {
                 boost::mutex::scoped_lock lm (_mutex);
 
                 _video_length = video_length;
 
-                _subtitle_streams = decoder->subtitle_streams ();
+                _subtitle_streams = examiner->subtitle_streams ();
                 if (!_subtitle_streams.empty ()) {
                         _subtitle_stream = _subtitle_streams.front ();
                 }
                 
-                _audio_streams = decoder->audio_streams ();
+                _audio_streams = examiner->audio_streams ();
                 if (!_audio_streams.empty ()) {
                         _audio_stream = _audio_streams.front ();
                 }
+
+               _first_video = examiner->first_video ();
         }
 
-        take_from_video_decoder (decoder);
+        take_from_video_examiner (examiner);
 
-        signal_changed (VideoContentProperty::VIDEO_LENGTH);
+        signal_changed (ContentProperty::LENGTH);
         signal_changed (FFmpegContentProperty::SUBTITLE_STREAMS);
         signal_changed (FFmpegContentProperty::SUBTITLE_STREAM);
         signal_changed (FFmpegContentProperty::AUDIO_STREAMS);
@@ -202,12 +214,12 @@ FFmpegContent::set_audio_stream (shared_ptr<FFmpegAudioStream> s)
         signal_changed (FFmpegContentProperty::AUDIO_STREAM);
 }
 
-ContentAudioFrame
+AudioContent::Frame
 FFmpegContent::audio_length () const
 {
        int const cafr = content_audio_frame_rate ();
        int const vfr  = video_frame_rate ();
-       ContentVideoFrame const vl = video_length ();
+       VideoContent::Frame const vl = video_length ();
 
        boost::mutex::scoped_lock lm (_mutex);
         if (!_audio_stream) {
@@ -242,8 +254,11 @@ FFmpegContent::content_audio_frame_rate () const
 }
 
 int
-FFmpegContent::output_audio_frame_rate (shared_ptr<const Film> film) const
+FFmpegContent::output_audio_frame_rate () const
 {
+       shared_ptr<const Film> film = _film.lock ();
+       assert (film);
+       
        /* Resample to a DCI-approved sample rate */
        double t = dcp_audio_frame_rate (content_audio_frame_rate ());
 
@@ -281,6 +296,7 @@ FFmpegAudioStream::FFmpegAudioStream (shared_ptr<const cxml::Node> node)
        frame_rate = node->number_child<int> ("FrameRate");
        channels = node->number_child<int64_t> ("Channels");
        mapping = AudioMapping (node->node_child ("Mapping"));
+       first_audio = node->optional_number_child<Time> ("FirstAudio");
 }
 
 void
@@ -290,6 +306,9 @@ FFmpegAudioStream::as_xml (xmlpp::Node* root) const
        root->add_child("Id")->add_child_text (lexical_cast<string> (id));
        root->add_child("FrameRate")->add_child_text (lexical_cast<string> (frame_rate));
        root->add_child("Channels")->add_child_text (lexical_cast<string> (channels));
+       if (first_audio) {
+               root->add_child("FirstAudio")->add_child_text (lexical_cast<string> (first_audio));
+       }
        mapping.as_xml (root->add_child("Mapping"));
 }
 
@@ -317,8 +336,11 @@ FFmpegContent::clone () const
 }
 
 Time
-FFmpegContent::length (shared_ptr<const Film> film) const
+FFmpegContent::length () const
 {
+       shared_ptr<const Film> film = _film.lock ();
+       assert (film);
+       
        FrameRateConversion frc (video_frame_rate (), film->dcp_video_frame_rate ());
        return video_length() * frc.factor() * TIME_HZ / film->dcp_video_frame_rate ();
 }
@@ -332,7 +354,23 @@ FFmpegContent::audio_mapping () const
                return AudioMapping ();
        }
 
-       cout << "returning am from stream " << _audio_stream.get() << ".\n";
        return _audio_stream->mapping;
 }
 
+void
+FFmpegContent::set_filters (vector<Filter const *> const & filters)
+{
+       {
+               boost::mutex::scoped_lock lm (_mutex);
+               _filters = filters;
+       }
+
+       signal_changed (FFmpegContentProperty::FILTERS);
+}
+
+void
+FFmpegContent::set_audio_mapping (AudioMapping m)
+{
+       audio_stream()->mapping = m;
+       signal_changed (AudioContentProperty::AUDIO_MAPPING);
+}