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