Use optional<> for _video_stream.
authorCarl Hetherington <cth@carlh.net>
Tue, 10 May 2016 10:57:05 +0000 (11:57 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 18 May 2016 10:50:29 +0000 (11:50 +0100)
src/lib/ffmpeg.cc
src/lib/ffmpeg.h
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_examiner.cc

index 656142cd42c7a42da00b1bdd7582b90b5ade641f..7b1eae2b102cdf1f0dfe3925c2fc0f1404871313 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
-    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
 
     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
@@ -56,7 +56,6 @@ FFmpeg::FFmpeg (boost::shared_ptr<const FFmpegContent> c)
        , _avio_context (0)
        , _format_context (0)
        , _frame (0)
        , _avio_context (0)
        , _format_context (0)
        , _frame (0)
-       , _video_stream (-1)
 {
        setup_general ();
        setup_decoders ();
 {
        setup_general ();
        setup_decoders ();
@@ -140,7 +139,7 @@ FFmpeg::setup_general ()
 
        /* Find video stream */
 
 
        /* 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];
 
        for (uint32_t i = 0; i < _format_context->nb_streams; ++i) {
                AVStream* s = _format_context->streams[i];
@@ -158,11 +157,11 @@ FFmpeg::setup_general ()
        /* 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.
        */
        /* 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"));
        }
 
                throw DecodeError (N_("could not find video stream"));
        }
 
@@ -224,7 +223,8 @@ FFmpeg::setup_decoders ()
 AVCodecContext *
 FFmpeg::video_codec_context () const
 {
 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 *
 }
 
 AVCodecContext *
index 43efcf74f456fd031cb900aab1ae3c5d58c65238..d38fd63626359a09c41b79c97d3d39927e2a2bf2 100644 (file)
@@ -72,7 +72,7 @@ protected:
        AVFrame* _frame;
 
        /** Index of video stream within AVFormatContext */
        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
 
        /* It would appear (though not completely verified) that one must have
           a mutex around calls to avcodec_open* and avcodec_close... and here
index 68dcd518618eccfb10eac0467e8218e6ff65a3cd..72df69126857bde91d0b86ba27a9e48ea4f4c6d6 100644 (file)
@@ -121,7 +121,7 @@ FFmpegDecoder::pass (PassReason reason, bool accurate)
        int const si = _packet.stream_index;
        shared_ptr<const FFmpegContent> fc = _ffmpeg_content;
 
        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 ();
                decode_video_packet ();
        } else if (fc->subtitle_stream() && fc->subtitle_stream()->uses_index (_format_context, si)) {
                decode_subtitle_packet ();
@@ -295,11 +295,18 @@ FFmpegDecoder::seek (ContentTime time, bool accurate)
           http://www.mjbshaw.com/2012/04/seeking-in-ffmpeg-know-your-timestamp.html
        */
 
           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 ();
        }
        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());
 
 
        avcodec_flush_buffers (video_codec_context());
 
@@ -380,6 +387,8 @@ FFmpegDecoder::decode_audio_packet ()
 bool
 FFmpegDecoder::decode_video_packet ()
 {
 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;
        int frame_finished;
        if (avcodec_decode_video2 (video_codec_context(), _frame, &frame_finished, &_packet) < 0 || !frame_finished) {
                return false;
@@ -410,7 +419,7 @@ FFmpegDecoder::decode_video_packet ()
                shared_ptr<Image> image = i->first;
 
                if (i->second != AV_NOPTS_VALUE) {
                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 ())
                        video (
                                shared_ptr<ImageProxy> (new RawImageProxy (image)),
                                llrint (pts * _ffmpeg_content->active_video_frame_rate ())
index 2b8b2b743f82d61b4e83ea3bbf37cd5577c38647..eeb0cfc389c5df32f335fd324633231ac6b25b55 100644 (file)
@@ -113,7 +113,7 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c, shared_ptr<Jo
 
                AVCodecContext* context = _format_context->streams[_packet.stream_index]->codec;
 
 
                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);
                }
 
                        video_packet (context);
                }
 
@@ -179,6 +179,8 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c, shared_ptr<Jo
 void
 FFmpegExaminer::video_packet (AVCodecContext* context)
 {
 void
 FFmpegExaminer::video_packet (AVCodecContext* context)
 {
+       DCPOMATIC_ASSERT (_video_stream);
+
        if (_first_video && !_need_video_length) {
                return;
        }
        if (_first_video && !_need_video_length) {
                return;
        }
@@ -186,11 +188,11 @@ FFmpegExaminer::video_packet (AVCodecContext* context)
        int frame_finished;
        if (avcodec_decode_video2 (context, _frame, &frame_finished, &_packet) >= 0 && frame_finished) {
                if (!_first_video) {
        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 (
                }
                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 ());
                }
        }
                                ).get_value_or (ContentTime ()).frames_round (video_frame_rate().get ());
                }
        }
@@ -297,11 +299,12 @@ FFmpegExaminer::frame_time (AVStream* s) const
 optional<double>
 FFmpegExaminer::video_frame_rate () const
 {
 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.
         */
        /* 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
 }
 
 dcp::Size
@@ -320,7 +323,8 @@ FFmpegExaminer::video_length () const
 optional<double>
 FFmpegExaminer::sample_aspect_ratio () const
 {
 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> ();
        if (sar.num == 0) {
                /* I assume this means that we don't know */
                return optional<double> ();