#pragma once #include #include #include "seekable_buffer.h" #include "stream.h" #if defined(_MSC_VER) #include using ssize_t = SSIZE_T; #endif namespace ffmpeg { /** * Class uses FFMPEG library to decode media streams. * Media bytes can be explicitly provided through read-callback * or fetched internally by FFMPEG library */ class Decoder : public MediaDecoder { public: Decoder(); ~Decoder() override; // MediaDecoder overrides bool init( const DecoderParameters& params, DecoderInCallback&& in, std::vector* metadata) override; int decode_all(const DecoderOutCallback& callback) override; void shutdown() override; void interrupt() override; protected: // function does actual work, derived class calls it in working thread // periodically. On success method returns 0, ENOADATA on EOF, ETIMEDOUT if // no frames got decoded in the specified timeout time, and error on // unrecoverable error. int getFrame(size_t workingTimeInMs = 100); // Derived class must override method and consume the provided message virtual void push(DecoderOutputMessage&& buffer) = 0; // Fires on init call virtual void onInit() {} public: // C-style FFMPEG API requires C/static methods for callbacks static void logFunction(void* avcl, int level, const char* cfmt, va_list vl); static int shutdownFunction(void* ctx); static int readFunction(void* opaque, uint8_t* buf, int size); static int64_t seekFunction(void* opaque, int64_t offset, int whence); // can be called by any classes or API static void initOnce(); int* getPrintPrefix() { return &printPrefix; } private: // mark below function for a proper invocation bool enableLogLevel(int level) const; void logCallback(int level, const std::string& message); int readCallback(uint8_t* buf, int size); int64_t seekCallback(int64_t offset, int whence); int shutdownCallback(); bool openStreams(std::vector* metadata); Stream* findByIndex(int streamIndex) const; Stream* findByType(const MediaFormat& format) const; int processPacket( Stream* stream, AVPacket* packet, bool* gotFrame, bool* hasMsg, bool fastSeek = false); void flushStreams(); void cleanUp(); protected: DecoderParameters params_; private: SeekableBuffer seekableBuffer_; int printPrefix{1}; std::atomic interrupted_{false}; AVFormatContext* inputCtx_{nullptr}; AVIOContext* avioCtx_{nullptr}; std::unordered_map> streams_; std::bitset<64> inRange_; }; } // namespace ffmpeg