Improve OpenFileError so that it doesn't say "opening for read"
[dcpomatic.git] / src / lib / ffmpeg_decoder.cc
index 3d9e965a9d169ad3e66a014cb3cb4e0d7a750c1b..62d4d2655f59c84af57f96c8c3d25e747794a352 100644 (file)
@@ -59,7 +59,6 @@ extern "C" {
 
 #include "i18n.h"
 
-
 using std::cout;
 using std::string;
 using std::vector;
@@ -74,13 +73,14 @@ using boost::split;
 using boost::optional;
 using boost::dynamic_pointer_cast;
 using dcp::Size;
+using namespace dcpomatic;
 
 FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> film, shared_ptr<const FFmpegContent> c, bool fast)
        : FFmpeg (c)
        , Decoder (film)
        , _have_current_subtitle (false)
 {
-       if (c->video) {
+       if (c->video && c->video->use()) {
                video.reset (new VideoDecoder (this, c));
                _pts_offset = pts_offset (c->ffmpeg_audio_streams(), c->first_video(), c->active_video_frame_rate(film));
                /* It doesn't matter what size or pixel format this is, it just needs to be black */
@@ -158,6 +158,12 @@ FFmpegDecoder::flush ()
 bool
 FFmpegDecoder::pass ()
 {
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+       if (_ffmpeg_content->encrypted() && !_ffmpeg_content->kdm()) {
+               return true;
+       }
+#endif
+
        int r = av_read_frame (_format_context, &_packet);
 
        /* AVERROR_INVALIDDATA can apparently be returned sometimes even when av_read_frame
@@ -179,7 +185,7 @@ FFmpegDecoder::pass ()
        int const si = _packet.stream_index;
        shared_ptr<const FFmpegContent> fc = _ffmpeg_content;
 
-       if (_video_stream && si == _video_stream.get() && !video->ignore()) {
+       if (_video_stream && si == _video_stream.get() && video && !video->ignore()) {
                decode_video_packet ();
        } else if (fc->subtitle_stream() && fc->subtitle_stream()->uses_index(_format_context, si) && !only_text()->ignore()) {
                decode_subtitle_packet ();
@@ -358,6 +364,7 @@ FFmpegDecoder::seek (ContentTime time, bool accurate)
        if (_video_stream) {
                stream = _video_stream;
        } else {
+               DCPOMATIC_ASSERT (_ffmpeg_content->audio);
                shared_ptr<FFmpegAudioStream> s = dynamic_pointer_cast<FFmpegAudioStream> (_ffmpeg_content->audio->stream ());
                if (s) {
                        stream = s->index (_format_context);
@@ -377,6 +384,14 @@ FFmpegDecoder::seek (ContentTime time, bool accurate)
                AVSEEK_FLAG_BACKWARD
                );
 
+       {
+               /* Force re-creation of filter graphs to reset them and hence to make sure
+                  they don't have any pre-seek frames knocking about.
+               */
+               boost::mutex::scoped_lock lm (_filter_graphs_mutex);
+               _filter_graphs.clear ();
+       }
+
        if (video_codec_context ()) {
                avcodec_flush_buffers (video_codec_context());
        }
@@ -659,8 +674,19 @@ FFmpegDecoder::decode_bitmap_subtitle (AVSubtitleRect const * rect, ContentTime
                out_p += image->stride()[0] / sizeof (uint32_t);
        }
 
-       int const target_width = subtitle_codec_context()->width;
-       int const target_height = subtitle_codec_context()->height;
+       int target_width = subtitle_codec_context()->width;
+       if (target_width == 0 && video_codec_context()) {
+               /* subtitle_codec_context()->width == 0 has been seen in the wild but I don't
+                  know if it's supposed to mean something from FFmpeg's point of view.
+               */
+               target_width = video_codec_context()->width;
+       }
+       int target_height = subtitle_codec_context()->height;
+       if (target_height == 0 && video_codec_context()) {
+               target_height = video_codec_context()->height;
+       }
+       DCPOMATIC_ASSERT (target_width);
+       DCPOMATIC_ASSERT (target_height);
        dcpomatic::Rect<double> const scaled_rect (
                static_cast<double> (rect->x) / target_width,
                static_cast<double> (rect->y) / target_height,