diff --git a/src/Lib/AbstractMediaContext.hh b/src/Lib/AbstractMediaContext.hh index bc896bfcc193203a6f1732eb93116c34c1e1178a..1267b175146f8bac7889e3e687e10f7fe59ce15c 100644 --- a/src/Lib/AbstractMediaContext.hh +++ b/src/Lib/AbstractMediaContext.hh @@ -82,7 +82,7 @@ protected: } public: - virtual ~AbstractMediaStream() noexcept = default; + virtual ~AbstractMediaStream() noexcept {} int getStreamIndex() const noexcept { return streamIndexInContext; } QString getName() const noexcept { return QString::fromUtf8(codec->name); } AVCodecID getCodecId() const noexcept { return codecId; } diff --git a/src/Lib/Video.cc b/src/Lib/Video.cc index d6fe6e57eda1ae7d358d8d4be4a5ef2ccbd99fd5..390b82a7b44626c218d7875c34bd9b103f874d26 100644 --- a/src/Lib/Video.cc +++ b/src/Lib/Video.cc @@ -6,45 +6,31 @@ using namespace Vivy; -VideoContext::VideoContext(const QString &path) - : filePath(path) +VideoStream::VideoStream(AVCodec *streamCodec, AVFormatContext *formatArg, AVStream *streamArg, + int index) + : Super(streamCodec, formatArg, streamArg, index) { - if (!format) - throw std::runtime_error("out of memory, can't create allocate the AVFormatContext"); - - const std::string stdFilename = filePath.toStdString(); - const char *filename = stdFilename.c_str(); - AVFormatContext *formatPtr = format.get(); - - // Get info from video file - if (avformat_open_input(&formatPtr, filename, nullptr, nullptr) != 0) { - [[maybe_unused]] void *relatedOnFailure = format.release(); // freed by avformat_open_input - throw std::runtime_error("failed to open file"); - } +} - if (avformat_find_stream_info(formatPtr, nullptr) < 0) { - throw std::runtime_error("failed to get video stream info"); - } +QJsonObject +VideoStream::getProperties() const noexcept +{ + return Super::getProperties(); +} - // Populate all the stream indexes - for (uint i = 0; i < format->nb_streams; ++i) { - AVStream *itFormat = format->streams[i]; - AVCodecParameters *params = itFormat->codecpar; - AVCodec *streamCodec = avcodec_find_decoder(params->codec_id); - if (streamCodec && streamCodec->type == AVMEDIA_TYPE_VIDEO) { - videoStreams.insert(i, std::make_shared<Stream>(streamCodec, formatPtr, itFormat, i)); - } - } +VideoContext::VideoContext(const QString &path) + : Super(path) +{ +} - // Get the default stream - defaultStreamIndex = av_find_best_stream(formatPtr, AVMEDIA_TYPE_VIDEO, - -1, // Let AV find one stream - -1, // We don't want related streams - nullptr, 0); - if (defaultStreamIndex < 0) { - qCritical() << "Could not find the best video stream"; - } +QJsonDocument +VideoContext::getProperties() const noexcept +{ + return Super::getProperties(); +} - qDebug() << "Opened video context for" << path << "with duration" << formatPtr->duration - << "and default stream index" << defaultStreamIndex; +QString +VideoContext::getElementName() const noexcept +{ + return "Video" + Super::getElementName(); } diff --git a/src/Lib/Video.hh b/src/Lib/Video.hh index 8dbb47580865610cb94b14c54c59ad1fdfaefe0d..e0826f0c3c191234e594b33f990b4de7b8360dff 100644 --- a/src/Lib/Video.hh +++ b/src/Lib/Video.hh @@ -21,68 +21,38 @@ extern "C" { namespace Vivy { -class VideoContext; - -// Like an audio context, but for videos. -class VideoContext final { - VIVY_UNMOVABLE_OBJECT(VideoContext) +// Hold all the data for a video stream. Should only be owned by the parent +// VideoContext instance. +class VideoStream final : public AbstractMediaStream<AVMEDIA_TYPE_VIDEO> { + VIVY_UNMOVABLE_OBJECT(VideoStream) + using Super = AbstractMediaStream<AVMEDIA_TYPE_VIDEO>; public: - // Hold all the data for a video stream. Should only be owned by the parent - // VideoContext instance. - class Stream final { - VIVY_UNMOVABLE_OBJECT(Stream) - - public: - Stream(AVCodec *, AVFormatContext *, AVStream *, int index); - ~Stream() noexcept; - - size_t getWidth() const noexcept; - size_t getHeight() const noexcept; - size_t getDuration() const noexcept; - size_t getFramesPerSecond() const noexcept; + VideoStream(AVCodec *, AVFormatContext *, AVStream *, int index); + ~VideoStream() noexcept override = default; - QJsonObject getProperties() const noexcept; + size_t getWidth() const noexcept; + size_t getHeight() const noexcept; + size_t getDuration() const noexcept; + size_t getFramesPerSecond() const noexcept; - static inline Utils::DeleterFunctionType<AVCodecContext> codecContexteleter = - std::bind_front(Utils::freePPtrIfNotNull<AVCodecContext>, avcodec_free_context); + QJsonObject getProperties() const noexcept override; - using AVCodecContextPtr = std::unique_ptr<AVCodecContext, decltype(codecContexteleter)>; + static inline Utils::DeleterFunctionType<AVCodecContext> codecContexteleter = + std::bind_front(Utils::freePPtrIfNotNull<AVCodecContext>, avcodec_free_context); - private: - AVCodecID codecId{ AV_CODEC_ID_NONE }; - AVCodec *codec{ nullptr }; - AVCodecParameters *codecParams{ nullptr }; - AVCodecContextPtr codecContext{ nullptr }; - - AVStream *videoStream{ nullptr }; - - int streamIndexInVideoContext; - }; +private: +}; - using StreamPtr = std::shared_ptr<Stream>; - using StreamWeakPtr = std::weak_ptr<Stream>; +// Like an audio context, but for videos. +class VideoContext final : public AbstractMediaContext<VideoStream> { + VIVY_UNMOVABLE_OBJECT(VideoContext) + using Super = AbstractMediaContext<VideoStream>; public: VideoContext(const QString &path); - StreamWeakPtr getStream(int) const noexcept; - StreamWeakPtr getDefaultStream() const noexcept; - - QString getElementName() const noexcept; - QJsonDocument getProperties() const noexcept; - -private: - static inline Utils::DeleterFunctionType<AVFormatContext> avFormatContextDeleter = - std::bind_front(Utils::freePtrIfNotNull<AVFormatContext>, avformat_free_context); - using AVFormatContextPtr = std::unique_ptr<AVFormatContext, decltype(avFormatContextDeleter)>; - AVFormatContextPtr format{ avformat_alloc_context(), avFormatContextDeleter }; - - const QString filePath; - QMap<uint, StreamPtr> videoStreams{}; - - int defaultStreamIndex{ -1 }; - - StreamPtr spareNullSreamPtr{ nullptr }; -}; + QString getElementName() const noexcept override; + QJsonDocument getProperties() const noexcept override; }; +}