Remove support for FFmpeg postprocessing filters.
[dcpomatic.git] / src / lib / ffmpeg_decoder.cc
index d9b7796599b8c7cdf7687454fd6dc668db5195ef..851c64606b705af1974c1c953fa1d14863c6af89 100644 (file)
@@ -68,8 +68,7 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegC
        , _subtitle_codec (0)
        , _decode_video (video)
        , _decode_audio (audio)
-       , _video_pts_offset (0)
-       , _audio_pts_offset (0)
+       , _pts_offset (0)
        , _just_sought (false)
 {
        setup_subtitle ();
@@ -84,8 +83,8 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegC
           insertion of black frames to work.
 
           We will do:
-            audio_pts_to_use = audio_pts_from_ffmpeg + audio_pts_offset;
-            video_pts_to_use = video_pts_from_ffmpeg + video_pts_offset;
+            audio_pts_to_use = audio_pts_from_ffmpeg + pts_offset;
+            video_pts_to_use = video_pts_from_ffmpeg + pts_offset;
        */
 
        bool const have_video = video && c->first_video();
@@ -94,16 +93,16 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegC
        /* First, make one of them start at 0 */
 
        if (have_audio && have_video) {
-               _video_pts_offset = _audio_pts_offset = - min (c->first_video().get(), c->audio_stream()->first_audio.get());
+               _pts_offset = - min (c->first_video().get(), c->audio_stream()->first_audio.get());
        } else if (have_video) {
-               _video_pts_offset = - c->first_video().get();
+               _pts_offset = - c->first_video().get();
        } else if (have_audio) {
-               _audio_pts_offset = - c->audio_stream()->first_audio.get();
+               _pts_offset = - c->audio_stream()->first_audio.get();
        }
 
        /* Now adjust both so that the video pts starts on a frame */
        if (have_video && have_audio) {
-               double first_video = c->first_video().get() + _video_pts_offset;
+               double first_video = c->first_video().get() + _pts_offset;
                double const old_first_video = first_video;
                
                /* Round the first video up to a frame boundary */
@@ -111,8 +110,7 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegC
                        first_video = ceil (first_video * c->video_frame_rate()) / c->video_frame_rate ();
                }
 
-               _video_pts_offset += first_video - old_first_video;
-               _audio_pts_offset += first_video - old_first_video;
+               _pts_offset += first_video - old_first_video;
        }
 }
 
@@ -167,8 +165,6 @@ FFmpegDecoder::pass ()
                return;
        }
 
-       avcodec_get_frame_defaults (_frame);
-
        shared_ptr<const Film> film = _film.lock ();
        assert (film);
 
@@ -176,9 +172,9 @@ FFmpegDecoder::pass ()
        
        if (si == _video_stream && _decode_video) {
                decode_video_packet ();
-       } else if (_ffmpeg_content->audio_stream() && si == _ffmpeg_content->audio_stream()->index (_format_context) && _decode_audio) {
+       } else if (_ffmpeg_content->audio_stream() && _ffmpeg_content->audio_stream()->uses_index (_format_context, si) && _decode_audio) {
                decode_audio_packet ();
-       } else if (_ffmpeg_content->subtitle_stream() && si == _ffmpeg_content->subtitle_stream()->index (_format_context) && film->with_subtitles ()) {
+       } else if (_ffmpeg_content->subtitle_stream() && _ffmpeg_content->subtitle_stream()->uses_index (_format_context, si) && film->with_subtitles ()) {
                decode_subtitle_packet ();
        }
 
@@ -203,6 +199,23 @@ FFmpegDecoder::deinterleave_audio (uint8_t** data, int size)
        shared_ptr<AudioBuffers> audio (new AudioBuffers (_ffmpeg_content->audio_channels(), frames));
 
        switch (audio_sample_format()) {
+       case AV_SAMPLE_FMT_U8:
+       {
+               uint8_t* p = reinterpret_cast<uint8_t *> (data[0]);
+               int sample = 0;
+               int channel = 0;
+               for (int i = 0; i < total_samples; ++i) {
+                       audio->data(channel)[sample] = float(*p++) / (1 << 23);
+
+                       ++channel;
+                       if (channel == _ffmpeg_content->audio_channels()) {
+                               channel = 0;
+                               ++sample;
+                       }
+               }
+       }
+       break;
+       
        case AV_SAMPLE_FMT_S16:
        {
                int16_t* p = reinterpret_cast<int16_t *> (data[0]);
@@ -317,7 +330,7 @@ FFmpegDecoder::seek (VideoContent::Frame frame, bool accurate)
        }
 
        /* Initial seek time in the stream's timebase */
-       int64_t const initial_vt = ((initial / _ffmpeg_content->video_frame_rate()) - _video_pts_offset) / time_base;
+       int64_t const initial_vt = ((initial / _ffmpeg_content->video_frame_rate()) - _pts_offset) / time_base;
 
        av_seek_frame (_format_context, _video_stream, initial_vt, AVSEEK_FLAG_BACKWARD);
 
@@ -326,7 +339,16 @@ FFmpegDecoder::seek (VideoContent::Frame frame, bool accurate)
                avcodec_flush_buffers (_subtitle_codec_context);
        }
 
