BOOST_FOREACH.
[dcpomatic.git] / src / lib / ffmpeg_decoder.cc
index 3c5a09aea965fb41e17c4562e17d35e72aa0a146..b050fc594a76f97ab72833c38792f62daf4f100d 100644 (file)
@@ -42,6 +42,7 @@
 #include "compose.hpp"
 #include "text_content.h"
 #include "audio_content.h"
+#include "frame_interval_checker.h"
 #include <dcp/subtitle_string.h>
 #include <sub/ssa_reader.h>
 #include <sub/subtitle.h>
@@ -50,7 +51,6 @@ extern "C" {
 #include <libavcodec/avcodec.h>
 #include <libavformat/avformat.h>
 }
-#include <boost/foreach.hpp>
 #include <boost/algorithm/string.hpp>
 #include <vector>
 #include <iomanip>
@@ -67,11 +67,11 @@ using std::min;
 using std::pair;
 using std::max;
 using std::map;
-using boost::shared_ptr;
+using std::shared_ptr;
 using boost::is_any_of;
 using boost::split;
 using boost::optional;
-using boost::dynamic_pointer_cast;
+using std::dynamic_pointer_cast;
 using dcp::Size;
 using namespace dcpomatic;
 
@@ -133,7 +133,7 @@ FFmpegDecoder::flush ()
                }
        }
 
