summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/ffmpeg.cc5
-rw-r--r--src/lib/ffmpeg.h2
-rw-r--r--src/lib/ffmpeg_examiner.cc50
-rw-r--r--src/lib/ffmpeg_examiner.h2
-rw-r--r--src/lib/ffmpeg_video_stream.h36
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;
+};
+