Merge master.
[dcpomatic.git] / src / lib / ffmpeg_decoder.cc
index 32b00a1d640e321a1d464cd151ddacc7ce6ed636..d251a37446ff96e2e49d514575b7719e53f44b6c 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -27,7 +27,6 @@
 #include <iomanip>
 #include <iostream>
 #include <stdint.h>
-#include <boost/lexical_cast.hpp>
 #include <sndfile.h>
 extern "C" {
 #include <libavcodec/avcodec.h>
@@ -42,6 +41,7 @@ extern "C" {
 #include "filter_graph.h"
 #include "audio_buffers.h"
 #include "ffmpeg_content.h"
+#include "image_proxy.h"
 
 #include "i18n.h"
 
@@ -57,17 +57,13 @@ using boost::optional;
 using boost::dynamic_pointer_cast;
 using dcp::Size;
 
-FFmpegDecoder::FFmpegDecoder (shared_ptr<const FFmpegContent> c, shared_ptr<Log> log, bool video, bool audio, bool subtitles)
+FFmpegDecoder::FFmpegDecoder (shared_ptr<const FFmpegContent> c, shared_ptr<Log> log)
        : VideoDecoder (c)
        , AudioDecoder (c)
        , FFmpeg (c)
        , _log (log)
        , _subtitle_codec_context (0)
        , _subtitle_codec (0)
-       , _decode_video (video)
-       , _decode_audio (audio)
-       , _decode_subtitles (subtitles)
-       , _pts_offset (0)
 {
        setup_subtitle ();
 
@@ -83,8 +79,8 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const FFmpegContent> c, shared_ptr<Log>
           We will do pts_to_use = pts_from_ffmpeg + pts_offset;
        */
 
-       bool const have_video = video && c->first_video();
-       bool const have_audio = _decode_audio && c->audio_stream () && c->audio_stream()->first_audio;
+       bool const have_video = c->first_video();
+       bool const have_audio = c->audio_stream () && c->audio_stream()->first_audio;
 
        /* First, make one of them start at 0 */
 
@@ -123,11 +119,9 @@ FFmpegDecoder::flush ()
        
        /* XXX: should we reset _packet.data and size after each *_decode_* call? */
        
-       if (_decode_video) {
-               while (decode_video_packet ()) {}
-       }
+       while (decode_video_packet ()) {}
        
-       if (_ffmpeg_content->audio_stream() && _decode_audio) {
+       if (_ffmpeg_content->audio_stream()) {
                decode_audio_packet ();
                AudioDecoder::flush ();
        }
@@ -152,11 +146,11 @@ FFmpegDecoder::pass ()
 
        int const si = _packet.stream_index;
        
-       if (si == _video_stream && _decode_video) {
+       if (si == _video_stream) {
                decode_video_packet ();
-       } else if (_ffmpeg_content->audio_stream() && _ffmpeg_content->audio_stream()->uses_index (_format_context, si) && _decode_audio) {
+       } else if (_ffmpeg_content->audio_stream() && _ffmpeg_content->audio_stream()->uses_index (_format_context, si)) {
                decode_audio_packet ();
-       } else if (_ffmpeg_content->subtitle_stream() && _ffmpeg_content->subtitle_stream()->uses_index (_format_context, si) && _decode_subtitles) {
+       } else if (_ffmpeg_content->subtitle_stream() && _ffmpeg_content->subtitle_stream()->uses_index (_format_context, si)) {
                decode_subtitle_packet ();
        }
 
@@ -319,9 +313,9 @@ FFmpegDecoder::minimal_run (boost::function<bool (optional<ContentTime>, optiona
 
                        avcodec_get_frame_defaults (_frame);
                        
-                       int finished = 0;
-                       r = avcodec_decode_video2 (video_codec_context(), _frame, &finished, &_packet);
-                       if (r >= 0 && finished) {
+                       int got_picture = 0;
+                       r = avcodec_decode_video2 (video_codec_context(), _frame, &got_picture, &_packet);
+                       if (r >= 0 && got_picture) {
                                last_video = ContentTime::from_seconds (av_frame_get_best_effort_timestamp (_frame) * time_base) + _pts_offset;
                        }
 
@@ -329,9 +323,9 @@ FFmpegDecoder::minimal_run (boost::function<bool (optional<ContentTime>, optiona
                        AVPacket copy_packet = _packet;
                        while (copy_packet.size > 0) {
 
-                               int finished;
-                               r = avcodec_decode_audio4 (audio_codec_context(), _frame, &finished, &_packet);
-                               if (r >= 0 && finished) {
+                               int got_frame;
+                               r = avcodec_decode_audio4 (audio_codec_context(), _frame, &got_frame, &_packet);
+                               if (r >= 0 && got_frame) {
                                        last_audio = ContentTime::from_seconds (av_frame_get_best_effort_timestamp (_frame) * time_base) + _pts_offset;
                                }
                                        
@@ -390,17 +384,15 @@ FFmpegDecoder::seek_and_flush (ContentTime t)
 void
 FFmpegDecoder::seek (ContentTime time, bool accurate)
 {
-       Decoder::seek (time, accurate);
-       if (_decode_audio) {
-               AudioDecoder::seek (time, accurate);
-       }
+       VideoDecoder::seek (time, accurate);
+       AudioDecoder::seek (time, accurate);
        
-       /* If we are doing an accurate seek, our initial shot will be 200ms (200 being
+       /* If we are doing an accurate seek, our initial shot will be 2s (2 being
           a number plucked from the air) earlier than we want to end up.  The loop below
           will hopefully then step through to where we want to be.
        */
 
-       ContentTime pre_roll = accurate ? ContentTime::from_seconds (0.2) : ContentTime (0);
+       ContentTime pre_roll = accurate ? ContentTime::from_seconds (2) : ContentTime (0);
        ContentTime initial_seek = time - pre_roll;
        if (initial_seek < ContentTime (0)) {
                initial_seek = ContentTime (0);
@@ -492,7 +484,8 @@ FFmpegDecoder::decode_video_packet ()
                shared_ptr<Image> image = i->first;
                
                if (i->second != AV_NOPTS_VALUE) {
-                       video (image, false, ContentTime::from_seconds (i->second * av_q2d (_format_context->streams[_video_stream]->time_base)) + _pts_offset);
+                       double const pts = i->second * av_q2d (_format_context->streams[_video_stream]->time_base) + _pts_offset.seconds ();
+                       video (shared_ptr<ImageProxy> (new RawImageProxy (image)), rint (pts * _ffmpeg_content->video_frame_rate ()));
                } else {
                        _log->log ("Dropping frame without PTS");
                }
@@ -540,7 +533,7 @@ FFmpegDecoder::decode_subtitle_packet ()
           indicate that the previous subtitle should stop.
        */
        if (sub.num_rects <= 0) {
-               image_subtitle (shared_ptr<Image> (), dcpomatic::Rect<double> (), ContentTime (), ContentTime ());
+               image_subtitle (ContentTime (), ContentTime (), shared_ptr<Image> (), dcpomatic::Rect<double> ());
                return;
        } else if (sub.num_rects > 1) {
                throw DecodeError (_("multi-part subtitles not yet supported"));
@@ -558,7 +551,9 @@ FFmpegDecoder::decode_subtitle_packet ()
        AVSubtitleRect const * rect = sub.rects[0];
 
        if (rect->type != SUBTITLE_BITMAP) {
-               throw DecodeError (_("non-bitmap subtitles not yet supported"));
+               /* XXX */
+               // throw DecodeError (_("non-bitmap subtitles not yet supported"));
+               return;
        }
 
        /* Note RGBA is expressed little-endian, so the first byte in the word is R, second
@@ -589,17 +584,16 @@ FFmpegDecoder::decode_subtitle_packet ()
        dcp::Size const vs = _ffmpeg_content->video_size ();
 
        image_subtitle (
+               from,
+               to,
                image,
                dcpomatic::Rect<double> (
                        static_cast<double> (rect->x) / vs.width,
                        static_cast<double> (rect->y) / vs.height,
                        static_cast<double> (rect->w) / vs.width,
                        static_cast<double> (rect->h) / vs.height
-                       ),
-               from,
-               to
+                       )
                );
-                         
        
        avsubtitle_free (&sub);
 }