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