#include <libavformat/avformat.h>
#include <libswscale/swscale.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 "raw_convert.h"
#include "i18n.h"
using std::string;
using std::cout;
-using std::stringstream;
using boost::shared_ptr;
-using dcp::raw_convert;
boost::mutex FFmpeg::_mutex;
_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;
/* 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<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 ());
}
/* Find video stream */
+ int video_stream_undefined_frame_rate = -1;
+
for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
AVStream* s = _format_context->streams[i];
+ /* 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) {
- _video_stream = i;
+ if (s->avg_frame_rate.num > 0 && s->avg_frame_rate.den > 0) {
+ /* This is definitely our video stream */
+ _video_stream = i;
+ } else {
+ /* This is our video stream if we don't get a better offer */
+ video_stream_undefined_frame_rate = i;
+ }
}
}
+ /* Files from iTunes sometimes have two video streams, one with the avg_frame_rate.num and .den set
+ to zero. Only use such a stream if there is no alternative.
+ */
+ if (_video_stream == -1 && video_stream_undefined_frame_rate != -1) {
+ _video_stream = video_stream_undefined_frame_rate;
+ }
+
if (_video_stream < 0) {
throw DecodeError (N_("could not find video stream"));
}
- /* Hack: if the AVStreams have zero IDs, put some in. We
- use the IDs so that we can cope with VOBs, in which streams
+ /* Hack: if the AVStreams have duplicate IDs, replace them with our
+ own. 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.
+ VOBs. However, some files have duplicate IDs, hence this hack.
*/
-
- uint32_t i = 0;
- while (i < _format_context->nb_streams && _format_context->streams[i]->id == 0) {
- ++i;
+
+ bool duplicates = false;
+ for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
+ for (uint32_t j = i + 1; j < _format_context->nb_streams; ++j) {
+ if (_format_context->streams[i]->id == _format_context->streams[j]->id) {
+ duplicates = true;
+ }
+ }
}
- if (i == _format_context->nb_streams) {
+ if (duplicates) {
/* Put in our own IDs */
for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
_format_context->streams[i]->id = i;
for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
AVCodecContext* context = _format_context->streams[i]->codec;
-
+
AVCodec* codec = avcodec_find_decoder (context->codec_id);
if (codec) {
- if (avcodec_open2 (context, codec, 0) < 0) {
+
+ /* This option disables decoding of DCA frame footers in our patched version
+ of FFmpeg. I believe these footers are of no use to us, and they can cause
+ problems when FFmpeg fails to decode them (mantis #352).
+ */
+ AVDictionary* options = 0;
+ av_dict_set (&options, "disable_footer", "1", 0);
+
+ if (avcodec_open2 (context, codec, &options) < 0) {
throw DecodeError (N_("could not open decoder"));
}
}
}
AVCodecContext *
-FFmpeg::audio_codec_context () const
+FFmpeg::subtitle_codec_context () const
{
- if (!_ffmpeg_content->audio_stream ()) {
+ if (!_ffmpeg_content->subtitle_stream ()) {
return 0;
}
-
- return _ffmpeg_content->audio_stream()->stream(_format_context)->codec;
+
+ return _ffmpeg_content->subtitle_stream()->stream(_format_context)->codec;
}
int
if (whence == AVSEEK_SIZE) {
return _file_group.length ();
}
-
+
return _file_group.seek (pos, whence);
}