X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fffmpeg.cc;h=4fe1c04484ab38527db8bf67a051904e8fb60eee;hb=f90d74f7a0382f0dc63eef81bd553d7a7b38edb2;hp=b78a0bbf65760bd6b6b44d170b6450fd270d4229;hpb=fde38b664c98205dd4fe3721b125469d5dd2ecbe;p=dcpomatic.git diff --git a/src/lib/ffmpeg.cc b/src/lib/ffmpeg.cc index b78a0bbf6..4fe1c0448 100644 --- a/src/lib/ffmpeg.cc +++ b/src/lib/ffmpeg.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2013 Carl Hetherington + Copyright (C) 2013-2014 Carl Hetherington 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 @@ -22,8 +22,11 @@ extern "C" { #include #include } +#include #include "ffmpeg.h" #include "ffmpeg_content.h" +#include "ffmpeg_audio_stream.h" +#include "ffmpeg_subtitle_stream.h" #include "exceptions.h" #include "util.h" @@ -31,17 +34,10 @@ extern "C" { using std::string; using std::cout; -using std::stringstream; using boost::shared_ptr; -using boost::lexical_cast; +using dcp::raw_convert; -/* This should not really be a pointer, but I find that __cxa_finalize tries - * to destroy the mutex while a call to ~FFmpeg is in progress; this crashes - * with a failure of assert (!posix::pthread_mutex_destroy(&m)); - * - * The hacky work-around is never to destroy the mutex... - */ -boost::mutex* FFmpeg::_mutex; +boost::mutex FFmpeg::_mutex; FFmpeg::FFmpeg (boost::shared_ptr c) : _ffmpeg_content (c) @@ -52,28 +48,19 @@ FFmpeg::FFmpeg (boost::shared_ptr c) , _frame (0) , _video_stream (-1) { - if (!_mutex) { - _mutex = new boost::mutex (); - } - setup_general (); - setup_video (); - setup_audio (); + setup_decoders (); } FFmpeg::~FFmpeg () { - boost::mutex::scoped_lock lm (*_mutex); + 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); } @@ -104,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 (5 * 60 * 1e6).c_str(), 0); - av_dict_set (&options, "probesize", lexical_cast (5 * 60 * 1e6).c_str(), 0); + av_dict_set (&options, "analyzeduration", raw_convert (5 * 60 * 1000000).c_str(), 0); + av_dict_set (&options, "probesize", raw_convert (5 * 60 * 1000000).c_str(), 0); if (avformat_open_input (&_format_context, 0, 0, &options) < 0) { throw OpenFileError (_ffmpeg_content->path(0).string ()); @@ -119,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; } } @@ -153,46 +143,24 @@ FFmpeg::setup_general () } void -FFmpeg::setup_video () -{ - boost::mutex::scoped_lock lm (*_mutex); - - assert (_video_stream >= 0); - 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); + 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 { @@ -209,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) {