diff options
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/ffmpeg.cc | 5 | ||||
| -rw-r--r-- | src/lib/ffmpeg.h | 2 | ||||
| -rw-r--r-- | src/lib/ffmpeg_examiner.cc | 50 | ||||
| -rw-r--r-- | src/lib/ffmpeg_examiner.h | 2 | ||||
| -rw-r--r-- | src/lib/ffmpeg_video_stream.h | 36 |
5 files changed, 82 insertions, 13 deletions
diff --git a/src/lib/ffmpeg.cc b/src/lib/ffmpeg.cc index d7c741d09..59cde70cf 100644 --- a/src/lib/ffmpeg.cc +++ b/src/lib/ffmpeg.cc @@ -213,11 +213,12 @@ FFmpeg::setup_decoder(int stream_index) AVCodecContext * FFmpeg::video_codec_context () const { - if (!_video_stream) { + auto str = _ffmpeg_content->video_stream(); + if (!str) { return nullptr; } - return _codec_context[_video_stream.get()]; + return _codec_context[str->index(_format_context)]; } diff --git a/src/lib/ffmpeg.h b/src/lib/ffmpeg.h index 63446e5cd..08b0ddd28 100644 --- a/src/lib/ffmpeg.h +++ b/src/lib/ffmpeg.h @@ -79,8 +79,6 @@ protected: /** AVFrame used for decoding video */ AVFrame* _video_frame = nullptr; - /** Index of video stream within AVFormatContext */ - boost::optional<int> _video_stream; AVFrame* audio_frame (std::shared_ptr<const FFmpegAudioStream> stream); diff --git a/src/lib/ffmpeg_examiner.cc b/src/lib/ffmpeg_examiner.cc index 6b60f6de3..d41f68852 100644 --- a/src/lib/ffmpeg_examiner.cc +++ b/src/lib/ffmpeg_examiner.cc @@ -64,12 +64,20 @@ FFmpegExaminer::FFmpegExaminer(shared_ptr<const FFmpegContent> c, shared_ptr<Job : FFmpeg(c) { _need_length = _format_context->duration == AV_NOPTS_VALUE; - /* Find audio and subtitle streams */ + + /* Find streams */ for (uint32_t i = 0; i < _format_context->nb_streams; ++i) { auto s = _format_context->streams[i]; auto codec = _codec_context[i] ? _codec_context[i]->codec : nullptr; - if (s->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && codec) { + if (s->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + _video_streams.push_back( + make_shared<FFmpegVideoStream>( + stream_name(s), + s->id, + av_q2d(av_guess_frame_rate(_format_context, _format_context->streams[i], 0)) + )); + } else if (s->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && codec) { DCPOMATIC_ASSERT(codec->name); @@ -95,6 +103,30 @@ FFmpegExaminer::FFmpegExaminer(shared_ptr<const FFmpegContent> c, shared_ptr<Job _video_length = _need_length ? 0 : llrint((double(_format_context->duration) / AV_TIME_BASE) * video_frame_rate().get()); } + /* Choose the best video stream */ + using ScoredStream = pair<shared_ptr<FFmpegVideoStream>, int>; + vector<ScoredStream> streams_with_scores; + for (auto stream: _video_streams) { + auto s = stream->stream(_format_context); + auto const frame_rate = av_q2d(s->avg_frame_rate); + int score = 0; + if (1 < frame_rate && frame_rate < 1000) { + ++score; + } + if (s->avg_frame_rate.num > 0 && s->avg_frame_rate.den > 0) { + ++score; + } + streams_with_scores.push_back({stream, score}); + } + + streams_with_scores.sort([](ScoredStream const& a, ScoredStream const& b) { + return a.second > b.second; + }); + + if (!streams_with_scores.empty()) { + _best_video_stream = streams_with_scores[0].first; + } + if (job && _need_length) { job->sub(_("Finding length")); } @@ -172,8 +204,8 @@ FFmpegExaminer::FFmpegExaminer(shared_ptr<const FFmpegContent> c, shared_ptr<Job } } - if (_video_stream) { - auto context = _codec_context[_video_stream.get()]; + if (_best_video_stream) { + auto context = _codec_context[_best_video_stream->index(_format_context)]; while (video_packet(context, temporal_reference, nullptr)) {} } @@ -182,10 +214,10 @@ FFmpegExaminer::FFmpegExaminer(shared_ptr<const FFmpegContent> c, shared_ptr<Job audio_packet(context, i, nullptr); } - if (_video_stream) { + if (_best_video_stream) { /* This code taken from get_rotation() in ffmpeg:cmdutils.c */ - auto stream = _format_context->streams[*_video_stream]; - auto rotate_tag = av_dict_get(stream->metadata, "rotate", 0, 0); + auto stream = _best_video_stream->stream(_format_context); + auto rotate_tag = av_dict_get (stream->metadata, "rotate", 0, 0); if (rotate_tag && *rotate_tag->value && strcmp(rotate_tag->value, "0")) { char *tail; _rotation = av_strtod(rotate_tag->value, &tail); @@ -257,7 +289,7 @@ FFmpegExaminer::check_for_duplicate_ids() bool FFmpegExaminer::video_packet(AVCodecContext* context, string& temporal_reference, AVPacket* packet) { - DCPOMATIC_ASSERT(_video_stream); + DCPOMATIC_ASSERT(_best_video_stream); if (_first_video && !_need_length && temporal_reference.size() >= (PULLDOWN_CHECK_FRAMES * 2)) { return false; @@ -530,7 +562,7 @@ FFmpegExaminer::yuv() const bool FFmpegExaminer::has_video() const { - return static_cast<bool>(_video_stream); + return !_video_streams.empty(); } diff --git a/src/lib/ffmpeg_examiner.h b/src/lib/ffmpeg_examiner.h index 65fa9cb5c..ba9897031 100644 --- a/src/lib/ffmpeg_examiner.h +++ b/src/lib/ffmpeg_examiner.h @@ -97,6 +97,8 @@ private: std::string subtitle_stream_name(AVStream* s) const; boost::optional<dcpomatic::ContentTime> frame_time(AVFrame* frame, AVStream* stream) const; + std::vector<std::shared_ptr<FFmpegVideoStream>> _video_streams; + std::shared_ptr<FFmpegVideoStream> _best_video_stream; std::vector<std::shared_ptr<FFmpegSubtitleStream>> _subtitle_streams; std::vector<std::shared_ptr<FFmpegAudioStream>> _audio_streams; boost::optional<dcpomatic::ContentTime> _first_video; diff --git a/src/lib/ffmpeg_video_stream.h b/src/lib/ffmpeg_video_stream.h new file mode 100644 index 000000000..ea65388da --- /dev/null +++ b/src/lib/ffmpeg_video_stream.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2022 Carl Hetherington <cth@carlh.net> + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>. + +*/ + + +#include "ffmpeg_stream.h" + + +class FFmpegVideoStream : public FFmpegStream +{ +public: + FFmpegVideoStream(std::string name, int id, float frame_rate) + : FFmpegStream(name, id) + , _frame_rate(frame_rate) + {} + +private: + float _frame_rate; +}; + |