-       _just_sought = true;
+       /* This !accurate is piling hack upon hack; setting _just_sought to true
+          even with accurate == true defeats our attempt to align the start
+          of the video and audio.  Here we disable that defeat when accurate == true
+          i.e. when we are making a DCP rather than just previewing one.
+          Ewww.  This should be gone in 2.0.
+       */
+       if (!accurate) {
+               _just_sought = true;
+       }
+       
        _video_position = frame;
        
        if (frame == 0 || !accurate) {
@@ -345,13 +367,11 @@ FFmpegDecoder::seek (VideoContent::Frame frame, bool accurate)
                        continue;
                }
                
-               avcodec_get_frame_defaults (_frame);
-               
                int finished = 0;
                r = avcodec_decode_video2 (video_codec_context(), _frame, &finished, &_packet);
                if (r >= 0 && finished) {
                        _video_position = rint (
-                               (av_frame_get_best_effort_timestamp (_frame) * time_base + _video_pts_offset) * _ffmpeg_content->video_frame_rate()
+                               (av_frame_get_best_effort_timestamp (_frame) * time_base + _pts_offset) * _ffmpeg_content->video_frame_rate()
                                );
 
                        if (_video_position >= (frame - 1)) {
@@ -389,7 +409,7 @@ FFmpegDecoder::decode_audio_packet ()
                        if (_audio_position == 0) {
                                /* Where we are in the source, in seconds */
                                double const pts = av_q2d (_format_context->streams[copy_packet.stream_index]->time_base)
-                                       * av_frame_get_best_effort_timestamp(_frame) + _audio_pts_offset;
+                                       * av_frame_get_best_effort_timestamp(_frame) + _pts_offset;
 
                                if (pts > 0) {
                                        /* Emit some silence */
@@ -448,18 +468,13 @@ FFmpegDecoder::decode_video_packet ()
 
        list<pair<shared_ptr<Image>, int64_t> > images = graph->process (_frame);
 
-       string post_process = Filter::ffmpeg_strings (_ffmpeg_content->filters()).second;
-       
        for (list<pair<shared_ptr<Image>, int64_t> >::iterator i = images.begin(); i != images.end(); ++i) {
 
                shared_ptr<Image> image = i->first;
-               if (!post_process.empty ()) {
-                       image = image->post_process (post_process, true);
-               }
                
                if (i->second != AV_NOPTS_VALUE) {
 
-                       double const pts = i->second * av_q2d (_format_context->streams[_video_stream]->time_base) + _video_pts_offset;
+                       double const pts = i->second * av_q2d (_format_context->streams[_video_stream]->time_base) + _pts_offset;
 
                        if (_just_sought) {
                                /* We just did a seek, so disable any attempts to correct for where we
@@ -513,15 +528,19 @@ FFmpegDecoder::setup_subtitle ()
 {
        boost::mutex::scoped_lock lm (_mutex);
        
-       if (!_ffmpeg_content->subtitle_stream() || _ffmpeg_content->subtitle_stream()->index (_format_context) >= int (_format_context->nb_streams)) {
+       if (!_ffmpeg_content->subtitle_stream()) {
                return;
        }
 
        _subtitle_codec_context = _ffmpeg_content->subtitle_stream()->stream(_format_context)->codec;
+       if (_subtitle_codec_context == 0) {
+               throw DecodeError (N_("could not find subtitle stream"));
+       }
+
        _subtitle_codec = avcodec_find_decoder (_subtitle_codec_context->codec_id);
 
        if (_subtitle_codec == 0) {
-               throw DecodeError (_("could not find subtitle decoder"));
+               throw DecodeError (N_("could not find subtitle decoder"));
        }
        
        if (avcodec_open2 (_subtitle_codec_context, _subtitle_codec, 0) < 0) {
@@ -559,8 +578,8 @@ FFmpegDecoder::decode_subtitle_packet ()
        /* Subtitle PTS in seconds (within the source, not taking into account any of the
           source that we may have chopped off for the DCP)
        */
-       double const packet_time = (static_cast<double> (sub.pts ) / AV_TIME_BASE) + _video_pts_offset;
-       
+       double const packet_time = (static_cast<double> (sub.pts ) / AV_TIME_BASE) + _pts_offset;
+
        /* hence start time for this sub */
        Time const from = (packet_time + (double (sub.start_display_time) / 1e3)) * TIME_HZ;
        Time const to = (packet_time + (double (sub.end_display_time) / 1e3)) * TIME_HZ;