Line data Source code
1 : /* 2 : * Copyright (C) 2004-2026 Savoir-faire Linux Inc. 3 : * 4 : * This program is free software: you can redistribute it and/or modify 5 : * it under the terms of the GNU General Public License as published by 6 : * the Free Software Foundation, either version 3 of the License, or 7 : * (at your option) any later version. 8 : * 9 : * This program is distributed in the hope that it will be useful, 10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 : * GNU General Public License for more details. 13 : * 14 : * You should have received a copy of the GNU General Public License 15 : * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 : */ 17 : #pragma once 18 : 19 : #ifdef HAVE_CONFIG_H 20 : #include "config.h" 21 : #endif 22 : 23 : #include "rational.h" 24 : #include "observer.h" 25 : 26 : #ifdef ENABLE_VIDEO 27 : #include "video/video_base.h" 28 : #include "video/video_scaler.h" 29 : #endif // ENABLE_VIDEO 30 : 31 : #ifdef ENABLE_HWACCEL 32 : #include "video/accel.h" 33 : #endif 34 : #include "logger.h" 35 : 36 : #include "audio/audio_format.h" 37 : 38 : #include "media_device.h" 39 : #include "media_stream.h" 40 : #include "media_buffer.h" 41 : #include "media_attribute.h" 42 : #include "noncopyable.h" 43 : 44 : #include <asio/steady_timer.hpp> 45 : 46 : #include <map> 47 : #include <string> 48 : #include <memory> 49 : #include <chrono> 50 : #include <queue> 51 : 52 : extern "C" { 53 : struct AVCodecContext; 54 : struct AVStream; 55 : struct AVDictionary; 56 : struct AVFormatContext; 57 : struct AVCodec; 58 : enum AVMediaType; 59 : } 60 : 61 : namespace libjami { 62 : class AudioFrame; 63 : } 64 : 65 : namespace jami { 66 : 67 : using AudioFrame = libjami::AudioFrame; 68 : #ifdef ENABLE_VIDEO 69 : using VideoFrame = libjami::VideoFrame; 70 : #endif 71 : struct AudioFormat; 72 : class RingBuffer; 73 : class Resampler; 74 : class MediaIOHandle; 75 : class MediaDecoder; 76 : 77 : enum class DecodeStatus { Success, FrameFinished, EndOfFile, ReadError, DecodeError, RestartRequired, FallBack }; 78 : 79 : class MediaDemuxer : public std::enable_shared_from_this<MediaDemuxer> 80 : { 81 : public: 82 : MediaDemuxer(); 83 : ~MediaDemuxer(); 84 : 85 : enum class Status { Success, EndOfFile, ReadBufferOverflow, ReadError, FallBack, RestartRequired }; 86 : 87 : static const char* getStatusStr(Status status); 88 : 89 : enum class CurrentState { Demuxing, Finished }; 90 : using StreamCallback = std::function<DecodeStatus(AVPacket&)>; 91 : 92 : int openInput(const DeviceParams&); 93 : 94 : void setInterruptCallback(int (*cb)(void*), void* opaque); 95 : void setIOContext(MediaIOHandle* ioctx); 96 : 97 : void setKeyFrameRequestCb(std::function<void()> cb); 98 : 99 : void findStreamInfo(bool videoStream = false); 100 : int selectStream(AVMediaType type); 101 : 102 308 : void setStreamCallback(unsigned stream, StreamCallback cb = {}) 103 : { 104 308 : if (streams_.size() <= stream) 105 304 : streams_.resize(stream + 1); 106 308 : streams_[stream] = std::move(cb); 107 308 : } 108 : 109 15 : void updateCurrentState(MediaDemuxer::CurrentState state) { currentState_ = state; } 110 : 111 : void setFileFinishedCb(std::function<void(bool)> cb); 112 : 113 : MediaDemuxer::CurrentState getCurrentState() { return currentState_; } 114 : 115 308 : AVStream* getStream(unsigned stream) 116 : { 117 308 : if (stream >= inputCtx_->nb_streams) { 118 0 : JAMI_ERR("Stream index is out of range: %u", stream); 119 0 : return {}; 120 : } 121 308 : return inputCtx_->streams[stream]; 122 : } 123 : 124 : Status decode(); 125 : Status demuxe(); 126 : 127 : int64_t getDuration() const; 128 : bool seekFrame(int stream_index, int64_t timestamp); 129 : void setNeedFrameCb(std::function<void()> cb); 130 : bool emitFrame(bool isAudio); 131 : 132 : private: 133 : bool streamInfoFound_ {false}; 134 : std::unique_ptr<asio::steady_timer> streamInfoTimer_; 135 : AVFormatContext* inputCtx_ = nullptr; 136 : std::vector<StreamCallback> streams_; 137 : int64_t startTime_; 138 : int64_t lastReadPacketTime_ {}; 139 : DeviceParams inputParams_; 140 : AVDictionary* options_ = nullptr; 141 : MediaDemuxer::CurrentState currentState_; 142 : std::mutex audioBufferMutex_ {}; 143 : std::mutex videoBufferMutex_ {}; 144 : std::queue<std::unique_ptr<AVPacket, std::function<void(AVPacket*)>>> videoBuffer_ {}; 145 : std::queue<std::unique_ptr<AVPacket, std::function<void(AVPacket*)>>> audioBuffer_ {}; 146 : std::function<void()> needFrameCb_; 147 : std::function<void(bool)> fileFinishedCb_; 148 : std::function<void()> keyFrameRequestCb_; 149 : void clearFrames(); 150 : bool pushFrameFrom(std::queue<std::unique_ptr<AVPacket, std::function<void(AVPacket*)>>>& buffer, 151 : bool isAudio, 152 : std::mutex& mutex); 153 : int baseWidth_ {}; 154 : int baseHeight_ {}; 155 : }; 156 : 157 : class MediaDecoder 158 : { 159 : public: 160 : MediaDecoder(); 161 : MediaDecoder(MediaObserver observer); 162 : MediaDecoder(const std::shared_ptr<MediaDemuxer>& demuxer, int index); 163 : MediaDecoder(const std::shared_ptr<MediaDemuxer>& demuxer, int index, MediaObserver observer); 164 : MediaDecoder(const std::shared_ptr<MediaDemuxer>& demuxer, AVMediaType type) 165 : : MediaDecoder(demuxer, demuxer->selectStream(type)) 166 : {} 167 : ~MediaDecoder(); 168 : 169 10 : void emulateRate() { emulateRate_ = true; } 170 : 171 : int openInput(const DeviceParams&); 172 : void setInterruptCallback(int (*cb)(void*), void* opaque); 173 : void setIOContext(MediaIOHandle* ioctx); 174 : 175 : int setup(AVMediaType type); 176 167 : int setupAudio() { return setup(AVMEDIA_TYPE_AUDIO); } 177 131 : int setupVideo() { return setup(AVMEDIA_TYPE_VIDEO); } 178 : void setKeyFrameRequestCb(std::function<void()> cb); 179 : 180 : MediaDemuxer::Status decode(); 181 : DecodeStatus flush(); 182 : 183 : int getWidth() const; 184 : int getHeight() const; 185 : std::string getDecoderName() const; 186 : 187 : rational<double> getFps() const; 188 : AVPixelFormat getPixelFormat() const; 189 : 190 : void updateStartTime(int64_t startTime); 191 : 192 : bool emitFrame(bool isAudio); 193 : void flushBuffers(); 194 : void setSeekTime(int64_t time); 195 : #ifdef ENABLE_HWACCEL 196 : void enableAccel(bool enableAccel); 197 : #endif 198 : 199 : MediaStream getStream(std::string name = "") const; 200 : 201 131 : void setResolutionChangedCallback(std::function<void(int, int)> cb) { resolutionChangedCallback_ = std::move(cb); } 202 : 203 166 : void setFEC(bool enable) { fecEnabled_ = enable; } 204 : 205 299 : void setContextCallback(const std::function<void()>& cb) 206 : { 207 299 : firstDecode_.exchange(true); 208 299 : contextCallback_ = cb; 209 299 : } 210 : 211 : private: 212 : NON_COPYABLE(MediaDecoder); 213 : 214 : DecodeStatus decode(AVPacket&); 215 : 216 : rational<unsigned> getTimeBase() const; 217 : 218 : std::shared_ptr<MediaDemuxer> demuxer_; 219 : 220 : const AVCodec* inputDecoder_ = nullptr; 221 : AVCodecContext* decoderCtx_ = nullptr; 222 : AVStream* avStream_ = nullptr; 223 : bool emulateRate_ = false; 224 : int64_t startTime_; 225 : int64_t lastTimestamp_ {0}; 226 : 227 : DeviceParams inputParams_; 228 : 229 : int correctPixFmt(int input_pix_fmt); 230 : int setupStream(); 231 : 232 : bool fallback_ = false; 233 : 234 : #ifdef ENABLE_HWACCEL 235 : bool enableAccel_ = true; 236 : std::unique_ptr<video::HardwareAccel> accel_; 237 : unsigned short accelFailures_ = 0; 238 : #endif 239 : MediaObserver callback_; 240 : int prepareDecoderContext(); 241 : int64_t seekTime_ = -1; 242 0 : void resetSeekTime() { seekTime_ = -1; } 243 : std::function<void(int, int)> resolutionChangedCallback_; 244 : 245 : int width_; 246 : int height_; 247 : 248 : bool fecEnabled_ {false}; 249 : 250 : std::function<void()> contextCallback_; 251 : std::atomic_bool firstDecode_ {true}; 252 : 253 : protected: 254 : AVDictionary* options_ = nullptr; 255 : }; 256 : 257 : } // namespace jami