Ring Daemon 16.0.0
Loading...
Searching...
No Matches
media_decoder.h
Go to the documentation of this file.
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 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
50extern "C" {
51struct AVCodecContext;
52struct AVStream;
53struct AVDictionary;
54struct AVFormatContext;
55struct AVCodec;
56enum AVMediaType;
57}
58
59namespace libjami {
60class AudioFrame;
61}
62
63namespace jami {
64
66#ifdef ENABLE_VIDEO
68#endif
69struct AudioFormat;
70class RingBuffer;
71class Resampler;
72class MediaIOHandle;
73class MediaDecoder;
74
84
86{
87public:
90
91 enum class Status {
92 Success,
98 };
99
100 static const char* getStatusStr(Status status);
101
103 using StreamCallback = std::function<DecodeStatus(AVPacket&)>;
104
105 int openInput(const DeviceParams&);
106
107 void setInterruptCallback(int (*cb)(void*), void* opaque);
109
110 void findStreamInfo();
111 int selectStream(AVMediaType type);
112
113 void setStreamCallback(unsigned stream, StreamCallback cb = {})
114 {
115 if (streams_.size() <= stream)
116 streams_.resize(stream + 1);
117 streams_[stream] = std::move(cb);
118 }
119
120 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 AVStream* getStream(unsigned stream)
127 {
128 if (stream >= inputCtx_->nb_streams) {
129 JAMI_ERR("Stream index is out of range: %u", stream);
130 return {};
131 }
132 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
143private:
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
167{
168public:
169 MediaDecoder();
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 {}
177
178 void emulateRate() { emulateRate_ = true; }
179
180 int openInput(const DeviceParams&);
181 void setInterruptCallback(int (*cb)(void*), void* opaque);
183
184 int setup(AVMediaType type);
187
190
191 int getWidth() const;
192 int getHeight() const;
193 std::string getDecoderName() const;
194
195 rational<double> getFps() const;
197
199
200 bool emitFrame(bool isAudio);
201 void flushBuffers();
203#ifdef RING_ACCEL
204 void enableAccel(bool enableAccel);
205#endif
206
207 MediaStream getStream(std::string name = "") const;
208
209 void setResolutionChangedCallback(std::function<void(int, int)> cb)
210 {
211 resolutionChangedCallback_ = std::move(cb);
212 }
213
214 void setFEC(bool enable) { fecEnabled_ = enable; }
215
216 void setContextCallback(const std::function<void()>& cb)
217 {
218 firstDecode_.exchange(true);
219 contextCallback_ = cb;
220 }
221
222private:
224
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 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
264protected:
266};
267
268} // namespace jami
DecodeStatus flush()
void updateStartTime(int64_t startTime)
AVDictionary * options_
MediaStream getStream(std::string name="") const
int setup(AVMediaType type)
void setResolutionChangedCallback(std::function< void(int, int)> cb)
void setIOContext(MediaIOHandle *ioctx)
int openInput(const DeviceParams &)
bool emitFrame(bool isAudio)
void setInterruptCallback(int(*cb)(void *), void *opaque)
MediaDemuxer::Status decode()
rational< double > getFps() const
AVPixelFormat getPixelFormat() const
MediaDecoder(const std::shared_ptr< MediaDemuxer > &demuxer, AVMediaType type)
void setSeekTime(int64_t time)
std::string getDecoderName() const
void setContextCallback(const std::function< void()> &cb)
void setFEC(bool enable)
int openInput(const DeviceParams &)
MediaDemuxer::CurrentState getCurrentState()
void setInterruptCallback(int(*cb)(void *), void *opaque)
void setIOContext(MediaIOHandle *ioctx)
static const char * getStatusStr(Status status)
bool seekFrame(int stream_index, int64_t timestamp)
void updateCurrentState(MediaDemuxer::CurrentState state)
int64_t getDuration() const
void setStreamCallback(unsigned stream, StreamCallback cb={})
int selectStream(AVMediaType type)
AVStream * getStream(unsigned stream)
bool emitFrame(bool isAudio)
void setNeedFrameCb(std::function< void()> cb)
void setFileFinishedCb(std::function< void(bool)> cb)
std::function< DecodeStatus(AVPacket &)> StreamCallback
Naive implementation of the boost::rational interface, described here: http://www....
Definition rational.h:38
#define JAMI_ERR(...)
Definition logger.h:218
void emitSignal(Args... args)
Definition ring_signal.h:64
libjami::VideoFrame VideoFrame
Definition video_base.h:53
std::function< void(std::shared_ptr< MediaFrame > &&)> MediaObserver
libjami::AudioFrame AudioFrame
Simple macro to hide class' copy constructor and assignment operator.
#define NON_COPYABLE(ClassName)
Definition noncopyable.h:30
DeviceParams Parameters used by MediaDecoder and MediaEncoder to open a LibAV device/stream.