// Copyright (c) 2012-2017 VideoStitch SAS // Copyright (c) 2018 stitchEm #pragma once #include "libvideostitch/input.hpp" #include "libvideostitch/inputFactory.hpp" #include <deque> #include <chrono> extern "C" { #include <libavutil/pixfmt.h> #ifdef SUP_QUICKSYNC #include <libavcodec/qsv.h> #endif } #undef PixelFormat struct AVFormatContext; struct AVCodecContext; struct AVCodec; struct AVFrame; struct AVPacket; class CHWDevice; class D3DFrameAllocator; static const int INVALID_STREAM_ID(-1); namespace VideoStitch { namespace Util { class TimeoutHandler; enum AvErrorCode : short; } // namespace Util namespace Input { #ifdef QUICKSYNC class QSVContext { public: bool initMFX(); static int getQSVBuffer(AVCodecContext* avctx, AVFrame* frame, int flags); static void freeQSVBuffer(void* opaque, uint8_t* data); mfxSession session; CHWDevice* hwdev; D3DFrameAllocator* allocator; mfxMemId* surface_ids; int* surface_used; int nb_surfaces; mfxFrameInfo frame_info; }; #endif /** * A deleter that does nothing */ template <class T> struct NoopDeleter { NoopDeleter() {} NoopDeleter(const NoopDeleter<T>& /*other*/) {} void operator()(T*) const {} }; /** * libav image reader. */ class LibavReader : public VideoReader, public AudioReader { public: // TODOLATERSTATUS replace by Input::ReadStatus enum class LibavReadStatus { Ok, EndOfPackets, Error }; static ProbeResult probe(const std::string& fileNameTemplate); // ~ is protected, can't use Potential's DefaultDeleter typedef Potential<LibavReader, NoopDeleter<LibavReader>> PotentialLibavReader; static PotentialLibavReader create(const std::string& fileNameTemplate, VideoStitch::Plugin::VSReaderPlugin::Config runtime); virtual ReadStatus readSamples(size_t nbSamples, Audio::Samples& audioSamples) override; virtual Status seekFrame(frameid_t) override; Status seekFrame(mtime_t) override; virtual size_t available() override; bool eos() override; protected: LibavReader(const std::string& displayName, const int64_t width, const int64_t height, const frameid_t firstFrame, const AVPixelFormat fmt, AddressSpace addrSpace, struct AVFormatContext* formatCtx, #ifdef QUICKSYNC class QSVContext* qsvCtx, #endif struct AVCodecContext* videoDecoderCtx, struct AVCodecContext* audioDecoderCtx, struct AVCodec* videoCodec, struct AVCodec* audioCodec, struct AVFrame* video, struct AVFrame* audio, Util::TimeoutHandler* interruptCallback, const int videoIdx, const int audioIdx, const Audio::ChannelLayout layout, const Audio::SamplingRate samplingRate, const Audio::SamplingDepth samplingDepth); ~LibavReader(); LibavReadStatus readPacket(AVPacket* pkt); static void findAvStreams(struct AVFormatContext* formatCtx, int& videoIdx, int& audioIdx); static enum AVPixelFormat selectFormat(struct AVCodecContext*, const enum AVPixelFormat*); void decodeVideoPacket(bool* got_picture, AVPacket* pkt, unsigned char* frame, bool flush = false); void flushVideoDecoder(bool* got_picture, unsigned char* frame); void decodeAudioPacket(AVPacket* pkt, bool flush = false); struct AVFormatContext* formatCtx; #ifdef QUICKSYNC QSVContext* qsvCtx; #endif struct AVCodecContext* videoDecoderCtx; struct AVCodecContext* audioDecoderCtx; const struct AVCodec* videoCodec; const struct AVCodec* audioCodec; struct AVFrame* videoFrame; struct AVFrame* audioFrame; Util::TimeoutHandler* interruptCallback; const int videoIdx; const int audioIdx; // time code of the last decoded video frame, // expressed in time_base units (eg. 1/90000 second), // from the start of the container (see start_time semantics) int64_t currentVideoPts; // time code of the first video frame, in container clock // in libvideostitch loadFrame date, this is 0 int64_t firstVideoFramePts; std::vector<std::deque<uint8_t>> audioBuffer; size_t nbSamplesInAudioBuffer; mtime_t videoTimeStamp; mtime_t audioTimeStamp; bool expectingIncreasingVideoPts; private: static Util::AvErrorCode avDecodePacket(AVCodecContext* s, AVPacket* pkt, AVFrame* frame, bool* got_frame, bool flush = false); static int getBuffer(AVCodecContext* s, AVFrame* pic); static void releaseBuffer(AVCodecContext* /*s*/, AVFrame* pic); }; } // namespace Input } // namespace VideoStitch