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