Replace aligned bool with enum Alignment.
[dcpomatic.git] / src / lib / ffmpeg_decoder.cc
index db88562ea09b2bb05001d14b2c031ad018c19f6f..2baa99876b173adbf58e52d4774f80c5a2c393cd 100644 (file)
 
 */
 
+
 /** @file  src/ffmpeg_decoder.cc
  *  @brief A decoder using FFmpeg to decode content.
  */
 
-#include "filter.h"
-#include "exceptions.h"
-#include "image.h"
-#include "util.h"
-#include "log.h"
+
+#include "audio_buffers.h"
+#include "audio_content.h"
+#include "audio_decoder.h"
+#include "compose.hpp"
 #include "dcpomatic_log.h"
-#include "ffmpeg_decoder.h"
-#include "text_decoder.h"
+#include "exceptions.h"
 #include "ffmpeg_audio_stream.h"
-#include "ffmpeg_subtitle_stream.h"
-#include "video_filter_graph.h"
-#include "audio_buffers.h"
 #include "ffmpeg_content.h"
-#include "raw_image_proxy.h"
-#include "video_decoder.h"
+#include "ffmpeg_decoder.h"
+#include "ffmpeg_subtitle_stream.h"
 #include "film.h"
-#include "audio_decoder.h"
-#include "compose.hpp"
-#include "text_content.h"
-#include "audio_content.h"
+#include "filter.h"
 #include "frame_interval_checker.h"
+#include "image.h"
+#include "log.h"
+#include "raw_image_proxy.h"
+#include "text_content.h"
+#include "text_decoder.h"
+#include "util.h"
+#include "video_decoder.h"
+#include "video_filter_graph.h"
 #include <dcp/subtitle_string.h>
 #include <sub/ssa_reader.h>
 #include <sub/subtitle.h>
@@ -52,28 +54,22 @@ extern "C" {
 #include <libavformat/avformat.h>
 }
 #include <boost/algorithm/string.hpp>
-#include <vector>
 #include <iomanip>
 #include <iostream>
+#include <vector>
 #include <stdint.h>
 
 #include "i18n.h"
 
+
 using std::cout;
-using std::string;
-using std::vector;
-using std::list;
+using std::dynamic_pointer_cast;
+using std::make_shared;
 using std::min;
-using std::pair;
-using std::max;
-using std::map;
 using std::shared_ptr;
-using std::make_shared;
-using std::make_pair;
-using boost::is_any_of;
-using boost::split;
+using std::string;
+using std::vector;
 using boost::optional;
-using std::dynamic_pointer_cast;
 using dcp::Size;
 using namespace dcpomatic;
 
@@ -86,7 +82,7 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> film, shared_ptr<const FFmp
                video = make_shared<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 */
-               _black_image.reset (new Image (AV_PIX_FMT_RGB24, dcp::Size (128, 128), true));
+               _black_image = make_shared<Image>(AV_PIX_FMT_RGB24, dcp::Size (128, 128), Image::Alignment::PADDED);
                _black_image->make_black ();
        } else {
                _pts_offset = {};
@@ -427,6 +423,12 @@ FFmpegDecoder::seek (ContentTime time, bool accurate)
        for (auto& i: _next_time) {
                i.second = boost::optional<dcpomatic::ContentTime>();
        }
+
+       /* We find that we get some errors from av_send_packet after a seek.  Perhaps we should ignore
+        * all of them (which seems risky), or perhaps we should have some proper fix.  But instead
+        * let's ignore the next 2 errors.
+        */
+       _errors_to_ignore = 2;
 }
 
 
@@ -513,6 +515,12 @@ FFmpegDecoder::decode_and_process_audio_packet (AVPacket* packet)
                /* We could cope with AVERROR(EAGAIN) and re-send the packet but I think it should never happen.
                 * Likewise I think AVERROR_EOF should not happen.
                 */
+               if (_errors_to_ignore > 0) {
+                       /* We see errors here after a seek, which is hopefully to be nothing to worry about */
+                       --_errors_to_ignore;
+                       LOG_GENERAL("Ignoring error %1 avcodec_send_packet after seek; will ignore %2 more", r, _errors_to_ignore);
+                       return;
+               }
                throw DecodeError (N_("avcodec_send_packet"), N_("FFmpegDecoder::decode_and_process_audio_packet"), r);
        }
 
@@ -548,9 +556,13 @@ FFmpegDecoder::decode_and_process_video_packet (AVPacket* packet)
        }
 
        r = avcodec_receive_frame (context, _frame);
-       if (r == AVERROR(EAGAIN) || r == AVERROR_EOF) {
-               /* More input is required, or no more frames are coming */
+       if (r == AVERROR(EAGAIN) || r == AVERROR_EOF || (r < 0 && !packet)) {
+               /* More input is required, no more frames are coming, or we are flushing and there was
+                * some error which we just want to ignore.
+                */
                return false;
+       } else if (r < 0) {
+               throw DecodeError (N_("avcodec_receive_frame"), N_("FFmpeg::decode_and_process_video_packet"), r);
        }
 
        /* We assume we'll only get one frame here, which I think is safe */
@@ -606,25 +618,27 @@ FFmpegDecoder::decode_and_process_subtitle_packet (AVPacket* packet)
                return;
        }
 
+       auto sub_period = subtitle_period (packet, ffmpeg_content()->subtitle_stream()->stream(_format_context), sub);
+
        /* Stop any current subtitle, either at the time it was supposed to stop, or now if now is sooner */
        if (_have_current_subtitle) {
                if (_current_subtitle_to) {
-                       only_text()->emit_stop (min(*_current_subtitle_to, subtitle_period(sub).from + _pts_offset));
+                       only_text()->emit_stop (min(*_current_subtitle_to, sub_period.from + _pts_offset));
                } else {
-                       only_text()->emit_stop (subtitle_period(sub).from + _pts_offset);
+                       only_text()->emit_stop (sub_period.from + _pts_offset);
                }
                _have_current_subtitle = false;
        }
 
        if (sub.num_rects <= 0) {
                /* Nothing new in this subtitle */
+               avsubtitle_free (&sub);
                return;
        }
 
        /* Subtitle PTS (within the source, not taking into account any of the
           source that we may have chopped off for the DCP).
        */
-       auto sub_period = subtitle_period (sub);
        ContentTime from;
        from = sub_period.from + _pts_offset;
        if (sub_period.to) {
@@ -666,7 +680,7 @@ FFmpegDecoder::process_bitmap_subtitle (AVSubtitleRect const * rect, ContentTime
        /* Note BGRA is expressed little-endian, so the first byte in the word is B, second
           G, third R, fourth A.
        */
-       auto image = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (rect->w, rect->h), true);
+       auto image = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (rect->w, rect->h), Image::Alignment::PADDED);
 
 #ifdef DCPOMATIC_HAVE_AVSUBTITLERECT_PICT
        /* Start of the first line in the subtitle */