-       BOOST_FOREACH (shared_ptr<FFmpegAudioStream> i, _ffmpeg_content->ffmpeg_audio_streams ()) {
+       for (auto i: _ffmpeg_content->ffmpeg_audio_streams ()) {
                ContentTime a = audio->stream_position(film(), i);
                /* Unfortunately if a is 0 that really means that we don't know the stream position since
                   there has been no data on it since the last seek.  In this case we'll just do nothing
@@ -144,7 +144,7 @@ FFmpegDecoder::flush ()
                                ContentTime to_do = min (full_length - a, ContentTime::from_seconds (0.1));
                                shared_ptr<AudioBuffers> silence (new AudioBuffers (i->channels(), to_do.frames_ceil (i->frame_rate())));
                                silence->make_silent ();
-                               audio->emit (film(), i, silence, a);
+                               audio->emit (film(), i, silence, a, true);
                                a += to_do;
                        }
                }
@@ -158,12 +158,6 @@ 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
@@ -205,9 +199,14 @@ FFmpegDecoder::deinterleave_audio (shared_ptr<FFmpegAudioStream> stream) const
 {
        DCPOMATIC_ASSERT (bytes_per_audio_sample (stream));
 
+DCPOMATIC_DISABLE_WARNINGS
        int const size = av_samples_get_buffer_size (
                0, stream->stream(_format_context)->codec->channels, _frame->nb_samples, audio_sample_format (stream), 1
                );
+DCPOMATIC_ENABLE_WARNINGS
+
+       /* XXX: can't we just use _frame->nb_samples directly here? */
+       /* XXX: can't we use swr_convert() to do the format conversion? */
 
        /* Deinterleave and convert to float */
 
@@ -314,6 +313,7 @@ FFmpegDecoder::deinterleave_audio (shared_ptr<FFmpegAudioStream> stream) const
        case AV_SAMPLE_FMT_FLTP:
        {
                float** p = reinterpret_cast<float**> (_frame->data);
+               DCPOMATIC_ASSERT (_frame->channels <= channels);
                /* Sometimes there aren't as many channels in the _frame as in the stream */
                for (int i = 0; i < _frame->channels; ++i) {
                        memcpy (data[i], p[i], frames * sizeof(float));
@@ -334,7 +334,9 @@ FFmpegDecoder::deinterleave_audio (shared_ptr<FFmpegAudioStream> stream) const
 AVSampleFormat
 FFmpegDecoder::audio_sample_format (shared_ptr<FFmpegAudioStream> stream) const
 {
+DCPOMATIC_DISABLE_WARNINGS
        return stream->stream (_format_context)->codec->sample_fmt;
+DCPOMATIC_ENABLE_WARNINGS
 }
 
 int
@@ -396,15 +398,21 @@ FFmpegDecoder::seek (ContentTime time, bool accurate)
                avcodec_flush_buffers (video_codec_context());
        }
 
-       BOOST_FOREACH (shared_ptr<FFmpegAudioStream> i, ffmpeg_content()->ffmpeg_audio_streams()) {
+DCPOMATIC_DISABLE_WARNINGS
+       for (auto i: ffmpeg_content()->ffmpeg_audio_streams()) {
                avcodec_flush_buffers (i->stream(_format_context)->codec);
        }
+DCPOMATIC_ENABLE_WARNINGS
 
        if (subtitle_codec_context ()) {
                avcodec_flush_buffers (subtitle_codec_context ());
        }
 
        _have_current_subtitle = false;
+
+       for (auto& i: _next_time) {
+               i = optional<ContentTime>();
+       }
 }
 
 void
@@ -429,6 +437,7 @@ FFmpegDecoder::decode_audio_packet ()
                return;
        }
 
+DCPOMATIC_DISABLE_WARNINGS
        while (copy_packet.size > 0) {
 
                int frame_finished;
@@ -453,12 +462,14 @@ FFmpegDecoder::decode_audio_packet ()
                        shared_ptr<AudioBuffers> data = deinterleave_audio (*stream);
 
                        ContentTime ct;
-                       if (_frame->pts == AV_NOPTS_VALUE && _next_time[stream_index]) {
+                       if (_frame->pts == AV_NOPTS_VALUE) {
                                /* In some streams we see not every frame coming through with a timestamp; for those
                                   that have AV_NOPTS_VALUE we need to work out the timestamp ourselves.  This is
                                   particularly noticeable with TrueHD streams (see #1111).
                                */
-                               ct = *_next_time[stream_index];
+                               if (_next_time[stream_index]) {
+                                       ct = *_next_time[stream_index];
+                               }
                        } else {
                                ct = ContentTime::from_seconds (
                                        av_frame_get_best_effort_timestamp (_frame) *
@@ -488,6 +499,7 @@ FFmpegDecoder::decode_audio_packet ()
                                        to_string(_pts_offset)
                                        );
                        }
+DCPOMATIC_ENABLE_WARNINGS
 
                        /* Give this data provided there is some, and its time is sane */
                        if (ct >= ContentTime() && data->frames() > 0) {
@@ -506,9 +518,11 @@ FFmpegDecoder::decode_video_packet ()
        DCPOMATIC_ASSERT (_video_stream);
 
        int frame_finished;
+DCPOMATIC_DISABLE_WARNINGS
        if (avcodec_decode_video2 (video_codec_context(), _frame, &frame_finished, &_packet) < 0 || !frame_finished) {
                return false;
        }
+DCPOMATIC_ENABLE_WARNINGS
 
        boost::mutex::scoped_lock lm (_filter_graphs_mutex);
 
@@ -624,23 +638,23 @@ FFmpegDecoder::decode_bitmap_subtitle (AVSubtitleRect const * rect, ContentTime
 #ifdef DCPOMATIC_HAVE_AVSUBTITLERECT_PICT
        /* Start of the first line in the subtitle */
        uint8_t* sub_p = rect->pict.data[0];
-       /* sub_p looks up into a BGRA palette which is here
+       /* 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)
        */
-       uint32_t const * palette = (uint32_t *) rect->pict.data[1];
+       uint8_t const * palette = rect->pict.data[1];
 #else
        /* Start of the first line in the subtitle */
        uint8_t* sub_p = rect->data[0];
        /* sub_p looks up into a BGRA palette which is at rect->data[1].
           (first byte B, second G, third R, fourth A)
        */
+       uint8_t const * palette = rect->data[1];
 #endif
        /* And the stream has a map of those palette colours to colours
           chosen by the user; created a `mapped' palette from those settings.
        */
        map<RGBA, RGBA> colour_map = ffmpeg_content()->subtitle_stream()->colours ();
        vector<RGBA> mapped_palette (rect->nb_colors);
-       uint8_t const * palette = rect->data[1];
        for (int i = 0; i < rect->nb_colors; ++i) {
                RGBA c (palette[2], palette[1], palette[0], palette[3]);
                map<RGBA, RGBA>::const_iterator j = colour_map.find (c);
@@ -729,7 +743,7 @@ FFmpegDecoder::decode_ass_subtitle (string ass, ContentTime from)
                _ffmpeg_content->video->size().height
                );
 
-       BOOST_FOREACH (sub::Subtitle const & i, sub::collect<list<sub::Subtitle> > (raw)) {
+       for (auto const& i: sub::collect<list<sub::Subtitle> > (raw)) {
                only_text()->emit_plain_start (from, i);
        }
 }