/*** Olive - Non-Linear Video Editor Copyright (C) 2019 Olive Team 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 the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 this program. If not, see . ***/ #ifndef FFMPEGDECODER_H #define FFMPEGDECODER_H extern "C" { #include #include #include } #include #include #include #include #include "audio/sampleformat.h" #include "avframeptr.h" #include "codec/decoder.h" #include "codec/waveoutput.h" #include "ffmpegframepool.h" #include "project/item/footage/videostream.h" OLIVE_NAMESPACE_ENTER class FFmpegDecoderInstance : public QObject { Q_OBJECT public: FFmpegDecoderInstance(const char* filename, int stream_index); virtual ~FFmpegDecoderInstance(); DISABLE_COPY_MOVE(FFmpegDecoderInstance) bool IsValid() const; void SetFramePool(FFmpegFramePool* frame_pool); int64_t RangeStart() const; int64_t RangeEnd() const; bool CacheContainsTime(const int64_t& t) const; bool CacheWillContainTime(const int64_t& t) const; bool CacheCouldContainTime(const int64_t& t) const; bool CacheIsEmpty() const; FFmpegFramePool::ElementPtr GetFrameFromCache(const int64_t& t) const; void RemoveFramesBefore(const qint64& t); void TruncateCacheRangeTo(const qint64& t); rational sample_aspect_ratio() const; AVStream* stream() const; void ClearFrameCache(); FFmpegFramePool::ElementPtr RetrieveFrame(const int64_t &target_ts, bool cache_is_locked); /** * @brief Uses the FFmpeg API to retrieve a packet (stored in pkt_) and decode it (stored in frame_) * * @return * * An FFmpeg error code, or >= 0 on success */ int GetFrame(AVPacket* pkt, AVFrame* frame); QMutex* cache_lock(); QWaitCondition* cache_wait_cond(); bool IsWorking() const; void SetWorking(bool working); private: void ClearResources(); void Seek(int64_t timestamp); AVFormatContext* fmt_ctx_; AVCodecContext* codec_ctx_; AVStream* avstream_; AVDictionary* opts_; int64_t second_ts_; QWaitCondition cache_wait_cond_; QMutex cache_lock_; QList cached_frames_; FFmpegFramePool* frame_pool_; int64_t cache_target_time_; bool is_working_; bool cache_at_zero_; bool cache_at_eof_; QTimer* clear_timer_; static const int kMaxFrameLife; private slots: void ClearTimerEvent(); }; /** * @brief A Decoder derivative that wraps FFmpeg functions as on Olive decoder */ class FFmpegDecoder : public Decoder { Q_OBJECT public: // Constructor FFmpegDecoder(); // Destructor virtual ~FFmpegDecoder() override; virtual bool Probe(Footage *f, const QAtomicInt *cancelled) override; virtual bool Open() override; virtual FramePtr RetrieveVideo(const rational &timecode, const int& divider) override; virtual SampleBufferPtr RetrieveAudio(const rational &timecode, const rational &length, const AudioRenderingParams& params) override; virtual void Close() override; virtual QString id() override; virtual bool SupportsVideo() override; virtual bool SupportsAudio() override; virtual bool ProxyVideo(const QAtomicInt* cancelled, int divider) override; virtual bool ConformAudio(const QAtomicInt* cancelled, const AudioRenderingParams& p) override; private: /** * @brief Handle an error * * Immediately closes the Decoder (freeing memory resources) and sends the string provided to the warning stream. * As this function closes the Decoder, no further Decoder functions should be performed after this is called * (unless the Decoder is opened again first). */ void Error(const QString& s); /** * @brief Handle an FFmpeg error code * * Uses the FFmpeg API to retrieve a descriptive string for this error code and sends it to Error(). As such, this * function also automatically closes the Decoder. * * @param error_code */ void FFmpegError(int error_code); virtual QString GetIndexFilename() const override; QString GetProxyFilename(int divider) const; void ClearResources(); void InitScaler(int divider); void FreeScaler(); QString GetProxyFrameFilename(const int64_t& timestamp, const int ÷r) const; static int GetScaledDimension(int dim, int divider); static PixelFormat::Format GetNativePixelFormat(AVPixelFormat pix_fmt); static uint64_t ValidateChannelLayout(AVStream *stream); SwsContext* scale_ctx_; int scale_divider_; AVPixelFormat src_pix_fmt_; AVPixelFormat ideal_pix_fmt_; PixelFormat::Format native_pix_fmt_; rational time_base_; rational aspect_ratio_; int64_t start_time_; static QHash< Stream*, QList > instance_map_; static QHash< Stream*, FFmpegFramePool* > frame_pool_map_; static QMutex instance_map_lock_; }; OLIVE_NAMESPACE_EXIT #endif // FFMPEGDECODER_H