#include "ffmpeg.h"
#include "ffmpeg_content.h"
#include "exceptions.h"
+#include "util.h"
#include "i18n.h"
boost::mutex FFmpeg::_mutex;
-/** @param long_probe true to do a long probe of the file looking for streams */
-FFmpeg::FFmpeg (boost::shared_ptr<const FFmpegContent> c, bool long_probe)
+FFmpeg::FFmpeg (boost::shared_ptr<const FFmpegContent> c)
: _ffmpeg_content (c)
, _avio_buffer (0)
, _avio_buffer_size (4096)
, _frame (0)
, _video_stream (-1)
{
- setup_general (long_probe);
+ setup_general ();
setup_video ();
setup_audio ();
}
}
}
- avcodec_free_frame (&_frame);
+ av_frame_free (&_frame);
avformat_close_input (&_format_context);
}
static int64_t
avio_seek_wrapper (void* data, int64_t offset, int whence)
{
- if (whence == AVSEEK_SIZE) {
- return reinterpret_cast<FFmpeg*>(data)->avio_length ();
- }
-
return reinterpret_cast<FFmpeg*>(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<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;
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<string> (5 * 60 * 1e6).c_str(), 0);
- av_dict_set (&options, "probesize", lexical_cast<string> (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", lexical_cast<string> (5 * 60 * 1e6).c_str(), 0);
+ av_dict_set (&options, "probesize", lexical_cast<string> (5 * 60 * 1e6).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 ());
}
throw DecodeError (N_("could not find video stream"));
}
- _frame = avcodec_alloc_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;
+ }
+
+ 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;
+ }
+ }
+
+ _frame = av_frame_alloc ();
if (_frame == 0) {
throw DecodeError (N_("could not allocate frame"));
}
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);
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;
}
int
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 ();
-}