X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fffmpeg.cc;h=fa369dda429c9342c2b08eed7a4b74ee50a38c35;hb=7b2054e2a73844450b5b55c5788c02af671812ce;hp=bbf853af1588aaad35a98618150a7594007152b4;hpb=13b2b8f48f3f1a22277a760a7fada980b9f37677;p=dcpomatic.git diff --git a/src/lib/ffmpeg.cc b/src/lib/ffmpeg.cc index bbf853af1..fa369dda4 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 @@ -21,24 +21,25 @@ extern "C" { #include #include #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" #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; -/** @param long_probe true to do a long probe of the file looking for streams */ -FFmpeg::FFmpeg (boost::shared_ptr c, bool long_probe) +FFmpeg::FFmpeg (boost::shared_ptr c) : _ffmpeg_content (c) , _avio_buffer (0) , _avio_buffer_size (4096) @@ -47,9 +48,8 @@ FFmpeg::FFmpeg (boost::shared_ptr c, bool long_probe) , _frame (0) , _video_stream (-1) { - setup_general (long_probe); - setup_video (); - setup_audio (); + setup_general (); + setup_decoders (); } FFmpeg::~FFmpeg () @@ -57,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); } - avcodec_free_frame (&_frame); - + av_frame_free (&_frame); avformat_close_input (&_format_context); } @@ -77,34 +73,28 @@ avio_read_wrapper (void* data, uint8_t* buffer, int amount) static int64_t avio_seek_wrapper (void* data, int64_t offset, int whence) { - if (whence == AVSEEK_SIZE) { - return reinterpret_cast(data)->avio_length (); - } - return reinterpret_cast(data)->avio_seek (offset, whence); } void -FFmpeg::setup_general (bool long_probe) +FFmpeg::setup_general () { av_register_all (); _file_group.set_paths (_ffmpeg_content->paths ()); - _avio_buffer = static_cast (av_malloc (_avio_buffer_size)); + _avio_buffer = static_cast (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; AVDictionary* options = 0; - if (long_probe) { - /* 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); - } + /* These durations are in microseconds, and represent how far into the content file + we will look for streams. + */ + 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, _ffmpeg_content->path(0).string().c_str(), 0, &options) < 0) { + if (avformat_open_input (&_format_context, 0, 0, &options) < 0) { throw OpenFileError (_ffmpeg_content->path(0).string ()); } @@ -125,52 +115,49 @@ FFmpeg::setup_general (bool long_probe) throw DecodeError (N_("could not find video stream")); } - _frame = avcodec_alloc_frame (); - if (_frame == 0) { - throw DecodeError (N_("could not allocate frame")); + /* Hack: if the AVStreams have zero IDs, put some in. We + use the IDs so that we can cope with VOBs, in which streams + move about in index but remain with the same ID in different + VOBs. However, some files have all-zero IDs, hence this hack. + */ + + uint32_t i = 0; + while (i < _format_context->nb_streams && _format_context->streams[i]->id == 0) { + ++i; } -} -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 (i == _format_context->nb_streams) { + /* Put in our own IDs */ + for (uint32_t i = 0; i < _format_context->nb_streams; ++i) { + _format_context->streams[i]->id = i; + } } - if (avcodec_open2 (context, codec, 0) < 0) { - throw DecodeError (N_("could not open video decoder")); + _frame = av_frame_alloc (); + if (_frame == 0) { + throw DecodeError (N_("could not allocate frame")); } } 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 { @@ -180,7 +167,21 @@ FFmpeg::video_codec_context () const AVCodecContext * FFmpeg::audio_codec_context () const { - return _format_context->streams[_ffmpeg_content->audio_stream()->id]->codec; + if (!_ffmpeg_content->audio_stream ()) { + return 0; + } + + 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 @@ -192,11 +193,9 @@ FFmpeg::avio_read (uint8_t* buffer, int const amount) int64_t FFmpeg::avio_seek (int64_t const pos, int whence) { + if (whence == AVSEEK_SIZE) { + return _file_group.length (); + } + return _file_group.seek (pos, whence); } - -int64_t -FFmpeg::avio_size () -{ - return _file_group.length (); -}