43#include <libavutil/display.h>
49 : frame_ {av_frame_alloc()}
52 throw std::bad_alloc();
65 packet_.reset(av_packet_alloc());
74 av_frame_unref(
frame_.get());
96 av_channel_layout_default(&d->ch_layout,
static_cast<int>(format.
nb_channels));
97 d->sample_rate =
static_cast<int>(format.
sample_rate);
110 return frame_->nb_samples;
114AudioFrame::reserve(
size_t nb_samples)
116 if (nb_samples != 0) {
118 d->nb_samples =
static_cast<int>(nb_samples);
120 if ((err = av_frame_get_buffer(d, 0)) < 0) {
121 throw std::bad_alloc();
131 if (f.ch_layout.nb_channels != fIn.ch_layout.nb_channels || f.format != fIn.format
132 || f.sample_rate != fIn.sample_rate) {
133 throw std::invalid_argument(
"Unable to mix frames with different formats");
135 if (f.nb_samples == 0) {
136 reserve(fIn.nb_samples);
138 }
else if (f.nb_samples != fIn.nb_samples) {
139 throw std::invalid_argument(
"Unable to mix frames with different length");
141 AVSampleFormat fmt = (AVSampleFormat) f.format;
142 bool isPlanar = av_sample_fmt_is_planar(fmt);
143 unsigned samplesPerChannel = isPlanar ? f.nb_samples : f.nb_samples * f.ch_layout.nb_channels;
144 unsigned channels = isPlanar ? f.ch_layout.nb_channels : 1;
145 if (fmt == AV_SAMPLE_FMT_S16 || fmt == AV_SAMPLE_FMT_S16P) {
146 for (
unsigned i = 0; i < channels; i++) {
147 auto* c = (int16_t*) f.extended_data[i];
148 auto* cIn = (int16_t*) fIn.extended_data[i];
149 for (
unsigned s = 0; s < samplesPerChannel; s++) {
150 c[s] =
static_cast<int16_t
>(std::clamp((int32_t) c[s] + (int32_t) cIn[s],
151 (int32_t) std::numeric_limits<int16_t>::min(),
152 (int32_t) std::numeric_limits<int16_t>::max()));
155 }
else if (fmt == AV_SAMPLE_FMT_FLT || fmt == AV_SAMPLE_FMT_FLTP) {
156 for (
unsigned i = 0; i < channels; i++) {
157 auto* c = (
float*) f.extended_data[i];
158 auto* cIn = (
float*) fIn.extended_data[i];
159 for (
unsigned s = 0; s < samplesPerChannel; s++) {
164 throw std::invalid_argument(std::string(
"Unsupported format for mixing: ") + av_get_sample_fmt_name(fmt));
172 auto fmt =
static_cast<AVSampleFormat
>(
frame_->format);
173 bool planar = av_sample_fmt_is_planar(fmt);
174 int perChannel = planar ?
frame_->nb_samples :
frame_->nb_samples *
frame_->ch_layout.nb_channels;
175 int channels = planar ?
frame_->ch_layout.nb_channels : 1;
176 if (fmt == AV_SAMPLE_FMT_S16 || fmt == AV_SAMPLE_FMT_S16P) {
177 for (
int c = 0; c < channels; ++c) {
178 auto* buf =
reinterpret_cast<int16_t*
>(
frame_->extended_data[c]);
179 for (
int i = 0; i < perChannel; ++i) {
180 auto sample =
static_cast<float>(buf[i]) * 0.000030517578125f;
181 rms += sample * sample;
184 }
else if (fmt == AV_SAMPLE_FMT_FLT || fmt == AV_SAMPLE_FMT_FLTP) {
185 for (
int c = 0; c < channels; ++c) {
186 auto* buf =
reinterpret_cast<float*
>(
frame_->extended_data[c]);
187 for (
int i = 0; i < perChannel; ++i) {
188 rms += buf[i] * buf[i];
193 JAMI_ERR() <<
"Unsupported format for getting volume level: " << av_get_sample_fmt_name(fmt);
197 return static_cast<float>(sqrt(rms / (
frame_->nb_samples *
frame_->ch_layout.nb_channels)));
204 if (releaseBufferCb_)
205 releaseBufferCb_(ptr_);
213 releaseBufferCb_ = {};
221 allocated_ = o.allocated_;
227 return av_image_get_buffer_size((AVPixelFormat)
frame_->format,
frame_->width,
frame_->height, 1);
249VideoFrame::setGeometry(
int format,
int width,
int height)
noexcept
251 frame_->format = format;
252 frame_->width = width;
253 frame_->height = height;
259 auto* libav_frame =
frame_.get();
263 if (
width == libav_frame->width and
height == libav_frame->height and
format == libav_frame->format)
264 av_frame_unref(libav_frame);
268 if (av_frame_get_buffer(libav_frame, 32))
269 throw std::bad_alloc();
271 releaseBufferCb_ = {};
278 setGeometry(format, width, height);
281 av_image_fill_arrays(frame_->data,
284 (AVPixelFormat) frame_->format,
292 uint8_t* ptr,
int format,
int width,
int height,
const std::function<
void(uint8_t*)>& cb)
noexcept
294 setFromMemory(ptr, format, width, height);
296 releaseBufferCb_ = cb;
305 releaseBufferCb_ = cb;
313 if (f->data[0] ==
nullptr)
315 for (std::size_t i = 0; i <
size(); ++i) {
316 f->data[0][i] = std::rand() & 255;
323 int32_t* matrix {
nullptr};
325 matrix =
reinterpret_cast<int32_t*
>(av_packet_get_side_data(p, AV_PKT_DATA_DISPLAYMATRIX,
nullptr));
326 }
else if (
const auto* p =
pointer()) {
327 if (AVFrameSideData* side_data = av_frame_get_side_data(p, AV_FRAME_DATA_DISPLAYMATRIX)) {
328 matrix =
reinterpret_cast<int32_t*
>(side_data->data);
332 double angle = av_display_rotation_get(matrix);
333 return std::isnan(angle) ? 0 : -(int) angle;
339getNewFrame(std::string_view
id)
342 if (
auto input = vm->getVideoInput(
id))
343 return &input->getNewFrame();
344 JAMI_WARNING(
"getNewFrame: Unable to find input {}",
id);
349publishFrame(std::string_view
id)
352 if (
auto input = vm->getVideoInput(
id))
353 input->publishFrame();
362std::vector<std::string>
366 return vm->videoDeviceMonitor.getDeviceList();
374 return vm->videoDeviceMonitor.getCapabilities(deviceId);
382 return vm->videoDeviceMonitor.getDefaultDevice();
389 JAMI_DBG(
"Setting default device to %s", deviceId.c_str());
391 if (vm->videoDeviceMonitor.setDefaultDevice(deviceId))
400 vm->setDeviceOrientation(deviceId, angle);
403std::map<std::string, std::string>
407 auto params = vm->videoDeviceMonitor.getDeviceParams(deviceId);
408 return {{
"format", params.format},
409 {
"width", std::to_string(params.width)},
410 {
"height", std::to_string(params.height)},
411 {
"rate", params.framerate.to_string()}};
416std::map<std::string, std::string>
420 return vm->videoDeviceMonitor.getSettings(deviceId).to_map();
426applySettings(
const std::string& deviceId,
const std::map<std::string, std::string>& settings)
429 vm->videoDeviceMonitor.applySettings(deviceId, settings);
438 auto id = path.empty() ? vm->videoDeviceMonitor.getMRLForDefaultDevice() : path;
439 auto& input = vm->clientVideoInputs[id];
452 return vm->clientVideoInputs.erase(
id) > 0;
462 vm->audioPreview = newPreview;
463 newPreview->switchInput(
"");
471 vm->audioPreview.reset();
477 auto rec = std::make_unique<jami::LocalRecorder>(videoInputId);
478 rec->setPath(filepath);
481 auto path = rec->getPath();
486 recordManager.insertRecorder(path, std::move(rec));
487 }
catch (
const std::invalid_argument&) {
491 auto ret = recordManager.getRecorderByPath(path)->start();
493 recordManager.removeRecorderByPath(filepath);
505 JAMI_WARN(
"Unable to stop non existing local recorder.");
518 sink->registerTarget(std::move(target));
521 JAMI_WARN(
"No sink found for id '%s'", sinkId.c_str());
528startShmSink(
const std::string& sinkId,
bool value)
532 sink->enableShm(value);
534 JAMI_WARN(
"No sink found for id '%s'", sinkId.c_str());
539std::map<std::string, std::string>
622 JAMI_DBG(
"%s hardware acceleration", (state ?
"Enabling" :
"Disabling"));
642 JAMI_DBG(
"%s hardware acceleration", (state ?
"Enabling" :
"Disabling"));
650 acc->setCodecActive(AV_CODEC_ID_HEVC);
652 acc->setCodecInactive(AV_CODEC_ID_HEVC);
654 acc->setActiveCodecs(acc->getActiveCodecs());
659#if defined(__ANDROID__) || (defined(TARGET_OS_IOS) && TARGET_OS_IOS)
661addVideoDevice(
const std::string& node,
const std::vector<std::map<std::string, std::string>>& devInfo)
664 videoManager->videoDeviceMonitor.addDevice(node, devInfo);
669removeVideoDevice(
const std::string& node)
672 videoManager->videoDeviceMonitor.removeDevice(node);
682video::VideoDeviceMonitor*
686 return &
vm->videoDeviceMonitor;
690std::shared_ptr<video::VideoInput>
697 std::lock_guard<std::mutex>
lk(
vmgr->videoMutex);
698 auto it =
vmgr->videoInputs.find(sinkId);
699 if (
it !=
vmgr->videoInputs.end()) {
700 if (
auto input =
it->second.lock()) {
706 vmgr->videoInputs[sinkId] = input;
711VideoManager::setDeviceOrientation(
const std::string& deviceId,
int angle)
717std::shared_ptr<AudioInput>
723 std::lock_guard<std::mutex>
lk(
vmgr->audioMutex);
726 for (
auto it =
vmgr->audioInputs.cbegin();
it !=
vmgr->audioInputs.cend();) {
727 if (
it->second.expired())
733 auto it =
vmgr->audioInputs.find(device);
734 if (
it !=
vmgr->audioInputs.end()) {
735 if (
auto input =
it->second.lock()) {
740 auto input = std::make_shared<AudioInput>(device);
741 vmgr->audioInputs[device] = input;
749 std::scoped_lock<std::mutex>
lk(
vmgr->mediaPlayersMutex);
750 return !
vmgr->mediaPlayers.empty();
755std::shared_ptr<MediaPlayer>
759 std::scoped_lock<std::mutex>
lk(
vmgr->mediaPlayersMutex);
760 auto it =
vmgr->mediaPlayers.find(
id);
761 if (
it !=
vmgr->mediaPlayers.end()) {
772 std::scoped_lock<std::mutex>
lk(
vmgr->mediaPlayersMutex);
775 player = std::make_shared<MediaPlayer>(path);
796 std::scoped_lock<std::mutex>
lk(
vm->mediaPlayersMutex);
797 return vm->mediaPlayers.erase(
id) > 0;
824 return player->getPlayerPosition();
832 return player->getPlayerDuration();
840 player->setAutoRestart(restart);
static LocalRecorderManager & instance()
LocalRecorder * getRecorderByPath(const std::string &path)
Get local recorder instance with passed path as key.
void removeRecorderByPath(const std::string &path)
Remove given local recorder instance from the map.
void stopRecording() override
Stops recording.
std::vector< std::shared_ptr< T > > getAllAccounts() const
Get a list of account pointers of type T (baseclass Account)
static LIBJAMI_TEST_EXPORT Manager & instance()
void saveConfig()
Save config to file.
VideoManager * getVideoManager() const
static const char *const DEFAULT_ID
void mix(const AudioFrame &o)
size_t getFrameSize() const
jami::AudioFormat getFormat() const
void reserve(int format, int width, int height)
std::size_t size() const noexcept
int format() const noexcept
void setFromMemory(uint8_t *data, int format, int width, int height) noexcept
int height() const noexcept
int getOrientation() const
int width() const noexcept
void setReleaseCb(const std::function< void(uint8_t *)> &cb) noexcept
void reset() noexcept override
void copyFrom(const VideoFrame &o)
#define JAMI_WARNING(formatstr,...)
void fillWithSilence(AVFrame *frame)
std::shared_ptr< MediaPlayer > getMediaPlayer(const std::string &id)
bool closeMediaPlayer(const std::string &id)
void emitSignal(Args... args)
libjami::VideoFrame VideoFrame
std::shared_ptr< AudioInput > getAudioInput(const std::string &device)
int64_t getPlayerDuration(const std::string &id)
void setAutoRestart(const std::string &id, bool restart)
bool playerSeekToTime(const std::string &id, int time)
int64_t getPlayerPosition(const std::string &id)
bool pausePlayer(const std::string &id, bool pause)
std::string createMediaPlayer(const std::string &path)
bool mutePlayerAudio(const std::string &id, bool mute)
LIBJAMI_PUBLIC void applySettings(const std::string &deviceId, const std::map< std::string, std::string > &settings)
LIBJAMI_PUBLIC std::map< std::string, std::string > getDeviceParams(const std::string &deviceId)
bool closeMediaPlayer(const std::string &id)
LIBJAMI_PUBLIC std::string getDefaultDevice()
bool getEncodingAccelerated()
std::string startLocalMediaRecorder(const std::string &videoInputId, const std::string &filepath)
bool playerSeekToTime(const std::string &id, const int &time)
std::map< std::string, std::string > getRenderer(const std::string &callId)
LIBJAMI_PUBLIC VideoCapabilities getCapabilities(const std::string &deviceId)
void setEncodingAccelerated(bool state)
bool registerSinkTarget(const std::string &sinkId, SinkTarget target)
LIBJAMI_PUBLIC void setDefaultDevice(const std::string &deviceId)
LIBJAMI_PUBLIC std::map< std::string, std::string > getSettings(const std::string &deviceId)
std::unique_ptr< AVPacket, AVPacket_deleter > PacketBuffer
bool pausePlayer(const std::string &id, const bool &pause)
void registerSignalHandlers(const std::map< std::string, std::shared_ptr< CallbackWrapperBase > > &handlers)
LIBJAMI_PUBLIC void registerVideoHandlers(const std::map< std::string, std::shared_ptr< CallbackWrapperBase > > &)
std::string createMediaPlayer(const std::string &path)
void setDecodingAccelerated(bool state)
void stopLocalRecorder(const std::string &filepath)
LIBJAMI_PUBLIC std::vector< std::string > getDeviceList()
bool getDecodingAccelerated()
LIBJAMI_PUBLIC std::string openVideoInput(const std::string &path)
std::map< std::string, std::map< std::string, std::vector< std::string > > > VideoCapabilities
int64_t getPlayerPosition(const std::string &id)
int64_t getPlayerDuration(const std::string &id)
LIBJAMI_PUBLIC void setDeviceOrientation(const std::string &deviceId, int angle)
LIBJAMI_PUBLIC bool closeVideoInput(const std::string &id)
void setAutoRestart(const std::string &id, const bool &restart)
bool mutePlayerAudio(const std::string &id, const bool &mute)