Line data Source code
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 :
18 : #include "libav_deps.h" // MUST BE INCLUDED FIRST
19 : #include "media_decoder.h"
20 : #include "media_device.h"
21 : #include "media_buffer.h"
22 : #include "media_io_handle.h"
23 : #include "audio/ringbufferpool.h"
24 : #include "decoder_finder.h"
25 : #include "manager.h"
26 :
27 : #ifdef ENABLE_HWACCEL
28 : #include "video/accel.h"
29 : #endif
30 :
31 : #include "string_utils.h"
32 : #include "logger.h"
33 : #include "client/jami_signal.h"
34 :
35 : #include <unistd.h>
36 : #include <cstddef>
37 : #include <thread> // hardware_concurrency
38 : #include <chrono>
39 : #include <algorithm>
40 : #include <asio/steady_timer.hpp>
41 :
42 : namespace jami {
43 :
44 : // maximum number of packets the jitter buffer can queue
45 : const unsigned jitterBufferMaxSize_ {1500};
46 : // maximum time a packet can be queued
47 : const constexpr auto jitterBufferMaxDelay_ = std::chrono::milliseconds(50);
48 :
49 370 : MediaDemuxer::MediaDemuxer()
50 370 : : inputCtx_(avformat_alloc_context())
51 740 : , startTime_(AV_NOPTS_VALUE)
52 370 : {}
53 :
54 370 : MediaDemuxer::~MediaDemuxer()
55 : {
56 370 : if (streamInfoTimer_) {
57 0 : streamInfoTimer_->cancel();
58 0 : streamInfoTimer_.reset();
59 : }
60 370 : if (inputCtx_)
61 316 : avformat_close_input(&inputCtx_);
62 370 : av_dict_free(&options_);
63 370 : }
64 :
65 : const char*
66 0 : MediaDemuxer::getStatusStr(Status status)
67 : {
68 0 : switch (status) {
69 0 : case Status::Success:
70 0 : return "Success";
71 0 : case Status::EndOfFile:
72 0 : return "End of file";
73 0 : case Status::ReadBufferOverflow:
74 0 : return "Read overflow";
75 0 : case Status::ReadError:
76 0 : return "Read error";
77 0 : case Status::FallBack:
78 0 : return "Fallback";
79 0 : case Status::RestartRequired:
80 0 : return "Restart required";
81 0 : default:
82 0 : return "Undefined";
83 : }
84 : }
85 :
86 : int
87 370 : MediaDemuxer::openInput(const DeviceParams& params)
88 : {
89 370 : inputParams_ = params;
90 370 : const auto* iformat = av_find_input_format(params.format.c_str());
91 :
92 369 : if (!iformat && !params.format.empty())
93 1 : JAMI_WARN("Unable to find format \"%s\"", params.format.c_str());
94 :
95 369 : std::string input;
96 :
97 370 : if (params.input == "pipewiregrab") {
98 : //
99 : // We rely on pipewiregrab for screen/window sharing on Wayland.
100 : // Because pipewiregrab is a "video source filter" (part of FFmpeg's libavfilter
101 : // library), its options must all be passed as part of the `input` string.
102 : //
103 0 : input = fmt::format("pipewiregrab=draw_mouse=1:fd={}:node={}", params.fd, params.node);
104 0 : JAMI_LOG("Attempting to open input {}", input);
105 : //
106 : // In all other cases, we use the `options_` AVDictionary to pass options to FFmpeg.
107 : //
108 : // NOTE: We rely on the "lavfi" virtual input device to read pipewiregrab's output
109 : // and create a corresponding stream (cf. the getDeviceParams function in
110 : // daemon/src/media/video/v4l2/video_device_impl.cpp). The `options_` dictionary
111 : // could be used to set lavfi's parameters if that was ever needed, but it isn't at
112 : // the moment. (Doc: https://ffmpeg.org/ffmpeg-devices.html#lavfi)
113 : //
114 : } else {
115 370 : if (params.width and params.height) {
116 0 : auto sizeStr = fmt::format("{}x{}", params.width, params.height);
117 0 : av_dict_set(&options_, "video_size", sizeStr.c_str(), 0);
118 0 : }
119 :
120 370 : if (params.framerate) {
121 : #ifdef _WIN32
122 : // On Windows, framerate settings don't reduce to avrational values
123 : // that correspond to valid video device formats.
124 : // e.g. A the rational<double>(10000000, 333333) or 30.000030000
125 : // will be reduced by av_reduce to 999991/33333 or 30.00003000003
126 : // which cause the device opening routine to fail.
127 : // So we treat this imprecise reduction and adjust the value,
128 : // or let dshow choose the framerate, which is, unfortunately,
129 : // NOT the highest according to our experimentations.
130 : auto framerate {params.framerate.real()};
131 : framerate = params.framerate.numerator() / (params.framerate.denominator() + 0.5);
132 : if (params.framerate.denominator() != 4999998)
133 : av_dict_set(&options_, "framerate", jami::to_string(framerate).c_str(), 0);
134 : #else
135 1 : av_dict_set(&options_, "framerate", jami::to_string(params.framerate.real()).c_str(), 0);
136 : #endif
137 : }
138 :
139 370 : if (params.offset_x || params.offset_y) {
140 0 : av_dict_set(&options_, "offset_x", std::to_string(params.offset_x).c_str(), 0);
141 0 : av_dict_set(&options_, "offset_y", std::to_string(params.offset_y).c_str(), 0);
142 : }
143 370 : if (params.channel)
144 0 : av_dict_set(&options_, "channel", std::to_string(params.channel).c_str(), 0);
145 370 : av_dict_set(&options_, "loop", params.loop.c_str(), 0);
146 370 : av_dict_set(&options_, "sdp_flags", params.sdp_flags.c_str(), 0);
147 :
148 : // Set jitter buffer options
149 370 : av_dict_set(&options_, "reorder_queue_size", std::to_string(jitterBufferMaxSize_).c_str(), 0);
150 369 : auto us = std::chrono::duration_cast<std::chrono::microseconds>(jitterBufferMaxDelay_).count();
151 369 : av_dict_set(&options_, "max_delay", std::to_string(us).c_str(), 0);
152 :
153 369 : if (!params.pixel_format.empty()) {
154 0 : av_dict_set(&options_, "pixel_format", params.pixel_format.c_str(), 0);
155 : }
156 369 : if (!params.window_id.empty()) {
157 0 : av_dict_set(&options_, "window_id", params.window_id.c_str(), 0);
158 : }
159 369 : av_dict_set(&options_, "draw_mouse", "1", 0);
160 370 : av_dict_set(&options_, "is_area", std::to_string(params.is_area).c_str(), 0);
161 :
162 : #if defined(__APPLE__) && TARGET_OS_MAC
163 : input = params.name;
164 : #else
165 370 : input = params.input;
166 : #endif
167 :
168 1479 : JAMI_LOG("Attempting to open input {} with format {}, pixel format {}, size {}x{}, rate {}",
169 : input,
170 : params.format,
171 : params.pixel_format,
172 : params.width,
173 : params.height,
174 : params.framerate.real());
175 : }
176 :
177 : // Ask FFmpeg to open the input using the options set above
178 370 : if (params.disable_dts_probe_delay && params.format == "sdp") {
179 134 : av_opt_set_int(inputCtx_, "max_ts_probe", 0, AV_OPT_SEARCH_CHILDREN);
180 134 : av_opt_set_int(inputCtx_, "fpsprobesize", 0, AV_OPT_SEARCH_CHILDREN);
181 : } else {
182 : // Don't waste time fetching framerate when finding stream info
183 236 : av_opt_set_int(inputCtx_, "fpsprobesize", 1, AV_OPT_SEARCH_CHILDREN);
184 : }
185 :
186 370 : int ret = avformat_open_input(&inputCtx_, input.c_str(), iformat, options_ ? &options_ : NULL);
187 :
188 370 : if (ret) {
189 216 : JAMI_ERROR("avformat_open_input failed: {}", libav_utils::getError(ret));
190 316 : } else if (inputCtx_->nb_streams > 0 && inputCtx_->streams[0]->codecpar) {
191 316 : baseWidth_ = inputCtx_->streams[0]->codecpar->width;
192 316 : baseHeight_ = inputCtx_->streams[0]->codecpar->height;
193 1264 : JAMI_LOG("Opened input using format {:s} and resolution {:d}x{:d}", params.format, baseWidth_, baseHeight_);
194 : }
195 :
196 370 : return ret;
197 370 : }
198 :
199 : int64_t
200 5 : MediaDemuxer::getDuration() const
201 : {
202 5 : return inputCtx_->duration;
203 : }
204 :
205 : bool
206 9 : MediaDemuxer::seekFrame(int, int64_t timestamp)
207 : {
208 9 : std::lock_guard lk(inputCtxMutex_);
209 9 : if (av_seek_frame(inputCtx_, -1, timestamp, AVSEEK_FLAG_BACKWARD) >= 0) {
210 9 : clearFrames();
211 9 : return true;
212 : }
213 0 : return false;
214 9 : }
215 :
216 : void
217 316 : MediaDemuxer::findStreamInfo(bool videoStream)
218 : {
219 316 : if (not streamInfoFound_) {
220 316 : inputCtx_->max_analyze_duration = 30l * AV_TIME_BASE;
221 316 : if (videoStream && keyFrameRequestCb_) {
222 134 : if (!streamInfoTimer_)
223 134 : streamInfoTimer_ = std::make_unique<asio::steady_timer>(*Manager::instance().ioContext());
224 134 : streamInfoTimer_->expires_after(std::chrono::milliseconds(1500));
225 134 : streamInfoTimer_->async_wait([weak = weak_from_this()](const std::error_code& ec) {
226 134 : if (ec)
227 66 : return;
228 68 : if (auto self = weak.lock()) {
229 68 : if (!self->streamInfoFound_) {
230 272 : JAMI_LOG("findStreamInfo: 1500ms elapsed, requesting keyframe to aid probing");
231 68 : if (self->keyFrameRequestCb_)
232 68 : self->keyFrameRequestCb_();
233 : }
234 68 : }
235 : });
236 : }
237 :
238 316 : int err = avformat_find_stream_info(inputCtx_, nullptr);
239 316 : if (err < 0) {
240 0 : JAMI_ERROR("Unable to find stream info: {}", libav_utils::getError(err));
241 : }
242 316 : streamInfoFound_ = true;
243 316 : if (streamInfoTimer_) {
244 134 : streamInfoTimer_->cancel();
245 134 : streamInfoTimer_.reset();
246 : }
247 : }
248 316 : }
249 :
250 : int
251 322 : MediaDemuxer::selectStream(AVMediaType type)
252 : {
253 322 : auto sti = av_find_best_stream(inputCtx_, type, -1, -1, nullptr, 0);
254 322 : if (type == AVMEDIA_TYPE_VIDEO && sti >= 0) {
255 140 : auto* st = inputCtx_->streams[sti];
256 140 : auto disposition = st->disposition;
257 140 : if (disposition & AV_DISPOSITION_ATTACHED_PIC) {
258 1 : JAMI_DBG("Skipping attached picture stream");
259 1 : sti = -1;
260 : }
261 : }
262 322 : return sti;
263 : }
264 :
265 : void
266 318 : MediaDemuxer::setInterruptCallback(int (*cb)(void*), void* opaque)
267 : {
268 318 : if (cb) {
269 319 : inputCtx_->interrupt_callback.callback = cb;
270 319 : inputCtx_->interrupt_callback.opaque = opaque;
271 : } else {
272 0 : inputCtx_->interrupt_callback.callback = 0;
273 : }
274 318 : }
275 : void
276 6 : MediaDemuxer::setNeedFrameCb(std::function<void()> cb)
277 : {
278 6 : needFrameCb_ = std::move(cb);
279 6 : }
280 :
281 : void
282 6 : MediaDemuxer::setFileFinishedCb(std::function<void(bool)> cb)
283 : {
284 6 : fileFinishedCb_ = std::move(cb);
285 6 : }
286 :
287 : void
288 134 : MediaDemuxer::setKeyFrameRequestCb(std::function<void()> cb)
289 : {
290 134 : keyFrameRequestCb_ = std::move(cb);
291 134 : }
292 :
293 : void
294 9 : MediaDemuxer::clearFrames()
295 : {
296 : {
297 9 : std::lock_guard lk {videoBufferMutex_};
298 9 : while (!videoBuffer_.empty()) {
299 0 : videoBuffer_.pop();
300 : }
301 9 : }
302 : {
303 9 : std::lock_guard lk {audioBufferMutex_};
304 9 : while (!audioBuffer_.empty()) {
305 0 : audioBuffer_.pop();
306 : }
307 9 : }
308 9 : }
309 :
310 : bool
311 0 : MediaDemuxer::emitFrame(bool isAudio)
312 : {
313 0 : if (isAudio) {
314 0 : return pushFrameFrom(audioBuffer_, isAudio, audioBufferMutex_);
315 : } else {
316 0 : return pushFrameFrom(videoBuffer_, isAudio, videoBufferMutex_);
317 : }
318 : }
319 :
320 : bool
321 0 : MediaDemuxer::pushFrameFrom(std::queue<std::unique_ptr<AVPacket, std::function<void(AVPacket*)>>>& buffer,
322 : bool isAudio,
323 : std::mutex& mutex)
324 : {
325 0 : std::unique_lock lock(mutex);
326 0 : if (buffer.empty()) {
327 0 : if (currentState_ == MediaDemuxer::CurrentState::Finished) {
328 0 : fileFinishedCb_(isAudio);
329 : } else {
330 0 : needFrameCb_();
331 : }
332 0 : return false;
333 : }
334 0 : auto packet = std::move(buffer.front());
335 0 : if (!packet) {
336 0 : return false;
337 : }
338 0 : auto streamIndex = packet->stream_index;
339 0 : if (static_cast<unsigned>(streamIndex) >= streams_.size() || streamIndex < 0) {
340 0 : return false;
341 : }
342 0 : if (auto& cb = streams_[streamIndex]) {
343 0 : buffer.pop();
344 0 : lock.unlock();
345 0 : cb(*packet.get());
346 : }
347 0 : return true;
348 0 : }
349 :
350 : MediaDemuxer::Status
351 0 : MediaDemuxer::demuxe()
352 : {
353 0 : auto packet = std::unique_ptr<AVPacket, std::function<void(AVPacket*)>>(av_packet_alloc(), [](AVPacket* p) {
354 0 : if (p)
355 0 : av_packet_free(&p);
356 0 : });
357 :
358 : bool isVideo;
359 : {
360 0 : std::lock_guard lk(inputCtxMutex_);
361 0 : int ret = av_read_frame(inputCtx_, packet.get());
362 0 : if (ret == AVERROR(EAGAIN)) {
363 0 : return Status::Success;
364 0 : } else if (ret == AVERROR_EOF) {
365 0 : return Status::EndOfFile;
366 0 : } else if (ret < 0) {
367 0 : JAMI_ERR("Unable to read frame: %s\n", libav_utils::getError(ret).c_str());
368 0 : return Status::ReadError;
369 : }
370 :
371 0 : auto streamIndex = packet->stream_index;
372 0 : if (static_cast<unsigned>(streamIndex) >= streams_.size() || streamIndex < 0) {
373 0 : return Status::Success;
374 : }
375 :
376 0 : isVideo = inputCtx_->streams[streamIndex]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO;
377 0 : }
378 :
379 0 : if (isVideo) {
380 0 : std::lock_guard lk {videoBufferMutex_};
381 0 : videoBuffer_.push(std::move(packet));
382 0 : if (videoBuffer_.size() >= 90) {
383 0 : return Status::ReadBufferOverflow;
384 : }
385 0 : } else {
386 0 : std::lock_guard lk {audioBufferMutex_};
387 0 : audioBuffer_.push(std::move(packet));
388 0 : if (audioBuffer_.size() >= 300) {
389 0 : return Status::ReadBufferOverflow;
390 : }
391 0 : }
392 0 : return Status::Success;
393 0 : }
394 :
395 : void
396 618 : MediaDemuxer::setIOContext(MediaIOHandle* ioctx)
397 : {
398 618 : inputCtx_->pb = ioctx->getContext();
399 618 : }
400 :
401 : MediaDemuxer::Status
402 5218 : MediaDemuxer::decode()
403 : {
404 5218 : if (inputParams_.format == "x11grab" || inputParams_.format == "dxgigrab") {
405 0 : auto ret = inputCtx_->iformat->read_header(inputCtx_);
406 0 : if (ret == AVERROR_EXTERNAL) {
407 0 : JAMI_ERR("Unable to read frame: %s\n", libav_utils::getError(ret).c_str());
408 0 : return Status::ReadError;
409 : }
410 0 : auto* codecpar = inputCtx_->streams[0]->codecpar;
411 0 : if (baseHeight_ != codecpar->height || baseWidth_ != codecpar->width) {
412 0 : baseHeight_ = codecpar->height;
413 0 : baseWidth_ = codecpar->width;
414 0 : inputParams_.height = ((baseHeight_ >> 3) << 3);
415 0 : inputParams_.width = ((baseWidth_ >> 3) << 3);
416 0 : return Status::RestartRequired;
417 : }
418 : }
419 :
420 5218 : libjami::PacketBuffer packet(av_packet_alloc());
421 5218 : int ret = av_read_frame(inputCtx_, packet.get());
422 5218 : if (ret == AVERROR(EAGAIN)) {
423 : /*no data available. Calculate time until next frame.
424 : We do not use the emulated frame mechanism from the decoder because it will affect all
425 : platforms. With the current implementation, the demuxer will be waiting just in case when
426 : av_read_frame returns EAGAIN. For some platforms, av_read_frame is blocking and it will
427 : never happen.
428 : */
429 0 : if (inputParams_.framerate.numerator() == 0)
430 0 : return Status::Success;
431 0 : rational<double> frameTime = 1e6 / inputParams_.framerate;
432 0 : int64_t timeToSleep = lastReadPacketTime_ - av_gettime_relative() + frameTime.real<int64_t>();
433 0 : if (timeToSleep <= 0) {
434 0 : return Status::Success;
435 : }
436 0 : std::this_thread::sleep_for(std::chrono::microseconds(timeToSleep));
437 0 : return Status::Success;
438 5218 : } else if (ret == AVERROR_EOF) {
439 118 : return Status::EndOfFile;
440 5100 : } else if (ret == AVERROR(EACCES)) {
441 0 : return Status::RestartRequired;
442 5100 : } else if (ret < 0) {
443 0 : auto media = inputCtx_->streams[0]->codecpar->codec_type;
444 0 : const auto* const type = media == AVMediaType::AVMEDIA_TYPE_AUDIO
445 0 : ? "AUDIO"
446 0 : : (media == AVMediaType::AVMEDIA_TYPE_VIDEO ? "VIDEO" : "UNSUPPORTED");
447 0 : JAMI_ERR("Unable to read [%s] frame: %s\n", type, libav_utils::getError(ret).c_str());
448 0 : return Status::ReadError;
449 : }
450 :
451 5100 : auto streamIndex = packet->stream_index;
452 5100 : if (static_cast<unsigned>(streamIndex) >= streams_.size() || streamIndex < 0) {
453 0 : return Status::Success;
454 : }
455 :
456 5100 : lastReadPacketTime_ = av_gettime_relative();
457 :
458 5100 : auto& cb = streams_[streamIndex];
459 5100 : if (cb) {
460 5100 : DecodeStatus ret = cb(*packet.get());
461 5100 : if (ret == DecodeStatus::FallBack)
462 0 : return Status::FallBack;
463 : }
464 5100 : return Status::Success;
465 5218 : }
466 :
467 0 : MediaDecoder::MediaDecoder(const std::shared_ptr<MediaDemuxer>& demuxer, int index)
468 0 : : demuxer_(demuxer)
469 0 : , avStream_(demuxer->getStream(index))
470 : {
471 0 : demuxer->setStreamCallback(index, [this](AVPacket& packet) { return decode(packet); });
472 0 : setupStream();
473 0 : }
474 :
475 10 : MediaDecoder::MediaDecoder(const std::shared_ptr<MediaDemuxer>& demuxer, int index, MediaObserver observer)
476 10 : : demuxer_(demuxer)
477 10 : , avStream_(demuxer->getStream(index))
478 20 : , callback_(std::move(observer))
479 : {
480 10 : demuxer->setStreamCallback(index, [this](AVPacket& packet) { return decode(packet); });
481 10 : setupStream();
482 10 : }
483 :
484 : bool
485 0 : MediaDecoder::emitFrame(bool isAudio)
486 : {
487 0 : return demuxer_->emitFrame(isAudio);
488 : }
489 :
490 0 : MediaDecoder::MediaDecoder()
491 0 : : demuxer_(new MediaDemuxer)
492 0 : {}
493 :
494 364 : MediaDecoder::MediaDecoder(MediaObserver o)
495 364 : : demuxer_(new MediaDemuxer)
496 363 : , callback_(std::move(o))
497 364 : {}
498 :
499 374 : MediaDecoder::~MediaDecoder()
500 : {
501 : #ifdef ENABLE_HWACCEL
502 374 : if (decoderCtx_ && decoderCtx_->hw_device_ctx)
503 0 : av_buffer_unref(&decoderCtx_->hw_device_ctx);
504 : #endif
505 374 : if (decoderCtx_)
506 320 : avcodec_free_context(&decoderCtx_);
507 374 : }
508 :
509 : void
510 18 : MediaDecoder::flushBuffers()
511 : {
512 18 : avcodec_flush_buffers(decoderCtx_);
513 18 : }
514 :
515 : int
516 364 : MediaDecoder::openInput(const DeviceParams& p)
517 : {
518 364 : return demuxer_->openInput(p);
519 : }
520 :
521 : void
522 319 : MediaDecoder::setInterruptCallback(int (*cb)(void*), void* opaque)
523 : {
524 319 : demuxer_->setInterruptCallback(cb, opaque);
525 319 : }
526 :
527 : void
528 618 : MediaDecoder::setIOContext(MediaIOHandle* ioctx)
529 : {
530 618 : demuxer_->setIOContext(ioctx);
531 618 : }
532 :
533 : void
534 134 : MediaDecoder::setKeyFrameRequestCb(std::function<void()> cb)
535 : {
536 134 : demuxer_->setKeyFrameRequestCb(std::move(cb));
537 134 : }
538 :
539 : int
540 310 : MediaDecoder::setup(AVMediaType type)
541 : {
542 310 : demuxer_->findStreamInfo(type == AVMEDIA_TYPE_VIDEO);
543 310 : auto stream = demuxer_->selectStream(type);
544 310 : if (stream < 0) {
545 0 : JAMI_ERR("No stream found for type %i", static_cast<int>(type));
546 0 : return -1;
547 : }
548 310 : avStream_ = demuxer_->getStream(stream);
549 310 : if (avStream_ == nullptr) {
550 0 : JAMI_ERR("No stream found at index %i", stream);
551 0 : return -1;
552 : }
553 5410 : demuxer_->setStreamCallback(stream, [this](AVPacket& packet) { return decode(packet); });
554 310 : return setupStream();
555 : }
556 :
557 : int
558 320 : MediaDecoder::setupStream()
559 : {
560 320 : int ret = 0;
561 320 : avcodec_free_context(&decoderCtx_);
562 :
563 320 : if (prepareDecoderContext() < 0)
564 0 : return -1; // failed
565 :
566 : #ifdef ENABLE_HWACCEL
567 : // if there was a fallback to software decoding, do not enable accel
568 : // it has been disabled already by the video_receive_thread/video_input
569 320 : enableAccel_ &= Manager::instance().videoPreferences.getDecodingAccelerated();
570 :
571 320 : if (enableAccel_ and not fallback_) {
572 320 : auto APIs = video::HardwareAccel::getCompatibleAccel(decoderCtx_->codec_id,
573 320 : decoderCtx_->width,
574 320 : decoderCtx_->height,
575 320 : CODEC_DECODER);
576 727 : for (const auto& it : APIs) {
577 407 : accel_ = std::make_unique<video::HardwareAccel>(it); // save accel
578 406 : auto ret = accel_->initAPI(false, nullptr);
579 407 : if (ret < 0) {
580 407 : accel_.reset();
581 407 : continue;
582 : }
583 0 : if (prepareDecoderContext() < 0)
584 0 : return -1; // failed
585 0 : accel_->setDetails(decoderCtx_);
586 0 : decoderCtx_->opaque = accel_.get();
587 0 : decoderCtx_->pix_fmt = accel_->getFormat();
588 0 : if (avcodec_open2(decoderCtx_, inputDecoder_, &options_) < 0) {
589 : // Failed to open codec
590 0 : JAMI_WARN("Fail to open hardware decoder for %s with %s",
591 : avcodec_get_name(decoderCtx_->codec_id),
592 : it.getName().c_str());
593 0 : avcodec_free_context(&decoderCtx_);
594 0 : decoderCtx_ = nullptr;
595 0 : accel_.reset();
596 0 : continue;
597 : } else {
598 : // Codec opened successfully.
599 0 : JAMI_WARN("Using hardware decoding for %s with %s",
600 : avcodec_get_name(decoderCtx_->codec_id),
601 : it.getName().c_str());
602 0 : break;
603 : }
604 : }
605 320 : }
606 : #endif
607 :
608 1280 : JAMI_LOG("Using {} ({}) decoder for {}",
609 : inputDecoder_->long_name,
610 : inputDecoder_->name,
611 : av_get_media_type_string(avStream_->codecpar->codec_type));
612 320 : decoderCtx_->thread_count = std::max(1, std::min(8, static_cast<int>(std::thread::hardware_concurrency()) / 2));
613 320 : if (emulateRate_)
614 0 : JAMI_DBG() << "Using framerate emulation";
615 320 : startTime_ = av_gettime(); // Used to set pts after decoding, and for rate emulation
616 :
617 : #ifdef ENABLE_HWACCEL
618 320 : if (!accel_) {
619 320 : JAMI_WARN("Not using hardware decoding for %s", avcodec_get_name(decoderCtx_->codec_id));
620 320 : ret = avcodec_open2(decoderCtx_, inputDecoder_, nullptr);
621 : }
622 : #else
623 : ret = avcodec_open2(decoderCtx_, inputDecoder_, nullptr);
624 : #endif
625 320 : if (ret < 0) {
626 0 : JAMI_ERR() << "Unable to open codec: " << libav_utils::getError(ret);
627 0 : return -1;
628 : }
629 :
630 320 : return 0;
631 : }
632 :
633 : int
634 320 : MediaDecoder::prepareDecoderContext()
635 : {
636 320 : inputDecoder_ = findDecoder(avStream_->codecpar->codec_id);
637 320 : if (!inputDecoder_) {
638 0 : JAMI_ERROR("Unsupported codec");
639 0 : return -1;
640 : }
641 :
642 320 : decoderCtx_ = avcodec_alloc_context3(inputDecoder_);
643 320 : if (!decoderCtx_) {
644 0 : JAMI_ERROR("Failed to create decoder context");
645 0 : return -1;
646 : }
647 320 : avcodec_parameters_to_context(decoderCtx_, avStream_->codecpar);
648 320 : decoderCtx_->pkt_timebase = avStream_->time_base;
649 320 : width_ = decoderCtx_->width;
650 320 : height_ = decoderCtx_->height;
651 320 : decoderCtx_->framerate = avStream_->avg_frame_rate;
652 320 : if (avStream_->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
653 139 : if (decoderCtx_->framerate.num == 0 || decoderCtx_->framerate.den == 0)
654 134 : decoderCtx_->framerate = inputParams_.framerate;
655 139 : if (decoderCtx_->framerate.num == 0 || decoderCtx_->framerate.den == 0)
656 134 : decoderCtx_->framerate = {30, 1};
657 181 : } else if (avStream_->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
658 181 : if (decoderCtx_->codec_id == AV_CODEC_ID_OPUS) {
659 179 : av_opt_set_int(decoderCtx_, "decode_fec", fecEnabled_ ? 1 : 0, AV_OPT_SEARCH_CHILDREN);
660 : }
661 181 : auto format = libav_utils::choose_sample_fmt_default(
662 181 : inputDecoder_, Manager::instance().getRingBufferPool().getInternalAudioFormat().sampleFormat);
663 181 : decoderCtx_->sample_fmt = format;
664 181 : decoderCtx_->request_sample_fmt = format;
665 : }
666 320 : return 0;
667 : }
668 :
669 : void
670 52 : MediaDecoder::updateStartTime(int64_t startTime)
671 : {
672 52 : startTime_ = startTime;
673 52 : }
674 :
675 : DecodeStatus
676 5100 : MediaDecoder::decode(AVPacket& packet)
677 : {
678 5100 : int frameFinished = 0;
679 5100 : auto ret = avcodec_send_packet(decoderCtx_, &packet);
680 : // TODO: Investigate avcodec_send_packet returning AVERROR_INVALIDDATA.
681 : // * Bug Windows documented here: git.jami.net/savoirfairelinux/jami-daemon/-/issues/1116
682 : // where avcodec_send_packet returns AVERROR_INVALIDDATA when the size information in the
683 : // packet is incorrect. Falling back onto sw decoding in this causes a segfault.
684 : // * A second problem occurs on some Windows devices with intel CPUs in which hardware
685 : // decoding fails with AVERROR_INVALIDDATA when using H.264. However, in this scenario,
686 : // falling back to software decoding works fine.
687 : // We need to figure out why this behavior occurs and how to discriminate between the two.
688 5100 : if (ret < 0 && ret != AVERROR(EAGAIN)) {
689 : #ifdef ENABLE_HWACCEL
690 0 : if (accel_) {
691 0 : JAMI_WARN("Decoding error falling back to software");
692 0 : fallback_ = true;
693 0 : accel_.reset();
694 0 : avcodec_flush_buffers(decoderCtx_);
695 0 : setupStream();
696 0 : return DecodeStatus::FallBack;
697 : }
698 : #endif
699 0 : avcodec_flush_buffers(decoderCtx_);
700 0 : return ret == AVERROR_EOF ? DecodeStatus::Success : DecodeStatus::DecodeError;
701 : }
702 :
703 : #ifdef ENABLE_VIDEO
704 5100 : auto f = (inputDecoder_->type == AVMEDIA_TYPE_VIDEO)
705 5096 : ? std::static_pointer_cast<MediaFrame>(std::make_shared<VideoFrame>())
706 10200 : : std::static_pointer_cast<MediaFrame>(std::make_shared<AudioFrame>());
707 : #else
708 : auto f = std::static_pointer_cast<MediaFrame>(std::make_shared<AudioFrame>());
709 : #endif
710 5100 : auto* frame = f->pointer();
711 5100 : ret = avcodec_receive_frame(decoderCtx_, frame);
712 : // time_base is not set in AVCodecContext for decoding
713 : // fail to set it causes pts to be incorrectly computed down in the function
714 5100 : if (inputDecoder_->type == AVMEDIA_TYPE_VIDEO) {
715 5096 : decoderCtx_->time_base.num = decoderCtx_->framerate.den;
716 5096 : decoderCtx_->time_base.den = decoderCtx_->framerate.num;
717 : } else {
718 4 : decoderCtx_->time_base.num = 1;
719 4 : decoderCtx_->time_base.den = decoderCtx_->sample_rate;
720 : }
721 5100 : frame->time_base = decoderCtx_->time_base;
722 5100 : if (resolutionChangedCallback_) {
723 5096 : if (decoderCtx_->width != width_ or decoderCtx_->height != height_) {
724 0 : JAMI_DBG("Resolution changed from %dx%d to %dx%d", width_, height_, decoderCtx_->width, decoderCtx_->height);
725 0 : width_ = decoderCtx_->width;
726 0 : height_ = decoderCtx_->height;
727 0 : resolutionChangedCallback_(width_, height_);
728 : }
729 : }
730 5100 : if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
731 0 : return DecodeStatus::DecodeError;
732 : }
733 5100 : if (ret >= 0)
734 4848 : frameFinished = 1;
735 :
736 5100 : if (frameFinished) {
737 4848 : if (inputDecoder_->type == AVMEDIA_TYPE_VIDEO) {
738 4844 : frame->format = (AVPixelFormat) correctPixFmt(frame->format);
739 : } else {
740 : // It's possible (albeit rare) for avcodec_receive_frame to return a frame with
741 : // unspecified channel order. This can cause issues later on in the resampler
742 : // because swr_convert_frame expects the ch_layout of the input frame to match
743 : // the in_ch_layout of the SwrContext, but swr_init sets in_ch_layout to a default
744 : // value based on the number of channels if the channel order of the input frame
745 : // is unspecified.
746 4 : if (frame->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) {
747 4 : av_channel_layout_default(&frame->ch_layout, frame->ch_layout.nb_channels);
748 : }
749 : }
750 4848 : auto packetTimestamp = frame->pts; // in stream time base
751 4848 : frame->pts = av_rescale_q_rnd(av_gettime() - startTime_,
752 : {1, AV_TIME_BASE},
753 4848 : decoderCtx_->time_base,
754 : static_cast<AVRounding>(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
755 4848 : lastTimestamp_ = frame->pts;
756 4848 : if (emulateRate_ and packetTimestamp != AV_NOPTS_VALUE) {
757 0 : auto startTime = avStream_->start_time == AV_NOPTS_VALUE ? 0 : avStream_->start_time;
758 0 : rational<double> frame_time = rational<double>(getTimeBase())
759 0 : * rational<double>(static_cast<double>(packetTimestamp - startTime));
760 0 : auto target_relative = static_cast<std::int64_t>(frame_time.real() * 1e6);
761 0 : auto target_absolute = startTime_ + target_relative;
762 0 : if (target_relative < seekTime_) {
763 0 : return DecodeStatus::Success;
764 : }
765 : // required frame found. Reset seek time
766 0 : if (target_relative >= seekTime_) {
767 0 : resetSeekTime();
768 : }
769 0 : auto now = av_gettime();
770 0 : if (target_absolute > now) {
771 0 : std::this_thread::sleep_for(std::chrono::microseconds(target_absolute - now));
772 : }
773 : }
774 :
775 4848 : if (callback_)
776 4848 : callback_(std::move(f));
777 :
778 4848 : if (contextCallback_ && firstDecode_.load()) {
779 30 : firstDecode_.exchange(false);
780 30 : contextCallback_();
781 : }
782 4848 : return DecodeStatus::FrameFinished;
783 : }
784 252 : return DecodeStatus::Success;
785 5100 : }
786 :
787 : void
788 18 : MediaDecoder::setSeekTime(int64_t time)
789 : {
790 18 : seekTime_ = time;
791 18 : }
792 :
793 : MediaDemuxer::Status
794 5218 : MediaDecoder::decode()
795 : {
796 5218 : auto ret = demuxer_->decode();
797 5218 : if (ret == MediaDemuxer::Status::RestartRequired) {
798 0 : avcodec_flush_buffers(decoderCtx_);
799 0 : setupStream();
800 0 : ret = MediaDemuxer::Status::EndOfFile;
801 : }
802 5218 : return ret;
803 : }
804 :
805 : #ifdef ENABLE_VIDEO
806 : #ifdef ENABLE_HWACCEL
807 : void
808 0 : MediaDecoder::enableAccel(bool enableAccel)
809 : {
810 0 : enableAccel_ = enableAccel;
811 0 : emitSignal<libjami::ConfigurationSignal::HardwareDecodingChanged>(enableAccel_);
812 0 : if (!enableAccel) {
813 0 : accel_.reset();
814 0 : if (decoderCtx_)
815 0 : decoderCtx_->opaque = nullptr;
816 : }
817 0 : }
818 : #endif
819 :
820 : DecodeStatus
821 0 : MediaDecoder::flush()
822 : {
823 : AVPacket inpacket;
824 0 : av_init_packet(&inpacket);
825 :
826 0 : int frameFinished = 0;
827 0 : int ret = 0;
828 0 : ret = avcodec_send_packet(decoderCtx_, &inpacket);
829 0 : if (ret < 0 && ret != AVERROR(EAGAIN))
830 0 : return ret == AVERROR_EOF ? DecodeStatus::Success : DecodeStatus::DecodeError;
831 :
832 0 : auto result = std::make_shared<MediaFrame>();
833 0 : ret = avcodec_receive_frame(decoderCtx_, result->pointer());
834 0 : if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
835 0 : return DecodeStatus::DecodeError;
836 0 : if (ret >= 0)
837 0 : frameFinished = 1;
838 :
839 0 : if (frameFinished) {
840 0 : av_packet_unref(&inpacket);
841 0 : if (callback_)
842 0 : callback_(std::move(result));
843 0 : return DecodeStatus::FrameFinished;
844 : }
845 :
846 0 : return DecodeStatus::Success;
847 0 : }
848 : #endif // ENABLE_VIDEO
849 :
850 : int
851 144 : MediaDecoder::getWidth() const
852 : {
853 144 : return decoderCtx_ ? decoderCtx_->width : 0;
854 : }
855 :
856 : int
857 144 : MediaDecoder::getHeight() const
858 : {
859 144 : return decoderCtx_ ? decoderCtx_->height : 0;
860 : }
861 :
862 : std::string
863 0 : MediaDecoder::getDecoderName() const
864 : {
865 0 : return decoderCtx_ ? decoderCtx_->codec->name : "";
866 : }
867 :
868 : rational<double>
869 5 : MediaDecoder::getFps() const
870 : {
871 5 : return {(double) avStream_->avg_frame_rate.num, (double) avStream_->avg_frame_rate.den};
872 : }
873 :
874 : rational<unsigned>
875 0 : MediaDecoder::getTimeBase() const
876 : {
877 0 : return {(unsigned) avStream_->time_base.num, (unsigned) avStream_->time_base.den};
878 : }
879 :
880 : AVPixelFormat
881 5 : MediaDecoder::getPixelFormat() const
882 : {
883 5 : return decoderCtx_->pix_fmt;
884 : }
885 :
886 : int
887 4844 : MediaDecoder::correctPixFmt(int input_pix_fmt)
888 : {
889 : // https://ffmpeg.org/pipermail/ffmpeg-user/2014-February/020152.html
890 : int pix_fmt;
891 4844 : switch (input_pix_fmt) {
892 0 : case AV_PIX_FMT_YUVJ420P:
893 0 : pix_fmt = AV_PIX_FMT_YUV420P;
894 0 : break;
895 0 : case AV_PIX_FMT_YUVJ422P:
896 0 : pix_fmt = AV_PIX_FMT_YUV422P;
897 0 : break;
898 0 : case AV_PIX_FMT_YUVJ444P:
899 0 : pix_fmt = AV_PIX_FMT_YUV444P;
900 0 : break;
901 0 : case AV_PIX_FMT_YUVJ440P:
902 0 : pix_fmt = AV_PIX_FMT_YUV440P;
903 0 : break;
904 4844 : default:
905 4844 : pix_fmt = input_pix_fmt;
906 4844 : break;
907 : }
908 4844 : return pix_fmt;
909 : }
910 :
911 : MediaStream
912 177 : MediaDecoder::getStream(const std::string& name) const
913 : {
914 177 : if (!decoderCtx_) {
915 81 : JAMI_WARN("No decoder context");
916 81 : return {};
917 : }
918 96 : auto ms = MediaStream(name, decoderCtx_, lastTimestamp_);
919 : #ifdef ENABLE_HWACCEL
920 : // accel_ is null if not using accelerated codecs
921 96 : if (accel_)
922 8 : ms.format = accel_->getSoftwareFormat();
923 : #endif
924 96 : return ms;
925 96 : }
926 :
927 : } // namespace jami
|