Merge master.
[dcpomatic.git] / src / lib / ffmpeg.cc
index 4bf9415234e3d54b844e8881e56a75dd30558492..4fe1c04484ab38527db8bf67a051904e8fb60eee 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-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
@@ -21,19 +21,21 @@ extern "C" {
 #include <libavcodec/avcodec.h>
 #include <libavformat/avformat.h>
 #include <libswscale/swscale.h>
-#include <libpostproc/postprocess.h>
 }
+#include <dcp/raw_convert.h>
 #include "ffmpeg.h"
 #include "ffmpeg_content.h"
+#include "ffmpeg_audio_stream.h"
+#include "ffmpeg_subtitle_stream.h"
 #include "exceptions.h"
+#include "util.h"
 
 #include "i18n.h"
 
 using std::string;
 using std::cout;
-using std::stringstream;
 using boost::shared_ptr;
-using boost::lexical_cast;
+using dcp::raw_convert;
 
 boost::mutex FFmpeg::_mutex;
 
@@ -47,8 +49,7 @@ FFmpeg::FFmpeg (boost::shared_ptr<const FFmpegContent> c)
        , _video_stream (-1)
 {
        setup_general ();
-       setup_video ();
-       setup_audio ();
+       setup_decoders ();
 }
 
 FFmpeg::~FFmpeg ()
@@ -56,14 +57,10 @@ FFmpeg::~FFmpeg ()
        boost::mutex::scoped_lock lm (_mutex);
 
        for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
-               AVCodecContext* context = _format_context->streams[i]->codec;
-               if (context->codec_type == AVMEDIA_TYPE_VIDEO || context->codec_type == AVMEDIA_TYPE_AUDIO) {
-                       avcodec_close (context);
-               }
+               avcodec_close (_format_context->streams[i]->codec);
        }
 
        av_frame_free (&_frame);
-       
        avformat_close_input (&_format_context);
 }
 
@@ -85,7 +82,7 @@ FFmpeg::setup_general ()
        av_register_all ();
 
        _file_group.set_paths (_ffmpeg_content->paths ());
-       _avio_buffer = static_cast<uint8_t*> (av_malloc (_avio_buffer_size));
+       _avio_buffer = static_cast<uint8_t*> (wrapped_av_malloc (_avio_buffer_size));
        _avio_context = avio_alloc_context (_avio_buffer, _avio_buffer_size, 0, this, avio_read_wrapper, 0, avio_seek_wrapper);
        _format_context = avformat_alloc_context ();
        _format_context->pb = _avio_context;
@@ -94,8 +91,8 @@ FFmpeg::setup_general ()
        /* These durations are in microseconds, and represent how far into the content file
           we will look for streams.
        */
-       av_dict_set (&options, "analyzeduration", lexical_cast<string> (5 * 60 * 1e6).c_str(), 0);
-       av_dict_set (&options, "probesize", lexical_cast<string> (5 * 60 * 1e6).c_str(), 0);
+       av_dict_set (&options, "analyzeduration", raw_convert<string> (5 * 60 * 1000000).c_str(), 0);
+       av_dict_set (&options, "probesize", raw_convert<string> (5 * 60 * 1000000).c_str(), 0);
        
        if (avformat_open_input (&_format_context, 0, 0, &options) < 0) {
                throw OpenFileError (_ffmpeg_content->path(0).string ());
@@ -109,7 +106,10 @@ FFmpeg::setup_general ()
 
        for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
                AVStream* s = _format_context->streams[i];
-               if (s->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+               /* Files from iTunes sometimes have two video streams, one with the avg_frame_rate.num and .den set
+                  to zero.  Ignore these streams.
+               */
+               if (s->codec->codec_type == AVMEDIA_TYPE_VIDEO && s->avg_frame_rate.num > 0 && s->avg_frame_rate.den > 0) {
                        _video_stream = i;
                }
        }
@@ -143,45 +143,24 @@ FFmpeg::setup_general ()
 }
 
 void
-FFmpeg::setup_video ()
-{
-       boost::mutex::scoped_lock lm (_mutex);
-       
-       AVCodecContext* context = _format_context->streams[_video_stream]->codec;
-       AVCodec* codec = avcodec_find_decoder (context->codec_id);
-
-       if (codec == 0) {
-               throw DecodeError (_("could not find video decoder"));
-       }
-
-       if (avcodec_open2 (context, codec, 0) < 0) {
-               throw DecodeError (N_("could not open video decoder"));
-       }
-}
-
-void
-FFmpeg::setup_audio ()
+FFmpeg::setup_decoders ()
 {
        boost::mutex::scoped_lock lm (_mutex);
 
        for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
                AVCodecContext* context = _format_context->streams[i]->codec;
-               if (context->codec_type != AVMEDIA_TYPE_AUDIO) {
-                       continue;
-               }
                
                AVCodec* codec = avcodec_find_decoder (context->codec_id);
-               if (codec == 0) {
-                       throw DecodeError (_("could not find audio decoder"));
-               }
-               
-               if (avcodec_open2 (context, codec, 0) < 0) {
-                       throw DecodeError (N_("could not open audio decoder"));
+               if (codec) {
+                       if (avcodec_open2 (context, codec, 0) < 0) {
+                               throw DecodeError (N_("could not open decoder"));
+                       }
                }
+
+               /* We are silently ignoring any failures to find suitable decoders here */
        }
 }
 
-
 AVCodecContext *
 FFmpeg::video_codec_context () const
 {
@@ -198,6 +177,16 @@ FFmpeg::audio_codec_context () const
        return _ffmpeg_content->audio_stream()->stream(_format_context)->codec;
 }
 
+AVCodecContext *
+FFmpeg::subtitle_codec_context () const
+{
+       if (!_ffmpeg_content->subtitle_stream ()) {
+               return 0;
+       }
+       
+       return _ffmpeg_content->subtitle_stream()->stream(_format_context)->codec;
+}
+
 int
 FFmpeg::avio_read (uint8_t* buffer, int const amount)
 {