Line data Source code
1 : /* 2 : * Copyright (C) 2004-2025 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 <map> 45 : #include <string> 46 : #include <memory> 47 : #include <chrono> 48 : #include <queue> 49 : 50 : extern "C" { 51 : struct AVCodecContext; 52 : struct AVStream; 53 : struct AVDictionary; 54 : struct AVFormatContext; 55 : struct AVCodec; 56 : enum AVMediaType; 57 : } 58 : 59 : namespace libjami { 60 : class AudioFrame; 61 : } 62 : 63 : namespace jami { 64 : 65 : using AudioFrame = libjami::AudioFrame; 66 : #ifdef ENABLE_VIDEO 67 : using VideoFrame = libjami::VideoFrame; 68 : #endif 69 : struct AudioFormat; 70 : class RingBuffer; 71 : class Resampler; 72 : class MediaIOHandle; 73 : class MediaDecoder; 74 : 75 : enum class DecodeStatus { Success, FrameFinished, EndOfFile, ReadError, DecodeError, RestartRequired, FallBack }; 76 : 77 : class MediaDemuxer 78 : { 79 : public: 80 : MediaDemuxer(); 81 : ~MediaDemuxer(); 82 : 83 : enum class Status { Success, EndOfFile, ReadBufferOverflow, ReadError, FallBack, RestartRequired }; 84 : 85 : static const char* getStatusStr(Status status); 86 : 87 : enum class CurrentState { Demuxing, Finished }; 88 : using StreamCallback = std::function<DecodeStatus(AVPacket&)>; 89 : 90 : int openInput(const DeviceParams&); 91 : 92 : void setInterruptCallback(int (*cb)(void*), void* opaque); 93 : void setIOContext(MediaIOHandle* ioctx); 94 : 95 : void findStreamInfo(); 96 : int selectStream(AVMediaType type); 97 : 98 330 : void setStreamCallback(unsigned stream, StreamCallback cb = {}) 99 : { 100 330 : if (streams_.size() <= stream) 101 326 : streams_.resize(stream + 1); 102 330 : streams_[stream] = std::move(cb); 103 330 : } 104 : 105 15 : void updateCurrentState(MediaDemuxer::CurrentState state) { currentState_ = state; } 106 : 107 : void setFileFinishedCb(std::function<void(bool)> cb); 108 : 109 : MediaDemuxer::CurrentState getCurrentState() { return currentState_; } 110 : 111 330 : AVStream* getStream(unsigned stream) 112 : { 113 330 : if (stream >= inputCtx_->nb_streams) { 114 0 : JAMI_ERR("Stream index is out of range: %u", stream); 115 0 : return {}; 116 : } 117 330 : return inputCtx_->streams[stream]; 118 : } 119 : 120 : Status decode(); 121 : Status demuxe(); 122 : 123 : int64_t getDuration() const; 124 : bool seekFrame(int stream_index, int64_t timestamp); 125 : void setNeedFrameCb(std::function<void()> cb); 126 : bool emitFrame(bool isAudio); 127 : 128 : private: 129 : bool streamInfoFound_ {false}; 130 : AVFormatContext* inputCtx_ = nullptr; 131 : std::vector<StreamCallback> streams_; 132 : int64_t startTime_; 133 : int64_t lastReadPacketTime_ {}; 134 : DeviceParams inputParams_; 135 : AVDictionary* options_ = nullptr; 136 : MediaDemuxer::CurrentState currentState_; 137 : std::mutex audioBufferMutex_ {}; 138 : std::mutex videoBufferMutex_ {}; 139 : std::queue<std::unique_ptr<AVPacket, std::function<void(AVPacket*)>>> videoBuffer_ {}; 140 : std::queue<std::unique_ptr<AVPacket, std::function<void(AVPacket*)>>> audioBuffer_ {}; 141 : std::function<void()> needFrameCb_; 142 : std::function<void(bool)> fileFinishedCb_; 143 : void clearFrames(); 144 : bool pushFrameFrom(std::queue<std::unique_ptr<AVPacket, std::function<void(AVPacket*)>>>& buffer, 145 : bool isAudio, 146 : std::mutex& mutex); 147 : int baseWidth_ {}; 148 : int baseHeight_ {}; 149 : }; 150 : 151 : class MediaDecoder 152 : { 153 : public: 154 : MediaDecoder(); 155 : MediaDecoder(MediaObserver observer); 156 : MediaDecoder(const std::shared_ptr<MediaDemuxer>& demuxer, int index); 157 : MediaDecoder(const std::shared_ptr<MediaDemuxer>& demuxer, int index, MediaObserver observer); 158 : MediaDecoder(const std::shared_ptr<MediaDemuxer>& demuxer, AVMediaType type) 159 : : MediaDecoder(demuxer, demuxer->selectStream(type)) 160 : {} 161 : ~MediaDecoder(); 162 : 163 10 : void emulateRate() { emulateRate_ = true; } 164 : 165 : int openInput(const DeviceParams&); 166 : void setInterruptCallback(int (*cb)(void*), void* opaque); 167 : void setIOContext(MediaIOHandle* ioctx); 168 : 169 : int setup(AVMediaType type); 170 181 : int setupAudio() { return setup(AVMEDIA_TYPE_AUDIO); } 171 139 : int setupVideo() { return setup(AVMEDIA_TYPE_VIDEO); } 172 : 173 : MediaDemuxer::Status decode(); 174 : DecodeStatus flush(); 175 : 176 : int getWidth() const; 177 : int getHeight() const; 178 : std::string getDecoderName() const; 179 : 180 : rational<double> getFps() const; 181 : AVPixelFormat getPixelFormat() const; 182 : 183 : void updateStartTime(int64_t startTime); 184 : 185 : bool emitFrame(bool isAudio); 186 : void flushBuffers(); 187 : void setSeekTime(int64_t time); 188 : #ifdef ENABLE_HWACCEL 189 : void enableAccel(bool enableAccel); 190 : #endif 191 : 192 : MediaStream getStream(std::string name = "") const; 193 : 194 139 : void setResolutionChangedCallback(std::function<void(int, int)> cb) { resolutionChangedCallback_ = std::move(cb); } 195 : 196 180 : void setFEC(bool enable) { fecEnabled_ = enable; } 197 : 198 321 : void setContextCallback(const std::function<void()>& cb) 199 : { 200 321 : firstDecode_.exchange(true); 201 321 : contextCallback_ = cb; 202 321 : } 203 : 204 : private: 205 : NON_COPYABLE(MediaDecoder); 206 : 207 : DecodeStatus decode(AVPacket&); 208 : 209 : rational<unsigned> getTimeBase() const; 210 : 211 : std::shared_ptr<MediaDemuxer> demuxer_; 212 : 213 : const AVCodec* inputDecoder_ = nullptr; 214 : AVCodecContext* decoderCtx_ = nullptr; 215 : AVStream* avStream_ = nullptr; 216 : bool emulateRate_ = false; 217 : int64_t startTime_; 218 : int64_t lastTimestamp_ {0}; 219 : 220 : DeviceParams inputParams_; 221 : 222 : int correctPixFmt(int input_pix_fmt); 223 : int setupStream(); 224 : 225 : bool fallback_ = false; 226 : 227 : #ifdef ENABLE_HWACCEL 228 : bool enableAccel_ = true; 229 : std::unique_ptr<video::HardwareAccel> accel_; 230 : unsigned short accelFailures_ = 0; 231 : #endif 232 : MediaObserver callback_; 233 : int prepareDecoderContext(); 234 : int64_t seekTime_ = -1; 235 0 : void resetSeekTime() { seekTime_ = -1; } 236 : std::function<void(int, int)> resolutionChangedCallback_; 237 : 238 : int width_; 239 : int height_; 240 : 241 : bool fecEnabled_ {false}; 242 : 243 : std::function<void()> contextCallback_; 244 : std::atomic_bool firstDecode_ {true}; 245 : 246 : protected: 247 : AVDictionary* options_ = nullptr; 248 : }; 249 : 250 : } // namespace jami