Ring Daemon
Loading...
Searching...
No Matches
media_decoder.h
Go to the documentation of this file.
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
25#ifdef ENABLE_VIDEO
26#include "video/video_base.h"
27#endif // ENABLE_VIDEO
28
29#ifdef ENABLE_HWACCEL
30#include "video/accel.h"
31#endif
32#include "logger.h"
33
34#include "media_device.h"
35#include "media_stream.h"
36#include "media_buffer.h"
37#include "noncopyable.h"
38
39#include <asio/steady_timer.hpp>
40
41#include <string>
42#include <memory>
43#include <queue>
44
45extern "C" {
46struct AVCodecContext;
47struct AVStream;
48struct AVDictionary;
49struct AVFormatContext;
50struct AVCodec;
51enum AVMediaType;
52}
53
54namespace libjami {
55class AudioFrame;
56}
57
58namespace jami {
59
61#ifdef ENABLE_VIDEO
63#endif
64struct AudioFormat;
65class RingBuffer;
66class Resampler;
67class MediaIOHandle;
68class MediaDecoder;
69
79
80class MediaDemuxer : public std::enable_shared_from_this<MediaDemuxer>
81{
82public:
85
87
88 static const char* getStatusStr(Status status);
89
91 using StreamCallback = std::function<DecodeStatus(AVPacket&)>;
92
93 int openInput(const DeviceParams&);
94
95 void setInterruptCallback(int (*cb)(void*), void* opaque);
97
98 void setKeyFrameRequestCb(std::function<void()> cb);
99
100 void findStreamInfo(bool videoStream = false);
101 int selectStream(AVMediaType type);
102
103 void setStreamCallback(unsigned stream, StreamCallback cb = {})
104 {
105 if (streams_.size() <= stream)
106 streams_.resize(stream + 1);
107 streams_[stream] = std::move(cb);
108 }
109
110 void updateCurrentState(MediaDemuxer::CurrentState state) { currentState_ = state; }
111
112 void setFileFinishedCb(std::function<void(bool)> cb);
113
114 MediaDemuxer::CurrentState getCurrentState() { return currentState_; }
115
116 AVStream* getStream(unsigned stream)
117 {
118 if (stream >= inputCtx_->nb_streams) {
119 JAMI_ERR("Stream index is out of range: %u", stream);
120 return {};
121 }
122 return inputCtx_->streams[stream];
123 }
124
125 Status decode();
126 Status demuxe();
127
128 int64_t getDuration() const;
129 bool seekFrame(int stream_index, int64_t timestamp);
130 void setNeedFrameCb(std::function<void()> cb);
131 bool emitFrame(bool isAudio);
132
133private:
134 bool streamInfoFound_ {false};
135 std::unique_ptr<asio::steady_timer> streamInfoTimer_;
136 AVFormatContext* inputCtx_ = nullptr;
137 std::vector<StreamCallback> streams_;
138 int64_t startTime_;
139 int64_t lastReadPacketTime_ {};
140 DeviceParams inputParams_;
141 AVDictionary* options_ = nullptr;
142 MediaDemuxer::CurrentState currentState_;
143 std::mutex inputCtxMutex_ {};
144 std::mutex audioBufferMutex_ {};
145 std::mutex videoBufferMutex_ {};
146 std::queue<std::unique_ptr<AVPacket, std::function<void(AVPacket*)>>> videoBuffer_ {};
147 std::queue<std::unique_ptr<AVPacket, std::function<void(AVPacket*)>>> audioBuffer_ {};
148 std::function<void()> needFrameCb_;
149 std::function<void(bool)> fileFinishedCb_;
150 std::function<void()> keyFrameRequestCb_;
151 void clearFrames();
152 bool pushFrameFrom(std::queue<std::unique_ptr<AVPacket, std::function<void(AVPacket*)>>>& buffer,
153 bool isAudio,
154 std::mutex& mutex);
155 int baseWidth_ {};
156 int baseHeight_ {};
157};
158
160{
161public:
162 MediaDecoder();
164 MediaDecoder(const std::shared_ptr<MediaDemuxer>& demuxer, int index);
165 MediaDecoder(const std::shared_ptr<MediaDemuxer>& demuxer, int index, MediaObserver observer);
166 MediaDecoder(const std::shared_ptr<MediaDemuxer>& demuxer, AVMediaType type)
167 : MediaDecoder(demuxer, demuxer->selectStream(type))
168 {}
170
171 void emulateRate() { emulateRate_ = true; }
172
173 int openInput(const DeviceParams&);
174 void setInterruptCallback(int (*cb)(void*), void* opaque);
176
177 int setup(AVMediaType type);
180 void setKeyFrameRequestCb(std::function<void()> cb);
181
184
185 int getWidth() const;
186 int getHeight() const;
187 std::string getDecoderName() const;
188
189 rational<double> getFps() const;
191
193
194 bool emitFrame(bool isAudio);
195 void flushBuffers();
197#ifdef ENABLE_HWACCEL
198 void enableAccel(bool enableAccel);
199#endif
200
201 MediaStream getStream(const std::string& name = "") const;
202
203 void setResolutionChangedCallback(std::function<void(int, int)> cb) { resolutionChangedCallback_ = std::move(cb); }
204
205 void setFEC(bool enable) { fecEnabled_ = enable; }
206
207 void setContextCallback(const std::function<void()>& cb)
208 {
209 firstDecode_.exchange(true);
210 contextCallback_ = cb;
211 }
212
213private:
215
217
218 rational<unsigned> getTimeBase() const;
219
220 std::shared_ptr<MediaDemuxer> demuxer_;
221
222 const AVCodec* inputDecoder_ = nullptr;
223 AVCodecContext* decoderCtx_ = nullptr;
224 AVStream* avStream_ = nullptr;
225 bool emulateRate_ = false;
226 int64_t startTime_;
227 int64_t lastTimestamp_ {0};
228
229 DeviceParams inputParams_;
230
231 int correctPixFmt(int input_pix_fmt);
232 int setupStream();
233
234 bool fallback_ = false;
235
236#ifdef ENABLE_HWACCEL
237 bool enableAccel_ = true;
238 std::unique_ptr<video::HardwareAccel> accel_;
239 unsigned short accelFailures_ = 0;
240#endif
241 MediaObserver callback_;
242 int prepareDecoderContext();
243 int64_t seekTime_ = -1;
244 void resetSeekTime() { seekTime_ = -1; }
245 std::function<void(int, int)> resolutionChangedCallback_;
246
247 int width_;
248 int height_;
249
250 bool fecEnabled_ {false};
251
252 std::function<void()> contextCallback_;
253 std::atomic_bool firstDecode_ {true};
254
255protected:
257};
258
259} // namespace jami
DecodeStatus flush()
void updateStartTime(int64_t startTime)
AVDictionary * options_
int setup(AVMediaType type)
void setKeyFrameRequestCb(std::function< void()> cb)
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
MediaStream getStream(const std::string &name="") 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 &)
void setKeyFrameRequestCb(std::function< void()> cb)
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 findStreamInfo(bool videoStream=false)
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: https://www....
Definition rational.h:39
#define JAMI_ERR(...)
Definition logger.h:230
void emitSignal(Args... args)
Definition jami_signal.h:64
libjami::VideoFrame VideoFrame
Definition video_base.h:49
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.