From 6edac68a2309b213ee2c83c3d917d005210d5124 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 27 Oct 2022 22:22:07 +0200 Subject: wip: hacks --- src/lib/ffmpeg.cc | 5 +++-- src/lib/ffmpeg.h | 2 -- src/lib/ffmpeg_examiner.cc | 50 +++++++++++++++++++++++++++++++++++-------- src/lib/ffmpeg_examiner.h | 2 ++ src/lib/ffmpeg_video_stream.h | 36 +++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 src/lib/ffmpeg_video_stream.h 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 _video_stream; AVFrame* audio_frame (std::shared_ptr 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 c, shared_ptrduration == 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( + 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 c, shared_ptrduration) / AV_TIME_BASE) * video_frame_rate().get()); } + /* Choose the best video stream */ + using ScoredStream = pair, int>; + vector 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 c, shared_ptrindex(_format_context)]; while (video_packet(context, temporal_reference, nullptr)) {} } @@ -182,10 +214,10 @@ FFmpegExaminer::FFmpegExaminer(shared_ptr c, shared_ptrstreams[*_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(_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 frame_time(AVFrame* frame, AVStream* stream) const; + std::vector> _video_streams; + std::shared_ptr _best_video_stream; std::vector> _subtitle_streams; std::vector> _audio_streams; boost::optional _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 + + 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 . + +*/ + + +#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; +}; + -- cgit v1.2.3