swaroop: fix encryption of files encoded from DCP.
[dcpomatic.git] / src / lib / ffmpeg.cc
index af6c8e1674e66c12b01dcafbbc2f428ddc96d561..17ec564d321fa04fbec6f1760816500fc53a53e5 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2019 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
 #include "exceptions.h"
 #include "util.h"
 #include "log.h"
+#include "dcpomatic_log.h"
 #include "ffmpeg_subtitle_stream.h"
 #include "ffmpeg_audio_stream.h"
+#include "decrypted_ecinema_kdm.h"
 #include "digester.h"
 #include "compose.hpp"
+#include "config.h"
 #include <dcp/raw_convert.h>
 extern "C" {
 #include <libavcodec/avcodec.h>
@@ -47,9 +50,9 @@ using std::vector;
 using boost::shared_ptr;
 using boost::optional;
 using dcp::raw_convert;
+using namespace dcpomatic;
 
 boost::mutex FFmpeg::_mutex;
-boost::weak_ptr<Log> FFmpeg::_ffmpeg_log;
 
 FFmpeg::FFmpeg (boost::shared_ptr<const FFmpegContent> c)
        : _ffmpeg_content (c)
@@ -97,25 +100,17 @@ FFmpeg::ffmpeg_log_callback (void* ptr, int level, const char* fmt, va_list vl)
        char line[1024];
        static int prefix = 0;
        av_log_format_line (ptr, level, fmt, vl, line, sizeof (line), &prefix);
-       shared_ptr<Log> log = _ffmpeg_log.lock ();
-       if (log) {
-               string str (line);
-               boost::algorithm::trim (str);
-               log->log (String::compose ("FFmpeg: %1", str), LogEntry::TYPE_GENERAL);
-       } else {
-               cerr << line;
-       }
+       string str (line);
+       boost::algorithm::trim (str);
+       dcpomatic_log->log (String::compose ("FFmpeg: %1", str), LogEntry::TYPE_GENERAL);
 }
 
 void
 FFmpeg::setup_general ()
 {
-       av_register_all ();
-
        /* This might not work too well in some cases of multiple FFmpeg decoders,
           but it's probably good enough.
        */
-       _ffmpeg_log = _ffmpeg_content->film()->log ();
        av_log_set_callback (FFmpeg::ffmpeg_log_callback);
 
        _file_group.set_paths (_ffmpeg_content->paths ());
@@ -130,6 +125,12 @@ FFmpeg::setup_general ()
        */
        av_dict_set (&options, "analyzeduration", raw_convert<string> (5 * 60 * 1000000).c_str(), 0);
        av_dict_set (&options, "probesize", raw_convert<string> (5 * 60 * 1000000).c_str(), 0);
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+       if (_ffmpeg_content->kdm()) {
+               DecryptedECinemaKDM kdm (_ffmpeg_content->kdm().get(), Config::instance()->decryption_chain()->key().get());
+               av_dict_set (&options, "decryption_key", kdm.key().hex().c_str(), 0);
+       }
+#endif
 
        int e = avformat_open_input (&_format_context, 0, 0, &options);
        if (e < 0) {
@@ -146,7 +147,7 @@ FFmpeg::setup_general ()
 
        for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
                AVStream* s = _format_context->streams[i];
-               if (s->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+               if (s->codec->codec_type == AVMEDIA_TYPE_VIDEO && avcodec_find_decoder(s->codec->codec_id)) {
                        if (s->avg_frame_rate.num > 0 && s->avg_frame_rate.den > 0) {
                                /* This is definitely our video stream */
                                _video_stream = i;
@@ -213,13 +214,15 @@ FFmpeg::setup_decoders ()
                           https://trac.ffmpeg.org/ticket/5681
                        */
                        av_dict_set_int (&options, "strict", FF_COMPLIANCE_EXPERIMENTAL, 0);
+                       /* Enable following of links in files */
+                       av_dict_set_int (&options, "enable_drefs", 1, 0);
 
                        if (avcodec_open2 (context, codec, &options) < 0) {
                                throw DecodeError (N_("could not open decoder"));
                        }
+               } else {
+                       dcpomatic_log->log (String::compose ("No codec found for stream %1", i), LogEntry::TYPE_WARNING);
                }
-
-               /* We are silently ignoring any failures to find suitable decoders here */
        }
 }
 
@@ -275,65 +278,6 @@ FFmpeg::subtitle_period (AVSubtitle const & sub)
                );
 }
 
-string
-FFmpeg::subtitle_id (AVSubtitle const & sub)
-{
-       Digester digester;
-       digester.add (sub.pts);
-       for (unsigned int i = 0; i < sub.num_rects; ++i) {
-               AVSubtitleRect* rect = sub.rects[i];
-               if (rect->type == SUBTITLE_BITMAP) {
-                       digester.add (rect->x);
-                       digester.add (rect->y);
-                       digester.add (rect->w);
-                       digester.add (rect->h);
-#ifdef DCPOMATIC_HAVE_AVSUBTITLERECT_PICT
-                       int const line = rect->pict.linesize[0];
-                       for (int j = 0; j < rect->h; ++j) {
-                               digester.add (rect->pict.data[0] + j * line, line);
-                       }
-#else
-                       int const line = rect->linesize[0];
-                       for (int j = 0; j < rect->h; ++j) {
-                               digester.add (rect->data[0] + j * line, line);
-                       }
-#endif
-               } else if (rect->type == SUBTITLE_TEXT) {
-                       digester.add (string (rect->text));
-               } else if (rect->type == SUBTITLE_ASS) {
-                       digester.add (string (rect->ass));
-               }
-       }
-       return digester.get ();
-}
-
-/** @return true if sub starts a new image subtitle */
-bool
-FFmpeg::subtitle_starts_image (AVSubtitle const & sub)
-{
-       bool image = false;
-       bool text = false;
-
-       for (unsigned int i = 0; i < sub.num_rects; ++i) {
-               switch (sub.rects[i]->type) {
-               case SUBTITLE_BITMAP:
-                       image = true;
-                       break;
-               case SUBTITLE_TEXT:
-               case SUBTITLE_ASS:
-                       text = true;
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       /* We can't cope with mixed image/text in one AVSubtitle */
-       DCPOMATIC_ASSERT (!image || !text);
-
-       return image;
-}
-
 /** Compute the pts offset to use given a set of audio streams and some video details.
  *  Sometimes these parameters will have just been determined by an Examiner, sometimes
  *  they will have been retrieved from a piece of Content, hence the need for this method
@@ -381,7 +325,7 @@ FFmpeg::pts_offset (vector<shared_ptr<FFmpegAudioStream> > audio_streams, option
        /* Now adjust so that the video pts starts on a frame */
        if (first_video) {
                ContentTime const fvc = first_video.get() + po;
-               po += fvc.round_up (video_frame_rate) - fvc;
+               po += fvc.ceil (video_frame_rate) - fvc;
        }
 
        return po;