More correctly calculate bitmap subtitle scaling (#2670).
[dcpomatic.git] / src / lib / ffmpeg_decoder.cc
index efe1515302dcfc5170119030aacd01f9b8b03fd1..ab3f0b5be05e817cc0189c539d33407162c89e60 100644 (file)
@@ -266,6 +266,10 @@ deinterleave_audio(AVFrame* frame)
        auto audio = make_shared<AudioBuffers>(channels, frames);
        auto data = audio->data();
 
+       if (frames == 0) {
+               return audio;
+       }
+
        switch (format) {
        case AV_SAMPLE_FMT_U8:
        {
@@ -630,9 +634,14 @@ FFmpegDecoder::process_video_frame ()
 void
 FFmpegDecoder::decode_and_process_subtitle_packet (AVPacket* packet)
 {
+       auto context = subtitle_codec_context();
+       if (!context) {
+               return;
+       }
+
        int got_subtitle;
        AVSubtitle sub;
-       if (avcodec_decode_subtitle2 (subtitle_codec_context(), &sub, &got_subtitle, packet) < 0 || !got_subtitle) {
+       if (avcodec_decode_subtitle2(context, &sub, &got_subtitle, packet) < 0 || !got_subtitle) {
                return;
        }
 
@@ -711,7 +720,7 @@ FFmpegDecoder::process_bitmap_subtitle (AVSubtitleRect const * rect)
        /* sub_p looks up into a BGRA palette which is at rect->pict.data[1];
           (i.e. first byte B, second G, third R, fourth A)
        */
-       auto const palette = rect->pict.data[1];
+       auto const* palette = rect->pict.data[1];
 #else
        /* Start of the first line in the subtitle */
        auto sub_p = rect->data[0];
@@ -761,27 +770,41 @@ FFmpegDecoder::process_bitmap_subtitle (AVSubtitleRect const * rect)
                out_p += image->stride()[0];
        }
 
-       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;
+       optional<dcp::Size> video_size;
+       if (_ffmpeg_content->video) {
+               video_size = _ffmpeg_content->video->size();
        }
-       int target_height = subtitle_codec_context()->height;
-       if (target_height == 0 && video_codec_context()) {
-               target_height = video_codec_context()->height;
+
+       dcp::Size target_size = { subtitle_codec_context()->width, subtitle_codec_context()->height };
+       if (target_size.width == 0 || target_size.height == 0 || (video_size && *video_size == target_size)) {
+               /* Either the subtitle codec has no specified size, or it's the same as the video.
+                * In either case we'll use the target size once it has been cropped etc. as we
+                * assume that whatever happens to the video should also be done to the subtitles.
+                */
+               if (auto s = ffmpeg_content()->video->scaled_size(film()->frame_size())) {
+                       target_size = *s;
+               }
+       }
+
+       int x_offset = 0;
+       int y_offset = 0;
+       if (_ffmpeg_content->video && _ffmpeg_content->video->use()) {
+               auto const crop = _ffmpeg_content->video->actual_crop();
+               x_offset = -crop.left;
+               y_offset = -crop.top;
        }
-       DCPOMATIC_ASSERT (target_width);
-       DCPOMATIC_ASSERT (target_height);
+
+       DCPOMATIC_ASSERT(target_size.width > 0);
+       DCPOMATIC_ASSERT(target_size.height > 0);
+
        dcpomatic::Rect<double> const scaled_rect (
-               static_cast<double>(rect->x) / target_width,
-               static_cast<double>(rect->y) / target_height,
-               static_cast<double>(rect->w) / target_width,
-               static_cast<double>(rect->h) / target_height
+               static_cast<double>(rect->x + x_offset) / target_size.width,
+               static_cast<double>(rect->y + y_offset) / target_size.height,
+               static_cast<double>(rect->w) / target_size.width,
+               static_cast<double>(rect->h) / target_size.height
                );
 
-       return { image, scaled_rect };
+       return { target_size, image, scaled_rect };
 }
 
 
@@ -807,11 +830,14 @@ FFmpegDecoder::process_ass_subtitle (string ass, ContentTime from)
        }
 
        sub::RawSubtitle base;
+       auto video_size = _ffmpeg_content->video->size();
+       DCPOMATIC_ASSERT(video_size);
+
        auto raw = sub::SSAReader::parse_line (
                base,
                text,
-               _ffmpeg_content->video->size().width,
-               _ffmpeg_content->video->size().height,
+               video_size->width,
+               video_size->height,
                sub::Colour(1, 1, 1)
                );