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