/*
- Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2016 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
, _avio_context (0)
, _format_context (0)
, _frame (0)
- , _video_stream (-1)
{
setup_general ();
setup_decoders ();
/* Find video stream */
- int video_stream_undefined_frame_rate = -1;
+ optional<int> video_stream_undefined_frame_rate;
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. 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 && video_stream_undefined_frame_rate) {
+ _video_stream = video_stream_undefined_frame_rate.get();
}
- if (_video_stream < 0) {
+ if (!_video_stream) {
throw DecodeError (N_("could not find video stream"));
}
AVCodecContext *
FFmpeg::video_codec_context () const
{
- return _format_context->streams[_video_stream]->codec;
+ DCPOMATIC_ASSERT (_video_stream);
+ return _format_context->streams[_video_stream.get()]->codec;
}
AVCodecContext *
AVFrame* _frame;
/** Index of video stream within AVFormatContext */
- int _video_stream;
+ boost::optional<int> _video_stream;
/* It would appear (though not completely verified) that one must have
a mutex around calls to avcodec_open* and avcodec_close... and here
int const si = _packet.stream_index;
shared_ptr<const FFmpegContent> fc = _ffmpeg_content;
- if (si == _video_stream && !_ignore_video && (accurate || reason != PASS_REASON_SUBTITLE)) {
+ if (_video_stream && si == _video_stream.get() && !_ignore_video && (accurate || reason != PASS_REASON_SUBTITLE)) {
decode_video_packet ();
} else if (fc->subtitle_stream() && fc->subtitle_stream()->uses_index (_format_context, si)) {
decode_subtitle_packet ();
http://www.mjbshaw.com/2012/04/seeking-in-ffmpeg-know-your-timestamp.html
*/
+ DCPOMATIC_ASSERT (_video_stream);
+
ContentTime u = time - _pts_offset;
if (u < ContentTime ()) {
u = ContentTime ();
}
- av_seek_frame (_format_context, _video_stream, u.seconds() / av_q2d (_format_context->streams[_video_stream]->time_base), AVSEEK_FLAG_BACKWARD);
+ av_seek_frame (
+ _format_context,
+ _video_stream.get(),
+ u.seconds() / av_q2d (_format_context->streams[_video_stream.get()]->time_base),
+ AVSEEK_FLAG_BACKWARD
+ );
avcodec_flush_buffers (video_codec_context());
bool
FFmpegDecoder::decode_video_packet ()
{
+ DCPOMATIC_ASSERT (_video_stream);
+
int frame_finished;
if (avcodec_decode_video2 (video_codec_context(), _frame, &frame_finished, &_packet) < 0 || !frame_finished) {
return false;
shared_ptr<Image> image = i->first;
if (i->second != AV_NOPTS_VALUE) {
- double const pts = i->second * av_q2d (_format_context->streams[_video_stream]->time_base) + _pts_offset.seconds ();
+ double const pts = i->second * av_q2d (_format_context->streams[_video_stream.get()]->time_base) + _pts_offset.seconds ();
video (
shared_ptr<ImageProxy> (new RawImageProxy (image)),
llrint (pts * _ffmpeg_content->active_video_frame_rate ())
AVCodecContext* context = _format_context->streams[_packet.stream_index]->codec;
- if (_packet.stream_index == _video_stream) {
+ if (_video_stream && _packet.stream_index == _video_stream.get()) {
video_packet (context);
}
void
FFmpegExaminer::video_packet (AVCodecContext* context)
{
+ DCPOMATIC_ASSERT (_video_stream);
+
if (_first_video && !_need_video_length) {
return;
}
int frame_finished;
if (avcodec_decode_video2 (context, _frame, &frame_finished, &_packet) >= 0 && frame_finished) {
if (!_first_video) {
- _first_video = frame_time (_format_context->streams[_video_stream]);
+ _first_video = frame_time (_format_context->streams[_video_stream.get()]);
}
if (_need_video_length) {
_video_length = frame_time (
- _format_context->streams[_video_stream]
+ _format_context->streams[_video_stream.get()]
).get_value_or (ContentTime ()).frames_round (video_frame_rate().get ());
}
}
optional<double>
FFmpegExaminer::video_frame_rate () const
{
+ DCPOMATIC_ASSERT (_video_stream);
/* This use of r_frame_rate is debateable; there's a few different
* frame rates in the format context, but this one seems to be the most
* reliable.
*/
- return av_q2d (av_stream_get_r_frame_rate (_format_context->streams[_video_stream]));
+ return av_q2d (av_stream_get_r_frame_rate (_format_context->streams[_video_stream.get()]));
}
dcp::Size
optional<double>
FFmpegExaminer::sample_aspect_ratio () const
{
- AVRational sar = av_guess_sample_aspect_ratio (_format_context, _format_context->streams[_video_stream], 0);
+ DCPOMATIC_ASSERT (_video_stream);
+ AVRational sar = av_guess_sample_aspect_ratio (_format_context, _format_context->streams[_video_stream.get()], 0);
if (sar.num == 0) {
/* I assume this means that we don't know */
return optional<double> ();